blob: 805a58149f3394e37a69ba2961c597368e119387 [file] [log] [blame]
/*
* Copyright (c) 2013-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 wma.c
\brief Implementation of WMA
========================================================================*/
/**=========================================================================
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
-------- --- -----------------------------------------
12/03/2013 Ganesh Implementation of WMA APIs.
Kondabattini
27/03/2013 Ganesh Rx Management Support added
Babu
==========================================================================*/
/* ################ Header files ################ */
#include "ieee80211_common.h" /* ieee80211_frame */
#include "wma.h"
#include "wma_api.h"
#include "vos_api.h"
#include "wmi_unified_api.h"
#include "wlan_qct_sys.h"
#include "wniApi.h"
#include "aniGlobal.h"
#include "wmi_unified.h"
#include "wni_cfg.h"
#include "cfgApi.h"
#include "ol_txrx_ctrl_api.h"
#if defined(CONFIG_HL_SUPPORT)
#include "wlan_tgt_def_config_hl.h"
#else
#include "wlan_tgt_def_config.h"
#endif
#if defined(QCA_IBSS_SUPPORT)
#include "wlan_hdd_assoc.h"
#endif
#include "adf_nbuf.h"
#include "adf_os_types.h"
#include "ol_txrx_api.h"
#include "vos_memory.h"
#include "ol_txrx_types.h"
#include "ol_txrx_peer_find.h"
#include "wlan_qct_wda.h"
#include "wlan_qct_wda_msg.h"
#include "limApi.h"
#include "limSessionUtils.h"
#include "wdi_out.h"
#include "wdi_in.h"
#include "vos_cnss.h"
#include "vos_utils.h"
#include "tl_shim.h"
#if defined(QCA_WIFI_FTM)
#include "testmode.h"
#endif
#if !defined(REMOVE_PKT_LOG)
#include "pktlog_ac.h"
#endif
#include "dbglog_host.h"
/* FIXME: Inclusion of .c looks odd but this is how it is in internal codebase */
#include "wmi_version_whitelist.c"
#include "csrApi.h"
#include "ol_fw.h"
#include "dfs.h"
#include "radar_filters.h"
#include "regdomain_common.h"
#include "wma_ocb.h"
#include "wma_nan_datapath.h"
#include "adf_trace.h"
/* ################### defines ################### */
/*
* TODO: Following constant should be shared by firwmare in
* wmi_unified.h. This will be done once wmi_unified.h is updated.
*/
#define WMI_PEER_STATE_AUTHORIZED 0x2
#define WMA_2_4_GHZ_MAX_FREQ 3000
#define WOW_CSA_EVENT_OFFSET 12
/*
* In the WMI_WOW_WAKEUP_HOST_EVENTID after the fixed param
* the wmi nan event is at an offset of 12
* This is to extract and decode the NAN WMI event.
*/
#define WOW_NAN_EVENT_OFFSET 12
#define WMA_DEFAULT_SCAN_REQUESTER_ID 1
#define WMI_SCAN_FINISH_EVENTS (WMI_SCAN_EVENT_START_FAILED |\
WMI_SCAN_EVENT_COMPLETED |\
WMI_SCAN_EVENT_DEQUEUED)
/* default value */
#define DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD 20
/* pdev vdev and peer stats*/
#define FW_PDEV_STATS_SET 0x1
#define FW_VDEV_STATS_SET 0x2
#define FW_PEER_STATS_SET 0x4
#define FW_RSSI_PER_CHAIN_STATS_SET 0x8
#define FW_STATS_SET 0xf
/*AR9888/AR6320 noise floor approx value
* similar to the mentioned the TLSHIM
*/
#define WMA_TGT_NOISE_FLOOR_DBM (-96)
#define WMA_TGT_RSSI_INVALID 96
/*
* Make sure that link monitor and keep alive
* default values should be in sync with CFG.
*/
#define WMA_LINK_MONITOR_DEFAULT_TIME_SECS 10
#define WMA_KEEP_ALIVE_DEFAULT_TIME_SECS 5
#define AGC_DUMP 1
#define CHAN_DUMP 2
#define WD_DUMP 3
#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
#define PCIE_DUMP 4
#endif
/* conformance test limits */
#define FCC 0x10
#define MKK 0x40
#define ETSI 0x30
/* Maximum Buffer length allowed for DFS phyerrors */
#define DFS_MAX_BUF_LENGHT 4096
#define WMI_DEFAULT_NOISE_FLOOR_DBM (-96)
/* Threshold to print tx time taken in ms*/
#define WDA_TX_TIME_THRESHOLD 1000
#define WMI_MCC_MIN_CHANNEL_QUOTA 20
#define WMI_MCC_MAX_CHANNEL_QUOTA 80
#define WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY 30
/* The maximum number of patterns that can be transmitted by the firmware
* and maximum patterns size.
*/
#define WMA_MAXNUM_PERIODIC_TX_PTRNS 6
#define WMI_MAX_HOST_CREDITS 2
#define WMI_WOW_REQUIRED_CREDITS 1
#define WMI_MAX_MHF_ENTRIES 32
#ifdef FEATURE_WLAN_D0WOW
#define DISABLE_PCIE_POWER_COLLAPSE 1
#define ENABLE_PCIE_POWER_COLLAPSE 0
#endif
#define MAX_HT_MCS_IDX 8
#define MAX_VHT_MCS_IDX 10
#define INVALID_MCS_IDX 255
#define LINK_STATUS_LEGACY 0
#define LINK_STATUS_VHT 0x1
#define LINK_STATUS_MIMO 0x2
#define LINK_SUPPORT_VHT 0x4
#define LINK_SUPPORT_MIMO 0x8
#define LINK_RATE_VHT 0x3
#define WMA_MCC_MIRACAST_REST_TIME 400
#define WMA_LOG_COMPLETION_TIMER 10000 /* 10 seconds */
#define WMA_FW_TIME_SYNC_TIMER 60000 /* 1 min */
#define WMA_FW_TIME_STAMP_LOW_MASK 0xffffffff
#define WMI_TLV_HEADROOM 128
#define WMA_SUSPEND_TIMEOUT_IN_SSR 1
#define WMA_DEL_BSS_TIMEOUT_IN_SSR 10
#ifdef FEATURE_WLAN_SCAN_PNO
static int wma_nlo_scan_cmp_evt_handler(void *handle, u_int8_t *event,
u_int32_t len);
#endif
static enum powersave_qpower_mode wma_get_qpower_config(tp_wma_handle wma);
#ifdef FEATURE_WLAN_DIAG_SUPPORT
/**
* wma_wow_wakeup_stats_event()- send wow wakeup stats
* tp_wma_handle wma: WOW wakeup packet counter
*
* This function sends wow wakeup stats diag event
*
* Return: void.
*/
static void wma_wow_wakeup_stats_event(tp_wma_handle wma)
{
WLAN_VOS_DIAG_EVENT_DEF(WowStats,
vos_event_wlan_powersave_wow_stats);
vos_mem_zero(&WowStats, sizeof(WowStats));
WowStats.wow_ucast_wake_up_count = wma->wow_ucast_wake_up_count;
WowStats.wow_bcast_wake_up_count = wma->wow_bcast_wake_up_count;
WowStats.wow_ipv4_mcast_wake_up_count =
wma->wow_ipv4_mcast_wake_up_count;
WowStats.wow_ipv6_mcast_wake_up_count =
wma->wow_ipv6_mcast_wake_up_count;
WowStats.wow_ipv6_mcast_ra_stats = wma->wow_ipv6_mcast_ra_stats;
WowStats.wow_ipv6_mcast_ns_stats = wma->wow_ipv6_mcast_ns_stats;
WowStats.wow_ipv6_mcast_na_stats = wma->wow_ipv6_mcast_na_stats;
WowStats.wow_pno_match_wake_up_count = wma->wow_pno_match_wake_up_count;
WowStats.wow_pno_complete_wake_up_count =
wma->wow_pno_complete_wake_up_count;
WowStats.wow_gscan_wake_up_count = wma->wow_gscan_wake_up_count;
WowStats.wow_low_rssi_wake_up_count = wma->wow_low_rssi_wake_up_count;
WowStats.wow_rssi_breach_wake_up_count =
wma->wow_rssi_breach_wake_up_count;
WowStats.wow_icmpv4_count = wma->wow_icmpv4_count;
WowStats.wow_icmpv6_count = wma->wow_icmpv6_count;
WowStats.wow_oem_response_wake_up_count =
wma->wow_oem_response_wake_up_count;
WLAN_VOS_DIAG_EVENT_REPORT(&WowStats, EVENT_WLAN_POWERSAVE_WOW_STATS);
}
#else
static void wma_wow_wakeup_stats_event(tp_wma_handle wma)
{
return;
}
#endif
#ifdef FEATURE_WLAN_EXTSCAN
/**
* enum extscan_report_events_type - extscan report events type
* @EXTSCAN_REPORT_EVENTS_BUFFER_FULL: report only when scan history is % full
* @EXTSCAN_REPORT_EVENTS_EACH_SCAN: report a scan completion event after scan
* @EXTSCAN_REPORT_EVENTS_FULL_RESULTS: forward scan results
* (beacons/probe responses + IEs)
* in real time to HAL, in addition to completion events.
* Note: To keep backward compatibility,
* fire completion events regardless of REPORT_EVENTS_EACH_SCAN.
* @EXTSCAN_REPORT_EVENTS_NO_BATCH: controls batching,
* 0 => batching, 1 => no batching
*/
enum extscan_report_events_type {
EXTSCAN_REPORT_EVENTS_BUFFER_FULL = 0x00,
EXTSCAN_REPORT_EVENTS_EACH_SCAN = 0x01,
EXTSCAN_REPORT_EVENTS_FULL_RESULTS = 0x02,
EXTSCAN_REPORT_EVENTS_NO_BATCH = 0x04,
EXTSCAN_REPORT_EVENTS_CONTEXT_HUB = 0x08,
};
#define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION (5 * 1000) /* in msec */
/*
* Maximum number of entires that could be present in the
* WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware
*/
#define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10
#endif
/* Data rate 100KBPS based on IE Index */
struct index_data_rate_type
{
v_U8_t mcs_index;
v_U16_t ht20_rate[2];
v_U16_t ht40_rate[2];
};
#ifdef WLAN_FEATURE_11AC
struct index_vht_data_rate_type
{
v_U8_t mcs_index;
v_U16_t ht20_rate[2];
v_U16_t ht40_rate[2];
v_U16_t ht80_rate[2];
};
#endif
/* MCS Based rate table */
/* HT MCS parameters with Nss = 1 */
static struct index_data_rate_type mcs_nss1[] =
{
/* MCS L20 S20 L40 S40 */
{0, {65, 72}, {135, 150 }},
{1, {130, 144}, {270, 300 }},
{2, {195, 217}, {405, 450 }},
{3, {260, 289}, {540, 600 }},
{4, {390, 433}, {815, 900 }},
{5, {520, 578}, {1080, 1200}},
{6, {585, 650}, {1215, 1350}},
{7, {650, 722}, {1350, 1500}}
};
/* HT MCS parameters with Nss = 2 */
static struct index_data_rate_type mcs_nss2[] =
{
/* MCS L20 S20 L40 S40 */
{0, {130, 144}, {270, 300 }},
{1, {260, 289}, {540, 600 }},
{2, {390, 433}, {810, 900 }},
{3, {520, 578}, {1080, 1200}},
{4, {780, 867}, {1620, 1800}},
{5, {1040, 1156}, {2160, 2400}},
{6, {1170, 1300}, {2430, 2700}},
{7, {1300, 1440}, {2700, 3000}}
};
#ifdef WLAN_FEATURE_11AC
/* MCS Based VHT rate table */
/* MCS parameters with Nss = 1*/
static struct index_vht_data_rate_type vht_mcs_nss1[] =
{
/* MCS L20 S20 L40 S40 L80 S80 */
{0, {65, 72 }, {135, 150}, {293, 325} },
{1, {130, 144}, {270, 300}, {585, 650} },
{2, {195, 217}, {405, 450}, {878, 975} },
{3, {260, 289}, {540, 600}, {1170, 1300}},
{4, {390, 433}, {810, 900}, {1755, 1950}},
{5, {520, 578}, {1080, 1200}, {2340, 2600}},
{6, {585, 650}, {1215, 1350}, {2633, 2925}},
{7, {650, 722}, {1350, 1500}, {2925, 3250}},
{8, {780, 867}, {1620, 1800}, {3510, 3900}},
{9, {865, 960}, {1800, 2000}, {3900, 4333}}
};
/*MCS parameters with Nss = 2*/
static struct index_vht_data_rate_type vht_mcs_nss2[] =
{
/* MCS L20 S20 L40 S40 L80 S80 */
{0, {130, 144}, {270, 300}, { 585, 650}},
{1, {260, 289}, {540, 600}, {1170, 1300}},
{2, {390, 433}, {810, 900}, {1755, 1950}},
{3, {520, 578}, {1080, 1200}, {2340, 2600}},
{4, {780, 867}, {1620, 1800}, {3510, 3900}},
{5, {1040, 1156}, {2160, 2400}, {4680, 5200}},
{6, {1170, 1300}, {2430, 2700}, {5265, 5850}},
{7, {1300, 1444}, {2700, 3000}, {5850, 6500}},
{8, {1560, 1733}, {3240, 3600}, {7020, 7800}},
{9, {1730, 1920}, {3600, 4000}, {7800, 8667}}
};
#endif
void wma_send_msg(tp_wma_handle wma_handle, u_int16_t msg_type,
void *body_ptr, u_int32_t body_val);
#ifdef QCA_IBSS_SUPPORT
static void wma_data_tx_ack_comp_hdlr(void *wma_context,
adf_nbuf_t netbuf,
int32_t status);
#endif
static VOS_STATUS wma_vdev_detach(tp_wma_handle wma_handle,
tpDelStaSelfParams pdel_sta_self_req_param,
u_int8_t generateRsp);
static int32_t wmi_unified_vdev_stop_send(wmi_unified_t wmi, u_int8_t vdev_id);
static tANI_U32 gFwWlanFeatCaps;
static eHalStatus wma_set_ppsconfig(tANI_U8 vdev_id, tANI_U16 pps_param,
int value);
static eHalStatus wma_set_mimops(tp_wma_handle wma_handle,
tANI_U8 vdev_id, int value);
#ifdef FEATURE_WLAN_TDLS
static int wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams);
static int wma_update_tdls_peer_state(WMA_HANDLE handle,
tTdlsPeerStateParams *peerStateParams);
static int wma_set_tdls_offchan_mode(WMA_HANDLE wma_handle,
tTdlsChanSwitchParams *pChanSwitchParams);
#endif
static eHalStatus wma_set_smps_params(tp_wma_handle wma_handle,
tANI_U8 vdev_id, int value);
#if defined(QCA_WIFI_FTM)
void wma_utf_attach(tp_wma_handle wma_handle);
void wma_utf_detach(tp_wma_handle wma_handle);
static VOS_STATUS
wma_process_ftm_command(tp_wma_handle wma_handle,
struct ar6k_testmode_cmd_data *msg_buffer);
#endif
VOS_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev,
ol_txrx_vdev_handle vdev, u8 peer_addr[6],
u_int32_t peer_type, u_int8_t vdev_id,
v_BOOL_t roam_synch_in_progress);
static ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle,
tpAddStaSelfParams self_sta_req,
u_int8_t generateRsp);
static void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info);
/*DFS Attach*/
struct ieee80211com* wma_dfs_attach(struct ieee80211com *ic);
static void wma_dfs_detach(struct ieee80211com *ic);
void wma_set_bss_rate_flags(struct wma_txrx_node *iface,
tpAddBssParams add_bss);
/*Configure DFS with radar tables and regulatory domain*/
void wma_dfs_configure(struct ieee80211com *ic);
/*Configure the current channel with the DFS*/
struct ieee80211_channel *
wma_dfs_configure_channel(struct ieee80211com *dfs_ic,
wmi_channel *chan,
WLAN_PHY_MODE chanmode,
struct wma_vdev_start_req *req);
/* VDEV UP */
static int
wmi_unified_vdev_up_send(wmi_unified_t wmi,
u_int8_t vdev_id, u_int16_t aid,
u_int8_t bssid[IEEE80211_ADDR_LEN]);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
void wma_process_roam_synch_complete(WMA_HANDLE handle,
tSirSmeRoamOffloadSynchCnf *synchcnf);
void wma_process_roam_synch_fail(WMA_HANDLE handle,
tSirRoamOffloadSynchFail *synchfail);
#endif
static VOS_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle,
t_thermal_cmd_params thermal_info);
#ifdef FEATURE_WLAN_CH_AVOID
VOS_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle,
tSirChAvoidUpdateReq *ch_avoid_update_req);
#endif /* FEATURE_WLAN_CH_AVOID */
static void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info);
static void wma_beacon_miss_handler(tp_wma_handle wma, u_int32_t vdev_id,
uint32_t rssi);
static void wma_set_suspend_dtim(tp_wma_handle wma);
static void wma_set_resume_dtim(tp_wma_handle wma);
static int wma_roam_event_callback(WMA_HANDLE handle, u_int8_t *event_buf,
u_int32_t len);
static VOS_STATUS wma_stop_scan(tp_wma_handle wma_handle,
tAbortScanParams *abort_scan_req);
static void wma_set_sap_keepalive(tp_wma_handle wma, u_int8_t vdev_id);
static void wma_set_vdev_mgmt_rate(tp_wma_handle wma, u_int8_t vdev_id);
static int wma_smps_force_mode_callback(WMA_HANDLE handle, uint8_t *event_buf,
uint32_t len);
static void wma_send_time_stamp_sync_cmd(void *data);
tANI_U8 wma_getCenterChannel(tANI_U8 chan, tANI_U8 chan_offset);
/*
* 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
* 0 for no restriction
* 1 for 1/4 us - Our lower layer calculations limit our precision to 1 msec
* 2 for 1/2 us - Our lower layer calculations limit our precision to 1 msec
* 3 for 1 us
* 4 for 2 us
* 5 for 4 us
* 6 for 8 us
* 7 for 16 us
*/
static const u_int8_t wma_mpdu_spacing[] = {0, 1, 1, 1, 2, 4, 8, 16};
static inline uint8_t wma_parse_mpdudensity(u_int8_t mpdudensity)
{
if (mpdudensity < sizeof(wma_mpdu_spacing))
return wma_mpdu_spacing[mpdudensity];
else
return 0;
}
/* Function : wma_get_vdev_count
* Discription : Returns number of active vdev.
* Args : @wma - wma handle
* Returns : Returns valid vdev count.
*/
static inline u_int8_t wma_get_vdev_count(tp_wma_handle wma)
{
u_int8_t vdev_count = 0, i;
for (i = 0; i < wma->max_bssid; i++) {
if (wma->interfaces[i].handle)
vdev_count++;
}
return vdev_count;
}
/**
* wma_did_ssr_happen() - Check if SSR happened by comparing current
* wma handle and new wma handle
* @wma: Pointer to wma handle
*
* This API will compare saved wma handle and new wma handle using global
* vos context. If both doesn't match implies that WMA handle got changed
* while waiting for command which will happen in SSR.
*
* Return: True if SSR happened else false
*/
static bool wma_did_ssr_happen(tp_wma_handle wma)
{
return vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_VOSS, NULL)) != wma;
}
/* Function : wma_is_vdev_in_ap_mode
* Description : Helper function to know whether given vdev id
* is in AP mode or not.
* Args : @wma - wma handle, @ vdev_id - vdev ID.
* Returns : True - if given vdev id is in AP mode.
* False - if given vdev id is not in AP mode.
*/
static bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, u_int8_t vdev_id)
{
struct wma_txrx_node *intf = wma->interfaces;
if (vdev_id >= wma->max_bssid) {
WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id);
VOS_ASSERT(0);
return false;
}
if ((intf[vdev_id].type == WMI_VDEV_TYPE_AP) &&
((intf[vdev_id].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) ||
(intf[vdev_id].sub_type == 0)))
return true;
return false;
}
#ifdef QCA_IBSS_SUPPORT
/* Function : wma_is_vdev_in_ibss_mode
s_vdev_in_ibss_mode* Description : Helper function to know whether given vdev id
* is in IBSS mode or not.
* Args : @wma - wma handle, @ vdev_id - vdev ID.
* Retruns : True - if given vdev id is in IBSS mode.
* False - if given vdev id is not in IBSS mode.
*/
static bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, u_int8_t vdev_id)
{
struct wma_txrx_node *intf = wma->interfaces;
if (vdev_id >= wma->max_bssid) {
WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id);
VOS_ASSERT(0);
return false;
}
if (intf[vdev_id].type == WMI_VDEV_TYPE_IBSS)
return true;
return false;
}
#endif
/*
* Function : wma_find_bssid_by_vdev_id
* Description : Get the BSS ID corresponding to the vdev ID
* Args : @wma - wma handle, @vdev_id - vdev ID
* Returns : Returns pointer to bssid on success,
* otherwise returns NULL.
*/
static inline u_int8_t *wma_find_bssid_by_vdev_id(tp_wma_handle wma,
u_int8_t vdev_id)
{
if (vdev_id >= wma->max_bssid)
return NULL;
return wma->interfaces[vdev_id].bssid;
}
/*
* Function : wma_find_vdev_by_bssid
* Description : Get the VDEV ID corresponding from BSS ID
* Args : @wma - wma handle, @vdev_id - vdev ID
* Returns : Returns pointer to bssid on success,
* otherwise returns NULL.
*/
static void *wma_find_vdev_by_bssid(tp_wma_handle wma, u_int8_t *bssid,
u_int8_t *vdev_id)
{
int i;
for (i = 0; i < wma->max_bssid; i++) {
if (vos_is_macaddr_equal(
(v_MACADDR_t *)wma->interfaces[i].bssid,
(v_MACADDR_t *)bssid) == VOS_TRUE) {
*vdev_id = i;
return wma->interfaces[i].handle;
}
}
return NULL;
}
#ifdef BIG_ENDIAN_HOST
/* ############# function definitions ############ */
/* function : wma_swap_bytes
* Description :
* Args :
* Retruns :
*/
v_VOID_t wma_swap_bytes(v_VOID_t *pv, v_SIZE_t n)
{
v_SINT_t no_words;
v_SINT_t i;
v_U32_t *word_ptr;
no_words = n/sizeof(v_U32_t);
word_ptr = (v_U32_t *)pv;
for (i=0; i<no_words; i++) {
*(word_ptr + i) = __cpu_to_le32(*(word_ptr + i));
}
}
#define SWAPME(x, len) wma_swap_bytes(&x, len);
#endif
/**
* mcs_rate_match() - find the match mcs rate
* @is_sgi: return if the SGI rate is found
* @nss: the nss in use
* @nss1_rate: the nss1 rate
* @nss1_srate: the nss1 SGI rate
* @nss2_rate: the nss2 rate
* @nss2_srate: the nss2 SGI rate
*
* This is a helper function to find the match of the tx_rate
* in terms of the nss1/nss2 rate with non-SGI/SGI.
*
* Return: the found rate or 0 otherwise
*/
static inline uint16_t mcs_rate_match(uint16_t match_rate, bool *is_sgi,
uint8_t nss, uint16_t nss1_rate, uint16_t nss1_srate,
uint16_t nss2_rate, uint16_t nss2_srate)
{
if (match_rate == nss1_rate)
return nss1_rate;
else if (match_rate == nss1_srate) {
*is_sgi = true;
return nss1_srate;
} else if (nss == 2 && match_rate == nss2_rate)
return nss2_rate;
else if (nss == 2 && match_rate == nss2_srate) {
*is_sgi = true;
return nss2_srate;
} else
return 0;
}
static tANI_U8 wma_get_mcs_idx(tANI_U16 maxRate, tANI_U8 rate_flags,
tANI_U8 nss,
tANI_U8 *mcsRateFlag)
{
tANI_U8 curIdx = 0;
tANI_U16 cur_rate = 0;
bool is_sgi = false;
WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d",
__func__, maxRate,rate_flags, nss);
*mcsRateFlag = rate_flags;
*mcsRateFlag &= ~eHAL_TX_RATE_SGI;
#ifdef WLAN_FEATURE_11AC
for (curIdx = 0; curIdx < MAX_VHT_MCS_IDX; curIdx++) {
if (rate_flags & eHAL_TX_RATE_VHT80) {
/* check for vht80 nss1/2 rate set */
cur_rate = mcs_rate_match(maxRate, &is_sgi, nss,
vht_mcs_nss1[curIdx].ht80_rate[0],
vht_mcs_nss1[curIdx].ht80_rate[1],
vht_mcs_nss2[curIdx].ht80_rate[0],
vht_mcs_nss2[curIdx].ht80_rate[1]);
if (cur_rate)
goto rate_found;
}
if ((rate_flags & eHAL_TX_RATE_VHT40) |
(rate_flags & eHAL_TX_RATE_VHT80)) {
/* check for vht40 nss1/2 rate set */
cur_rate = mcs_rate_match(maxRate, &is_sgi, nss,
vht_mcs_nss1[curIdx].ht40_rate[0],
vht_mcs_nss1[curIdx].ht40_rate[1],
vht_mcs_nss2[curIdx].ht40_rate[0],
vht_mcs_nss2[curIdx].ht40_rate[1]);
if (cur_rate) {
*mcsRateFlag &= ~eHAL_TX_RATE_VHT80;
goto rate_found;
}
}
if ((rate_flags & eHAL_TX_RATE_VHT20) |
(rate_flags & eHAL_TX_RATE_VHT40) |
(rate_flags & eHAL_TX_RATE_VHT80)) {
/* check for vht20 nss1/2 rate set */
cur_rate = mcs_rate_match(maxRate, &is_sgi, nss,
vht_mcs_nss1[curIdx].ht20_rate[0],
vht_mcs_nss1[curIdx].ht20_rate[1],
vht_mcs_nss2[curIdx].ht20_rate[0],
vht_mcs_nss2[curIdx].ht20_rate[1]);
if (cur_rate) {
*mcsRateFlag &= ~(eHAL_TX_RATE_VHT80 |
eHAL_TX_RATE_VHT40);
goto rate_found;
}
}
}
#endif
for (curIdx = 0; curIdx < MAX_HT_MCS_IDX; curIdx++) {
if (rate_flags & eHAL_TX_RATE_HT40) {
/* check for ht40 nss1/2 rate set */
cur_rate = mcs_rate_match(maxRate, &is_sgi, nss,
mcs_nss1[curIdx].ht40_rate[0],
mcs_nss1[curIdx].ht40_rate[1],
mcs_nss2[curIdx].ht40_rate[0],
mcs_nss2[curIdx].ht40_rate[1]);
if (cur_rate) {
*mcsRateFlag = eHAL_TX_RATE_HT40;
goto rate_found;
}
}
if ((rate_flags & eHAL_TX_RATE_HT20) ||
(rate_flags & eHAL_TX_RATE_HT40)) {
/* check for ht20 nss1/2 rate set */
cur_rate = mcs_rate_match(maxRate, &is_sgi, nss,
mcs_nss1[curIdx].ht20_rate[0],
mcs_nss1[curIdx].ht20_rate[1],
mcs_nss2[curIdx].ht20_rate[0],
mcs_nss2[curIdx].ht20_rate[1]);
if (cur_rate) {
*mcsRateFlag = eHAL_TX_RATE_HT20;
goto rate_found;
}
}
}
rate_found:
/* set SGI flag only if this is SGI rate */
if (cur_rate && is_sgi == true)
*mcsRateFlag |= eHAL_TX_RATE_SGI;
WMA_LOGD("%s - cur_rate: %d index: %d rate_flag: 0x%x is_sgi: %d",
__func__, cur_rate, curIdx, *mcsRateFlag, is_sgi);
return (cur_rate ? curIdx : INVALID_MCS_IDX);
}
static struct wma_target_req *wma_find_vdev_req(tp_wma_handle wma,
u_int8_t vdev_id,
u_int8_t type)
{
struct wma_target_req *req_msg = NULL, *tmp;
bool found = false;
adf_os_spin_lock_bh(&wma->vdev_respq_lock);
list_for_each_entry_safe(req_msg, tmp,
&wma->vdev_resp_queue, node) {
if (req_msg->vdev_id != vdev_id)
continue;
if (req_msg->type != type)
continue;
found = true;
list_del(&req_msg->node);
break;
}
adf_os_spin_unlock_bh(&wma->vdev_respq_lock);
if (!found) {
WMA_LOGP("%s: target request not found for vdev_id %d type %d",
__func__, vdev_id, type);
return NULL;
}
WMA_LOGD("%s: target request found for vdev id: %d type %d msg %d",
__func__, vdev_id, type, req_msg->msg_type);
return req_msg;
}
/**
* wma_peek_vdev_req() - peek what request message is queued for response.
* the function does not delete the node after found
* @wma: WMA handle
* @vdev_id: vdev ID
* @type: request message type
*
* Return: the request message found
*/
static struct wma_target_req *wma_peek_vdev_req(tp_wma_handle wma,
uint8_t vdev_id,
uint8_t type)
{
struct wma_target_req *req_msg = NULL, *tmp;
bool found = false;
adf_os_spin_lock_bh(&wma->vdev_respq_lock);
list_for_each_entry_safe(req_msg, tmp, &wma->vdev_resp_queue, node) {
if (req_msg->vdev_id != vdev_id)
continue;
if (req_msg->type != type)
continue;
found = true;
break;
}
adf_os_spin_unlock_bh(&wma->vdev_respq_lock);
if (!found) {
WMA_LOGP("%s: target request not found for vdev_id %d type %d",
__func__, vdev_id, type);
return NULL;
}
WMA_LOGD("%s: target request found for vdev id: %d type %d msg %d",
__func__, vdev_id, type, req_msg->msg_type);
return req_msg;
}
/**
* wma_get_bpf_caps_event_handler() - Event handler for get bpf capability
* @handle: WMA global handle
* @cmd_param_info: command event data
* @len: Length of @cmd_param_info
*
* Return: 0 on Success or Errno on failure
*/
static int wma_get_bpf_caps_event_handler(void *handle,
u_int8_t *cmd_param_info,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *param_buf;
wmi_bpf_capability_info_evt_fixed_param *event;
struct sir_bpf_get_offload *bpf_get_offload;
tpAniSirGlobal pmac = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pmac) {
WMA_LOGE("%s: Invalid pmac", __func__);
return -EINVAL;
}
if (!pmac->sme.pbpf_get_offload_cb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *)cmd_param_info;
event = param_buf->fixed_param;
bpf_get_offload = vos_mem_malloc(sizeof(*bpf_get_offload));
if (!bpf_get_offload) {
WMA_LOGP("%s: Memory allocation failed.", __func__);
return -ENOMEM;
}
bpf_get_offload->bpf_version = event->bpf_version;
bpf_get_offload->max_bpf_filters = event->max_bpf_filters;
bpf_get_offload->max_bytes_for_bpf_inst =
event->max_bytes_for_bpf_inst;
WMA_LOGD("%s: BPF capabilities version: %d max bpf filter size: %d",
__func__, bpf_get_offload->bpf_version,
bpf_get_offload->max_bytes_for_bpf_inst);
WMA_LOGD("%s: sending bpf capabilities event to hdd", __func__);
pmac->sme.pbpf_get_offload_cb(pmac->hHdd, bpf_get_offload);
vos_mem_free(bpf_get_offload);
return 0;
}
/**
* wma_lost_link_info_handler() - collect lost link information and inform SME
* when disconnection in STA mode.
* @wma: WMA handle
* @vdev_id: vdev ID
* @rssi: rssi at disconnection time
*
* Return: none
*/
static void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id,
int8_t rssi)
{
struct sir_lost_link_info *lost_link_info;
VOS_STATUS vos_status;
vos_msg_t sme_msg = {0};
/* report lost link information only for STA mode */
if (wma->interfaces[vdev_id].vdev_up &&
(WMI_VDEV_TYPE_STA == wma->interfaces[vdev_id].type) &&
(0 == wma->interfaces[vdev_id].sub_type)) {
lost_link_info = vos_mem_malloc(sizeof(*lost_link_info));
if (NULL == lost_link_info) {
WMA_LOGE("%s: failed to allocate memory", __func__);
return;
}
lost_link_info->vdev_id = vdev_id;
lost_link_info->rssi = rssi;
sme_msg.type = eWNI_SME_LOST_LINK_INFO_IND;
sme_msg.bodyptr = lost_link_info;
sme_msg.bodyval = 0;
WMA_LOGI("%s: post msg to SME, bss_idx %d, rssi %d",
__func__,
lost_link_info->vdev_id,
lost_link_info->rssi);
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGE("%s: fail to post msg to SME",
__func__);
vos_mem_free(lost_link_info);
}
}
}
tSmpsModeValue host_map_smps_mode (A_UINT32 fw_smps_mode)
{
tSmpsModeValue smps_mode = SMPS_MODE_DISABLED;
switch (fw_smps_mode) {
case WMI_SMPS_FORCED_MODE_STATIC:
smps_mode = STATIC_SMPS_MODE;
break;
case WMI_SMPS_FORCED_MODE_DYNAMIC:
smps_mode = DYNAMIC_SMPS_MODE;
break;
default:
smps_mode = SMPS_MODE_DISABLED;
}
return smps_mode;
}
/**
* wma_smps_mode_to_force_mode_param() - Map smps mode to force
* mode commmand param
* @smps_mode: SMPS mode according to the protocol
*
* Return: int > 0 for success else failure
*/
static int wma_smps_mode_to_force_mode_param(uint8_t smps_mode)
{
int param = -EINVAL;
switch (smps_mode) {
case STATIC_SMPS_MODE:
param = WMI_SMPS_FORCED_MODE_STATIC;
break;
case DYNAMIC_SMPS_MODE:
param = WMI_SMPS_FORCED_MODE_DYNAMIC;
break;
case SMPS_MODE_DISABLED:
param = WMI_SMPS_FORCED_MODE_DISABLED;
break;
default:
WMA_LOGE(FL("smps mode cannot be mapped :%d "),
smps_mode);
}
return param;
}
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
/* function : wma_post_auto_shutdown_msg
* Description : function to post auto shutdown event to sme
*/
static int wma_post_auto_shutdown_msg(void)
{
tSirAutoShutdownEvtParams *auto_sh_evt;
VOS_STATUS vos_status;
vos_msg_t sme_msg = {0} ;
auto_sh_evt = (tSirAutoShutdownEvtParams *)
vos_mem_malloc(sizeof(tSirAutoShutdownEvtParams));
if (!auto_sh_evt) {
WMA_LOGE("%s: No Mem", __func__);
return -ENOMEM;
}
auto_sh_evt->shutdown_reason =
WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY;
sme_msg.type = eWNI_SME_AUTO_SHUTDOWN_IND;
sme_msg.bodyptr = auto_sh_evt;
sme_msg.bodyval = 0;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if ( !VOS_IS_STATUS_SUCCESS(vos_status) ) {
WMA_LOGE("Fail to post eWNI_SME_AUTO_SHUTDOWN_IND msg to SME");
vos_mem_free(auto_sh_evt);
return -EINVAL;
}
return 0;
}
/* function : wma_auto_shutdown_event_handler
* Description : function to process auto shutdown timer trigger
*/
static int wma_auto_shutdown_event_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
wmi_host_auto_shutdown_event_fixed_param *wmi_auto_sh_evt;
WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *param_buf =
(WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *)
event;
if (!param_buf || !param_buf->fixed_param) {
WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__,
__LINE__);
return -EINVAL;
}
wmi_auto_sh_evt = param_buf->fixed_param;
if (wmi_auto_sh_evt->shutdown_reason
!= WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY) {
WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__,
__LINE__);
return -EINVAL;
}
WMA_LOGD("%s:%d: Auto Shutdown Evt: %d", __func__, __LINE__,
wmi_auto_sh_evt->shutdown_reason);
return(wma_post_auto_shutdown_msg());
}
/* function : wma_set_auto_shutdown_timer_req
* Description : function sets auto shutdown timer in firmware
* Args : wma handle, auto shutdown timer value
* Returns : status of wmi cmd
*/
static VOS_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle,
tSirAutoShutdownCmdParams *auto_sh_cmd)
{
int status = 0;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_host_auto_shutdown_cfg_cmd_fixed_param *wmi_auto_sh_cmd;
int len = sizeof(wmi_host_auto_shutdown_cfg_cmd_fixed_param);
if (auto_sh_cmd == NULL) {
WMA_LOGE("%s : Invalid Autoshutdown cfg cmd", __func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("%s: Set WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID:TIMER_VAL=%d",
__func__, auto_sh_cmd->timer_val);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
wmi_auto_sh_cmd = (wmi_host_auto_shutdown_cfg_cmd_fixed_param *)buf_ptr;
wmi_auto_sh_cmd->timer_value = auto_sh_cmd->timer_val;
WMITLV_SET_HDR(&wmi_auto_sh_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_host_auto_shutdown_cfg_cmd_fixed_param));
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID);
if (status != EOK) {
WMA_LOGE("%s: WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID Err %d",
__func__, status);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#endif
static void wma_vdev_start_rsp(tp_wma_handle wma,
tpAddBssParams add_bss,
wmi_vdev_start_response_event_fixed_param *resp_event)
{
struct beacon_info *bcn;
#ifdef QCA_IBSS_SUPPORT
WMA_LOGD("%s: vdev start response received for %s mode", __func__,
add_bss->operMode == BSS_OPERATIONAL_MODE_IBSS ? "IBSS" : "non-IBSS");
#endif
if (resp_event->status) {
add_bss->status = VOS_STATUS_E_FAILURE;
goto send_fail_resp;
}
if ((add_bss->operMode == BSS_OPERATIONAL_MODE_AP)
#ifdef QCA_IBSS_SUPPORT
|| (add_bss->operMode == BSS_OPERATIONAL_MODE_IBSS)
#endif
) {
wma->interfaces[resp_event->vdev_id].beacon =
vos_mem_malloc(sizeof(struct beacon_info));
bcn = wma->interfaces[resp_event->vdev_id].beacon;
if (!bcn) {
WMA_LOGE("%s: Failed alloc memory for beacon struct",
__func__);
add_bss->status = VOS_STATUS_E_FAILURE;
goto send_fail_resp;
}
vos_mem_zero(bcn, sizeof(*bcn));
bcn->buf = adf_nbuf_alloc(NULL, WMA_BCN_BUF_MAX_SIZE, 0,
sizeof(u_int32_t), 0);
if (!bcn->buf) {
WMA_LOGE("%s: No memory allocated for beacon buffer",
__func__);
vos_mem_free(bcn);
add_bss->status = VOS_STATUS_E_FAILURE;
goto send_fail_resp;
}
bcn->seq_no = MIN_SW_SEQ;
adf_os_spinlock_init(&bcn->lock);
adf_os_atomic_set(&wma->interfaces[resp_event->vdev_id].bss_status,
WMA_BSS_STATUS_STARTED);
WMA_LOGD("%s: AP mode (type %d subtype %d) BSS is started", __func__,
wma->interfaces[resp_event->vdev_id].type,
wma->interfaces[resp_event->vdev_id].sub_type);
WMA_LOGD("%s: Allocated beacon struct %pK, template memory %pK",
__func__, bcn, bcn->buf);
}
add_bss->status = VOS_STATUS_SUCCESS;
add_bss->bssIdx = resp_event->vdev_id;
add_bss->chainMask = resp_event->chain_mask;
add_bss->smpsMode = host_map_smps_mode(resp_event->smps_mode);
send_fail_resp:
WMA_LOGD("%s: Sending add bss rsp to umac(vdev %d status %d)",
__func__, resp_event->vdev_id, add_bss->status);
wma_send_msg(wma, WDA_ADD_BSS_RSP, (void *)add_bss, 0);
}
static int wma_vdev_start_resp_handler(void *handle, u_int8_t *cmd_param_info,
u_int32_t len)
{
WMI_VDEV_START_RESP_EVENTID_param_tlvs *param_buf;
wmi_vdev_start_response_event_fixed_param *resp_event;
u_int8_t *buf;
vos_msg_t vos_msg = {0};
tp_wma_handle wma = (tp_wma_handle) handle;
ol_txrx_pdev_handle pdev = NULL;
WMA_LOGI("%s: Enter", __func__);
param_buf = (WMI_VDEV_START_RESP_EVENTID_param_tlvs *) cmd_param_info;
if (!param_buf) {
WMA_LOGE("Invalid start response event buffer");
return -EINVAL;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (pdev == NULL) {
WMA_LOGE("vdev start resp fail as pdev is NULL");
return -EINVAL;
}
resp_event = param_buf->fixed_param;
buf = vos_mem_malloc(sizeof(wmi_vdev_start_response_event_fixed_param));
if (!buf) {
WMA_LOGE("%s: Failed alloc memory for buf", __func__);
return -EINVAL;
}
if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) {
adf_os_spin_lock_bh(&wma->dfs_ic->chan_lock);
wma->dfs_ic->disable_phy_err_processing = false;
adf_os_spin_unlock_bh(&wma->dfs_ic->chan_lock);
}
if (wma->pause_other_vdev_on_mcc_start) {
WMA_LOGD("%s: unpause other vdevs since paused when MCC start", __func__);
wma->pause_other_vdev_on_mcc_start = false;
wdi_in_pdev_unpause_other_vdev(pdev,
OL_TXQ_PAUSE_REASON_MCC_VDEV_START,
resp_event->vdev_id);
}
vos_mem_zero(buf, sizeof(wmi_vdev_start_response_event_fixed_param));
vos_mem_copy(buf, (u_int8_t *)resp_event,
sizeof(wmi_vdev_start_response_event_fixed_param));
vos_msg.type = WDA_VDEV_START_RSP_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGP("%s: Failed to post WDA_VDEV_START_RSP_IND msg", __func__);
vos_mem_free(buf);
return -1;
}
WMA_LOGD("WDA_VDEV_START_RSP_IND posted");
return 0;
}
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
/**
* wma_find_mcc_ap() - finds if device is operating AP in MCC mode or not
* @wma: wma handle.
* @vdev_id: vdev ID of device for which MCC has to be checked
* @add: flag indicating if current device is added or deleted
*
* This function parses through all the interfaces in wma and finds if
* any of those devces are in MCC mode with AP. If such a vdev is found
* involved AP vdevs are sent WDA_UPDATE_Q2Q_IE_IND msg to update their
* beacon template to include Q2Q IE.
*
* Return: void
*/
void wma_find_mcc_ap(tp_wma_handle wma,
uint8_t vdev_id,
bool add)
{
uint8_t i;
uint16_t prev_ch_freq = 0;
bool is_ap = false;
bool result = false;
uint8_t * ap_vdev_ids = NULL;
uint8_t num_ch = 0;
ap_vdev_ids = vos_mem_malloc(wma->max_bssid);
if (!ap_vdev_ids) {
return;
}
for(i = 0; i < wma->max_bssid; i++) {
ap_vdev_ids[i] = -1;
if( add == false && i == vdev_id)
continue;
if( wma->interfaces[i].vdev_up || (i == vdev_id && add) ) {
if(wma->interfaces[i].type == WMI_VDEV_TYPE_AP) {
is_ap = true;
ap_vdev_ids[i] = i;
}
if(wma->interfaces[i].mhz != prev_ch_freq) {
num_ch++;
prev_ch_freq = wma->interfaces[i].mhz;
}
}
}
if( is_ap && (num_ch > 1) )
result = true;
else
result = false;
wma_send_msg(wma, WDA_UPDATE_Q2Q_IE_IND, (void*)ap_vdev_ids, result);
}
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
static const wmi_channel_width mode_to_width[MODE_MAX] =
{
[MODE_11A] = WMI_CHAN_WIDTH_20,
[MODE_11G] = WMI_CHAN_WIDTH_20,
[MODE_11B] = WMI_CHAN_WIDTH_20,
[MODE_11GONLY] = WMI_CHAN_WIDTH_20,
[MODE_11NA_HT20] = WMI_CHAN_WIDTH_20,
[MODE_11NG_HT20] = WMI_CHAN_WIDTH_20,
[MODE_11AC_VHT20] = WMI_CHAN_WIDTH_20,
[MODE_11AC_VHT20_2G] = WMI_CHAN_WIDTH_20,
[MODE_11NA_HT40] = WMI_CHAN_WIDTH_40,
[MODE_11NG_HT40] = WMI_CHAN_WIDTH_40,
[MODE_11AC_VHT40] = WMI_CHAN_WIDTH_40,
[MODE_11AC_VHT40_2G] = WMI_CHAN_WIDTH_40,
[MODE_11AC_VHT80] = WMI_CHAN_WIDTH_80,
#if CONFIG_160MHZ_SUPPORT
[MODE_11AC_VHT80_80] = WMI_CHAN_WIDTH_80P80,
[MODE_11AC_VHT160] = WMI_CHAN_WIDTH_160,
#endif
};
/**
* chanmode_to_chanwidth() - get channel width through channel mode
* @chanmode: channel phy mode
*
* Return: channel width
*/
static wmi_channel_width chanmode_to_chanwidth(WLAN_PHY_MODE chanmode)
{
wmi_channel_width chan_width;
if (chanmode >= MODE_11A && chanmode < MODE_MAX)
chan_width = mode_to_width[chanmode];
else
chan_width = WMI_CHAN_WIDTH_20;
return chan_width;
}
static int wma_vdev_start_rsp_ind(tp_wma_handle wma, u_int8_t *buf)
{
struct wma_target_req *req_msg;
struct wma_txrx_node *iface;
int err;
wmi_channel_width chanwidth;
wmi_vdev_start_response_event_fixed_param *resp_event;
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == mac_ctx) {
WMA_LOGE("%s: Failed to get mac_ctx", __func__);
return -EINVAL;
}
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
resp_event = (wmi_vdev_start_response_event_fixed_param *)buf;
if (!resp_event) {
WMA_LOGE("Invalid start response event buffer");
return -EINVAL;
}
if (resp_event->vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: received invalid vdev_id %d",
__func__, resp_event->vdev_id);
return -EINVAL;
}
iface = &wma->interfaces[resp_event->vdev_id];
if ((resp_event->vdev_id < wma->max_bssid) &&
(adf_os_atomic_read(
&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) &&
(wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == true)) {
WMA_LOGE(
"%s: vdev restart event recevied for hidden ssid set using IOCTL",
__func__);
if (wmi_unified_vdev_up_send(wma->wmi_handle, resp_event->vdev_id, 0,
wma->interfaces[resp_event->vdev_id].bssid) < 0) {
WMA_LOGE("%s : failed to send vdev up", __func__);
return -EEXIST;
}
adf_os_atomic_set(
&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress, 0);
wma->interfaces[resp_event->vdev_id].vdev_up = TRUE;
/*
* Unpause TX queue in SAP case while configuring hidden ssid
* enable or disable, else the data path is paused forever
* causing data packets(starting from DHCP offer) to get stuck
*/
wdi_in_vdev_unpause(iface->handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST);
}
req_msg = wma_find_vdev_req(wma, resp_event->vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_START);
if (!req_msg) {
WMA_LOGE("%s: Failed to lookup request message for vdev %d",
__func__, resp_event->vdev_id);
return -EINVAL;
}
vos_timer_stop(&req_msg->event_timeout);
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
if (resp_event->status == VOS_STATUS_SUCCESS
&& mac_ctx->sap.sap_channel_avoidance)
wma_find_mcc_ap(wma, resp_event->vdev_id, true);
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
if (req_msg->msg_type == WDA_CHNL_SWITCH_REQ) {
tpSwitchChannelParams params =
(tpSwitchChannelParams) req_msg->user_data;
if(!params) {
WMA_LOGE("%s: channel switch params is NULL for vdev %d",
__func__, resp_event->vdev_id);
return -EINVAL;
}
WMA_LOGD("%s: Send channel switch resp vdev %d status %d",
__func__, resp_event->vdev_id, resp_event->status);
params->chainMask = resp_event->chain_mask;
params->smpsMode = host_map_smps_mode(resp_event->smps_mode);
params->status = resp_event->status;
if (wma->interfaces[resp_event->vdev_id].is_channel_switch)
wma->interfaces[resp_event->vdev_id].is_channel_switch =
VOS_FALSE;
if (((resp_event->resp_type == WMI_VDEV_RESTART_RESP_EVENT) &&
(iface->type == WMI_VDEV_TYPE_STA)) ||
((resp_event->resp_type == WMI_VDEV_START_RESP_EVENT) &&
(iface->type == WMI_VDEV_TYPE_MONITOR))) {
err = wma_set_peer_param(wma, iface->bssid,
WMI_PEER_PHYMODE, iface->chanmode,
resp_event->vdev_id);
WMA_LOGD("%s:vdev_id %d chanmode %d status %d",
__func__, resp_event->vdev_id,
iface->chanmode, err);
chanwidth = chanmode_to_chanwidth(iface->chanmode);
err = wma_set_peer_param(wma, iface->bssid,
WMI_PEER_CHWIDTH, chanwidth,
resp_event->vdev_id);
WMA_LOGD("%s:vdev_id %d chanwidth %d status %d",
__func__, resp_event->vdev_id,
chanwidth, err);
if (wmi_unified_vdev_up_send(wma->wmi_handle,
resp_event->vdev_id, iface->aid,
iface->bssid)) {
WMA_LOGE("%s:vdev_up failed vdev_id %d",
__func__, resp_event->vdev_id);
wma->interfaces[resp_event->vdev_id].vdev_up =
FALSE;
} else {
wma->interfaces[resp_event->vdev_id].vdev_up =
TRUE;
}
}
wma_send_msg(wma, WDA_SWITCH_CHANNEL_RSP, (void *)params, 0);
} else if (req_msg->msg_type == WDA_ADD_BSS_REQ) {
tpAddBssParams bssParams = (tpAddBssParams) req_msg->user_data;
vos_mem_copy(iface->bssid, bssParams->bssId, ETH_ALEN);
wma_vdev_start_rsp(wma, bssParams, resp_event);
} else if (req_msg->msg_type == WDA_OCB_SET_CONFIG_CMD) {
if (wmi_unified_vdev_up_send(wma->wmi_handle,
resp_event->vdev_id, iface->aid,
iface->bssid) < 0) {
WMA_LOGE(FL("failed to send vdev up"));
return -EEXIST;
}
iface->vdev_up = TRUE;
wma_ocb_start_resp_ind_cont(wma);
}
if ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) &&
wma->interfaces[resp_event->vdev_id].vdev_up)
wma_set_sap_keepalive(wma, resp_event->vdev_id);
vos_timer_destroy(&req_msg->event_timeout);
adf_os_mem_free(req_msg);
return 0;
}
#define BIG_ENDIAN_MAX_DEBUG_BUF 500
/* function : wma_unified_debug_print_event_handler
* Description :
* Args :
* Returns :
*/
static int wma_unified_debug_print_event_handler(void *handle, u_int8_t *datap,
u_int32_t len)
{
WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf;
u_int8_t *data;
u_int32_t datalen;
param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *)datap;
if (!param_buf) {
WMA_LOGE("Get NULL point message from FW");
return -ENOMEM;
}
data = param_buf->data;
datalen = param_buf->num_data;
#ifdef BIG_ENDIAN_HOST
{
if (datalen > BIG_ENDIAN_MAX_DEBUG_BUF) {
WMA_LOGE("%s Invalid data len %d, limiting to max",
__func__, datalen);
datalen = BIG_ENDIAN_MAX_DEBUG_BUF;
}
char dbgbuf[BIG_ENDIAN_MAX_DEBUG_BUF] = { 0 };
memcpy(dbgbuf, data, datalen);
SWAPME(dbgbuf, datalen);
WMA_LOGD("FIRMWARE:%s", dbgbuf);
return 0;
}
#else
WMA_LOGD("FIRMWARE:%s", data);
return 0;
#endif
}
int wmi_unified_vdev_set_param_send(wmi_unified_t wmi_handle, u_int32_t if_id,
u_int32_t param_id, u_int32_t param_value)
{
int ret;
wmi_vdev_set_param_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int16_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_vdev_set_param_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_set_param_cmd_fixed_param));
cmd->vdev_id = if_id;
cmd->param_id = param_id;
cmd->param_value = param_value;
WMA_LOGD("Setting vdev %d param = %x, value = %u",
if_id, param_id, param_value);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_VDEV_SET_PARAM_CMDID);
if (ret < 0) {
WMA_LOGE("Failed to send set param command ret = %d", ret);
wmi_buf_free(buf);
}
return ret;
}
VOS_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle,
A_INT32 first_bcnt,
A_UINT32 final_bcnt,
u_int32_t vdev_id)
{
int status = 0;
WMA_LOGI("%s: first_bcnt=%d, final_bcnt=%d", __func__,
first_bcnt, final_bcnt);
status = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
vdev_id,
WMI_VDEV_PARAM_BMISS_FIRST_BCNT,
first_bcnt);
if (status != EOK) {
WMA_LOGE("wmi_unified_vdev_set_param_send"
"WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d",status);
return VOS_STATUS_E_FAILURE;
}
status = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
vdev_id,
WMI_VDEV_PARAM_BMISS_FINAL_BCNT,
final_bcnt);
if (status != EOK) {
WMA_LOGE("wmi_unified_vdev_set_param_send"
"WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d",status);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
static v_VOID_t wma_set_default_tgt_config(tp_wma_handle wma_handle)
{
struct ol_softc *scn;
u_int8_t no_of_peers_supported;
wmi_resource_config tgt_cfg = {
0, /* Filling zero for TLV Tag and Length fields */
CFG_TGT_NUM_VDEV,
CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2,
CFG_TGT_NUM_OFFLOAD_PEERS,
CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS,
CFG_TGT_NUM_PEER_KEYS,
CFG_TGT_NUM_TIDS,
CFG_TGT_AST_SKID_LIMIT,
CFG_TGT_DEFAULT_TX_CHAIN_MASK,
CFG_TGT_DEFAULT_RX_CHAIN_MASK,
{ CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_HI_PRI },
CFG_TGT_RX_DECAP_MODE,
CFG_TGT_DEFAULT_SCAN_MAX_REQS,
CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV,
CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV,
CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES,
CFG_TGT_DEFAULT_NUM_MCAST_GROUPS,
CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS,
CFG_TGT_DEFAULT_MCAST2UCAST_MODE,
CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE,
CFG_TGT_WDS_ENTRIES,
CFG_TGT_DEFAULT_DMA_BURST_SIZE,
CFG_TGT_DEFAULT_MAC_AGGR_DELIM,
CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK,
CFG_TGT_DEFAULT_VOW_CONFIG,
CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV,
CFG_TGT_NUM_MSDU_DESC,
CFG_TGT_MAX_FRAG_TABLE_ENTRIES,
CFG_TGT_NUM_TDLS_VDEVS,
CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES,
CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV,
CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES,
0,
0,
0,
CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS,
CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS,
0,
CFG_TGT_NUM_OCB_VDEVS,
CFG_TGT_NUM_OCB_CHANNELS,
CFG_TGT_NUM_OCB_SCHEDULES,
};
/* Update the max number of peers */
scn = vos_get_context(VOS_MODULE_ID_HIF, wma_handle->vos_context);
if (!scn) {
WMA_LOGE("%s: vos_context is NULL", __func__);
return;
}
no_of_peers_supported = ol_get_number_of_peers_supported(scn);
tgt_cfg.num_peers = no_of_peers_supported + CFG_TGT_NUM_VDEV + 2;
#if defined(CONFIG_HL_SUPPORT)
tgt_cfg.num_tids = 4 * no_of_peers_supported;
#else
tgt_cfg.num_tids = (2 * (no_of_peers_supported + CFG_TGT_NUM_VDEV + 2));
#endif
WMITLV_SET_HDR(&tgt_cfg.tlv_header,WMITLV_TAG_STRUC_wmi_resource_config,
WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config));
/* reduce the peer/vdev if CFG_TGT_NUM_MSDU_DESC exceeds 1000 */
#ifdef PERE_IP_HDR_ALIGNMENT_WAR
if (scn->host_80211_enable) {
/*
* To make the IP header begins at dword aligned address,
* we make the decapsulation mode as Native Wifi.
*/
tgt_cfg.rx_decap_mode = CFG_TGT_RX_DECAP_MODE_NWIFI;
}
#endif
if (VOS_MONITOR_MODE == vos_get_conparam())
tgt_cfg.rx_decap_mode = CFG_TGT_RX_DECAP_MODE_RAW;
wma_handle->wlan_resource_config = tgt_cfg;
}
static int32_t wmi_unified_peer_delete_send(wmi_unified_t wmi,
u_int8_t peer_addr[IEEE80211_ADDR_LEN],
u_int8_t vdev_id)
{
wmi_peer_delete_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wmi, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_peer_delete_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_peer_delete_cmd_fixed_param));
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
cmd->vdev_id = vdev_id;
if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_DELETE_CMDID)) {
WMA_LOGP("%s: Failed to send peer delete command", __func__);
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id);
return 0;
}
static int32_t wmi_unified_peer_flush_tids_send(wmi_unified_t wmi,
u_int8_t peer_addr
[IEEE80211_ADDR_LEN],
u_int32_t peer_tid_bitmap,
u_int8_t vdev_id)
{
wmi_peer_flush_tids_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wmi, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_peer_flush_tids_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_peer_flush_tids_cmd_fixed_param));
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
cmd->peer_tid_bitmap = peer_tid_bitmap;
cmd->vdev_id = vdev_id;
if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_FLUSH_TIDS_CMDID)) {
WMA_LOGP("%s: Failed to send flush tid command", __func__);
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id);
return 0;
}
void wma_remove_peer(tp_wma_handle wma, u_int8_t *bssid,
u_int8_t vdev_id, ol_txrx_peer_handle peer,
v_BOOL_t roam_synch_in_progress)
{
#define PEER_ALL_TID_BITMASK 0xffffffff
u_int32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK;
u_int8_t *peer_addr = bssid;
if (!wma->interfaces[vdev_id].peer_count)
{
WMA_LOGE("%s: Can't remove peer with peer_addr %pM vdevid %d peer_count %d",
__func__, bssid, vdev_id, wma->interfaces[vdev_id].peer_count);
return;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (roam_synch_in_progress) {
WMA_LOGE("%s:LFR3:Removing peer with addr %pM vdevid %d peer_cnt %d",
__func__, bssid, vdev_id, wma->interfaces[vdev_id].peer_count);
goto peer_detach;
} else {
WMA_LOGI("%s: Removing peer with addr %pM vdevid %d peer_count %d",
__func__, bssid, vdev_id, wma->interfaces[vdev_id].peer_count);
}
#endif
/* Flush all TIDs except MGMT TID for this peer in Target */
peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID);
wmi_unified_peer_flush_tids_send(wma->wmi_handle, bssid,
peer_tid_bitmap, vdev_id);
#if defined(QCA_IBSS_SUPPORT)
if ((peer) && (wma_is_vdev_in_ibss_mode(wma, vdev_id))) {
WMA_LOGD("%s: bssid %pM peer->mac_addr %pM", __func__,
bssid, peer->mac_addr.raw);
peer_addr = peer->mac_addr.raw;
}
#endif
wmi_unified_peer_delete_send(wma->wmi_handle, peer_addr, vdev_id);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
peer_detach:
#endif
if (peer)
ol_txrx_peer_detach(peer);
wma->interfaces[vdev_id].peer_count--;
#undef PEER_ALL_TID_BITMASK
}
static int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *param_buf = NULL;
wmi_peer_sta_kickout_event_fixed_param *kickout_event = NULL;
u_int8_t vdev_id, peer_id, macaddr[IEEE80211_ADDR_LEN];
ol_txrx_peer_handle peer;
ol_txrx_pdev_handle pdev;
tpDeleteStaContext del_sta_ctx;
tpSirIbssPeerInactivityInd p_inactivity;
WMA_LOGD("%s: Enter", __func__);
param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) event;
kickout_event = param_buf->fixed_param;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (!pdev) {
WMA_LOGE("%s: pdev is NULL", __func__);
return -EINVAL;
}
WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, macaddr);
peer = ol_txrx_find_peer_by_addr(pdev, macaddr, &peer_id);
if (!peer) {
WMA_LOGE("PEER [%pM] not found", macaddr);
return -EINVAL;
}
if (tl_shim_get_vdevid(peer, &vdev_id) != VOS_STATUS_SUCCESS) {
WMA_LOGE("Not able to find BSSID for peer [%pM]", macaddr);
return -EINVAL;
}
WMA_LOGA("%s: PEER:[%pM], ADDR:[%pN], INTERFACE:%d, peer_id:%d, reason:%d",
__func__, macaddr,
wma->interfaces[vdev_id].addr, vdev_id,
peer_id, kickout_event->reason);
switch (kickout_event->reason) {
case WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT:
p_inactivity = (tpSirIbssPeerInactivityInd)
vos_mem_malloc(sizeof(tSirIbssPeerInactivityInd));
if (!p_inactivity) {
WMA_LOGE("VOS MEM Alloc Failed for tSirIbssPeerInactivity");
return -EINVAL;
}
p_inactivity->staIdx = peer_id;
vos_mem_copy(p_inactivity->peerAddr, macaddr, IEEE80211_ADDR_LEN);
wma_send_msg(wma, WDA_IBSS_PEER_INACTIVITY_IND, (void *)p_inactivity, 0);
goto exit_handler;
break;
#ifdef FEATURE_WLAN_TDLS
case WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT:
del_sta_ctx =
(tpDeleteStaContext)vos_mem_malloc(sizeof(tDeleteStaContext));
if (!del_sta_ctx) {
WMA_LOGE("%s: mem alloc failed for tDeleteStaContext for TDLS peer: %pM",
__func__, macaddr);
return -EINVAL;
}
del_sta_ctx->is_tdls = true;
del_sta_ctx->vdev_id = vdev_id;
del_sta_ctx->staId = peer_id;
vos_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN);
vos_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].bssid,
IEEE80211_ADDR_LEN);
del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE;
wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, (void *)del_sta_ctx,
0);
goto exit_handler;
break;
#endif /* FEATURE_WLAN_TDLS */
case WMI_PEER_STA_KICKOUT_REASON_XRETRY:
if(wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA &&
(wma->interfaces[vdev_id].sub_type == 0 ||
wma->interfaces[vdev_id].sub_type ==
WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) &&
vos_mem_compare(wma->interfaces[vdev_id].bssid,
macaddr, ETH_ALEN)) {
/*
* KICKOUT event is for current station-AP connection.
* Treat it like final beacon miss. Station may not have
* missed beacons but not able to transmit frames to AP
* for a long time. Must disconnect to get out of
* this sticky situation.
* In future implementation, roaming module will also
* handle this event and perform a scan.
*/
WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_XRETRY event for STA",
__func__);
wma_beacon_miss_handler(wma, vdev_id, kickout_event->rssi);
goto exit_handler;
}
break;
case WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED:
/*
* Default legacy value used by original firmware implementation.
*/
if(wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA &&
(wma->interfaces[vdev_id].sub_type == 0 ||
wma->interfaces[vdev_id].sub_type ==
WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) &&
vos_mem_compare(wma->interfaces[vdev_id].bssid,
macaddr, ETH_ALEN)) {
/*
* KICKOUT event is for current station-AP connection.
* Treat it like final beacon miss. Station may not have
* missed beacons but not able to transmit frames to AP
* for a long time. Must disconnect to get out of
* this sticky situation.
* In future implementation, roaming module will also
* handle this event and perform a scan.
*/
WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED event for STA",
__func__);
wma_beacon_miss_handler(wma, vdev_id, kickout_event->rssi);
goto exit_handler;
}
break;
case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY:
/* This could be for STA or SAP role */
default:
break;
}
/*
* default action is to send delete station context indication to LIM
*/
del_sta_ctx = (tpDeleteStaContext)vos_mem_malloc(sizeof(tDeleteStaContext));
if (!del_sta_ctx) {
WMA_LOGE("VOS MEM Alloc Failed for tDeleteStaContext");
return -EINVAL;
}
del_sta_ctx->is_tdls = false;
del_sta_ctx->vdev_id = vdev_id;
del_sta_ctx->staId = peer_id;
vos_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN);
vos_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].addr,
IEEE80211_ADDR_LEN);
del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE;
del_sta_ctx->rssi = kickout_event->rssi + WMA_TGT_NOISE_FLOOR_DBM;
wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, (void *)del_sta_ctx, 0);
wma_lost_link_info_handler(wma, vdev_id, kickout_event->rssi +
WMA_TGT_NOISE_FLOOR_DBM);
exit_handler:
WMA_LOGD("%s: Exit", __func__);
return 0;
}
static int wmi_unified_vdev_down_send(wmi_unified_t wmi, u_int8_t vdev_id)
{
wmi_vdev_down_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wmi, len);
if (!buf) {
WMA_LOGP("%s : wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_vdev_down_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_down_cmd_fixed_param));
cmd->vdev_id = vdev_id;
if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_DOWN_CMDID)) {
WMA_LOGP("%s: Failed to send vdev down", __func__);
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("%s: vdev_id %d", __func__, vdev_id);
return 0;
}
#ifdef QCA_IBSS_SUPPORT
static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id)
{
ol_txrx_vdev_handle vdev;
ol_txrx_peer_handle peer, temp;
if (!wma || vdev_id >= wma->max_bssid)
return;
vdev = wma->interfaces[vdev_id].handle;
if (!vdev)
return;
/* remove all remote peers of IBSS */
adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex);
temp = NULL;
TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, peer_list_elem) {
if (temp) {
adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex);
if (adf_os_atomic_read(&temp->delete_in_progress) == 0){
wma_remove_peer(wma, temp->mac_addr.raw,
vdev_id, temp, VOS_FALSE);
}
adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex);
}
/* self peer is deleted last */
if (peer == TAILQ_FIRST(&vdev->peer_list)) {
WMA_LOGE("%s: self peer removed by caller ", __func__);
break;
} else
temp = peer;
}
adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex);
/* remove IBSS bss peer last */
peer = TAILQ_FIRST(&vdev->peer_list);
wma_remove_peer(wma, wma->interfaces[vdev_id].bssid, vdev_id, peer,
VOS_FALSE);
}
#endif //#ifdef QCA_IBSS_SUPPORT
static void wma_delete_all_ap_remote_peers(tp_wma_handle wma, A_UINT32 vdev_id)
{
ol_txrx_vdev_handle vdev;
ol_txrx_peer_handle peer, temp;
if (!wma || vdev_id >= wma->max_bssid)
return;
vdev = wma->interfaces[vdev_id].handle;
if (!vdev)
return;
WMA_LOGE("%s: vdev_id - %d", __func__, vdev_id);
/* remove all remote peers of SAP */
adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex);
temp = NULL;
TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, peer_list_elem) {
if (temp) {
adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex);
if (adf_os_atomic_read(&temp->delete_in_progress) == 0){
wma_remove_peer(wma, temp->mac_addr.raw,
vdev_id, temp, VOS_FALSE);
}
adf_os_spin_lock_bh(&vdev->pdev->peer_ref_mutex);
}
/* self peer is deleted by caller */
if (peer == TAILQ_FIRST(&vdev->peer_list)){
WMA_LOGE("%s: self peer removed by caller ", __func__);
break;
} else
temp = peer;
}
adf_os_spin_unlock_bh(&vdev->pdev->peer_ref_mutex);
}
static int wma_vdev_stop_resp_handler(void *handle, u_int8_t *cmd_param_info,
u32 len)
{
WMI_VDEV_STOPPED_EVENTID_param_tlvs *param_buf;
wmi_vdev_stopped_event_fixed_param *event;
u_int8_t *buf;
vos_msg_t vos_msg = {0};
WMA_LOGI("%s: Enter", __func__);
param_buf = (WMI_VDEV_STOPPED_EVENTID_param_tlvs *) cmd_param_info;
if (!param_buf) {
WMA_LOGE("Invalid event buffer");
return -EINVAL;
}
event = param_buf->fixed_param;
buf = vos_mem_malloc(sizeof(wmi_vdev_stopped_event_fixed_param));
if (!buf) {
WMA_LOGE("%s: Failed alloc memory for buf", __func__);
return -EINVAL;
}
vos_mem_zero(buf, sizeof(wmi_vdev_stopped_event_fixed_param));
vos_mem_copy(buf, (u_int8_t *)event,
sizeof(wmi_vdev_stopped_event_fixed_param));
vos_msg.type = WDA_VDEV_STOP_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGP("%s: Failed to post WDA_VDEV_STOP_IND msg", __func__);
vos_mem_free(buf);
return -1;
}
WMA_LOGD("WDA_VDEV_STOP_IND posted");
return 0;
}
void wma_hidden_ssid_vdev_restart_on_vdev_stop(tp_wma_handle wma_handle, u_int8_t sessionId)
{
wmi_vdev_start_request_cmd_fixed_param *cmd;
wmi_buf_t buf;
wmi_channel *chan;
int32_t len;
u_int8_t *buf_ptr;
struct wma_txrx_node *intr = wma_handle->interfaces;
int32_t ret=0;
WLAN_PHY_MODE chanmode;
tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma_handle->vos_context);
if (!mac_ctx) {
WMA_LOGE("%s: Failed to get mac_ctx", __func__);
return;
}
len = sizeof(*cmd) + sizeof(wmi_channel) +
WMI_TLV_HDR_SIZE;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
adf_os_atomic_set(&intr[sessionId].vdev_restart_params.hidden_ssid_restart_in_progress,0);
return;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_vdev_start_request_cmd_fixed_param *) buf_ptr;
chan = (wmi_channel *) (buf_ptr + sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_start_request_cmd_fixed_param));
WMITLV_SET_HDR(&chan->tlv_header,
WMITLV_TAG_STRUC_wmi_channel,
WMITLV_GET_STRUCT_TLVLEN(wmi_channel));
cmd->vdev_id = sessionId;
cmd->ssid.ssid_len = intr[sessionId].vdev_restart_params.ssid.ssid_len;
vos_mem_copy(cmd->ssid.ssid,
intr[sessionId].vdev_restart_params.ssid.ssid,
cmd->ssid.ssid_len);
cmd->flags = intr[sessionId].vdev_restart_params.flags;
if (intr[sessionId].vdev_restart_params.ssidHidden)
cmd->flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID;
else
cmd->flags &= (0xFFFFFFFE);
cmd->requestor_id = intr[sessionId].vdev_restart_params.requestor_id;
cmd->disable_hw_ack = intr[sessionId].vdev_restart_params.disable_hw_ack;
chan->mhz = intr[sessionId].vdev_restart_params.chan.mhz;
chan->band_center_freq1 = intr[sessionId].vdev_restart_params.chan.band_center_freq1;
chan->band_center_freq2 = intr[sessionId].vdev_restart_params.chan.band_center_freq2;
chan->info = intr[sessionId].vdev_restart_params.chan.info;
chan->reg_info_1 = intr[sessionId].vdev_restart_params.chan.reg_info_1;
chan->reg_info_2 = intr[sessionId].vdev_restart_params.chan.reg_info_2;
if (chan->band_center_freq1 == 0) {
chan->band_center_freq1 = chan->mhz;
chanmode = intr[sessionId].chanmode;
if (chanmode == MODE_11AC_VHT80)
chan->band_center_freq1 = vos_chan_to_freq(
wma_getCenterChannel(
chan->mhz,
mac_ctx->roam.configParam.channelBondingMode5GHz));
if ((chanmode == MODE_11NA_HT40) ||
(chanmode == MODE_11AC_VHT40)) {
if (mac_ctx->roam.configParam.channelBondingMode5GHz ==
PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
chan->band_center_freq1 += 10;
else
chan->band_center_freq1 -= 10;
}
if ((chanmode == MODE_11NG_HT40) ||
(chanmode == MODE_11AC_VHT40_2G)) {
if (mac_ctx->roam.configParam.channelBondingMode24GHz ==
PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
chan->band_center_freq1 += 10;
else
chan->band_center_freq1 -= 10;
}
}
cmd->num_noa_descriptors = 0;
buf_ptr = (u_int8_t *)(((u_int8_t *) cmd) + sizeof(*cmd) +
sizeof(wmi_channel));
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
cmd->num_noa_descriptors *
sizeof(wmi_p2p_noa_descriptor));
ret = wmi_unified_cmd_send(wma_handle->wmi_handle,buf,len,
WMI_VDEV_RESTART_REQUEST_CMDID);
if (ret < 0) {
WMA_LOGE("%s: Failed to send vdev restart command", __func__);
adf_os_atomic_set(&intr[sessionId].vdev_restart_params.hidden_ssid_restart_in_progress,0);
wmi_buf_free(buf);
}
}
static int wma_vdev_stop_ind(tp_wma_handle wma, u_int8_t *buf)
{
wmi_vdev_stopped_event_fixed_param *resp_event;
struct wma_target_req *req_msg;
ol_txrx_peer_handle peer;
ol_txrx_pdev_handle pdev;
u_int8_t peer_id;
struct wma_txrx_node *iface;
int32_t status = 0;
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == mac_ctx) {
WMA_LOGE("%s: Failed to get mac_ctx", __func__);
return -EINVAL;
}
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
WMA_LOGI("%s: Enter", __func__);
if (!buf) {
WMA_LOGE("Invalid event buffer");
return -EINVAL;
}
resp_event = (wmi_vdev_stopped_event_fixed_param *)buf;
if ((resp_event->vdev_id < wma->max_bssid) &&
(adf_os_atomic_read(&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) &&
((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) &&
(wma->interfaces[resp_event->vdev_id].sub_type == 0))) {
WMA_LOGE("%s: vdev stop event recevied for hidden ssid set using IOCTL ", __func__);
req_msg = wma_fill_vdev_req(wma, resp_event->vdev_id,
WDA_HIDDEN_SSID_VDEV_RESTART,
WMA_TARGET_REQ_TYPE_VDEV_START, resp_event,
WMA_VDEV_START_REQUEST_TIMEOUT);
if (!req_msg) {
WMA_LOGE("%s: Failed to fill vdev request, vdev_id %d",
__func__, resp_event->vdev_id);
return -EINVAL;
}
wma_hidden_ssid_vdev_restart_on_vdev_stop(wma, resp_event->vdev_id);
}
req_msg = wma_find_vdev_req(wma, resp_event->vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_STOP);
if (!req_msg) {
WMA_LOGP("%s: Failed to lookup vdev request for vdev id %d",
__func__, resp_event->vdev_id);
return -EINVAL;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (!pdev) {
WMA_LOGE("%s: pdev is NULL", __func__);
status = -EINVAL;
vos_timer_stop(&req_msg->event_timeout);
goto free_req_msg;
}
vos_timer_stop(&req_msg->event_timeout);
if (req_msg->msg_type == WDA_DELETE_BSS_REQ) {
tpDeleteBssParams params =
(tpDeleteBssParams)req_msg->user_data;
struct beacon_info *bcn;
if (resp_event->vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %d", __func__,
resp_event->vdev_id);
vos_mem_free(params);
status = -EINVAL;
goto free_req_msg;
}
iface = &wma->interfaces[resp_event->vdev_id];
if (iface->handle == NULL) {
WMA_LOGE("%s vdev id %d is already deleted",
__func__, resp_event->vdev_id);
vos_mem_free(params);
status = -EINVAL;
goto free_req_msg;
}
/* Clear arp and ns offload cache */
vos_mem_zero(&iface->ns_offload_req,
sizeof(iface->ns_offload_req));
vos_mem_zero(&iface->arp_offload_req,
sizeof(iface->arp_offload_req));
#ifdef QCA_IBSS_SUPPORT
if ( wma_is_vdev_in_ibss_mode(wma, resp_event->vdev_id))
wma_delete_all_ibss_peers(wma, resp_event->vdev_id);
else
#endif
if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces,
resp_event->vdev_id)) {
wma_delete_all_nan_remote_peers(wma,
resp_event->vdev_id);
} else {
if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id))
{
wma_delete_all_ap_remote_peers(wma, resp_event->vdev_id);
}
peer = ol_txrx_find_peer_by_addr(pdev, params->bssid,
&peer_id);
if (!peer)
WMA_LOGD("%s Failed to find peer %pM",
__func__, params->bssid);
wma_remove_peer(wma, params->bssid, resp_event->vdev_id,
peer, VOS_FALSE);
}
if (wmi_unified_vdev_down_send(wma->wmi_handle, resp_event->vdev_id) < 0) {
WMA_LOGE("Failed to send vdev down cmd: vdev %d",
resp_event->vdev_id);
} else {
wma->interfaces[resp_event->vdev_id].vdev_up = FALSE;
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
if (mac_ctx->sap.sap_channel_avoidance)
wma_find_mcc_ap(wma,
resp_event->vdev_id,
false);
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
}
ol_txrx_vdev_flush(iface->handle);
WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp",
__func__, resp_event->vdev_id);
wdi_in_vdev_unpause(iface->handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST);
adf_os_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED);
WMA_LOGD("%s: (type %d subtype %d) BSS is stopped",
__func__, iface->type, iface->sub_type);
bcn = wma->interfaces[resp_event->vdev_id].beacon;
if (bcn) {
WMA_LOGD("%s: Freeing beacon struct %pK, "
"template memory %pK", __func__,
bcn, bcn->buf);
if (bcn->dma_mapped)
adf_nbuf_unmap_single(pdev->osdev, bcn->buf,
ADF_OS_DMA_TO_DEVICE);
adf_nbuf_free(bcn->buf);
vos_mem_free(bcn);
wma->interfaces[resp_event->vdev_id].beacon = NULL;
}
/* Timeout status means its WMA generated DEL BSS REQ when ADD
BSS REQ was timed out to stop the VDEV in this case no need to
send response to UMAC */
if (params->status == eHAL_STATUS_FW_MSG_TIMEDOUT){
vos_mem_free(params);
WMA_LOGE("%s: DEL BSS from ADD BSS timeout do not send "
"resp to UMAC (vdev id %x)",
__func__, resp_event->vdev_id);
} else {
params->status = VOS_STATUS_SUCCESS;
wma_send_msg(wma, WDA_DELETE_BSS_RSP, (void *)params, 0);
}
if (iface->del_staself_req) {
WMA_LOGA("scheduling defered deletion (vdev id %x)",
resp_event->vdev_id);
wma_vdev_detach(wma, iface->del_staself_req, 1);
}
}
free_req_msg:
vos_timer_destroy(&req_msg->event_timeout);
adf_os_mem_free(req_msg);
return status;
}
#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
static void wma_send_status_of_ext_wow(tp_wma_handle wma, boolean status)
{
tSirReadyToExtWoWInd *ready_to_extwow;
VOS_STATUS vstatus;
vos_msg_t vos_msg;
u_int8_t len;
WMA_LOGD("Posting ready to suspend indication to umac");
len = sizeof(tSirReadyToExtWoWInd);
ready_to_extwow = (tSirReadyToExtWoWInd *) vos_mem_malloc(len);
if (NULL == ready_to_extwow) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return;
}
ready_to_extwow->mesgType = eWNI_SME_READY_TO_EXTWOW_IND;
ready_to_extwow->mesgLen = len;
ready_to_extwow->status= status;
vos_msg.type = eWNI_SME_READY_TO_EXTWOW_IND;
vos_msg.bodyptr = (void *) ready_to_extwow;
vos_msg.bodyval = 0;
vstatus = vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg);
if (vstatus != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to post ready to suspend");
vos_mem_free(ready_to_extwow);
}
}
static int wma_enable_ext_wow(tp_wma_handle wma,
tpSirExtWoWParams params)
{
wmi_extwow_enable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(wmi_extwow_enable_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_extwow_enable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extwow_enable_cmd_fixed_param));
cmd->vdev_id = params->vdev_id;
cmd->type = params->type;
cmd->wakeup_pin_num = params->wakeup_pin_num;
WMA_LOGD("%s: vdev_id %d type %d Wakeup_pin_num %x",
__func__, cmd->vdev_id,
cmd->type, cmd->wakeup_pin_num);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_EXTWOW_ENABLE_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to set EXTWOW Enable", __func__);
wmi_buf_free(buf);
wma_send_status_of_ext_wow(wma, FALSE);
return VOS_STATUS_E_FAILURE;
}
wma_send_status_of_ext_wow(wma, TRUE);
return VOS_STATUS_SUCCESS;
}
static int wma_set_app_type1_params_in_fw(tp_wma_handle wma,
tpSirAppType1Params appType1Params)
{
wmi_extwow_set_app_type1_params_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(wmi_extwow_set_app_type1_params_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_extwow_set_app_type1_params_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extwow_set_app_type1_params_cmd_fixed_param));
cmd->vdev_id = appType1Params->vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(appType1Params->wakee_mac_addr,
&cmd->wakee_mac);
vos_mem_copy(cmd->ident, appType1Params->identification_id, 8);
cmd->ident_len = appType1Params->id_length;
vos_mem_copy(cmd->passwd, appType1Params->password, 16);
cmd->passwd_len = appType1Params->pass_length;
WMA_LOGD("%s: vdev_id %d wakee_mac_addr %pM "
"identification_id %.8s id_length %u "
"password %.16s pass_length %u",
__func__, cmd->vdev_id, appType1Params->wakee_mac_addr,
cmd->ident, cmd->ident_len,
cmd->passwd, cmd->passwd_len);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
static int wma_set_app_type2_params_in_fw(tp_wma_handle wma,
tpSirAppType2Params appType2Params)
{
wmi_extwow_set_app_type2_params_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(wmi_extwow_set_app_type2_params_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_extwow_set_app_type2_params_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extwow_set_app_type2_params_cmd_fixed_param));
cmd->vdev_id = appType2Params->vdev_id;
vos_mem_copy(cmd->rc4_key, appType2Params->rc4_key, 16);
cmd->rc4_key_len = appType2Params->rc4_key_len;
cmd->ip_id = appType2Params->ip_id;
cmd->ip_device_ip = appType2Params->ip_device_ip;
cmd->ip_server_ip = appType2Params->ip_server_ip;
cmd->tcp_src_port = appType2Params->tcp_src_port;
cmd->tcp_dst_port = appType2Params->tcp_dst_port;
cmd->tcp_seq = appType2Params->tcp_seq;
cmd->tcp_ack_seq = appType2Params->tcp_ack_seq;
cmd->keepalive_init = appType2Params->keepalive_init;
cmd->keepalive_min = appType2Params->keepalive_min;
cmd->keepalive_max = appType2Params->keepalive_max;
cmd->keepalive_inc = appType2Params->keepalive_inc;
WMI_CHAR_ARRAY_TO_MAC_ADDR(appType2Params->gateway_mac,
&cmd->gateway_mac);
cmd->tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val;
cmd->tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val;
WMA_LOGD("%s: vdev_id %d gateway_mac %pM "
"rc4_key %.16s rc4_key_len %u "
"ip_id %x ip_device_ip %x ip_server_ip %x "
"tcp_src_port %u tcp_dst_port %u tcp_seq %u "
"tcp_ack_seq %u keepalive_init %u keepalive_min %u "
"keepalive_max %u keepalive_inc %u "
"tcp_tx_timeout_val %u tcp_rx_timeout_val %u",
__func__, cmd->vdev_id, appType2Params->gateway_mac,
cmd->rc4_key, cmd->rc4_key_len,
cmd->ip_id, cmd->ip_device_ip, cmd->ip_server_ip,
cmd->tcp_src_port, cmd->tcp_dst_port, cmd->tcp_seq,
cmd->tcp_ack_seq, cmd->keepalive_init, cmd->keepalive_min,
cmd->keepalive_max, cmd->keepalive_inc,
cmd->tcp_tx_timeout_val, cmd->tcp_rx_timeout_val);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to set APP TYPE2 PARAMS", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#endif
static void wma_update_pdev_stats(tp_wma_handle wma,
wmi_pdev_stats *pdev_stats)
{
tAniGetPEStatsRsp *stats_rsp_params;
tANI_U32 temp_mask;
tANI_U8 *stats_buf;
tCsrGlobalClassAStatsInfo *classa_stats = NULL;
struct wma_txrx_node *node;
u_int8_t i;
for (i = 0; i < wma->max_bssid; i++) {
node = &wma->interfaces[i];
stats_rsp_params = node->stats_rsp;
if (stats_rsp_params) {
node->fw_stats_set |= FW_PDEV_STATS_SET;
WMA_LOGD("<---FW PDEV STATS received for vdevId:%d",
i);
stats_buf = (tANI_U8 *) (stats_rsp_params + 1);
temp_mask = stats_rsp_params->statsMask;
if (temp_mask & (1 << eCsrSummaryStats))
stats_buf += sizeof(tCsrSummaryStatsInfo);
if (temp_mask & (1 << eCsrGlobalClassAStats)) {
classa_stats =
(tCsrGlobalClassAStatsInfo *) stats_buf;
classa_stats->max_pwr = pdev_stats->chan_tx_pwr;
}
}
}
}
/**
* wma_vdev_stats_lost_link_helper() - helper function to extract
* lost link information from vdev statistics event while deleting BSS.
* @wma: WMA handle
* @vdev_stats: statistics information from firmware
*
* This is for informing HDD to collect lost link information while
* disconnection. Following conditions to check
* 1. vdev is up
* 2. bssid is zero. When handling DELETE_BSS request message, it sets bssid to
* zero, hence add the check here to indicate the event comes during deleting
* BSS
* 3. DELETE_BSS is the request message queued. Put this condition check on the
* last one as it consumes more resource searching entries in the list
*
* Return: none
*/
static void wma_vdev_stats_lost_link_helper(tp_wma_handle wma,
wmi_vdev_stats *vdev_stats)
{
struct wma_txrx_node *node;
int8_t rssi;
struct wma_target_req *req_msg;
uint8_t zero_mac[ETH_ALEN] = {0};
int8_t bcn_snr, dat_snr;
node = &wma->interfaces[vdev_stats->vdev_id];
if (node->vdev_up &&
vos_mem_compare(node->bssid, zero_mac, ETH_ALEN)) {
req_msg = wma_peek_vdev_req(wma, vdev_stats->vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_STOP);
if ((NULL == req_msg) ||
(WDA_DELETE_BSS_REQ != req_msg->msg_type)) {
WMA_LOGD("%s: cannot find DELETE_BSS request message",
__func__);
return;
}
bcn_snr = vdev_stats->vdev_snr.bcn_snr;
dat_snr = vdev_stats->vdev_snr.dat_snr;
WMA_LOGD("%s: get vdev id %d, beancon snr %d, data snr %d",
__func__, vdev_stats->vdev_id, bcn_snr, dat_snr);
if ((bcn_snr != WMA_TGT_INVALID_SNR_OLD) &&
(bcn_snr != WMA_TGT_INVALID_SNR_NEW))
rssi = bcn_snr;
else if ((dat_snr != WMA_TGT_INVALID_SNR_OLD) &&
(dat_snr != WMA_TGT_INVALID_SNR_NEW))
rssi = dat_snr;
else
rssi = WMA_TGT_INVALID_SNR_OLD;
/* Get the absolute rssi value from the current rssi value */
rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
wma_lost_link_info_handler(wma, vdev_stats->vdev_id, rssi);
}
}
static void wma_update_vdev_stats(tp_wma_handle wma,
wmi_vdev_stats *vdev_stats)
{
tAniGetPEStatsRsp *stats_rsp_params;
tCsrSummaryStatsInfo *summary_stats = NULL;
tANI_U8 *stats_buf;
struct wma_txrx_node *node;
tANI_U8 i;
v_S7_t rssi = 0;
VOS_STATUS vos_status;
tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq*)wma->pGetRssiReq;
vos_msg_t sme_msg = {0};
int8_t bcn_snr, dat_snr;
node = &wma->interfaces[vdev_stats->vdev_id];
stats_rsp_params = node->stats_rsp;
if (stats_rsp_params) {
stats_buf = (tANI_U8 *) (stats_rsp_params + 1);
node->fw_stats_set |= FW_VDEV_STATS_SET;
WMA_LOGD("<---FW VDEV STATS received for vdevId:%d",
vdev_stats->vdev_id);
if (stats_rsp_params->statsMask &
(1 << eCsrSummaryStats)) {
summary_stats = (tCsrSummaryStatsInfo *) stats_buf;
for (i=0 ; i < 4 ; i++) {
summary_stats->tx_frm_cnt[i] =
vdev_stats->tx_frm_cnt[i];
summary_stats->fail_cnt[i] =
vdev_stats->fail_cnt[i];
summary_stats->multiple_retry_cnt[i] =
vdev_stats->multiple_retry_cnt[i];
}
summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt;
summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt;
summary_stats->rx_discard_cnt =
vdev_stats->rx_discard_cnt;
summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt;
summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt;
summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt;
}
}
bcn_snr = vdev_stats->vdev_snr.bcn_snr;
dat_snr = vdev_stats->vdev_snr.dat_snr;
WMA_LOGD("vdev id %d beancon snr %d data snr %d",
vdev_stats->vdev_id, bcn_snr, dat_snr);
if (pGetRssiReq &&
pGetRssiReq->sessionId == vdev_stats->vdev_id) {
if ((bcn_snr == WMA_TGT_INVALID_SNR_OLD ||
bcn_snr == WMA_TGT_INVALID_SNR_NEW) &&
(dat_snr == WMA_TGT_INVALID_SNR_OLD ||
dat_snr == WMA_TGT_INVALID_SNR_NEW)) {
/*
* Firmware sends invalid snr till it sees
* Beacon/Data after connection since after
* vdev up fw resets the snr to invalid.
* In this duartion Host will return the last know
* rssi during connection.
*/
rssi = wma->first_rssi;
} else {
if (bcn_snr != WMA_TGT_INVALID_SNR_OLD &&
bcn_snr != WMA_TGT_INVALID_SNR_NEW) {
rssi = bcn_snr;
} else if (dat_snr != WMA_TGT_INVALID_SNR_OLD &&
dat_snr != WMA_TGT_INVALID_SNR_NEW) {
rssi = dat_snr;
}
/*
* Get the absolute rssi value from the current rssi value
* the sinr value is hardcoded into 0 in the core stack
*/
rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM;
}
WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi,
pGetRssiReq->sessionId);
/* update the average rssi value to UMAC layer */
if (NULL != pGetRssiReq->rssiCallback) {
((tCsrRssiCallback)(pGetRssiReq->rssiCallback))(rssi,pGetRssiReq->staId,
pGetRssiReq->pDevContext);
}
adf_os_mem_free(pGetRssiReq);
wma->pGetRssiReq = NULL;
}
if (node->psnr_req) {
tAniGetSnrReq *p_snr_req = node->psnr_req;
if ((bcn_snr != WMA_TGT_INVALID_SNR_OLD) &&
(bcn_snr != WMA_TGT_INVALID_SNR_NEW))
p_snr_req->snr = bcn_snr;
else if ((dat_snr != WMA_TGT_INVALID_SNR_OLD) &&
(dat_snr != WMA_TGT_INVALID_SNR_NEW))
p_snr_req->snr = dat_snr;
else
p_snr_req->snr = WMA_TGT_INVALID_SNR_OLD;
sme_msg.type = eWNI_SME_SNR_IND;
sme_msg.bodyptr = p_snr_req;
sme_msg.bodyval = 0;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGE("%s: Fail to post snr ind msg", __func__);
vos_mem_free(p_snr_req);
}
node->psnr_req = NULL;
}
wma_vdev_stats_lost_link_helper(wma, vdev_stats);
}
static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node)
{
tAniGetPEStatsRsp *stats_rsp_params;
stats_rsp_params = node->stats_rsp;
/* send response to UMAC*/
wma_send_msg(wma, WDA_GET_STATISTICS_RSP, (void *)stats_rsp_params, 0) ;
node->stats_rsp = NULL;
node->fw_stats_set = 0;
}
static void wma_update_peer_stats(tp_wma_handle wma, wmi_peer_stats *peer_stats)
{
tAniGetPEStatsRsp *stats_rsp_params;
tCsrGlobalClassAStatsInfo *classa_stats = NULL;
struct wma_txrx_node *node;
tANI_U8 *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags;
tANI_U32 temp_mask;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]);
if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id))
return;
node = &wma->interfaces[vdev_id];
if (node->stats_rsp) {
node->fw_stats_set |= FW_PEER_STATS_SET;
WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id);
stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
stats_buf = (tANI_U8 *) (stats_rsp_params + 1);
temp_mask = stats_rsp_params->statsMask;
if (temp_mask & (1 << eCsrSummaryStats))
stats_buf += sizeof(tCsrSummaryStatsInfo);
if (temp_mask & (1 << eCsrGlobalClassAStats)) {
classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf;
WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate);
/*The linkspeed returned by fw is in kbps so convert
*it in to units of 500kbps which is expected by UMAC*/
if (peer_stats->peer_tx_rate) {
classa_stats->tx_rate =
peer_stats->peer_tx_rate/500;
}
classa_stats->tx_rate_flags = node->rate_flags;
if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) {
classa_stats->mcs_index =
wma_get_mcs_idx((peer_stats->peer_tx_rate/100),
node->rate_flags,
node->nss,
&mcsRateFlags);
/* rx_frag_cnt and promiscuous_rx_frag_cnt
* parameter is currently not used. lets use the
* same parameter to hold the nss value and mcs
* rate flags */
classa_stats->rx_frag_cnt = node->nss;
classa_stats->promiscuous_rx_frag_cnt = mcsRateFlags;
}
/* FW returns tx power in intervals of 0.5 dBm
Convert it back to intervals of 1 dBm */
classa_stats->max_pwr =
roundup(classa_stats->max_pwr, 2) >> 1;
}
}
}
static void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus,
u_int8_t link_status)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
vos_msg_t sme_msg = {0} ;
pGetLinkStatus->linkStatus = link_status;
sme_msg.type = eWNI_SME_LINK_STATUS_IND;
sme_msg.bodyptr = pGetLinkStatus;
sme_msg.bodyval = 0;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGE("%s: Fail to post link status ind msg", __func__);
vos_mem_free(pGetLinkStatus);
}
}
/**
* wma_update_per_chain_rssi_stats() - to store per chain rssi stats for
* all vdevs for which the stats were requested into csr stats structure.
* @wma: wma handle
* @rssi_stats: rssi stats
* @rssi_per_chain_stats: buffer where rssi stats to be stored
*
* This function stores per chain rssi stats received from fw for all vdevs for
* which the stats were requested into a csr stats structure.
*
* Return: void
*/
static void wma_update_per_chain_rssi_stats(tp_wma_handle wma,
wmi_rssi_stats *rssi_stats,
struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats)
{
int i;
int8_t bcn_snr, dat_snr;
for (i = 0; i < NUM_CHAINS_MAX; i++) {
bcn_snr = rssi_stats->rssi_avg_beacon[i];
dat_snr = rssi_stats->rssi_avg_data[i];
WMA_LOGD("chain %d beacon snr %d data snr %d",
i, bcn_snr, dat_snr);
if ((dat_snr != WMA_TGT_INVALID_SNR_OLD &&
dat_snr != WMA_TGT_INVALID_SNR_NEW))
rssi_per_chain_stats->rssi[i] = dat_snr;
else if ((bcn_snr != WMA_TGT_INVALID_SNR_OLD &&
bcn_snr != WMA_TGT_INVALID_SNR_NEW))
rssi_per_chain_stats->rssi[i] = bcn_snr;
else
/*
* Firmware sends invalid snr till it sees
* Beacon/Data after connection since after
* vdev up fw resets the snr to invalid.
* In this duartion Host will return an invalid rssi
* value.
*/
rssi_per_chain_stats->rssi[i] = WMA_TGT_RSSI_INVALID;
/*
* Get the absolute rssi value from the current rssi value the
* sinr value is hardcoded into 0 in the CORE stack
*/
rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr),
rssi_per_chain_stats->peer_mac_addr);
}
}
/**
* wma_update_rssi_stats() - to update rssi stats for all vdevs
* for which the stats were requested.
* @wma: wma handle
* @rssi_stats: rssi stats
*
* This function updates the rssi stats for all vdevs for which
* the stats were requested.
*
* Return: void
*/
static void wma_update_rssi_stats(tp_wma_handle wma,
wmi_rssi_stats *rssi_stats)
{
tAniGetPEStatsRsp *stats_rsp_params;
struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL;
struct wma_txrx_node *node;
uint8_t *stats_buf;
uint32_t temp_mask;
uint8_t vdev_id;
vdev_id = rssi_stats->vdev_id;
node = &wma->interfaces[vdev_id];
if (node->stats_rsp) {
node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET;
WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d",
vdev_id);
stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp;
stats_buf = (tANI_U8 *) (stats_rsp_params + 1);
temp_mask = stats_rsp_params->statsMask;
if (temp_mask & (1 << eCsrSummaryStats))
stats_buf += sizeof(tCsrSummaryStatsInfo);
if (temp_mask & (1 << eCsrGlobalClassAStats))
stats_buf += sizeof(tCsrGlobalClassAStatsInfo);
if (temp_mask & (1 << eCsrGlobalClassBStats))
stats_buf += sizeof(tCsrGlobalClassBStatsInfo);
if (temp_mask & (1 << eCsrGlobalClassCStats))
stats_buf += sizeof(tCsrGlobalClassCStatsInfo);
if (temp_mask & (1 << eCsrGlobalClassDStats))
stats_buf += sizeof(tCsrGlobalClassDStatsInfo);
if (temp_mask & (1 << eCsrPerStaStats))
stats_buf += sizeof(tCsrPerStaStatsInfo);
if (temp_mask & (1 << csr_per_chain_rssi_stats)) {
rssi_per_chain_stats =
(struct csr_per_chain_rssi_stats_info *)stats_buf;
wma_update_per_chain_rssi_stats(wma, rssi_stats,
rssi_per_chain_stats);
}
}
}
static int wma_link_status_rsp(tp_wma_handle wma, u_int8_t *buf)
{
wmi_vdev_rate_stats_event_fixed_param *event;
wmi_vdev_rate_ht_info *ht_info;
struct wma_txrx_node *intr = wma->interfaces;
u_int8_t link_status = LINK_STATUS_LEGACY;
int i;
event = (wmi_vdev_rate_stats_event_fixed_param *)buf;
ht_info = (wmi_vdev_rate_ht_info *)(buf + sizeof(*event));
WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats);
for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) {
WMA_LOGD(
"%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d",
__func__,
ht_info->vdevid,
ht_info->tx_nss,
ht_info->rx_nss,
ht_info->tx_preamble,
ht_info->rx_preamble);
if (ht_info->vdevid < wma->max_bssid &&
intr[ht_info->vdevid].plink_status_req) {
if (ht_info->tx_nss || ht_info->rx_nss)
link_status = LINK_STATUS_MIMO;
if ((ht_info->tx_preamble == LINK_RATE_VHT) ||
(ht_info->rx_preamble == LINK_RATE_VHT))
link_status |= LINK_STATUS_VHT;
if (intr[ht_info->vdevid].nss == 2)
link_status |= LINK_SUPPORT_MIMO;
if (intr[ht_info->vdevid].rate_flags &
(eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 |
eHAL_TX_RATE_VHT80))
link_status |= LINK_SUPPORT_VHT;
wma_post_link_status(intr[ht_info->vdevid].plink_status_req,
link_status);
intr[ht_info->vdevid].plink_status_req = NULL;
link_status = LINK_STATUS_LEGACY;
}
ht_info++;
}
return 0;
}
static int wma_link_status_event_handler(void *handle, u_int8_t *cmd_param_info,
u_int32_t len)
{
WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf;
wmi_vdev_rate_stats_event_fixed_param *event;
vos_msg_t vos_msg = {0};
u_int32_t buf_size;
u_int8_t *buf;
param_buf =
(WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *)cmd_param_info;
if (!param_buf) {
WMA_LOGA("%s: Invalid stats event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
if (event->num_vdev_stats > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*event)) / sizeof(wmi_vdev_rate_ht_info))) {
WMA_LOGE("%s: excess vdev_stats buffers:%d", __func__,
event->num_vdev_stats);
VOS_ASSERT(0);
return -EINVAL;
}
buf_size = sizeof(wmi_vdev_rate_stats_event_fixed_param) +
sizeof(wmi_vdev_rate_ht_info) * event->num_vdev_stats;
buf = vos_mem_malloc(buf_size);
if (!buf) {
WMA_LOGE("%s: Failed alloc memory for buf", __func__);
return -ENOMEM;
}
vos_mem_zero(buf, buf_size);
vos_mem_copy(buf, param_buf->fixed_param,
sizeof(wmi_vdev_rate_stats_event_fixed_param));
vos_mem_copy((buf + sizeof(wmi_vdev_rate_stats_event_fixed_param)),
param_buf->ht_info,
sizeof(wmi_vdev_rate_ht_info) * event->num_vdev_stats);
vos_msg.type = WDA_GET_LINK_STATUS_RSP_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGP("%s: Failed to post WDA_GET_LINK_STATUS_RSP_IND msg",
__func__);
vos_mem_free(buf);
return -1;
}
WMA_LOGD("posted WDA_GET_LINK_STATUS_RSP_IND");
return 0;
}
/**
* wma_update_mib_stats() - send mib stats to hdd
* @wma_handle: pointer to wma handle.
* @event: mib stats
*
* This API handles the requested Mib stats and calls the callback to
* update hdd
*
* Return: Success or error code
*/
static int wma_update_mib_stats(tp_wma_handle wma_handle ,
wmi_mib_stats *event)
{
struct mib_stats_metrics mib_stats;
tpAniSirGlobal mac = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma_handle->vos_context);
if (!mac) {
WMA_LOGE("%s: Invalid mac context", __func__);
return -EINVAL;
}
if (!mac->sme.csr_mib_stats_callback) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
mib_stats.mib_counters.tx_frags =
event->tx_mpdu_grp_frag_cnt;
mib_stats.mib_counters.group_tx_frames =
event->tx_msdu_grp_frm_cnt;
mib_stats.mib_counters.failed_cnt = event->tx_msdu_fail_cnt;
mib_stats.mib_counters.rx_frags = event->rx_mpdu_frag_cnt;
mib_stats.mib_counters.group_rx_frames =
event->rx_msdu_grp_frm_cnt;
mib_stats.mib_counters.fcs_error_cnt =
event->rx_mpdu_fcs_err;
mib_stats.mib_counters.tx_frames =
event->tx_msdu_frm_cnt;
mib_stats.mib_mac_statistics.retry_cnt =
event->tx_msdu_retry_cnt;
mib_stats.mib_mac_statistics.frame_dup_cnt =
event->rx_frm_dup_cnt;
mib_stats.mib_mac_statistics.rts_success_cnt =
event->tx_rts_success_cnt;
mib_stats.mib_mac_statistics.rts_fail_cnt =
event->tx_rts_fail_cnt;
mib_stats.mib_qos_counters.qos_tx_frag_cnt =
event->tx_Qos_mpdu_grp_frag_cnt;
mib_stats.mib_qos_counters.qos_retry_cnt =
event->tx_Qos_msdu_retry_UP;
mib_stats.mib_qos_counters.qos_failed_cnt = event->tx_Qos_msdu_fail_UP;
mib_stats.mib_qos_counters.qos_frame_dup_cnt =
event->rx_Qos_frm_dup_cnt_UP;
mib_stats.mib_qos_counters.qos_rts_success_cnt =
event->tx_Qos_rts_success_cnt_UP;
mib_stats.mib_qos_counters.qos_rts_fail_cnt =
event->tx_Qos_rts_fail_cnt_UP;
mib_stats.mib_qos_counters.qos_rx_frag_cnt =
event->rx_Qos_mpdu_frag_cnt_UP;
mib_stats.mib_qos_counters.qos_tx_frame_cnt =
event->tx_Qos_msdu_frm_cnt_UP;
mib_stats.mib_qos_counters.qos_discarded_frame_cnt =
event->rx_Qos_msdu_discard_cnt_UP;
mib_stats.mib_qos_counters.qos_mpdu_rx_cnt =
event->rx_Qos_mpdu_cnt;
mib_stats.mib_qos_counters.qos_retries_rx_cnt =
event->rx_Qos_mpdu_retryBit_cnt;
mib_stats.mib_rsna_stats.cmac_icv_err =
event->rsna_Mgmt_discard_CCMP_replay_err_cnt;
mib_stats.mib_rsna_stats.tkip_icv_err = event->rsna_TKIP_icv_err_cnt;
mib_stats.mib_rsna_stats.tkip_replays = event->rsna_TKIP_replay_err_cnt;
mib_stats.mib_rsna_stats.ccmp_decrypt_err =
event->rsna_CCMP_decrypt_err_cnt;
mib_stats.mib_counters_group3.tx_ampdu_cnt =
event->tx_ampdu_cnt;
mib_stats.mib_counters_group3.tx_mpdus_in_ampdu_cnt =
event->tx_mpdu_cnt_in_ampdu;
mib_stats.mib_counters_group3.tx_octets_in_ampdu_cnt =
event->tx_octets_in_ampdu.upload.high;
mib_stats.mib_counters_group3.tx_octets_in_ampdu_cnt =
mib_stats.mib_counters_group3.tx_octets_in_ampdu_cnt << 32;
mib_stats.mib_counters_group3.tx_octets_in_ampdu_cnt +=
event->tx_octets_in_ampdu.upload.low;
mib_stats.mib_counters_group3.ampdu_rx_cnt =
event->rx_ampdu_cnt;
mib_stats.mib_counters_group3.mpdu_in_rx_ampdu_cnt =
event->rx_mpdu_cnt_in_ampdu;
mib_stats.mib_counters_group3.rx_octets_in_ampdu_cnt =
event->rx_octets_in_ampdu.upload.rx_octets_in_ampdu_high;
mib_stats.mib_counters_group3.rx_octets_in_ampdu_cnt =
mib_stats.mib_counters_group3.rx_octets_in_ampdu_cnt << 32;
mib_stats.mib_counters_group3.rx_octets_in_ampdu_cnt +=
event->rx_octets_in_ampdu.upload.rx_octets_in_ampdu_low;
/* ccmp replays attack count will be updated
* by host
*/
mib_stats.mib_rsna_stats.ccmp_replays =
wma_handle->ccmp_replays_attack_cnt;
/* Update stats using callback to hdd */
mac->sme.csr_mib_stats_callback(&mib_stats, mac->sme.mib_stats_context);
WMA_LOGD("%s: Invoke sme.csr_mib_stats_callback callback", __func__);
return 0;
}
static int wma_stats_event_handler(void *handle, u_int8_t *cmd_param_info,
u_int32_t len)
{
WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
wmi_stats_event_fixed_param *event;
wmi_per_chain_rssi_stats *rssi_event;
vos_msg_t vos_msg = {0};
u_int32_t buf_size, buf_data_size;
u_int8_t *buf, *temp;
u_int32_t buf_len = 0;
bool excess_data = false;
bool rssi_stats_support = FALSE;
param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)cmd_param_info;
if (!param_buf) {
WMA_LOGA("%s: Invalid stats event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
do {
if (event->num_pdev_stats > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*event)) / sizeof(wmi_pdev_stats))) {
excess_data = true;
break;
} else {
buf_len += event->num_pdev_stats * sizeof(wmi_pdev_stats);
}
if (event->num_vdev_stats > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*event)) / sizeof(wmi_vdev_stats))) {
excess_data = true;
break;
} else {
buf_len += event->num_vdev_stats * sizeof(wmi_vdev_stats);
}
if (event->num_peer_stats > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*event)) / sizeof(wmi_peer_stats))) {
excess_data = true;
break;
} else {
buf_len += event->num_peer_stats * sizeof(wmi_peer_stats);
}
if (event->num_mib_stats > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*event)) / sizeof(wmi_mib_stats))) {
excess_data = true;
break;
} else {
buf_len += event->num_mib_stats * sizeof(wmi_mib_stats);
}
rssi_event =
(wmi_per_chain_rssi_stats *) param_buf->chain_stats;
if (rssi_event) {
if ((rssi_event->num_per_chain_rssi_stats >
((WMA_SVC_MSG_MAX_SIZE - sizeof(*event)) /
sizeof(wmi_rssi_stats)))) {
excess_data = true;
break;
} else {
buf_len +=
rssi_event->num_per_chain_rssi_stats *
sizeof(wmi_rssi_stats);
}
}
} while (0);
if (excess_data ||
(sizeof(*event) > WMA_SVC_MSG_MAX_SIZE - buf_len)) {
WMA_LOGE("excess wmi buffer: stats pdev %d vdev %d peer %d",
event->num_pdev_stats, event->num_vdev_stats,
event->num_peer_stats);
VOS_ASSERT(0);
return -EINVAL;
}
buf_size = sizeof(*event) +
(event->num_pdev_stats * sizeof(wmi_pdev_stats)) +
(event->num_vdev_stats * sizeof(wmi_vdev_stats)) +
(event->num_peer_stats * sizeof(wmi_peer_stats)) +
(event->num_mib_stats * sizeof(wmi_mib_stats));
buf_data_size = buf_size - sizeof(*event);
rssi_event = param_buf->chain_stats;
if (rssi_event) {
if ((((rssi_event->tlv_header & 0xFFFF0000) >> 16) ==
WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) &&
((rssi_event->tlv_header & 0x0000FFFF) ==
WMITLV_GET_STRUCT_TLVLEN(
wmi_per_chain_rssi_stats))) {
buf_size += sizeof(*rssi_event) +
(rssi_event->num_per_chain_rssi_stats *
sizeof(wmi_rssi_stats));
rssi_stats_support = TRUE;
}
}
buf = vos_mem_malloc(buf_size);
if (!buf) {
WMA_LOGE("%s: Failed alloc memory for buf", __func__);
return -ENOMEM;
}
vos_mem_zero(buf, buf_size);
vos_mem_copy(buf, event, sizeof(*event));
temp = buf + sizeof(*event);
vos_mem_copy(temp, (uint8_t *)param_buf->data,
buf_data_size);
temp += buf_data_size;
if (rssi_stats_support) {
vos_mem_copy(temp, rssi_event, sizeof(*rssi_event));
temp += sizeof(*rssi_event);
vos_mem_copy(temp, (uint8_t *)param_buf->rssi_stats,
(rssi_event->num_per_chain_rssi_stats *
sizeof(wmi_rssi_stats)));
}
vos_msg.type = WDA_FW_STATS_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGP("%s: Failed to post WDA_FW_STATS_IND msg", __func__);
vos_mem_free(buf);
return -1;
}
return 0;
}
/**
* wma_fill_peer_info() - fill SIR peer info from WMI peer info struct
* @wma: wma interface
* @stats_info: WMI peer info pointer
* @peer_info: SIR peer info pointer
*
* This function will fill SIR peer info from WMI peer info struct
*
* Return: None
*/
static void wma_fill_peer_info(tp_wma_handle wma,
wmi_peer_stats_info *stats_info,
struct sir_peer_info_ext *peer_info)
{
peer_info->tx_packets = stats_info->tx_packets.low_32;
peer_info->tx_bytes = stats_info->tx_bytes.high_32;
peer_info->tx_bytes <<= 32;
peer_info->tx_bytes += stats_info->tx_bytes.low_32;
peer_info->rx_packets = stats_info->rx_packets.low_32;
peer_info->rx_bytes = stats_info->rx_bytes.high_32;
peer_info->rx_bytes <<= 32;
peer_info->rx_bytes += stats_info->rx_bytes.low_32;
peer_info->tx_retries = stats_info->tx_retries;
peer_info->tx_failed = stats_info->tx_failed;
peer_info->rssi = stats_info->peer_rssi;
peer_info->tx_rate = stats_info->last_tx_bitrate_kbps;
peer_info->tx_rate_code = stats_info->last_tx_rate_code;
peer_info->rx_rate = stats_info->last_rx_bitrate_kbps;
peer_info->rx_rate_code = stats_info->last_rx_rate_code;
}
/**
* wma_peer_info_ext_rsp() - fill SIR peer info from WMI peer info struct
* @handle: wma interface
* @buf: wmi event buf pointer
*
* This function will send eWNI_SME_GET_PEER_INFO_EXT_IND to SME
*
* Return: 0 on success, error code otherwise
*/
static VOS_STATUS wma_peer_info_ext_rsp(tp_wma_handle wma, u_int8_t *buf)
{
wmi_peer_stats_info_event_fixed_param *event;
wmi_peer_stats_info *stats_info = NULL;
struct sir_peer_info_ext_resp *resp;
struct sir_peer_info_ext *peer_info;
vos_msg_t sme_msg = {0};
int i, j = 0;
VOS_STATUS vos_status;
event = (wmi_peer_stats_info_event_fixed_param *)buf;
stats_info = (wmi_peer_stats_info *)(buf +
sizeof(wmi_peer_stats_info_event_fixed_param));
if (wma->get_one_peer_info) {
resp = vos_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
sizeof(resp->info[0]));
if (!resp) {
WMA_LOGE(FL("resp allocation failed."));
return VOS_STATUS_E_NOMEM;
}
resp->count = 0;
peer_info = &resp->info[0];
for (i = 0; i < event->num_peers; i++) {
WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
peer_info->peer_macaddr);
if (TRUE == vos_mem_compare(
peer_info->peer_macaddr,
wma->peer_macaddr.bytes,
VOS_MAC_ADDR_SIZE)) {
wma_fill_peer_info(wma, stats_info, peer_info);
resp->count++;
break;
}
stats_info = stats_info + 1;
}
} else {
resp = vos_mem_malloc(sizeof(struct sir_peer_info_ext_resp) +
event->num_peers * sizeof(resp->info[0]));
if (!resp) {
WMA_LOGE(FL("resp allocation failed."));
return VOS_STATUS_E_NOMEM;
}
resp->count = event->num_peers;
for (i = 0; i < event->num_peers; i++) {
peer_info = &resp->info[j];
WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr,
peer_info->peer_macaddr);
if (TRUE == vos_mem_compare(
peer_info->peer_macaddr,
wma->myaddr, VOS_MAC_ADDR_SIZE)) {
resp->count = resp->count - 1;
continue;
}
wma_fill_peer_info(wma, stats_info, peer_info);
stats_info = stats_info + 1;
j++;
}
}
sme_msg.type = eWNI_SME_GET_PEER_INFO_EXT_IND;
sme_msg.bodyptr = resp;
sme_msg.bodyval = 0;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGE("%s: Fail to post get peer info msg", __func__);
vos_mem_free(resp);
}
return vos_status;
}
/**
* dump_peer_stats_info() - dump wmi peer info struct
* @event: wmi peer info fixed param pointer
* @peer_stats: wmi peer stats info pointer
*
* This function will dump wmi peer info struct
*
* Return: None
*/
static void dump_peer_stats_info(wmi_peer_stats_info_event_fixed_param *event,
wmi_peer_stats_info *peer_stats)
{
int i;
wmi_peer_stats_info *stats = peer_stats;
char mac[6];
WMA_LOGI("%s vdev_id %d, num_peers %d more_data %d",
__func__, event->vdev_id,
event->num_peers, event->more_data);
for (i = 0; i < event->num_peers; i++) {
WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac);
WMA_LOGI("%s mac %pM", __func__, mac);
WMA_LOGI("%s tx_bytes %d %d tx_packets %d %d",
__func__,
stats->tx_bytes.low_32,
stats->tx_bytes.high_32,
stats->tx_packets.low_32,
stats->tx_packets.high_32);
WMA_LOGI("%s rx_bytes %d %d rx_packets %d %d",
__func__,
stats->rx_bytes.low_32,
stats->rx_bytes.high_32,
stats->rx_packets.low_32,
stats->rx_packets.high_32);
WMA_LOGI("%s tx_retries %d tx_failed %d",
__func__, stats->tx_retries, stats->tx_failed);
WMA_LOGI("%s tx_rate_code %x rx_rate_code %x",
__func__,
stats->last_tx_rate_code,
stats->last_rx_rate_code);
WMA_LOGI("%s tx_rate %x rx_rate %x",
__func__,
stats->last_tx_bitrate_kbps,
stats->last_rx_bitrate_kbps);
WMA_LOGI("%s peer_rssi %d", __func__, stats->peer_rssi);
stats++;
}
}
/**
* wma_peer_info_event_handler() - Handler for WMI_PEER_STATS_INFO_EVENTID
* @handle: WMA global handle
* @cmd_param_info: Command event data
* @len: Length of @cmd_param_info
*
* This function will handle WMI_PEER_STATS_INFO_EVENTID
*
* Return: 0 on success, error code otherwise
*/
static int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info,
u_int32_t len)
{
WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf;
wmi_peer_stats_info_event_fixed_param *event;
vos_msg_t vos_msg = {0};
u_int32_t buf_size;
u_int8_t *buf;
param_buf =
(WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)cmd_param_info;
if (!param_buf) {
WMA_LOGA("%s: Invalid stats event", __func__);
return -EINVAL;
}
WMA_LOGI("%s Recv WMI_PEER_STATS_INFO_EVENTID", __func__);
event = param_buf->fixed_param;
if (event->num_peers >
((WMA_SVC_MSG_MAX_SIZE -
sizeof(wmi_peer_stats_info_event_fixed_param))/
sizeof(wmi_peer_stats_info))) {
WMA_LOGE("Excess num of peers from fw %d", event->num_peers);
return -EINVAL;
}
buf_size = sizeof(wmi_peer_stats_info_event_fixed_param) +
sizeof(wmi_peer_stats_info) * event->num_peers;
buf = vos_mem_malloc(buf_size);
if (!buf) {
WMA_LOGE("%s: Failed alloc memory for buf", __func__);
return -ENOMEM;
}
vos_mem_zero(buf, buf_size);
vos_mem_copy(buf, param_buf->fixed_param,
sizeof(wmi_peer_stats_info_event_fixed_param));
vos_mem_copy((buf + sizeof(wmi_peer_stats_info_event_fixed_param)),
param_buf->peer_stats_info,
sizeof(wmi_peer_stats_info) * event->num_peers);
WMA_LOGI("%s dump peer stats info", __func__);
dump_peer_stats_info(event, param_buf->peer_stats_info);
vos_msg.type = WDA_GET_PEER_INFO_EXT_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGP("%s: Failed to post WDA_GET_LINK_STATUS_RSP_IND msg",
__func__);
vos_mem_free(buf);
return eHAL_STATUS_FAILURE;
}
WMA_LOGD("posted WDA_GET_PEER_INFO_EXT_IND");
return 0;
}
/**
* wma_get_peer_info_ext() - get peer info
* @handle: wma interface
* @prssi_req: get peer info request information
*
* This function will send WMI_REQUEST_PEER_STATS_INFO_CMDID to FW
*
* Return: 0 on success, otherwise error value
*/
static VOS_STATUS wma_get_peer_info_ext(WMA_HANDLE handle,
struct sir_peer_info_ext_req *peer_info_req)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
wmi_request_peer_stats_info_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
uint8_t *buf_ptr;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue get rssi",
__func__);
return VOS_STATUS_E_INVAL;
}
WMA_LOGI("%s send WMI_REQUEST_PEER_STATS_INFO_CMDID", __func__);
len = sizeof(wmi_request_peer_stats_info_cmd_fixed_param);
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *)wmi_buf_data(wmi_buf);
cmd = (wmi_request_peer_stats_info_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_request_peer_stats_info_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_request_peer_stats_info_cmd_fixed_param));
cmd->vdev_id = peer_info_req->sessionid;
cmd->request_type = WMI_REQUEST_ONE_PEER_STATS_INFO;
wma_handle->get_one_peer_info = TRUE;
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_info_req->peer_macaddr.bytes,
&cmd->peer_macaddr);
cmd->reset_after_request = peer_info_req->reset_after_request;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_REQUEST_PEER_STATS_INFO_CMDID)) {
WMA_LOGE("Failed to send host stats request to fw");
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGI("%s vdev_id %d, mac %pM, req_type %x, reset %x",
__func__,
cmd->vdev_id,
peer_info_req->peer_macaddr.bytes,
cmd->request_type,
cmd->reset_after_request);
vos_mem_copy(&(wma_handle->peer_macaddr),
&(peer_info_req->peer_macaddr),
VOS_MAC_ADDR_SIZE);
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_send_link_speed(u_int32_t link_speed)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
vos_msg_t sme_msg = {0} ;
tSirLinkSpeedInfo *ls_ind =
(tSirLinkSpeedInfo *) vos_mem_malloc(sizeof(tSirLinkSpeedInfo));
if (!ls_ind) {
WMA_LOGE("%s: Memory allocation failed.", __func__);
vos_status = VOS_STATUS_E_NOMEM;
}
else
{
ls_ind->estLinkSpeed = link_speed;
sme_msg.type = eWNI_SME_LINK_SPEED_IND;
sme_msg.bodyptr = ls_ind;
sme_msg.bodyval = 0;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status) ) {
WMA_LOGE("%s: Fail to post linkspeed ind msg", __func__);
vos_mem_free(ls_ind);
}
}
return vos_status;
}
static int wma_link_speed_event_handler(void *handle, u_int8_t *cmd_param_info,
u_int32_t len)
{
WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf;
wmi_peer_estimated_linkspeed_event_fixed_param *event;
VOS_STATUS vos_status;
param_buf = (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *)cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid linkspeed event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
vos_status = wma_send_link_speed(event->est_linkspeed_kbps);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
return -EINVAL;
}
return 0;
}
/**
* wma_handle_sta_peer_info() - handle peer information in
* peer stats
* @num_peer_stats: peer number
* @peer_stats: peer stats received from firmware
* @peer_macaddr: the specified mac address
* @sapaddr: sap mac address
*
* This function will send eWNI_SME_GET_PEER_INFO_IND
* to sme with stations' information
*
*/
static void wma_handle_sta_peer_info(uint32_t num_peer_stats,
wmi_peer_stats *peer_stats,
v_MACADDR_t peer_macaddr,
uint8_t *sapaddr)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_mac_addr temp_addr;
struct sir_peer_info_resp *peer_info;
vos_msg_t sme_msg = {0};
uint32_t i = 0;
uint32_t j = 0;
if (!vos_is_macaddr_broadcast(&peer_macaddr)) {
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_macaddr.bytes, &temp_addr);
for (i = 0; i < num_peer_stats; i++) {
if ((((temp_addr.mac_addr47to32) & 0x0000ffff) ==
((peer_stats->peer_macaddr.mac_addr47to32) &
0x0000ffff))
&&(temp_addr.mac_addr31to0 ==
peer_stats->peer_macaddr.mac_addr31to0)) {
break;
}
peer_stats = peer_stats + 1;
}
peer_info = vos_mem_malloc(sizeof(*peer_info) +
sizeof(peer_info->info[0]));
if (NULL == peer_info) {
WMA_LOGE("%s: Memory allocation failed.", __func__);
return;
}
if (i < num_peer_stats) {
peer_info->count = 1;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
peer_info->info[0].peer_macaddr);
peer_info->info[0].rssi =
peer_stats->peer_rssi;
peer_info->info[0].tx_rate = peer_stats->peer_tx_rate;
peer_info->info[0].rx_rate = peer_stats->peer_rx_rate;
WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
__func__,
peer_info->info[0].peer_macaddr,
peer_stats->peer_rssi,
peer_stats->peer_tx_rate,
peer_stats->peer_rx_rate);
} else {
WMA_LOGE("%s: no match mac address", __func__);
peer_info->count = 0;
}
} else {
peer_info = vos_mem_malloc(sizeof(*peer_info) +
num_peer_stats * sizeof(peer_info->info[0]));
if (NULL == peer_info) {
WMA_LOGE("%s: Memory allocation failed.", __func__);
return;
}
peer_info->count = num_peer_stats;
for (i = 0; i < num_peer_stats; i++) {
WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
peer_info->info[j].peer_macaddr);
peer_info->info[j].rssi = peer_stats->peer_rssi;
peer_info->info[j].tx_rate = peer_stats->peer_tx_rate;
peer_info->info[j].rx_rate = peer_stats->peer_rx_rate;
WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d",
__func__,
peer_info->info[j].peer_macaddr,
peer_stats->peer_rssi,
peer_stats->peer_tx_rate,
peer_stats->peer_rx_rate);
if (TRUE == vos_mem_compare(
peer_info->info[j].peer_macaddr,
sapaddr, VOS_MAC_ADDR_SIZE)) {
peer_info->count = peer_info->count - 1;
} else {
j++;
}
peer_stats = peer_stats + 1;
}
WMA_LOGD("WDA send peer num %d", peer_info->count);
}
sme_msg.type = eWNI_SME_GET_PEER_INFO_IND;
sme_msg.bodyptr = peer_info;
sme_msg.bodyval = 0;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status) ) {
WMA_LOGE("%s: Fail to post get rssi msg", __func__);
vos_mem_free(peer_info);
}
return;
}
static void wma_fw_stats_ind(tp_wma_handle wma, u_int8_t *buf)
{
wmi_stats_event_fixed_param *event = (wmi_stats_event_fixed_param *)buf;
wmi_pdev_stats *pdev_stats;
wmi_vdev_stats *vdev_stats;
wmi_peer_stats *peer_stats;
wmi_mib_stats *mib_stats;
wmi_rssi_stats *rssi_stats;
wmi_per_chain_rssi_stats *rssi_event;
struct wma_txrx_node *node;
u_int8_t i, *temp;
temp = buf + sizeof(*event);
WMA_LOGD("%s: num_stats: pdev: %u vdev: %u peer %u mib %u",
__func__, event->num_pdev_stats, event->num_vdev_stats,
event->num_peer_stats, event->num_mib_stats);
if (event->num_pdev_stats > 0) {
for (i = 0; i < event->num_pdev_stats; i++) {
pdev_stats = (wmi_pdev_stats*)temp;
wma_update_pdev_stats(wma, pdev_stats);
temp += sizeof(wmi_pdev_stats);
}
}
if (event->num_vdev_stats > 0) {
for (i = 0; i < event->num_vdev_stats; i++) {
vdev_stats = (wmi_vdev_stats *)temp;
wma_update_vdev_stats(wma, vdev_stats);
temp += sizeof(wmi_vdev_stats);
}
}
if (event->num_peer_stats > 0) {
if (wma->get_sta_peer_info == TRUE) {
wma_handle_sta_peer_info(event->num_peer_stats,
(wmi_peer_stats *)temp,
wma->peer_macaddr,
wma->myaddr);
} else {
for (i = 0; i < event->num_peer_stats; i++) {
peer_stats = (wmi_peer_stats *)temp;
wma_update_peer_stats(wma, peer_stats);
temp += sizeof(wmi_peer_stats);
}
}
}
if (event->num_mib_stats > 0) {
for (i = 0; i < event->num_mib_stats; i++) {
mib_stats = (wmi_mib_stats *)temp;
wma_update_mib_stats(wma, mib_stats);
temp += sizeof(wmi_mib_stats);
}
}
rssi_event = (wmi_per_chain_rssi_stats *)temp;
if ((((rssi_event->tlv_header & 0xFFFF0000) >> 16) ==
WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) &&
((rssi_event->tlv_header & 0x0000FFFF) ==
WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats))) {
if (rssi_event->num_per_chain_rssi_stats > 0) {
temp += sizeof(*rssi_event);
for (i = 0; i < rssi_event->num_per_chain_rssi_stats;
i++) {
rssi_stats = (wmi_rssi_stats *)temp;
wma_update_rssi_stats(wma, rssi_stats);
temp += sizeof(wmi_rssi_stats);
}
}
}
for (i = 0; i < wma->max_bssid; i++) {
node = &wma->interfaces[i];
if (node->fw_stats_set & FW_PEER_STATS_SET) {
WMA_LOGD("<--STATS RSP VDEV_ID:%d", i);
wma_post_stats(wma, node);
}
}
}
#ifdef FEATURE_WLAN_EXTSCAN
/**
* wma_extscan_rsp_handler() - extscan rsp handler
* @wma: WMA global handle
* @buf: event fixed param buffer
*
* Return: 0 on success, error number otherwise
*/
static int wma_extscan_rsp_handler(tp_wma_handle wma, uint8_t *buf)
{
wmi_extscan_start_stop_event_fixed_param *event;
struct sir_extscan_generic_response *extscan_ind;
uint16_t event_type;
uint8_t vdev_id;
tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!mac_ctx) {
WMA_LOGE("%s: Invalid mac_ctx", __func__);
return -EINVAL;
}
if (!mac_ctx->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
if (!buf) {
WMA_LOGE("Invalid event buffer");
return -EINVAL;
}
event = (wmi_extscan_start_stop_event_fixed_param *)buf;
if (event->vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: max vdev id's %d reached",
__func__, event->vdev_id);
return -EINVAL;
}
vdev_id = event->vdev_id;
extscan_ind = vos_mem_malloc(sizeof(*extscan_ind));
if (!extscan_ind) {
WMA_LOGE("%s: extscan memory allocation failed", __func__);
return -ENOMEM;
}
switch (event->command) {
case WMI_EXTSCAN_START_CMDID:
event_type = eSIR_EXTSCAN_START_RSP;
extscan_ind->status = event->status;
extscan_ind->request_id = event->request_id;
if (!extscan_ind->status)
wma->interfaces[vdev_id].extscan_in_progress = true;
break;
case WMI_EXTSCAN_STOP_CMDID:
event_type = eSIR_EXTSCAN_STOP_RSP;
extscan_ind->status = event->status;
extscan_ind->request_id = event->request_id;
if (!extscan_ind->status)
wma->interfaces[vdev_id].extscan_in_progress = false;
break;
case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID:
extscan_ind->status = event->status;
extscan_ind->request_id = event->request_id;
if (event->mode == WMI_EXTSCAN_MODE_STOP) {
event_type =
eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP;
} else {
event_type =
eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP;
}
break;
case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID:
extscan_ind->status = event->status;
extscan_ind->request_id = event->request_id;
if (event->mode == WMI_EXTSCAN_MODE_STOP) {
event_type =
eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP;
} else {
event_type =
eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP;
}
break;
case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID:
extscan_ind->status = event->status;
extscan_ind->request_id = event->request_id;
event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP;
break;
case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID:
extscan_ind->status = event->status;
extscan_ind->request_id = event->request_id;
if (event->mode == WMI_EXTSCAN_MODE_STOP) {
event_type =
eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP;
} else {
event_type =
eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP;
}
break;
default:
WMA_LOGE("%s: Unknown event %d from target vdev_id %u",
__func__, event->status, vdev_id);
vos_mem_free(extscan_ind);
return -EINVAL;
}
mac_ctx->sme.pExtScanIndCb(mac_ctx->hHdd,
event_type, extscan_ind);
WMA_LOGD("%s: sending event to umac for requestid %u with status %d",
__func__,
extscan_ind->request_id, extscan_ind->status);
vos_mem_free(extscan_ind);
return 0;
}
/**
* wma_extscan_start_stop_event_handler() - extscan event handler
* @handle: WMA global handle
* @cmd_param_info: command event data
* @len: Length of @cmd_param_info
*
* Return: 0 on success, error number otherwise
*/
static int wma_extscan_start_stop_event_handler(void *handle,
uint8_t *cmd_param_info, uint32_t len)
{
WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf;
wmi_extscan_start_stop_event_fixed_param *event;
u_int8_t *buf;
int buf_len = sizeof(*event);
vos_msg_t vos_msg = {0};
WMA_LOGI("%s: Enter", __func__);
param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid extscan event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
buf = vos_mem_malloc(buf_len);
if (!buf) {
WMA_LOGE("%s: extscan memory allocation failed", __func__);
return -ENOMEM;
}
vos_mem_zero(buf, buf_len);
vos_mem_copy(buf, (u_int8_t *)event, buf_len);
vos_msg.type = WDA_EXTSCAN_STATUS_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGP("%s: Failed to post WDA_EXTSCAN_STATUS_IND msg",
__func__);
vos_mem_free(buf);
return -EINVAL;
}
WMA_LOGI("WDA_EXTSCAN_STATUS_IND posted");
return 0;
}
/**
* wma_extscan_operations_ind_handler() - extscan operations handler
* @wma: WMA global handle
* @buf: command event data
*
* This function extracts the event data, fill in appropriate structures
* and invoke upper layer callback.
*
* Return: 0 on success, error number otherwise
*/
static int wma_extscan_operations_ind_handler(tp_wma_handle wma, uint8_t *buf)
{
tSirExtScanOnScanEventIndParams *oprn_ind, *evt_buf;
tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!mac_ctx) {
WMA_LOGE("%s: Invalid mac_ctx", __func__);
return -EINVAL;
}
if (!mac_ctx->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
if (!buf) {
WMA_LOGE("%s: Invalid event buffer", __func__);
return -EINVAL;
}
evt_buf = (tSirExtScanOnScanEventIndParams *)buf;
oprn_ind = vos_mem_malloc(sizeof(*oprn_ind));
if (!oprn_ind) {
WMA_LOGE(FL("extscan memory allocation failed"));
return -EINVAL;
}
vos_mem_zero(oprn_ind, sizeof(*oprn_ind));
oprn_ind->requestId = evt_buf->requestId;
switch (evt_buf->scanEventType) {
case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT:
WMA_LOGD("%s: received WMI_EXTSCAN_BUCKET_COMPLETED_EVENT",
__func__);
oprn_ind->status = 0;
goto exit_handler;
case WMI_EXTSCAN_CYCLE_STARTED_EVENT:
WMA_LOGD("%s: received WMI_EXTSCAN_CYCLE_STARTED_EVENT",
__func__);
vos_wake_lock_timeout_acquire(&wma->extscan_wake_lock,
WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION,
WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT;
oprn_ind->status = 0;
oprn_ind->buckets_scanned = evt_buf->buckets_scanned;
break;
case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT:
WMA_LOGD("%s: received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT",
__func__);
vos_wake_lock_release(&wma->extscan_wake_lock,
WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN);
oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT;
oprn_ind->status = 0;
/* Set bucket scanned mask to zero on cycle complete */
oprn_ind->buckets_scanned = 0;
break;
case WMI_EXTSCAN_BUCKET_STARTED_EVENT:
WMA_LOGD("%s: received WMI_EXTSCAN_BUCKET_STARTED_EVENT",
__func__);
oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT;
oprn_ind->status = 0;
goto exit_handler;
case WMI_EXTSCAN_THRESHOLD_NUM_SCANS:
WMA_LOGD("%s: received WMI_EXTSCAN_THRESHOLD_NUM_SCANS",
__func__);
oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS;
oprn_ind->status = 0;
break;
case WMI_EXTSCAN_THRESHOLD_PERCENT:
WMA_LOGD("%s: received WMI_EXTSCAN_THRESHOLD_PERCENT",
__func__);
oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT;
oprn_ind->status = 0;
break;
default:
WMA_LOGE("%s: Unknown event %d from target",
__func__, evt_buf->scanEventType);
vos_mem_free(oprn_ind);
return -EINVAL;
}
mac_ctx->sme.pExtScanIndCb(mac_ctx->hHdd,
eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND,
oprn_ind);
WMA_LOGD("%s: sending scan progress event to hdd", __func__);
exit_handler:
vos_mem_free(oprn_ind);
return 0;
}
/**
* wma_extscan_operations_event_handler() - extscan operations event handler
* @handle: WMA global handle
* @cmd_param_info: command event data
* @len: Length of @cmd_param_info
*
* Return: 0 on success, error number otherwise
*/
static int wma_extscan_operations_event_handler(void *handle,
uint8_t *cmd_param_info, uint32_t len)
{
WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf;
wmi_extscan_operation_event_fixed_param *event;
tSirExtScanOnScanEventIndParams *buf;
A_UINT32 cnt = 0;
int buf_len;
vos_msg_t vos_msg = {0};
param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid extscan event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
if (event->num_buckets > param_buf->num_bucket_id) {
WMA_LOGE("FW mesg num_buk %d more than TLV hdr %d",
event->num_buckets,
param_buf->num_bucket_id);
return -EINVAL;
}
buf_len = sizeof(*buf);
buf = vos_mem_malloc(buf_len);
if (!buf) {
WMA_LOGE("%s: extscan memory allocation failed", __func__);
return -ENOMEM;
}
vos_mem_zero(buf, buf_len);
buf->requestId = event->request_id;
buf->scanEventType = event->event;
if (event->event == WMI_EXTSCAN_CYCLE_STARTED_EVENT) {
for (cnt = 0; cnt < event->num_buckets; cnt++)
buf->buckets_scanned |=
(1 << param_buf->bucket_id[cnt]);
}
WMA_LOGI(FL("num_buckets: %u request_id: %u scanEventType: %u buckets_scanned: %u"),
event->num_buckets, buf->requestId,
buf->scanEventType, buf->buckets_scanned);
vos_msg.type = WDA_EXTSCAN_OPERATION_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGP("%s: Failed to post WDA_EXTSCAN_OPERATION_IND msg",
__func__);
vos_mem_free(buf);
return -EINVAL;
}
return 0;
}
static int wma_extscan_table_usage_event_handler (void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf;
wmi_extscan_table_usage_event_fixed_param *event;
tSirExtScanResultsAvailableIndParams *tbl_usg_ind;
tpAniSirGlobal pMac = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pMac) {
WMA_LOGE("%s: Invalid pMac", __func__);
return -EINVAL;
}
if (!pMac->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid table usage event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
tbl_usg_ind = vos_mem_malloc(sizeof(*tbl_usg_ind));
if (!tbl_usg_ind) {
WMA_LOGE("%s: table usage allocation failed", __func__);
return -EINVAL;
}
tbl_usg_ind->requestId = event->request_id;
tbl_usg_ind->numResultsAvailable = event->entries_in_use;
pMac->sme.pExtScanIndCb(pMac->hHdd,
eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND,
tbl_usg_ind);
WMA_LOGD("%s: sending scan_res available event to hdd", __func__);
vos_mem_free(tbl_usg_ind);
return 0;
}
static int wma_extscan_capabilities_event_handler (void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf;
wmi_extscan_capabilities_event_fixed_param *event;
wmi_extscan_cache_capabilities *src_cache;
wmi_extscan_hotlist_monitor_capabilities *src_hotlist;
wmi_extscan_wlan_change_monitor_capabilities *src_change;
struct ext_scan_capabilities_response *dest_capab;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pMac) {
WMA_LOGE("%s: Invalid pMac", __func__);
return -EINVAL;
}
if (!pMac->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid capabilities event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
src_cache = param_buf->extscan_cache_capabilities;
src_hotlist = param_buf->hotlist_capabilities;
src_change = param_buf->wlan_change_capabilities;
if (!src_cache || !src_hotlist || !src_change) {
WMA_LOGE("%s: Invalid capabilities list", __func__);
return -EINVAL;
}
dest_capab = vos_mem_malloc(sizeof(*dest_capab));
if (!dest_capab) {
WMA_LOGE("%s: Allocation failed for capabilities buffer",
__func__);
return -EINVAL;
}
dest_capab->requestId = event->request_id;
dest_capab->max_scan_buckets = src_cache->max_buckets;
dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size;
dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan;
dest_capab->max_scan_reporting_threshold =
src_cache->max_table_usage_threshold;
dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries;
dest_capab->max_rssi_sample_size =
src_change->max_rssi_averaging_samples;
dest_capab->max_bssid_history_entries =
src_change->max_rssi_history_entries;
dest_capab->max_significant_wifi_change_aps =
src_change->max_wlan_change_entries;
dest_capab->max_hotlist_ssids =
event->num_extscan_hotlist_ssid;
dest_capab->max_number_epno_networks =
event->num_epno_networks;
dest_capab->max_number_epno_networks_by_ssid =
event->num_epno_networks;
dest_capab->max_number_of_white_listed_ssid =
event->num_roam_ssid_whitelist;
dest_capab->max_number_of_black_listed_bssid =
event->num_roam_bssid_blacklist;
dest_capab->status = 0;
WMA_LOGD("%s: request_id: %u status: %d",
__func__, dest_capab->requestId, dest_capab->status);
WMA_LOGD("%s: Capabilities: max_scan_buckets: %d,"
"max_hotlist_bssids: %d, max_scan_cache_size: %d,"
"max_ap_cache_per_scan: %d, max_scan_reporting_threshold: %d,"
"max_rssi_sample_size: %d, max_bssid_history_entries: %d,"
"max_significant_wifi_change_aps: %d",
__func__, dest_capab->max_scan_buckets,
dest_capab->max_hotlist_bssids,
dest_capab->max_scan_cache_size,
dest_capab->max_ap_cache_per_scan,
dest_capab->max_scan_reporting_threshold,
dest_capab->max_rssi_sample_size,
dest_capab->max_bssid_history_entries,
dest_capab->max_significant_wifi_change_aps);
WMA_LOGD("%s: Capabilities: max_hotlist_ssids: %d,"
"max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d,"
"max_number_of_white_listed_ssid: %d,"
"max_number_of_black_listed_bssid: %d ",
__func__, dest_capab->max_hotlist_ssids,
dest_capab->max_number_epno_networks,
dest_capab->max_number_epno_networks_by_ssid,
dest_capab->max_number_of_white_listed_ssid,
dest_capab->max_number_of_black_listed_bssid);
pMac->sme.pExtScanIndCb(pMac->hHdd,
eSIR_EXTSCAN_GET_CAPABILITIES_IND,
dest_capab);
WMA_LOGD("%s: sending capabilities event to hdd", __func__);
vos_mem_free(dest_capab);
return 0;
}
static int wma_extscan_hotlist_match_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf;
wmi_extscan_hotlist_match_event_fixed_param *event;
struct extscan_hotlist_match *dest_hotlist;
tSirWifiScanResult *dest_ap;
wmi_extscan_wlan_descriptor *src_hotlist;
uint32_t numap;
int j, ap_found = 0;
uint32_t buf_len;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pMac) {
WMA_LOGE("%s: Invalid pMac", __func__);
return -EINVAL;
}
if (!pMac->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid hotlist match event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
src_hotlist = param_buf->hotlist_match;
numap = event->total_entries;
if (!src_hotlist || !numap) {
WMA_LOGE("%s: Hotlist AP's list invalid", __func__);
return -EINVAL;
}
if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) {
WMA_LOGE("%s: Total Entries %u greater than max",
__func__, numap);
numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES;
}
buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) +
(4 * sizeof(uint32_t)) +
(numap * sizeof(wmi_extscan_wlan_descriptor));
if (buf_len > len) {
WMA_LOGE("Invalid buf len from FW %d numap %d", len, numap);
return -EINVAL;
}
dest_hotlist = vos_mem_malloc(sizeof(*dest_hotlist) +
sizeof(*dest_ap) * numap);
if (!dest_hotlist) {
WMA_LOGE("%s: Allocation failed for hotlist buffer", __func__);
return -EINVAL;
}
dest_ap = &dest_hotlist->ap[0];
dest_hotlist->numOfAps = event->total_entries;
dest_hotlist->requestId = event->config_request_id;
if (event->first_entry_index +
event->num_entries_in_page < event->total_entries)
dest_hotlist->moreData = 1;
else
dest_hotlist->moreData = 0;
WMA_LOGD("%s: Hotlist match: requestId: %u,"
"numOfAps: %d", __func__,
dest_hotlist->requestId, dest_hotlist->numOfAps);
/*
* Currently firmware sends only one bss information in-case
* of both hotlist ap found and lost.
*/
for (j = 0; j < numap; j++) {
dest_ap->rssi = 0;
dest_ap->channel = src_hotlist->channel;
dest_ap->ts = src_hotlist->tstamp;
ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE;
dest_ap->rtt = src_hotlist->rtt;
dest_ap->rtt_sd = src_hotlist->rtt_sd;
dest_ap->beaconPeriod = src_hotlist->beacon_interval;
dest_ap->capability = src_hotlist->capabilities;
dest_ap->ieLength = src_hotlist-> ie_length;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
dest_ap->bssid);
vos_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid,
src_hotlist->ssid.ssid_len);
dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
dest_ap++;
src_hotlist++;
}
dest_hotlist->ap_found = ap_found;
pMac->sme.pExtScanIndCb(pMac->hHdd,
eSIR_EXTSCAN_HOTLIST_MATCH_IND,
dest_hotlist);
WMA_LOGD("%s: sending hotlist match event to hdd", __func__);
vos_mem_free(dest_hotlist);
return 0;
}
/** wma_extscan_find_unique_scan_ids() - find unique scan ids
* @cmd_param_info: event data.
*
* This utility function parses the input bss table of information
* and find the unique number of scan ids
*
* Return: 0 on success; error number otherwise
*/
static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info)
{
WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
wmi_extscan_cached_results_event_fixed_param *event;
wmi_extscan_wlan_descriptor *src_hotlist;
wmi_extscan_rssi_info *src_rssi;
int prev_scan_id, scan_ids_cnt, i;
param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
cmd_param_info;
event = param_buf->fixed_param;
src_hotlist = param_buf->bssid_list;
src_rssi = param_buf->rssi_list;
/* Find the unique number of scan_id's for grouping */
prev_scan_id = src_rssi->scan_cycle_id;
scan_ids_cnt = 1;
for (i = 1; i < event->num_entries_in_page; i++) {
src_rssi++;
if (prev_scan_id != src_rssi->scan_cycle_id) {
scan_ids_cnt++;
prev_scan_id = src_rssi->scan_cycle_id;
}
}
return scan_ids_cnt;
}
/** wma_fill_num_results_per_scan_id() - fill number of bss per scan id
* @cmd_param_info: event data.
* @scan_id_group: pointer to scan id group.
*
* This utility function parses the input bss table of information
* and finds how many bss are there per unique scan id.
*
* Return: 0 on success; error number otherwise
*/
static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info,
struct extscan_cached_scan_result *scan_id_group)
{
WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
wmi_extscan_cached_results_event_fixed_param *event;
wmi_extscan_wlan_descriptor *src_hotlist;
wmi_extscan_rssi_info *src_rssi;
struct extscan_cached_scan_result *t_scan_id_grp;
int i, prev_scan_id;
param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
cmd_param_info;
event = param_buf->fixed_param;
src_hotlist = param_buf->bssid_list;
src_rssi = param_buf->rssi_list;
t_scan_id_grp = scan_id_group;
prev_scan_id = src_rssi->scan_cycle_id;
t_scan_id_grp->scan_id = src_rssi->scan_cycle_id;
t_scan_id_grp->flags = src_rssi->flags;
t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned;
t_scan_id_grp->num_results = 1;
for (i = 1; i < event->num_entries_in_page; i++) {
src_rssi++;
if (prev_scan_id == src_rssi->scan_cycle_id) {
t_scan_id_grp->num_results++;
} else {
t_scan_id_grp++;
prev_scan_id = t_scan_id_grp->scan_id =
src_rssi->scan_cycle_id;
t_scan_id_grp->flags = src_rssi->flags;
t_scan_id_grp->buckets_scanned =
src_rssi->buckets_scanned;
t_scan_id_grp->num_results = 1;
}
}
return 0;
}
/** wma_group_num_bss_to_scan_id() - group bss to scan id table
* @cmd_param_info: event data.
* @cached_result: pointer to cached table.
*
* This function reads the bss information from the format
* ------------------------------------------------------------------------
* | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags |
* | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags |
* ........................................................................
* | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags |
* ------------------------------------------------------------------------
*
* and converts it into the below format and store it
*
* ------------------------------------------------------------------------
* | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1
* | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2
* ......................
* | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn
* ------------------------------------------------------------------------
*
* Return: 0 on success; error number otherwise
*/
static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info,
struct extscan_cached_scan_results *cached_result)
{
WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
wmi_extscan_cached_results_event_fixed_param *event;
wmi_extscan_wlan_descriptor *src_hotlist;
wmi_extscan_rssi_info *src_rssi;
struct extscan_cached_scan_results *t_cached_result;
struct extscan_cached_scan_result *t_scan_id_grp;
int i, j;
tSirWifiScanResult *ap;
param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
cmd_param_info;
event = param_buf->fixed_param;
src_hotlist = param_buf->bssid_list;
src_rssi = param_buf->rssi_list;
t_cached_result = cached_result;
t_scan_id_grp = &t_cached_result->result[0];
WMA_LOGD("%s: num_scan_ids:%d", __func__,
t_cached_result->num_scan_ids);
for (i = 0; i < t_cached_result->num_scan_ids; i++) {
WMA_LOGD("%s: num_results:%d", __func__,
t_scan_id_grp->num_results);
t_scan_id_grp->ap = vos_mem_malloc(t_scan_id_grp->num_results *
sizeof(*ap));
if (!t_scan_id_grp->ap) {
WMA_LOGD("%s: vos_mem_malloc failed", __func__);
return -ENOMEM;
}
ap = &t_scan_id_grp->ap[0];
for (j = 0; j < t_scan_id_grp->num_results; j++) {
ap->channel = src_hotlist->channel;
ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp);
ap->rtt = src_hotlist->rtt;
ap->rtt_sd = src_hotlist->rtt_sd;
ap->beaconPeriod = src_hotlist->beacon_interval;
ap->capability = src_hotlist->capabilities;
ap->ieLength = src_hotlist->ie_length;
/* Firmware already applied noise floor adjustment and
* due to WMI interface "UINT32 rssi", host driver
* receives a positive value, hence convert to
* signed char to get the absolute rssi.
*/
ap->rssi = (signed char) src_rssi->rssi;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid,
ap->bssid);
vos_mem_copy(ap->ssid, src_hotlist->ssid.ssid,
src_hotlist->ssid.ssid_len);
ap->ssid[src_hotlist->ssid.ssid_len] = '\0';
ap++;
src_rssi++;
src_hotlist++;
}
t_scan_id_grp++;
}
return 0;
}
static int wma_extscan_cached_results_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf;
wmi_extscan_cached_results_event_fixed_param *event;
struct extscan_cached_scan_results *dest_cachelist;
struct extscan_cached_scan_result *dest_result;
struct extscan_cached_scan_results empty_cachelist;
wmi_extscan_wlan_descriptor *src_hotlist;
wmi_extscan_rssi_info *src_rssi;
int numap, i, moredata, scan_ids_cnt;
int buf_len;
u_int32_t total_len;
bool excess_data = false;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pMac) {
WMA_LOGE("%s: Invalid pMac", __func__);
return -EINVAL;
}
if (!pMac->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid cached results event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
src_hotlist = param_buf->bssid_list;
src_rssi = param_buf->rssi_list;
numap = event->num_entries_in_page;
WMA_LOGI("Total_entries: %u first_entry_index: %u num_entries_in_page: %u",
event->total_entries, event->first_entry_index, numap);
if (!src_hotlist || !src_rssi || !numap) {
WMA_LOGW("%s: Cached results empty, send 0 results", __func__);
goto noresults;
}
if (event->first_entry_index +
event->num_entries_in_page < event->total_entries)
moredata = 1;
else
moredata = 0;
dest_cachelist = vos_mem_malloc(sizeof(*dest_cachelist));
if (!dest_cachelist) {
WMA_LOGE("%s: vos_mem_malloc failed", __func__);
return -ENOMEM;
}
vos_mem_zero(dest_cachelist, sizeof(*dest_cachelist));
dest_cachelist->request_id = event->request_id;
dest_cachelist->more_data = moredata;
scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info);
WMA_LOGI("scan_ids_cnt %d", scan_ids_cnt);
dest_cachelist->num_scan_ids = scan_ids_cnt;
if (event->num_entries_in_page >
(WMA_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist)) {
WMA_LOGE("%s:excess num_entries_in_page %d in WMI event",
__func__, event->num_entries_in_page);
vos_mem_free(dest_cachelist);
VOS_ASSERT(0);
return -EINVAL;
} else {
total_len = sizeof(*event) +
(event->num_entries_in_page * sizeof(*src_hotlist));
}
for (i = 0; i < event->num_entries_in_page; i++) {
if (src_hotlist[i].ie_length > WMA_SVC_MSG_MAX_SIZE -
total_len) {
excess_data = true;
break;
} else {
total_len += src_hotlist[i].ie_length;
WMA_LOGD("total len IE: %d", total_len);
}
if (src_hotlist[i].number_rssi_samples >
(WMA_SVC_MSG_MAX_SIZE - total_len)/sizeof(*src_rssi)) {
excess_data = true;
break;
} else {
total_len += (src_hotlist[i].number_rssi_samples *
sizeof(*src_rssi));
WMA_LOGD("total len RSSI samples: %d", total_len);
}
}
if (excess_data) {
WMA_LOGE("%s:excess data in WMI event", __func__);
vos_mem_free(dest_cachelist);
VOS_ASSERT(0);
return -EINVAL;
}
buf_len = sizeof(*dest_result) * scan_ids_cnt;
dest_cachelist->result = vos_mem_malloc(buf_len);
if (!dest_cachelist->result) {
WMA_LOGE("%s: vos_mem_malloc failed", __func__);
vos_mem_free(dest_cachelist);
return -ENOMEM;
}
dest_result = dest_cachelist->result;
wma_fill_num_results_per_scan_id(cmd_param_info, dest_result);
wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist);
pMac->sme.pExtScanIndCb(pMac->hHdd,
eSIR_EXTSCAN_CACHED_RESULTS_IND,
dest_cachelist);
dest_result = dest_cachelist->result;
for (i = 0; i < dest_cachelist->num_scan_ids; i++) {
vos_mem_free(dest_result->ap);
dest_result++;
}
vos_mem_free(dest_cachelist->result);
vos_mem_free(dest_cachelist);
return 0;
noresults:
empty_cachelist.request_id = event->request_id;
empty_cachelist.more_data = 0;
empty_cachelist.num_scan_ids = 0;
pMac->sme.pExtScanIndCb(pMac->hHdd,
eSIR_EXTSCAN_CACHED_RESULTS_IND,
&empty_cachelist);
return 0;
}
static int wma_extscan_change_results_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf;
wmi_extscan_wlan_change_results_event_fixed_param *event;
tSirWifiSignificantChangeEvent *dest_chglist;
tSirWifiSignificantChange *dest_ap;
wmi_extscan_wlan_change_result_bssid *src_chglist;
int numap;
int i, k;
u_int8_t *src_rssi;
int count = 0;
int moredata;
int rssi_num = 0;
u_int32_t buf_len;
bool excess_data = false;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pMac) {
WMA_LOGE("%s: Invalid pMac", __func__);
return -EINVAL;
}
if (!pMac->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid change monitor event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
src_chglist = param_buf->bssid_signal_descriptor_list;
src_rssi = param_buf->rssi_list;
numap = event->num_entries_in_page;
if (!src_chglist || !numap) {
WMA_LOGE("%s: Results invalid", __func__);
return -EINVAL;
}
for (i = 0; i < numap; i++) {
rssi_num += src_chglist->num_rssi_samples;
}
if (event->first_entry_index +
event->num_entries_in_page < event->total_entries)
moredata = 1;
else
moredata = 0;
do {
if (event->num_entries_in_page >
(WMA_SVC_MSG_MAX_SIZE - sizeof(*event))/
sizeof(*src_chglist)) {
excess_data = true;
break;
} else {
buf_len = sizeof(*event) +
(event->num_entries_in_page *
sizeof(*src_chglist));
}
if (rssi_num >
(WMA_SVC_MSG_MAX_SIZE - buf_len)/sizeof(int32_t)) {
excess_data = true;
break;
}
} while (0);
if (excess_data) {
WMA_LOGE("buffer len exceeds WMI payload,numap:%d, rssi_num:%d",
numap, rssi_num);
VOS_ASSERT(0);
return -EINVAL;
}
dest_chglist = vos_mem_malloc(sizeof(*dest_chglist) +
sizeof(*dest_ap) * numap +
sizeof(tANI_S32) * rssi_num);
if (!dest_chglist) {
WMA_LOGE("%s: vos_mem_malloc failed", __func__);
return -EINVAL;
}
dest_ap = &dest_chglist->ap[0];
for (i = 0; i < numap; i++) {
dest_ap->channel = src_chglist->channel;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid,
dest_ap->bssid);
dest_ap->numOfRssi =
src_chglist->num_rssi_samples;
if (dest_ap->numOfRssi) {
for (k = 0; k < dest_ap->numOfRssi; k++) {
dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM +
src_rssi[count++];
}
}
dest_ap += dest_ap->numOfRssi * sizeof(tANI_S32);
src_chglist++;
}
dest_chglist->requestId = event->request_id;
dest_chglist->moreData = moredata;
dest_chglist->numResults = event->total_entries;
pMac->sme.pExtScanIndCb(pMac->hHdd,
eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND,
dest_chglist);
WMA_LOGD("%s: sending change monitor results", __func__);
vos_mem_free(dest_chglist);
return 0;
}
/**
* wma_passpoint_match_event_handler() - passpoint match found event handler
* @handle: WMA handle
* @cmd_param_info: event data
* @len: event data length
*
* This is the passpoint match found event handler; it reads event data from
* @cmd_param_info and fill in the destination buffer and sends indication
* up layer.
*
* Return: 0 on success; error number otherwise
*/
static int wma_passpoint_match_event_handler(void *handle,
uint8_t *cmd_param_info,
uint32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf;
wmi_passpoint_event_hdr *event;
struct wifi_passpoint_match *dest_match;
tSirWifiScanResult *dest_ap;
uint8_t *buf_ptr;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pMac) {
WMA_LOGE("%s: Invalid pMac", __func__);
return -EINVAL;
}
if (!pMac->sme.pExtScanIndCb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid passpoint match event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
buf_ptr = (uint8_t *)param_buf->fixed_param;
/*
* All the below lengths are UINT32 and summing up and checking
* against a constant should not be an issue.
*/
if ((sizeof(*event) + event->ie_length + event->anqp_length) >
WMA_SVC_MSG_MAX_SIZE) {
WMA_LOGE("IE Length: %d or ANQP Length: %d is huge",
event->ie_length, event->anqp_length);
VOS_ASSERT(0);
return -EINVAL;
}
dest_match = vos_mem_malloc(sizeof(*dest_match) +
event->ie_length + event->anqp_length);
if (!dest_match) {
WMA_LOGE("%s: vos_mem_malloc failed", __func__);
return -EINVAL;
}
dest_ap = &dest_match->ap;
dest_match->request_id = 0;
dest_match->id = event->id;
dest_match->anqp_len = event->anqp_length;
WMA_LOGI("%s: passpoint match: id: %u anqp length %u", __func__,
dest_match->id, dest_match->anqp_len);
dest_ap->channel = event->channel_mhz;
dest_ap->ts = event->timestamp;
dest_ap->rtt = event->rtt;
dest_ap->rssi = event->rssi;
dest_ap->rtt_sd = event->rtt_sd;
dest_ap->beaconPeriod = event->beacon_period;
dest_ap->capability = event->capability;
dest_ap->ieLength = event->ie_length;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid);
vos_mem_copy(dest_ap->ssid, event->ssid.ssid,
event->ssid.ssid_len);
dest_ap->ssid[event->ssid.ssid_len] = '\0';
vos_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) +
WMI_TLV_HDR_SIZE, dest_ap->ieLength);
vos_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) +
WMI_TLV_HDR_SIZE + dest_ap->ieLength,
dest_match->anqp_len);
pMac->sme.pExtScanIndCb(pMac->hHdd,
eSIR_PASSPOINT_NETWORK_FOUND_IND,
dest_match);
WMA_LOGD("%s: sending passpoint match event to hdd", __func__);
vos_mem_free(dest_match);
return 0;
}
#endif
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
static int wma_unified_link_iface_stats_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
wmi_iface_link_stats_event_fixed_param *fixed_param;
wmi_iface_link_stats *link_stats;
wmi_wmm_ac_stats *ac_stats;
tSirLLStatsResults *link_stats_results;
u_int8_t *results, *t_link_stats, *t_ac_stats;
u_int32_t next_res_offset, next_ac_offset, count;
u_int32_t roaming_offset , roaming_size;
size_t link_stats_size, ac_stats_size, iface_info_size;
size_t link_stats_results_size;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!pMac) {
WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
return -EINVAL;
}
if (!pMac->sme.pLinkLayerStatsIndCallback) {
WMA_LOGD("%s: HDD callback is null", __func__);
return -EINVAL;
}
param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *)cmd_param_info;
if (!param_tlvs) {
WMA_LOGA("%s: Invalid stats event", __func__);
return -EINVAL;
}
/*
* cmd_param_info contains
* wmi_iface_link_stats_event_fixed_param fixed_param;
* wmi_iface_link_stats iface_link_stats;
* iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats)
*/
fixed_param = param_tlvs->fixed_param;
link_stats = param_tlvs->iface_link_stats;
ac_stats = param_tlvs->ac;
if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats)) {
WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__);
return -EINVAL;
}
if (link_stats->num_ac >= WIFI_AC_MAX) {
WMA_LOGE("%s: Excess data received from firmware num_ac %d",
__func__, link_stats->num_ac);
return -EINVAL;
}
link_stats_size = sizeof(tSirWifiIfaceStat);
iface_info_size = sizeof(tSirWifiInterfaceInfo);
ac_stats_size = sizeof(tSirWifiWmmAcStat);
link_stats_results_size = sizeof(*link_stats_results) +
link_stats_size;
link_stats_results = vos_mem_malloc(link_stats_results_size);
if (!link_stats_results) {
WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
__func__, link_stats_results_size);
return -ENOMEM;
}
vos_mem_zero(link_stats_results, link_stats_results_size);
link_stats_results->paramId = WMI_LINK_STATS_IFACE;
link_stats_results->rspId = fixed_param->request_id;
link_stats_results->ifaceId = fixed_param->vdev_id;
link_stats_results->num_peers = link_stats->num_peers;
link_stats_results->peer_event_number = 0;
link_stats_results->moreResultToFollow = 0;
results = (u_int8_t *)link_stats_results->results;
t_link_stats = (u_int8_t *)link_stats;
t_ac_stats = (u_int8_t *)ac_stats;
/* Copy roaming state */
roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming);
roaming_size = member_size(tSirWifiInterfaceInfo, roaming);
vos_mem_copy(results + roaming_offset, &link_stats->roam_state,
roaming_size);
vos_mem_copy(results + iface_info_size,
t_link_stats + WMI_TLV_HDR_SIZE,
link_stats_size - iface_info_size - WIFI_AC_MAX * ac_stats_size);
next_res_offset = link_stats_size - WIFI_AC_MAX * ac_stats_size;
next_ac_offset = WMI_TLV_HDR_SIZE;
for (count = 0; count < link_stats->num_ac; count++) {
ac_stats++;
vos_mem_copy(results + next_res_offset,
t_ac_stats + next_ac_offset,
ac_stats_size);
next_res_offset += ac_stats_size;
next_ac_offset += sizeof(*ac_stats);
}
/* call hdd callback with Link Layer Statistics
* vdev_id/ifacId in link_stats_results will be
* used to retrieve the correct HDD context
*/
pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
WDA_LINK_LAYER_STATS_RESULTS_RSP,
link_stats_results);
vos_mem_free(link_stats_results);
return 0;
}
static int wma_unified_link_peer_stats_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
wmi_peer_stats_event_fixed_param *fixed_param;
wmi_peer_link_stats *peer_stats, *temp_peer_stats;
wmi_rate_stats *rate_stats;
tSirLLStatsResults *link_stats_results;
u_int8_t *results, *t_peer_stats, *t_rate_stats;
u_int32_t count, rate_cnt;
uint32_t total_num_rates = 0;
u_int32_t next_res_offset, next_peer_offset, next_rate_offset;
size_t peer_info_size, peer_stats_size, rate_stats_size;
size_t link_stats_results_size;
bool excess_data = false;
u_int32_t buf_len;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!pMac) {
WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
return -EINVAL;
}
if (!pMac->sme.pLinkLayerStatsIndCallback) {
WMA_LOGD("%s: HDD callback is null", __func__);
return -EINVAL;
}
param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *)cmd_param_info;
if (!param_tlvs) {
WMA_LOGA("%s: Invalid stats event", __func__);
return -EINVAL;
}
/*
* cmd_param_info contains
* wmi_peer_stats_event_fixed_param fixed_param;
* num_peers * size of(struct wmi_peer_link_stats)
* total_num_rates * size of(struct wmi_rate_stats)
* total_num_rates is the sum of the rates of all the peers.
*/
fixed_param = param_tlvs->fixed_param;
peer_stats = param_tlvs->peer_stats;
rate_stats = param_tlvs->peer_rate_stats;
if (!fixed_param || !peer_stats ||
(peer_stats->num_rates && !rate_stats)) {
WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__);
return -EINVAL;
}
do {
if (fixed_param->num_peers >
WMA_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats)) {
excess_data = true;
break;
} else {
buf_len = fixed_param->num_peers *
sizeof(wmi_peer_link_stats);
}
temp_peer_stats = (wmi_peer_link_stats *) peer_stats;
for (count = 0; count < fixed_param->num_peers; count++) {
if (temp_peer_stats->num_rates >
WMA_SVC_MSG_MAX_SIZE / sizeof(wmi_rate_stats)) {
excess_data = true;
break;
} else {
total_num_rates += temp_peer_stats->num_rates;
if (total_num_rates >
WMA_SVC_MSG_MAX_SIZE /
sizeof(wmi_rate_stats)) {
excess_data = true;
break;
}
buf_len += temp_peer_stats->num_rates *
sizeof(wmi_rate_stats);
}
temp_peer_stats++;
}
} while (0);
if (excess_data ||
(sizeof(*fixed_param) > WMA_SVC_MSG_MAX_SIZE - buf_len)) {
WMA_LOGE("excess wmi buffer: rates:%d, peers:%d",
peer_stats->num_rates, fixed_param->num_peers);
VOS_ASSERT(0);
return -EINVAL;
}
peer_stats_size = sizeof(tSirWifiPeerStat);
peer_info_size = sizeof(tSirWifiPeerInfo);
rate_stats_size = sizeof(tSirWifiRateStat);
link_stats_results_size = sizeof(*link_stats_results) + peer_stats_size +
(fixed_param->num_peers * peer_info_size) +
(total_num_rates * rate_stats_size);
link_stats_results = vos_mem_malloc(link_stats_results_size);
if (NULL == link_stats_results ) {
WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
__func__, link_stats_results_size);
return -ENOMEM;
}
vos_mem_zero(link_stats_results, link_stats_results_size);
link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER;
link_stats_results->rspId = fixed_param->request_id;
link_stats_results->ifaceId = 0;
link_stats_results->num_peers = fixed_param->num_peers;
link_stats_results->peer_event_number = fixed_param->peer_event_number;
link_stats_results->moreResultToFollow = fixed_param->more_data;
vos_mem_copy(link_stats_results->results,
&fixed_param->num_peers, peer_stats_size);
results = (u_int8_t *)link_stats_results->results;
t_peer_stats = (u_int8_t *)peer_stats;
t_rate_stats = (u_int8_t *)rate_stats;
next_res_offset = peer_stats_size;
next_peer_offset = WMI_TLV_HDR_SIZE;
next_rate_offset = WMI_TLV_HDR_SIZE;
for (rate_cnt = 0; rate_cnt < fixed_param->num_peers; rate_cnt++) {
vos_mem_copy(results + next_res_offset,
t_peer_stats + next_peer_offset,
peer_info_size);
next_res_offset += peer_info_size;
/* Copy rate stats associated with this peer */
for (count = 0; count < peer_stats->num_rates; count++) {
rate_stats++;
vos_mem_copy(results + next_res_offset,
t_rate_stats + next_rate_offset,
rate_stats_size);
next_res_offset += rate_stats_size;
next_rate_offset += sizeof(*rate_stats);
}
next_peer_offset += sizeof(*peer_stats);
peer_stats++;
}
/* call hdd callback with Link Layer Statistics
* vdev_id/ifacId in link_stats_results will be
* used to retrieve the correct HDD context
*/
pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
WDA_LINK_LAYER_STATS_RESULTS_RSP,
link_stats_results);
vos_mem_free(link_stats_results);
return 0;
}
/**
* wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats
* @handle: WMI handle
* @cmd_param_info: command param info
* @len: Length of @cmd_param_info
*
* This is the WMI event handler function to receive radio stats tx
* power level stats.
*
* Return: 0 on success, error number otherwise.
*/
static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs;
wmi_tx_power_level_stats_evt_fixed_param *fixed_param;
uint8_t *tx_power_level_values;
tSirLLStatsResults *link_stats_results;
tSirWifiRadioStat *rs_results;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!pMac) {
WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
return -EINVAL;
}
if (!pMac->sme.pLinkLayerStatsIndCallback) {
WMA_LOGD("%s: HDD callback is null", __func__);
return -EINVAL;
}
param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *)cmd_param_info;
if (!param_tlvs) {
WMA_LOGA("%s: Invalid tx power level stats event", __func__);
return -EINVAL;
}
fixed_param = param_tlvs->fixed_param;
if (!fixed_param) {
WMA_LOGA("%s: Invalid param_tlvs for Radio tx_power level Stats", __func__);
return -EINVAL;
}
link_stats_results = wma_handle->link_stats_results;
if (!link_stats_results) {
WMA_LOGA("%s: link_stats_results is NULL", __func__);
return -EINVAL;
}
if (fixed_param->num_tx_power_levels > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*fixed_param)) / sizeof(uint32_t))) {
WMA_LOGE("%s: excess tx_power buffers:%d", __func__,
fixed_param->num_tx_power_levels);
VOS_ASSERT(0);
return -EINVAL;
}
rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0];
tx_power_level_values = (uint8 *) param_tlvs->tx_time_per_power_level;
rs_results->total_num_tx_power_levels =
fixed_param->total_num_tx_power_levels;
if (!rs_results->total_num_tx_power_levels)
goto post_stats;
if (!rs_results->tx_time_per_power_level) {
rs_results->tx_time_per_power_level = vos_mem_malloc(
sizeof(uint32_t) *
rs_results->total_num_tx_power_levels);
if (!rs_results->tx_time_per_power_level) {
WMA_LOGA("%s: Mem alloc failed for tx power level stats", __func__);
/* In error case, atleast send the radio stats without
* tx_power_level stats */
rs_results->total_num_tx_power_levels = 0;
goto post_stats;
}
}
vos_mem_copy(&rs_results->tx_time_per_power_level[fixed_param->power_level_offset],
tx_power_level_values,
sizeof(uint32_t) * fixed_param->num_tx_power_levels);
if (rs_results->total_num_tx_power_levels ==
(fixed_param->num_tx_power_levels + fixed_param->power_level_offset))
link_stats_results->moreResultToFollow = 0;
/* If still data to receive, return from here */
if (link_stats_results->moreResultToFollow)
return 0;
post_stats:
/* call hdd callback with Link Layer Statistics
* vdev_id/ifacId in link_stats_results will be
* used to retrieve the correct HDD context
*/
pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
WDA_LINK_LAYER_STATS_RESULTS_RSP,
link_stats_results);
vos_mem_free(rs_results->tx_time_per_power_level);
rs_results->tx_time_per_power_level = NULL;
vos_mem_free(wma_handle->link_stats_results);
wma_handle->link_stats_results = NULL;
return 0;
}
static int wma_unified_link_radio_stats_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
wmi_radio_link_stats_event_fixed_param *fixed_param;
wmi_radio_link_stats *radio_stats;
wmi_channel_stats *channel_stats;
tSirLLStatsResults *link_stats_results;
tSirWifiRadioStat *rs_results;
tSirWifiChannelStats *chn_results;
uint8_t *results, *t_radio_stats, *t_channel_stats;
uint32_t next_chan_offset, count;
size_t radio_stats_size, chan_stats_size;
size_t link_stats_results_size;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!pMac) {
WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__);
return -EINVAL;
}
if (!pMac->sme.pLinkLayerStatsIndCallback) {
WMA_LOGD("%s: HDD callback is null", __func__);
return -EINVAL;
}
param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *)cmd_param_info;
if (!param_tlvs) {
WMA_LOGA("%s: Invalid stats event", __func__);
return -EINVAL;
}
/*
* cmd_param_info contains
* wmi_radio_link_stats_event_fixed_param fixed_param;
* size of(struct wmi_radio_link_stats);
* num_channels * size of(struct wmi_channel_stats)
*/
fixed_param = param_tlvs->fixed_param;
radio_stats = param_tlvs->radio_stats;
channel_stats = param_tlvs->channel_stats;
if (!fixed_param || !radio_stats ||
(radio_stats->num_channels && !channel_stats)) {
WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__);
return -EINVAL;
}
if (radio_stats->num_channels >
NUM_2_4GHZ_CHANNELS + NUM_5GHZ_CHANNELS) {
WMA_LOGE("%s: Too many channels %d",
__func__, radio_stats->num_channels);
return -EINVAL;
}
radio_stats_size = sizeof(tSirWifiRadioStat);
chan_stats_size = sizeof(tSirWifiChannelStats);
if (fixed_param->num_radio >
(UINT_MAX - sizeof(*link_stats_results)) / radio_stats_size) {
WMA_LOGE("excess num_radio %d is leading to int overflow",
fixed_param->num_radio);
return -EINVAL;
}
link_stats_results_size = sizeof(*link_stats_results) +
radio_stats_size +
(radio_stats->num_channels * chan_stats_size);
wma_handle->link_stats_results = vos_mem_malloc(link_stats_results_size);
if (NULL == wma_handle->link_stats_results) {
WMA_LOGD("%s: could not allocate mem for stats results-len %zu",
__func__, link_stats_results_size);
return -ENOMEM;
}
link_stats_results = wma_handle->link_stats_results;
vos_mem_zero(link_stats_results, link_stats_results_size);
link_stats_results->paramId = WMI_LINK_STATS_RADIO;
link_stats_results->rspId = fixed_param->request_id;
link_stats_results->ifaceId = 0;
link_stats_results->num_radio = fixed_param->num_radio;
link_stats_results->peer_event_number = 0;
/*
* Backward compatibility:
* There are firmware(s) which will send Radio stats only with
* more_radio_events set to 0 and firmware which sends Radio stats
* followed by tx_power level stats with more_radio_events set to 1.
* if more_radio_events is set to 1, buffer the radio stats and
* wait for tx_power_level stats.
*/
link_stats_results->moreResultToFollow = fixed_param->more_radio_events;
results = (u_int8_t *)link_stats_results->results;
t_radio_stats = (u_int8_t *)radio_stats;
t_channel_stats = (u_int8_t *)channel_stats;
rs_results = (tSirWifiRadioStat *) &results[0];
rs_results->radio = radio_stats->radio_id;
rs_results->onTime = radio_stats->on_time;
rs_results->txTime = radio_stats->tx_time;
rs_results->rxTime = radio_stats->rx_time;
rs_results->onTimeScan = radio_stats->on_time_scan;
rs_results->onTimeNbd = radio_stats->on_time_nbd;
rs_results->onTimeGscan = radio_stats->on_time_gscan;
rs_results->onTimeRoamScan = radio_stats->on_time_roam_scan;
rs_results->onTimePnoScan = radio_stats->on_time_pno_scan;
rs_results->onTimeHs20 = radio_stats->on_time_hs20;
rs_results->total_num_tx_power_levels = 0;
rs_results->tx_time_per_power_level = NULL;
rs_results->numChannels = radio_stats->num_channels;
chn_results = (tSirWifiChannelStats *) &rs_results->channels[0];
next_chan_offset = WMI_TLV_HDR_SIZE;
for (count = 0; count < radio_stats->num_channels; count++) {
channel_stats++;
vos_mem_copy(chn_results,
t_channel_stats + next_chan_offset,
chan_stats_size);
chn_results++;
next_chan_offset += sizeof(*channel_stats);
}
if (link_stats_results->moreResultToFollow) {
/* More results coming, don't post yet */
return 0;
}
pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd,
WDA_LINK_LAYER_STATS_RESULTS_RSP,
link_stats_results);
vos_mem_free(wma_handle->link_stats_results);
WMA_LOGD(FL("Radio Stats event posted to HDD"));
wma_handle->link_stats_results = NULL;
return 0;
}
/**
* wma_peer_ps_evt_handler() - handler for PEER power state change.
* @handle: wma handle
* @event: FW event
* @len: length of FW event
*
* Once peer STA power state changes, an event will be indicated by
* FW. This function send a link layer state change msg to HDD. HDD
* link layer callback will converts the event to NL msg.
*
* Return: 0 Success. Others fail.
*/
static int wma_peer_ps_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *param_buf;
wmi_peer_sta_ps_statechange_event_fixed_param *fixed_param;
tSirWifiPeerStat *peer_stat;
tSirWifiPeerInfo *peer_info;
tSirLLStatsResults *link_stats_results;
tSirMacAddr mac_address;
uint32_t result_len;
tpAniSirGlobal mac;
vos_msg_t vos_msg;
mac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!mac) {
WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
return -EINVAL;
}
WMA_LOGD("%s: Posting Peer Stats PS event to HDD", __func__);
param_buf = (WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *)event;
fixed_param = param_buf->fixed_param;
result_len = sizeof(tSirLLStatsResults) +
sizeof(tSirWifiPeerStat) +
sizeof(tSirWifiPeerInfo);
link_stats_results = vos_mem_malloc(result_len);
if (link_stats_results == NULL) {
WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
return -EINVAL;
}
vos_mem_zero(link_stats_results, result_len);
WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_param->peer_macaddr, &mac_address[0]);
WMA_LOGD("Peer power state change event from FW");
WMA_LOGD("Fixed Param:");
WMA_LOGD("MAC address: %2x:%2x:%2x:%2x:%2x:%2x, Power state: %d",
mac_address[0], mac_address[1], mac_address[2],
mac_address[3], mac_address[4], mac_address[5],
fixed_param->peer_ps_state);
link_stats_results->paramId = WMI_LL_STATS_EXT_PS_CHG;
link_stats_results->num_peers = 1;
link_stats_results->peer_event_number = 1;
link_stats_results->moreResultToFollow = 0;
peer_stat = (tSirWifiPeerStat *)link_stats_results->results;
peer_stat->numPeers = 1;
peer_info = (tSirWifiPeerInfo *)peer_stat->peerInfo;
vos_mem_copy(&peer_info->peerMacAddress,
&mac_address, sizeof(tSirMacAddr));
peer_info->power_saving = fixed_param->peer_ps_state;
vos_msg.type = eWMI_SME_LL_STATS_IND;
vos_msg.bodyptr = (void *)link_stats_results;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg)) {
WMA_LOGP(FL("Failed to post peer stat change msg!"));
vos_mem_free(link_stats_results);
return -EINVAL;
}
return 0;
}
#define WMA_FILL_TX_STATS(eve, msg) do {\
(msg)->msdus = (eve)->tx_msdu_cnt;\
(msg)->mpdus = (eve)->tx_mpdu_cnt;\
(msg)->ppdus = (eve)->tx_ppdu_cnt;\
(msg)->bytes = (eve)->tx_bytes;\
(msg)->drops = (eve)->tx_msdu_drop_cnt;\
(msg)->drop_bytes = (eve)->tx_drop_bytes;\
(msg)->retries = (eve)->tx_mpdu_retry_cnt;\
(msg)->failed = (eve)->tx_mpdu_fail_cnt;\
} while (0)
#define WMA_FILL_RX_STATS(eve, msg) do {\
(msg)->mpdus = (eve)->mac_rx_mpdu_cnt;\
(msg)->bytes = (eve)->mac_rx_bytes;\
(msg)->ppdus = (eve)->phy_rx_ppdu_cnt;\
(msg)->ppdu_bytes = (eve)->phy_rx_bytes;\
(msg)->mpdu_retry = (eve)->rx_mpdu_retry_cnt;\
(msg)->mpdu_dup = (eve)->rx_mpdu_dup_cnt;\
(msg)->mpdu_discard = (eve)->rx_mpdu_discard_cnt;\
} while (0)
/**
* __wma_get_ll_stats_ext_buf() - alloc result buffer for MAC counters
* @len: buffer length output
* @peer_num: peer number
* @fixed_param: fixed parameters in WMI event
*
* Structure of the stats message
* LL_EXT_STATS
* |
* |--Channel stats[1~n]
* |--Peer[1~n]
* |
* +---Signal
* +---TX
* | +---BE
* | +---BK
* | +---VI
* | +---VO
* |
* +---RX
* +---BE
* +---BK
* +---VI
* +---VO
* For each Access Category, the arregation and mcs
* stats are as this:
* TX
* +-BE/BK/VI/VO
* +----tx_mpdu_aggr_array
* +----tx_succ_mcs_array
* +----tx_fail_mcs_array
* +----tx_delay_array
* RX
* +-BE/BK/VI/VO
* +----rx_mpdu_aggr_array
* +----rx_mcs_array
*
* return: Address for result buffer.
*/
static tSirLLStatsResults *__wma_get_ll_stats_ext_buf(uint32_t *len,
uint32_t peer_num,
wmi_report_stats_event_fixed_param *fixed_param)
{
tSirLLStatsResults *buf;
uint32_t buf_len;
uint32_t total_array_len, total_peer_len;
bool excess_data = false;
if (!len || !fixed_param) {
WMA_LOGE(FL("Invalid input parameters."));
return NULL;
}
/*
* Result buffer has a structure like this:
* ---------------------------------
* | trigger_cond_i |
* +-------------------------------+
* | cca_chgd_bitmap |
* +-------------------------------+
* | sig_chgd_bitmap |
* +-------------------------------+
* | tx_chgd_bitmap |
* +-------------------------------+
* | rx_chgd_bitmap |
* +-------------------------------+
* | peer_num |
* +-------------------------------+
* | channel_num |
* +-------------------------------+
* | time stamp |
* +-------------------------------+
* | tx_mpdu_aggr_array_len |
* +-------------------------------+
* | tx_succ_mcs_array_len |
* +-------------------------------+
* | tx_fail_mcs_array_len |
* +-------------------------------+
* | tx_delay_array_len |
* +-------------------------------+
* | rx_mpdu_aggr_array_len |
* +-------------------------------+
* | rx_mcs_array_len |
* +-------------------------------+
* | pointer to CCA stats |
* +-------------------------------+
* | CCA stats |
* +-------------------------------+
* | peer_stats |----+
* +-------------------------------+ |
* | TX aggr/mcs parameters array | |
* | Length of this buffer is | |
* | not fixed. |<-+ |
* +-------------------------------+ | |
* | per peer tx stats |--+ |
* | BE | <--+
* | BK | |
* | VI | |
* | VO | |
* +-------------------------------+ |
* | TX aggr/mcs parameters array | |
* | Length of this buffer is | |
* | not fixed. |<-+ |
* +-------------------------------+ | |
* | peer peer rx stats |--+ |
* | BE | <--+
* | BK |
* | VI |
* | VO |
* ---------------------------------
*/
buf_len = sizeof(tSirLLStatsResults) +
sizeof(struct sir_wifi_ll_ext_stats);
do {
if (fixed_param->num_chan_cca_stats > (WMA_SVC_MSG_MAX_SIZE /
sizeof(struct sir_wifi_chan_cca_stats))) {
excess_data = true;
break;
}
buf_len += (fixed_param->num_chan_cca_stats *
sizeof(struct sir_wifi_chan_cca_stats));
if (fixed_param->tx_mpdu_aggr_array_len >
WMA_SVC_MSG_MAX_SIZE) {
excess_data = true;
break;
} else {
total_array_len = fixed_param->tx_mpdu_aggr_array_len;
}
if (fixed_param->tx_succ_mcs_array_len >
(WMA_SVC_MSG_MAX_SIZE - total_array_len)) {
excess_data = true;
break;
} else {
total_array_len += fixed_param->tx_succ_mcs_array_len;
}
if (fixed_param->tx_fail_mcs_array_len >
(WMA_SVC_MSG_MAX_SIZE - total_array_len)) {
excess_data = true;
break;
} else {
total_array_len += fixed_param->tx_fail_mcs_array_len;
}
if (fixed_param->tx_ppdu_delay_array_len >
(WMA_SVC_MSG_MAX_SIZE - total_array_len)) {
excess_data = true;
break;
} else {
total_array_len += fixed_param->tx_ppdu_delay_array_len;
}
if (fixed_param->rx_mpdu_aggr_array_len >
(WMA_SVC_MSG_MAX_SIZE - total_array_len)) {
excess_data = true;
break;
} else {
total_array_len += fixed_param->rx_mpdu_aggr_array_len;
}
if (fixed_param->rx_mcs_array_len >
(WMA_SVC_MSG_MAX_SIZE - total_array_len)) {
excess_data = true;
break;
} else {
total_array_len += fixed_param->rx_mcs_array_len;
}
if (total_array_len > (WMA_SVC_MSG_MAX_SIZE /
(sizeof(uint16_t) * WLAN_MAX_AC))) {
excess_data = true;
break;
} else {
total_peer_len = (sizeof(uint32_t) * WLAN_MAX_AC *
total_array_len) +
(WLAN_MAX_AC *
(sizeof(struct sir_wifi_tx) +
sizeof(struct sir_wifi_rx)));
}
buf_len += peer_num *
(sizeof(struct sir_wifi_ll_ext_peer_stats) +
total_peer_len);
} while (0);
if (excess_data) {
WMA_LOGE("%s: excess wmi buffer: peer %d cca %d tx_mpdu %d ",
__func__, peer_num, fixed_param->num_chan_cca_stats,
fixed_param->tx_mpdu_aggr_array_len);
WMA_LOGE("tx_succ %d tx_fail %d tx_ppdu %d ",
fixed_param->tx_succ_mcs_array_len,
fixed_param->tx_fail_mcs_array_len,
fixed_param->tx_ppdu_delay_array_len);
WMA_LOGE("rx_mpdu %d rx_mcs %d",
fixed_param->rx_mpdu_aggr_array_len,
fixed_param->rx_mcs_array_len);
return NULL;
}
buf = (tSirLLStatsResults *)vos_mem_malloc(buf_len);
if (buf == NULL) {
WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
buf_len = 0;
return NULL;
}
vos_mem_zero(buf, buf_len);
*len = buf_len;
return buf;
}
/**
* __wma_fill_tx_stats() - Fix TX stats into result buffer
* @ll_stats: LL stats buffer
* @fix_param: parameters with fixed length in WMI event
* @param_buf: parameters without fixed length in WMI event
* @buf: buffer for TLV parameters
*/
static void __wma_fill_tx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
wmi_report_stats_event_fixed_param *fix_param,
WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
uint8_t **buf,
uint32_t *buf_length)
{
uint8_t *result;
uint32_t i, j, k;
wmi_peer_ac_tx_stats *wmi_peer_tx;
wmi_tx_stats *wmi_tx;
struct sir_wifi_tx *tx_stats;
struct sir_wifi_ll_ext_peer_stats *peer_stats;
uint8_t *counter;
uint32_t *tx_mpdu_aggr, *tx_succ_mcs, *tx_fail_mcs, *tx_delay;
uint32_t len, dst_len, tx_mpdu_aggr_array_len, tx_succ_mcs_array_len,
tx_fail_mcs_array_len, tx_delay_array_len;
result = *buf;
dst_len = *buf_length;
tx_mpdu_aggr_array_len = fix_param->tx_mpdu_aggr_array_len;
ll_stats->tx_mpdu_aggr_array_len = tx_mpdu_aggr_array_len;
tx_succ_mcs_array_len = fix_param->tx_succ_mcs_array_len;
ll_stats->tx_succ_mcs_array_len = tx_succ_mcs_array_len;
tx_fail_mcs_array_len = fix_param->tx_fail_mcs_array_len;
ll_stats->tx_fail_mcs_array_len = tx_fail_mcs_array_len;
tx_delay_array_len = fix_param->tx_ppdu_delay_array_len;
ll_stats->tx_delay_array_len = tx_delay_array_len;
wmi_peer_tx = param_buf->peer_ac_tx_stats;
wmi_tx = param_buf->tx_stats;
len = fix_param->num_peer_ac_tx_stats *
WLAN_MAX_AC * tx_mpdu_aggr_array_len;
if (len * sizeof(uint32_t) <= dst_len) {
tx_mpdu_aggr = (uint32_t *)result;
counter = (uint8_t *)param_buf->tx_mpdu_aggr;
for (i = 0; i < len; i++) {
result[4 * i] = counter[2 * i];
result[4 * i + 1] = counter[2 * i + 1];
}
result += len * sizeof(uint32_t);
dst_len -= len * sizeof(uint32_t);
} else {
WMA_LOGE(FL("TX_MPDU_AGGR buffer length is wrong."));
tx_mpdu_aggr = NULL;
}
len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
tx_succ_mcs_array_len;
if (len * sizeof(uint32_t) <= dst_len) {
tx_succ_mcs = (uint32_t *)result;
counter = (uint8_t *)param_buf->tx_succ_mcs;
for (i = 0; i < len; i++) {
result[4 * i] = counter[2 * i];
result[4 * i + 1] = counter[2 * i + 1];
}
len *= sizeof(uint32_t);
result += len;
dst_len -= len;
} else {
WMA_LOGE(FL("TX_SUCC_MCS buffer length is wrong."));
tx_succ_mcs = NULL;
}
len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC *
tx_fail_mcs_array_len;
if (len * sizeof(uint32_t) <= dst_len) {
tx_fail_mcs = (uint32_t *)result;
counter = (uint8_t *)param_buf->tx_fail_mcs;
for (i = 0; i < len; i++) {
result[4 * i] = counter[2 * i];
result[4 * i + 1] = counter[2 * i + 1];
}
len *= sizeof(uint32_t);
result += len;
dst_len -= len;
} else {
WMA_LOGE(FL("TX_FAIL_MCS buffer length is wrong."));
tx_fail_mcs = NULL;
}
len = fix_param->num_peer_ac_tx_stats *
WLAN_MAX_AC * tx_delay_array_len;
if (len * sizeof(uint32_t) <= dst_len) {
tx_delay = (uint32_t *)result;
counter = (uint8_t *)param_buf->tx_ppdu_delay;
for (i = 0; i < len; i++) {
result[4 * i] = counter[2 * i];
result[4 * i + 1] = counter[2 * i + 1];
}
len *= sizeof(uint32_t);
result += len;
dst_len -= len;
} else {
WMA_LOGE(FL("TX_DELAY buffer length is wrong."));
tx_delay = NULL;
}
/* per peer tx stats */
peer_stats = ll_stats->peer_stats;
for (i = 0; i < fix_param->num_peer_ac_tx_stats; i++) {
uint32_t peer_id = wmi_peer_tx[i].peer_id;
struct sir_wifi_tx *ac;
wmi_tx_stats *wmi_tx_stats;
for (j = 0; j < ll_stats->peer_num; j++) {
peer_stats += j;
if (peer_stats->peer_id == WIFI_INVALID_PEER_ID ||
peer_stats->peer_id == peer_id)
break;
}
if (j < ll_stats->peer_num) {
peer_stats->peer_id = wmi_peer_tx[i].peer_id;
peer_stats->vdev_id = wmi_peer_tx[i].vdev_id;
tx_stats = (struct sir_wifi_tx *)result;
for (k = 0; k < WLAN_MAX_AC; k++) {
wmi_tx_stats = &wmi_tx[i * WLAN_MAX_AC + k];
ac = &tx_stats[k];
WMA_FILL_TX_STATS(wmi_tx_stats, ac);
ac->mpdu_aggr_size = tx_mpdu_aggr;
ac->aggr_len = tx_mpdu_aggr_array_len *
sizeof(uint32_t);
ac->success_mcs_len = tx_succ_mcs_array_len *
sizeof(uint32_t);
ac->success_mcs = tx_succ_mcs;
ac->fail_mcs = tx_fail_mcs;
ac->fail_mcs_len = tx_fail_mcs_array_len *
sizeof(uint32_t);
ac->delay = tx_delay;
ac->delay_len = tx_delay_array_len *
sizeof(uint32_t);
peer_stats->ac_stats[k].tx_stats = ac;
peer_stats->ac_stats[k].type = k;
tx_mpdu_aggr += tx_mpdu_aggr_array_len;
tx_succ_mcs += tx_succ_mcs_array_len;
tx_fail_mcs += tx_fail_mcs_array_len;
tx_delay += tx_delay_array_len;
}
result += WLAN_MAX_AC * sizeof(struct sir_wifi_tx);
} else {
/*
* Buffer for Peer TX counter overflow.
* There is peer ID mismatch between TX, RX,
* signal counters.
*/
WMA_LOGE(FL("One peer TX info is dropped."));
tx_mpdu_aggr += tx_mpdu_aggr_array_len * WLAN_MAX_AC;
tx_succ_mcs += tx_succ_mcs_array_len * WLAN_MAX_AC;
tx_fail_mcs += tx_fail_mcs_array_len * WLAN_MAX_AC;
tx_delay += tx_delay_array_len * WLAN_MAX_AC;
}
}
*buf = result;
*buf_length = dst_len;
}
/**
* __wma_fill_rx_stats() - Fix RX stats into result buffer
* @ll_stats: LL stats buffer
* @fix_param: parameters with fixed length in WMI event
* @param_buf: parameters without fixed length in WMI event
* @buf: buffer for TLV parameters
*/
static void __wma_fill_rx_stats(struct sir_wifi_ll_ext_stats *ll_stats,
wmi_report_stats_event_fixed_param *fix_param,
WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf,
uint8_t **buf,
uint32_t *buf_length)
{
uint8 *result;
uint32_t i, j, k;
uint32_t *rx_mpdu_aggr, *rx_mcs;
wmi_rx_stats *wmi_rx;
wmi_peer_ac_rx_stats *wmi_peer_rx;
struct sir_wifi_rx *rx_stats;
struct sir_wifi_ll_ext_peer_stats *peer_stats;
uint32_t len, dst_len, rx_mpdu_aggr_array_len, rx_mcs_array_len;
uint8_t *counter;
rx_mpdu_aggr_array_len = fix_param->rx_mpdu_aggr_array_len;
ll_stats->rx_mpdu_aggr_array_len = rx_mpdu_aggr_array_len;
rx_mcs_array_len = fix_param->rx_mcs_array_len;
ll_stats->rx_mcs_array_len = rx_mcs_array_len;
wmi_peer_rx = param_buf->peer_ac_rx_stats;
wmi_rx = param_buf->rx_stats;
result = *buf;
dst_len = *buf_length;
len = fix_param->num_peer_ac_rx_stats *
WLAN_MAX_AC * rx_mpdu_aggr_array_len;
if (len * sizeof(uint32_t) <= dst_len) {
rx_mpdu_aggr = (uint32_t *)result;
counter = (uint8_t *)param_buf->rx_mpdu_aggr;
for (i = 0; i < len; i++) {
result[4 * i] = counter[2 * i];
result[4 * i + 1] = counter[2 * i + 1];
}
len *= sizeof(uint32_t);
result += len;
dst_len -= len;
} else {
WMA_LOGE(FL("RX_MPDU_AGGR array length is wrong."));
rx_mpdu_aggr = NULL;
}
len = fix_param->num_peer_ac_rx_stats *
WLAN_MAX_AC * rx_mcs_array_len;
if (len * sizeof(uint32_t) <= dst_len) {
rx_mcs = (uint32_t *)result;
counter = (uint8_t *)param_buf->rx_mcs;
for (i = 0; i < len; i++) {
result[4 * i] = counter[2 * i];
result[4 * i + 1] = counter[2 * i + 1];
}
len *= sizeof(uint32_t);
result += len;
dst_len -= len;
} else {
WMA_LOGE(FL("RX_MCS array length is wrong."));
rx_mcs = NULL;
}
/* per peer rx stats */
peer_stats = ll_stats->peer_stats;
for (i = 0; i < fix_param->num_peer_ac_rx_stats; i++) {
uint32_t peer_id = wmi_peer_rx[i].peer_id;
struct sir_wifi_rx *ac;
wmi_rx_stats *wmi_rx_stats;
for (j = 0; j < ll_stats->peer_num; j++) {
peer_stats += j;
if ((peer_stats->peer_id == WIFI_INVALID_PEER_ID) ||
(peer_stats->peer_id == peer_id))
break;
}
if (j < ll_stats->peer_num) {
peer_stats->peer_id = wmi_peer_rx[i].peer_id;
peer_stats->vdev_id = wmi_peer_rx[i].vdev_id;
peer_stats->sta_ps_inds = wmi_peer_rx[i].sta_ps_inds;
peer_stats->sta_ps_durs = wmi_peer_rx[i].sta_ps_durs;
peer_stats->rx_probe_reqs =
wmi_peer_rx[i].rx_probe_reqs;
peer_stats->rx_oth_mgmts = wmi_peer_rx[i].rx_oth_mgmts;
rx_stats = (struct sir_wifi_rx *)result;
for (k = 0; k < WLAN_MAX_AC; k++) {
wmi_rx_stats = &wmi_rx[i * WLAN_MAX_AC + k];
ac = &rx_stats[k];
WMA_FILL_RX_STATS(wmi_rx_stats, ac);
ac->mpdu_aggr = rx_mpdu_aggr;
ac->aggr_len = rx_mpdu_aggr_array_len *
sizeof(uint32_t);
ac->mcs = rx_mcs;
ac->mcs_len = rx_mcs_array_len *
sizeof(uint32_t);
peer_stats->ac_stats[k].rx_stats = ac;
peer_stats->ac_stats[k].type = k;
rx_mpdu_aggr += rx_mpdu_aggr_array_len;
rx_mcs += rx_mcs_array_len;
}
result += WLAN_MAX_AC * sizeof(struct sir_wifi_rx);
} else {
/*
* Buffer for Peer RX counter overflow.
* There is peer ID mismatch between TX, RX,
* signal counters.
*/
WMA_LOGE(FL("One peer RX info is dropped."));
rx_mpdu_aggr += rx_mpdu_aggr_array_len * WLAN_MAX_AC;
rx_mcs += rx_mcs_array_len * WLAN_MAX_AC;
}
}
*buf = result;
*buf_length = dst_len;
}
/**
* __wma_ll_stats_time_stamp() - log indication timestamp and counting duration
* @period - counting period on FW side
* @time_stamp - time stamp for user layer
*
* return: none
*/
static void __wma_ll_stats_time_stamp(wmi_stats_period *period,
struct sir_wifi_ll_ext_period *time_stamp)
{
time_stamp->end_time = vos_timer_get_system_time();
if (!period) {
WMA_LOGE(FL("Period buf is null."));
time_stamp->duration = 0;
return;
}
WMA_LOGD(FL("On fw side, start time is %d, start count is %d "),
period->start_low_freq_msec, period->start_low_freq_count);
time_stamp->duration = period->end_low_freq_msec -
period->start_low_freq_msec;
}
/**
* wma_ll_stats_evt_handler() - handler for MAC layer counters.
* @handle - wma handle
* @event - FW event
* @len - length of FW event
*
* return: 0 success.
*/
static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf;
wmi_report_stats_event_fixed_param *fixed_param;
tSirLLStatsResults *link_stats_results;
wmi_chan_cca_stats *wmi_cca_stats;
wmi_peer_signal_stats *wmi_peer_signal;
wmi_peer_ac_rx_stats *wmi_peer_rx;
struct sir_wifi_ll_ext_stats *ll_stats;
struct sir_wifi_ll_ext_peer_stats *peer_stats;
struct sir_wifi_chan_cca_stats *cca_stats;
struct sir_wifi_peer_signal_stats *peer_signal;
uint8_t *result;
uint32_t i, peer_num, result_size, dst_len;
tpAniSirGlobal mac;
vos_msg_t vos_msg;
struct ol_txrx_peer_t *peer;
ol_txrx_pdev_handle pdev;
wmi_stats_period *period;
mac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!mac) {
WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
return -EINVAL;
}
if (!mac->sme.link_layer_stats_ext_cb) {
WMA_LOGD("%s: HDD callback is null", __func__);
return -EINVAL;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma_handle->vos_context);
if (!pdev) {
WMA_LOGD("%s: NULL ol_txrx pdev ptr. Exiting", __func__);
return -EINVAL;
}
WMA_LOGD("%s: Posting MAC counters event to HDD", __func__);
param_buf = (WMI_REPORT_STATS_EVENTID_param_tlvs *)event;
fixed_param = param_buf->fixed_param;
wmi_cca_stats = param_buf->chan_cca_stats;
wmi_peer_signal = param_buf->peer_signal_stats;
wmi_peer_rx = param_buf->peer_ac_rx_stats;
period = param_buf->stats_period;
WMA_LOGD("%s: stats period length is %d. ", __func__,
fixed_param->stats_period_array_len);
/* Get the MAX of three peer numbers */
peer_num = fixed_param->num_peer_signal_stats >
fixed_param->num_peer_ac_tx_stats ?
fixed_param->num_peer_signal_stats :
fixed_param->num_peer_ac_tx_stats;
peer_num = peer_num > fixed_param->num_peer_ac_rx_stats ?
peer_num : fixed_param->num_peer_ac_rx_stats;
if (peer_num == 0)
return -EINVAL;
link_stats_results = __wma_get_ll_stats_ext_buf(&result_size,
peer_num,
fixed_param);
if (!link_stats_results) {
WMA_LOGE("%s: Fail to allocate stats buffer", __func__);
return -EINVAL;
}
link_stats_results->paramId = WMI_LL_STATS_EXT_MAC_COUNTER;
link_stats_results->num_peers = peer_num;
link_stats_results->peer_event_number = 1;
link_stats_results->moreResultToFollow = 0;
ll_stats = (struct sir_wifi_ll_ext_stats *)link_stats_results->results;
ll_stats->trigger_cond_id = fixed_param->trigger_cond_id;
ll_stats->cca_chgd_bitmap = fixed_param->cca_chgd_bitmap;
ll_stats->sig_chgd_bitmap = fixed_param->sig_chgd_bitmap;
ll_stats->tx_chgd_bitmap = fixed_param->tx_chgd_bitmap;
ll_stats->rx_chgd_bitmap = fixed_param->rx_chgd_bitmap;
ll_stats->channel_num = fixed_param->num_chan_cca_stats;
ll_stats->peer_num = peer_num;
__wma_ll_stats_time_stamp(period, &ll_stats->time_stamp);
result = (uint8_t *)ll_stats->stats;
peer_stats = (struct sir_wifi_ll_ext_peer_stats *)result;
ll_stats->peer_stats = peer_stats;
for (i = 0; i < peer_num; i++) {
peer_stats[i].peer_id = WIFI_INVALID_PEER_ID;
peer_stats[i].vdev_id = WIFI_INVALID_VDEV_ID;
}
/* Per peer signal */
result_size -= sizeof(struct sir_wifi_ll_ext_stats);
dst_len = sizeof(struct sir_wifi_peer_signal_stats);
for (i = 0; i < fixed_param->num_peer_signal_stats; i++) {
peer_stats[i].peer_id = wmi_peer_signal->peer_id;
peer_stats[i].vdev_id = wmi_peer_signal->vdev_id;
peer_signal = &peer_stats[i].peer_signal_stats;
WMA_LOGI("%d antennas for peer %d",
wmi_peer_signal->num_chains_valid,
wmi_peer_signal->peer_id);
if (dst_len <= result_size) {
peer_signal->vdev_id = wmi_peer_signal->vdev_id;
peer_signal->peer_id = wmi_peer_signal->peer_id;
peer_signal->num_chain =
wmi_peer_signal->num_chains_valid;
vos_mem_copy(peer_signal->per_ant_snr,
wmi_peer_signal->per_chain_snr,
sizeof(peer_signal->per_ant_snr));
vos_mem_copy(peer_signal->nf,
wmi_peer_signal->per_chain_nf,
sizeof(peer_signal->nf));
vos_mem_copy(peer_signal->per_ant_rx_mpdus,
wmi_peer_signal->per_antenna_rx_mpdus,
sizeof(peer_signal->per_ant_rx_mpdus));
vos_mem_copy(peer_signal->per_ant_tx_mpdus,
wmi_peer_signal->per_antenna_tx_mpdus,
sizeof(peer_signal->per_ant_tx_mpdus));
result_size -= dst_len;
} else {
WMA_LOGE(FL("Invalid length of PEER signal."));
}
peer = ol_txrx_peer_find_by_id(pdev,
wmi_peer_signal->peer_id);
if (!peer) {
WMA_LOGE(FL("Invalid Peer ID %d in FW message."),
wmi_peer_signal->peer_id);
} else {
vos_mem_copy(&peer_stats[i].mac_address,
&peer->mac_addr,
sizeof(peer_stats[i].mac_address));
WMA_LOGI("Peer %d mac address is: ",
wmi_peer_signal->peer_id);
WMA_LOGI("%2x:%2x:%2x:%2x:%2x:%2x.",
peer->mac_addr.raw[0], peer->mac_addr.raw[1],
peer->mac_addr.raw[2], peer->mac_addr.raw[3],
peer->mac_addr.raw[4], peer->mac_addr.raw[5]);
}
wmi_peer_signal++;
}
result += peer_num * sizeof(struct sir_wifi_ll_ext_peer_stats);
cca_stats = (struct sir_wifi_chan_cca_stats *)result;
ll_stats->cca = cca_stats;
dst_len = sizeof(struct sir_wifi_chan_cca_stats);
for (i = 0; i < ll_stats->channel_num; i++) {
if (dst_len <= result_size) {
vos_mem_copy(&cca_stats[i], &wmi_cca_stats->vdev_id,
dst_len);
result_size -= dst_len;
} else {
WMA_LOGE(FL("Invalid length of CCA."));
}
}
result += i * sizeof(struct sir_wifi_chan_cca_stats);
__wma_fill_tx_stats(ll_stats, fixed_param, param_buf,
&result, &result_size);
__wma_fill_rx_stats(ll_stats, fixed_param, param_buf,
&result, &result_size);
vos_msg.type = eWMI_SME_LL_STATS_IND;
vos_msg.bodyptr = (void *)link_stats_results;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg)) {
WMA_LOGP(FL("Failed to post peer stat change msg!"));
vos_mem_free(link_stats_results);
return -EINVAL;
}
return 0;
}
static int wmi_unified_pdev_set_param(wmi_unified_t wmi_handle,
WMI_PDEV_PARAM param_id,
u_int32_t param_value);
/**
* wma_tx_failure_cb() - TX failure callback
* @ctx: txrx context
* @num_msdu: number of msdu with the same status
* @tid: TID number
* @status: failure status
* 1: TX packet discarded
* 2: No ACK
* 3: Postpone
*/
void wma_tx_failure_cb(void *ctx, uint32_t num_msdu, uint8_t tid, uint32 status)
{
tSirLLStatsResults *results;
struct sir_wifi_iface_tx_fail *tx_fail;
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tpAniSirGlobal mac;
uint32_t len;
vos_msg_t vos_msg;
mac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE, vos_context);
if (!mac) {
WMA_LOGD("%s: NULL mac ptr. Exiting", __func__);
return;
}
len = sizeof(tSirLLStatsResults) +
sizeof(struct sir_wifi_iface_tx_fail);
results = vos_mem_malloc(len);
if (results == NULL) {
WMA_LOGE("%s: Cannot allocate link layer stats.", __func__);
return;
}
vos_mem_zero(results, len);
results->paramId = WMI_LL_STATS_EXT_TX_FAIL;
results->num_peers = 1;
results->peer_event_number = 1;
results->moreResultToFollow = 0;
tx_fail = (struct sir_wifi_iface_tx_fail *)results->results;
tx_fail->tid = tid;
tx_fail->msdu_num = num_msdu;
tx_fail->status = status;
vos_msg.type = eWMI_SME_LL_STATS_IND;
vos_msg.bodyptr = (void *)results;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg)) {
WMA_LOGP(FL("Failed to post tx failure msg!"));
vos_mem_free(results);
}
}
/**
* void wma_config_stats_ext_threshold - set threthold for MAC counters
* @wma: wma handler
* @threshold: threhold for MAC counters
*
* For each MAC layer counter, FW holds two copies. One is the current value.
* The other is the last report. Once a current counter's increment is larger
* than the threshold, FW will indicate that counter to host even if the
* monitoring timer does not expire.
*/
void wma_config_stats_ext_threshold(struct wma_handle *wma,
struct sir_ll_ext_stats_threshold *thresh)
{
uint32_t len, tag, hdr_len;
uint8_t *buf_ptr;
wmi_buf_t buf;
wmi_pdev_set_stats_threshold_cmd_fixed_param *cmd;
wmi_chan_cca_stats_thresh *cca;
wmi_peer_signal_stats_thresh *signal;
wmi_tx_stats_thresh *tx;
wmi_rx_stats_thresh *rx;
if (thresh->period != LL_STATS_INVALID_PERIOD) {
/*
* only set period,
* otherwise former threshold would be modified.
*/
if (wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
thresh->period))
WMA_LOGP(FL("Failed to set MAC counter period."));
WMA_LOGD(FL("Mac counter period=%d."), thresh->period);
return;
}
len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param) +
sizeof(wmi_chan_cca_stats_thresh) +
sizeof(wmi_peer_signal_stats_thresh) +
sizeof(wmi_tx_stats_thresh) +
sizeof(wmi_rx_stats_thresh) +
5 * WMI_TLV_HDR_SIZE;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return;
}
buf_ptr = (u_int8_t *)wmi_buf_data(buf);
tag = WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param;
hdr_len = WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_stats_threshold_cmd_fixed_param);
WMA_LOGD(FL("Setting fixed parameters. tag=%d, len=%d"), tag, hdr_len);
cmd = (wmi_pdev_set_stats_threshold_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header, tag, hdr_len);
cmd->enable_thresh = thresh->enable;
cmd->use_thresh_bitmap = thresh->enable_bitmap;
cmd->gbl_thresh = thresh->global_threshold;
cmd->cca_thresh_enable_bitmap = thresh->cca_bitmap;
cmd->signal_thresh_enable_bitmap = thresh->signal_bitmap;
cmd->tx_thresh_enable_bitmap = thresh->tx_bitmap;
cmd->rx_thresh_enable_bitmap = thresh->rx_bitmap;
len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param);
tag = WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh,
hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_chan_cca_stats_thresh);
cca = (wmi_chan_cca_stats_thresh *)(buf_ptr + len);
WMITLV_SET_HDR(&cca->tlv_header, tag, hdr_len);
WMA_LOGD(FL("Setting cca parameters. tag=%d, len=%d"), tag, hdr_len);
cca->idle_time = thresh->cca.idle_time;
cca->tx_time = thresh->cca.tx_time;
cca->rx_in_bss_time = thresh->cca.rx_in_bss_time;
cca->rx_out_bss_time = thresh->cca.rx_out_bss_time;
cca->rx_busy_time = thresh->cca.rx_busy_time;
cca->rx_in_bad_cond_time = thresh->cca.rx_in_bad_cond_time;
cca->tx_in_bad_cond_time = thresh->cca.tx_in_bad_cond_time;
cca->wlan_not_avail_time = thresh->cca.wlan_not_avail_time;
WMA_LOGD(FL("idle time=%d, tx_time=%d, in_bss=%d, out_bss=%d"),
cca->idle_time, cca->tx_time,
cca->rx_in_bss_time, cca->rx_out_bss_time);
WMA_LOGD(FL("rx_busy=%d, rx_bad=%d, tx_bad=%d, not_avail=%d"),
cca->rx_busy_time, cca->rx_in_bad_cond_time,
cca->tx_in_bad_cond_time, cca->wlan_not_avail_time);
len += sizeof(wmi_chan_cca_stats_thresh);
signal = (wmi_peer_signal_stats_thresh *)(buf_ptr + len);
tag = WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh;
hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_peer_signal_stats_thresh);
WMA_LOGD(FL("Setting signal parameters. tag=%d, len=%d"), tag, hdr_len);
WMITLV_SET_HDR(&signal->tlv_header, tag, hdr_len);
signal->per_chain_snr = thresh->signal.snr;
signal->per_chain_nf = thresh->signal.nf;
WMA_LOGD(FL("snr=%d, nf=%d"), signal->per_chain_snr,
signal->per_chain_nf);
len += sizeof(wmi_peer_signal_stats_thresh);
tx = (wmi_tx_stats_thresh *)(buf_ptr + len);
tag = WMITLV_TAG_STRUC_wmi_tx_stats_thresh;
hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_tx_stats_thresh);
WMA_LOGD(FL("Setting TX parameters. tag=%d, len=%d"), tag, len);
WMITLV_SET_HDR(&tx->tlv_header, tag, hdr_len);
tx->tx_msdu_cnt = thresh->tx.msdu;
tx->tx_mpdu_cnt = thresh->tx.mpdu;
tx->tx_ppdu_cnt = thresh->tx.ppdu;
tx->tx_bytes = thresh->tx.bytes;
tx->tx_msdu_drop_cnt = thresh->tx.msdu_drop;
tx->tx_drop_bytes = thresh->tx.byte_drop;
tx->tx_mpdu_retry_cnt = thresh->tx.mpdu_retry;
tx->tx_mpdu_fail_cnt = thresh->tx.mpdu_fail;
tx->tx_ppdu_fail_cnt = thresh->tx.ppdu_fail;
tx->tx_mpdu_aggr = thresh->tx.aggregation;
tx->tx_succ_mcs = thresh->tx.succ_mcs;
tx->tx_fail_mcs = thresh->tx.fail_mcs;
tx->tx_ppdu_delay = thresh->tx.delay;
WMA_LOGD(FL("msdu=%d, mpdu=%d, ppdu=%d, bytes=%d, msdu_drop=%d"),
tx->tx_msdu_cnt, tx->tx_mpdu_cnt, tx->tx_ppdu_cnt,
tx->tx_bytes, tx->tx_msdu_drop_cnt);
WMA_LOGD(FL("byte_drop=%d, mpdu_retry=%d, mpdu_fail=%d, ppdu_fail=%d"),
tx->tx_drop_bytes, tx->tx_mpdu_retry_cnt,
tx->tx_mpdu_fail_cnt, tx->tx_ppdu_fail_cnt);
WMA_LOGD(FL("aggr=%d, succ_mcs=%d, fail_mcs=%d, delay=%d"),
tx->tx_mpdu_aggr, tx->tx_succ_mcs, tx->tx_fail_mcs,
tx->tx_ppdu_delay);
len += sizeof(wmi_tx_stats_thresh);
rx = (wmi_rx_stats_thresh *)(buf_ptr + len);
tag = WMITLV_TAG_STRUC_wmi_rx_stats_thresh,
hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_rx_stats_thresh);
WMITLV_SET_HDR(&rx->tlv_header, tag, hdr_len);
WMA_LOGD(FL("Setting RX parameters. tag=%d, len=%d"), tag, hdr_len);
rx->mac_rx_mpdu_cnt = thresh->rx.mpdu;
rx->mac_rx_bytes = thresh->rx.bytes;
rx->phy_rx_ppdu_cnt = thresh->rx.ppdu;
rx->phy_rx_bytes = thresh->rx.ppdu_bytes;
rx->rx_disorder_cnt = thresh->rx.disorder;
rx->rx_mpdu_retry_cnt = thresh->rx.mpdu_retry;
rx->rx_mpdu_dup_cnt = thresh->rx.mpdu_dup;
rx->rx_mpdu_discard_cnt = thresh->rx.mpdu_discard;
rx->rx_mpdu_aggr = thresh->rx.aggregation;
rx->rx_mcs = thresh->rx.mcs;
rx->sta_ps_inds = thresh->rx.ps_inds;
rx->sta_ps_durs = thresh->rx.ps_durs;
rx->rx_probe_reqs = thresh->rx.probe_reqs;
rx->rx_oth_mgmts = thresh->rx.other_mgmt;
WMA_LOGD(FL("rx_mpdu=%d, rx_bytes=%d, rx_ppdu=%d, rx_pbytes=%d"),
rx->mac_rx_mpdu_cnt, rx->mac_rx_bytes,
rx->phy_rx_ppdu_cnt, rx->phy_rx_bytes);
WMA_LOGD(FL("disorder=%d, rx_dup=%d, rx_aggr=%d, rx_mcs=%d"),
rx->rx_disorder_cnt, rx->rx_mpdu_dup_cnt,
rx->rx_mpdu_aggr, rx->rx_mcs);
WMA_LOGD(FL("rx_ind=%d, rx_dur=%d, rx_probe=%d, rx_mgmt=%d"),
rx->sta_ps_inds, rx->sta_ps_durs,
rx->rx_probe_reqs, rx->rx_oth_mgmts);
len += sizeof(wmi_rx_stats_thresh);
WMA_LOGA("WMA --> WMI_PDEV_SET_STATS_THRESHOLD_CMDID(0x%x), length=%d",
WMI_PDEV_SET_STATS_THRESHOLD_CMDID, len);
if (EOK != wmi_unified_cmd_send(wma->wmi_handle,
buf, len,
WMI_PDEV_SET_STATS_THRESHOLD_CMDID)) {
WMA_LOGE("Failed to send WMI_PDEV_SET_STATS_THRESHOLD_CMDID");
wmi_buf_free(buf);
}
}
#else
/**
* wma_tx_failure_cb() - TX failure callback
* @ctx: txrx context
* @num_msdu: number of msdu with the same status
* @tid: TID number
* @status: failure status
* 1: TX packet discarded
* 2: No ACK
* 3: Postpone
*/
void wma_tx_failure_cb(void *ctx, uint32_t num_msdu, uint8_t tid, uint32 status)
{
}
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
/**
* wma_unified_power_debug_stats_event_handler() - WMA handler function to
* handle Power stats event from firmware
* @handle: Pointer to wma handle
* @cmd_param_info: Pointer to Power stats event TLV
* @len: Length of the cmd_param_info
*
* Return: 0 on success, error number otherwise
*/
#ifdef WLAN_POWER_DEBUGFS
static int wma_unified_power_debug_stats_event_handler(void *handle,
uint8_t *cmd_param_info, uint32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *param_tlvs;
struct power_stats_response *power_stats_results;
wmi_pdev_chip_power_stats_event_fixed_param *param_buf;
uint32_t power_stats_len, stats_registers_len, *debug_registers;
tpAniSirGlobal mac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
param_tlvs =
(WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *) cmd_param_info;
param_buf = (wmi_pdev_chip_power_stats_event_fixed_param *)
param_tlvs->fixed_param;
if (!mac || !mac->sme.power_stats_resp_callback) {
WMA_LOGD("%s: NULL mac ptr or HDD callback is null", __func__);
return -EINVAL;
}
if (!param_buf) {
WMA_LOGD("%s: NULL power stats event fixed param", __func__);
return -EINVAL;
}
if (param_buf->num_debug_register > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(wmi_pdev_chip_power_stats_event_fixed_param)) /
sizeof(uint32_t))) {
WMA_LOGE("excess payload: LEN num_debug_register:%u",
param_buf->num_debug_register);
return -EINVAL;
}
debug_registers = param_tlvs->debug_registers;
stats_registers_len =
(sizeof(uint32_t) * param_buf->num_debug_register);
power_stats_len = stats_registers_len + sizeof(*power_stats_results);
power_stats_results = vos_mem_malloc(power_stats_len);
if (NULL == power_stats_results) {
WMA_LOGD("%s: could not allocate mem for power stats results",
__func__);
return -ENOMEM;
}
vos_mem_zero(power_stats_results, power_stats_len);
WMA_LOGD("Cumulative sleep time %d cumulative total on time %d deep sleep enter counter %d last deep sleep enter tstamp ts %d debug registers fmt %d num debug register %d",
param_buf->cumulative_sleep_time_ms,
param_buf->cumulative_total_on_time_ms,
param_buf->deep_sleep_enter_counter,
param_buf->last_deep_sleep_enter_tstamp_ms,
param_buf->debug_register_fmt,
param_buf->num_debug_register);
power_stats_results->cumulative_sleep_time_ms
= param_buf->cumulative_sleep_time_ms;
power_stats_results->cumulative_total_on_time_ms
= param_buf->cumulative_total_on_time_ms;
power_stats_results->deep_sleep_enter_counter
= param_buf->deep_sleep_enter_counter;
power_stats_results->last_deep_sleep_enter_tstamp_ms
= param_buf->last_deep_sleep_enter_tstamp_ms;
power_stats_results->debug_register_fmt
= param_buf->debug_register_fmt;
power_stats_results->num_debug_register
= param_buf->num_debug_register;
power_stats_results->debug_registers
= (uint32_t *)(power_stats_results + 1);
vos_mem_copy(power_stats_results->debug_registers,
debug_registers, stats_registers_len);
mac->sme.power_stats_resp_callback(power_stats_results,
mac->sme.power_debug_stats_context);
vos_mem_free(power_stats_results);
return 0;
}
#else
static int wma_unified_power_debug_stats_event_handler(void *handle,
uint8_t *cmd_param_info, uint32_t len)
{
return 0;
}
#endif
static int wma_pdev_div_info_evt_handler(void *handle, u_int8_t *event_buf,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_PDEV_DIV_RSSI_ANTID_EVENTID_param_tlvs *param_buf;
wmi_pdev_div_rssi_antid_event_fixed_param *event;
struct chain_rssi_result chain_rssi_result;
u_int32_t i;
u_int8_t macaddr[IEEE80211_ADDR_LEN];
tpAniSirGlobal pmac = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!pmac) {
WMA_LOGE(FL("Invalid pmac"));
return -EINVAL;
}
param_buf = (WMI_PDEV_DIV_RSSI_ANTID_EVENTID_param_tlvs *) event_buf;
if (!param_buf) {
WMA_LOGE(FL("Invalid rssi antid event buffer"));
return -EINVAL;
}
event = param_buf->fixed_param;
if (!event) {
WMA_LOGE(FL("Invalid fixed param"));
return -EINVAL;
}
WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->macaddr, macaddr);
WMA_LOGD(FL("macaddr: " MAC_ADDRESS_STR), MAC_ADDR_ARRAY(macaddr));
if (event->num_chains_valid > CHAIN_MAX_NUM) {
WMA_LOGD("Sizing down the chains no %d to max",
event->num_chains_valid);
event->num_chains_valid = CHAIN_MAX_NUM;
}
WMA_LOGD(FL("num_chains_valid: %d"), event->num_chains_valid);
chain_rssi_result.num_chains_valid = event->num_chains_valid;
for (i = 0; i < CHAIN_MAX_NUM; i++)
WMA_LOGD(FL("chain_rssi: %d"), event->chain_rssi[i]);
vos_mem_copy(chain_rssi_result.chain_rssi, event->chain_rssi,
sizeof(event->chain_rssi));
for (i = 0; i < event->num_chains_valid; i++)
chain_rssi_result.chain_rssi[i] += WMA_TGT_NOISE_FLOOR_DBM;
for (i = 0; i < CHAIN_MAX_NUM; i++)
WMA_LOGD(FL("ant_id: %d"), event->ant_id[i]);
vos_mem_copy(chain_rssi_result.ant_id, event->ant_id,
sizeof(event->ant_id));
pmac->sme.pchain_rssi_ind_cb(pmac->hHdd, &chain_rssi_result);
return 0;
}
u_int8_t *wma_add_p2p_ie(u_int8_t *frm)
{
u_int8_t wfa_oui[3] = WMA_P2P_WFA_OUI;
struct p2p_ie *p2p_ie=(struct p2p_ie *) frm;
p2p_ie->p2p_id = WMA_P2P_IE_ID;
p2p_ie->p2p_oui[0] = wfa_oui[0];
p2p_ie->p2p_oui[1] = wfa_oui[1];
p2p_ie->p2p_oui[2] = wfa_oui[2];
p2p_ie->p2p_oui_type = WMA_P2P_WFA_VER;
p2p_ie->p2p_len = 4;
return (frm + sizeof(struct p2p_ie));
}
static void wma_update_beacon_noa_ie(
struct beacon_info *bcn,
u_int16_t new_noa_sub_ie_len)
{
struct p2p_ie *p2p_ie;
u_int8_t *buf;
/* if there is nothing to add, just return */
if (new_noa_sub_ie_len == 0) {
if (bcn->noa_sub_ie_len && bcn->noa_ie) {
WMA_LOGD("%s: NoA is present in previous beacon, "
"but not present in swba event, "
"So Reset the NoA",
__func__);
/* TODO: Assuming p2p noa ie is last ie in the beacon */
vos_mem_zero(bcn->noa_ie, (bcn->noa_sub_ie_len +
sizeof(struct p2p_ie)) );
bcn->len -= (bcn->noa_sub_ie_len +
sizeof(struct p2p_ie));
bcn->noa_ie = NULL;
bcn->noa_sub_ie_len = 0;
}
WMA_LOGD("%s: No need to update NoA", __func__);
return;
}
if (bcn->noa_sub_ie_len && bcn->noa_ie) {
/* NoA present in previous beacon, update it */
WMA_LOGD("%s: NoA present in previous beacon, "
"update the NoA IE, bcn->len %u"
"bcn->noa_sub_ie_len %u",
__func__, bcn->len, bcn->noa_sub_ie_len);
bcn->len -= (bcn->noa_sub_ie_len + sizeof(struct p2p_ie)) ;
vos_mem_zero(bcn->noa_ie,
(bcn->noa_sub_ie_len + sizeof(struct p2p_ie)));
} else { /* NoA is not present in previous beacon */
WMA_LOGD("%s: NoA not present in previous beacon, add it"
"bcn->len %u", __func__, bcn->len);
buf = adf_nbuf_data(bcn->buf);
bcn->noa_ie = buf + bcn->len;
}
bcn->noa_sub_ie_len = new_noa_sub_ie_len;
wma_add_p2p_ie(bcn->noa_ie);
p2p_ie = (struct p2p_ie *) bcn->noa_ie;
p2p_ie->p2p_len += new_noa_sub_ie_len;
vos_mem_copy((bcn->noa_ie + sizeof(struct p2p_ie)), bcn->noa_sub_ie,
new_noa_sub_ie_len);
bcn->len += (new_noa_sub_ie_len + sizeof(struct p2p_ie));
WMA_LOGI("%s: Updated beacon length with NoA Ie is %u",
__func__, bcn->len);
}
static void wma_p2p_create_sub_ie_noa(
u_int8_t *buf,
struct p2p_sub_element_noa *noa,
u_int16_t *new_noa_sub_ie_len)
{
u_int8_t tmp_octet = 0;
int i;
u_int8_t *buf_start = buf;
*buf++ = WMA_P2P_SUB_ELEMENT_NOA; /* sub-element id */
ASSERT(noa->num_descriptors <= WMA_MAX_NOA_DESCRIPTORS);
/*
* Length = (2 octets for Index and CTWin/Opp PS) and
* (13 octets for each NOA Descriptors)
*/
P2PIE_PUT_LE16(buf, WMA_NOA_IE_SIZE(noa->num_descriptors));
buf += 2;
*buf++ = noa->index; /* Instance Index */
tmp_octet = noa->ctwindow & WMA_P2P_NOA_IE_CTWIN_MASK;
if (noa->oppPS) {
tmp_octet |= WMA_P2P_NOA_IE_OPP_PS_SET;
}
*buf++ = tmp_octet; /* Opp Ps and CTWin capabilities */
for (i = 0; i < noa->num_descriptors; i++) {
ASSERT(noa->noa_descriptors[i].type_count != 0);
*buf++ = noa->noa_descriptors[i].type_count;
P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].duration);
buf += 4;
P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].interval);
buf += 4;
P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].start_time);
buf += 4;
}
*new_noa_sub_ie_len = (buf - buf_start);
}
static void wma_update_noa(struct beacon_info *beacon,
struct p2p_sub_element_noa *noa_ie)
{
u_int16_t new_noa_sub_ie_len;
/* Call this function by holding the spinlock on beacon->lock */
if (noa_ie) {
if ((noa_ie->ctwindow == 0) && (noa_ie->oppPS == 0) &&
(noa_ie->num_descriptors == 0)) {
/* NoA is not present */
WMA_LOGD("%s: NoA is not present", __func__);
new_noa_sub_ie_len = 0;
}
else {
/* Create the binary blob containing NOA sub-IE */
WMA_LOGD("%s: Create NOA sub ie", __func__);
wma_p2p_create_sub_ie_noa(&beacon->noa_sub_ie[0],
noa_ie, &new_noa_sub_ie_len);
}
}
else {
WMA_LOGD("%s: No need to add NOA", __func__);
new_noa_sub_ie_len = 0; /* no NOA IE sub-attributes */
}
wma_update_beacon_noa_ie(beacon, new_noa_sub_ie_len);
}
static void wma_update_probe_resp_noa(tp_wma_handle wma_handle,
struct p2p_sub_element_noa *noa_ie)
{
tSirP2PNoaAttr *noa_attr = (tSirP2PNoaAttr *) vos_mem_malloc(sizeof(tSirP2PNoaAttr));
if (!noa_attr) {
WMA_LOGE("Failed to allocate memory for tSirP2PNoaAttr");
return;
}
vos_mem_zero(noa_attr, sizeof(tSirP2PNoaAttr));
noa_attr->index = noa_ie->index;
noa_attr->oppPsFlag = noa_ie->oppPS;
noa_attr->ctWin = noa_ie->ctwindow;
if (!noa_ie->num_descriptors) {
WMA_LOGD("Zero NoA descriptors");
}
else {
noa_attr->uNoa1IntervalCnt =
noa_ie->noa_descriptors[0].type_count;
noa_attr->uNoa1Duration =
noa_ie->noa_descriptors[0].duration;
noa_attr->uNoa1Interval =
noa_ie->noa_descriptors[0].interval;
noa_attr->uNoa1StartTime =
noa_ie->noa_descriptors[0].start_time;
if (noa_ie->num_descriptors > 1) {
noa_attr->uNoa2IntervalCnt =
noa_ie->noa_descriptors[1].type_count;
noa_attr->uNoa2Duration =
noa_ie->noa_descriptors[1].duration;
noa_attr->uNoa2Interval =
noa_ie->noa_descriptors[1].interval;
noa_attr->uNoa2StartTime =
noa_ie->noa_descriptors[1].start_time;
}
}
wma_send_msg(wma_handle, SIR_HAL_P2P_NOA_ATTR_IND, (void *)noa_attr,
0);
}
void wma_ignore_radar_soon_after_assoc(void)
{
void *vos_context;
tp_wma_handle wma;
struct ieee80211com *ic = NULL;
struct ath_dfs *dfs = NULL;
vos_context = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL);
if (!vos_context) {
WMA_LOGE("%s: VOS context is invald!", __func__);
return;
}
wma = (tp_wma_handle)vos_get_context(VOS_MODULE_ID_WDA,
vos_context);
if (!wma) {
WMA_LOGE("%s: WMA context is invald!", __func__);
return;
}
ic = wma->dfs_ic;
if (ic && ic->ic_dfs) {
dfs = (struct ath_dfs *)ic->ic_dfs;
dfs->ath_radar_ignore_after_assoc = true;
vos_timer_start(&dfs->ath_dfs_radar_ignore_timer,
DFS_RADAR_IGNORE);
}
}
void wma_stop_radar_delay_timer(void)
{
void *vos_context;
tp_wma_handle wma;
struct ieee80211com *ic = NULL;
struct ath_dfs *dfs = NULL;
vos_context = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL);
if (!vos_context) {
WMA_LOGE("%s: VOS context is invald!", __func__);
return;
}
wma = (tp_wma_handle)vos_get_context(VOS_MODULE_ID_WDA,
vos_context);
if (!wma) {
WMA_LOGE("%s: WMA context is invald!", __func__);
return;
}
ic = wma->dfs_ic;
if (ic && ic->ic_dfs) {
dfs = (struct ath_dfs *)ic->ic_dfs;
if (dfs->ath_radar_delaysched) {
wma_update_dfs_cac_block_tx(false);
vos_timer_stop(&dfs->ath_dfs_radar_delay_timer);
dfs->ath_radar_delaysched = 0;
}
}
}
static void wma_send_bcn_buf_ll(tp_wma_handle wma,
ol_txrx_pdev_handle pdev,
u_int8_t vdev_id,
WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf)
{
wmi_bcn_send_from_host_cmd_fixed_param *cmd;
struct ieee80211_frame *wh;
struct beacon_info *bcn;
wmi_tim_info *tim_info = param_buf->tim_info;
u_int8_t *bcn_payload;
wmi_buf_t wmi_buf;
a_status_t ret;
struct beacon_tim_ie *tim_ie;
wmi_p2p_noa_info *p2p_noa_info = param_buf->p2p_noa_info;
struct p2p_sub_element_noa noa_ie;
u_int8_t i;
int status;
bcn = wma->interfaces[vdev_id].beacon;
if (!bcn->buf) {
WMA_LOGE("%s: Invalid beacon buffer", __func__);
return;
}
if (WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info) >
WMI_P2P_MAX_NOA_DESCRIPTORS) {
WMA_LOGE("%s: Too many descriptors %d", __func__,
WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info));
return;
}
wmi_buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd));
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return;
}
adf_os_spin_lock_bh(&bcn->lock);
bcn_payload = adf_nbuf_data(bcn->buf);
tim_ie = (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]);
if(tim_info->tim_changed) {
if(tim_info->tim_num_ps_pending)
vos_mem_copy(&tim_ie->tim_bitmap, tim_info->tim_bitmap,
WMA_TIM_SUPPORTED_PVB_LENGTH);
else
vos_mem_zero(&tim_ie->tim_bitmap,
WMA_TIM_SUPPORTED_PVB_LENGTH);
/*
* Currently we support fixed number of
* peers as limited by HAL_NUM_STA.
* tim offset is always 0
*/
tim_ie->tim_bitctl = 0;
}
/* Update DTIM Count */
if (tim_ie->dtim_count == 0)
tim_ie->dtim_count = tim_ie->dtim_period - 1;
else
tim_ie->dtim_count--;
/*
* DTIM count needs to be backedup so that
* when umac updates the beacon template
* current dtim count can be updated properly
*/
bcn->dtim_count = tim_ie->dtim_count;
/* update state for buffered multicast frames on DTIM */
if (tim_info->tim_mcast && (tim_ie->dtim_count == 0 ||
tim_ie->dtim_period == 1))
tim_ie->tim_bitctl |= 1;
else
tim_ie->tim_bitctl &= ~1;
/* To avoid sw generated frame sequence the same as H/W generated frame,
* the value lower than min_sw_seq is reserved for HW generated frame */
if ((bcn->seq_no & IEEE80211_SEQ_MASK) < MIN_SW_SEQ)
bcn->seq_no = MIN_SW_SEQ;
wh = (struct ieee80211_frame *) bcn_payload;
*(u_int16_t *)&wh->i_seq[0] = htole16(bcn->seq_no
<< IEEE80211_SEQ_SEQ_SHIFT);
bcn->seq_no++;
if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) {
vos_mem_zero(&noa_ie, sizeof(noa_ie));
noa_ie.index = (u_int8_t)WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info);
noa_ie.oppPS = (u_int8_t)WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info);
noa_ie.ctwindow = (u_int8_t)WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info);
noa_ie.num_descriptors = (u_int8_t)WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(
p2p_noa_info);
WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, "
"num_descriptors = %u", __func__, noa_ie.index,
noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors);
for(i = 0; i < noa_ie.num_descriptors; i++) {
noa_ie.noa_descriptors[i].type_count =
(u_int8_t)p2p_noa_info->noa_descriptors[i].type_count;
noa_ie.noa_descriptors[i].duration =
p2p_noa_info->noa_descriptors[i].duration;
noa_ie.noa_descriptors[i].interval =
p2p_noa_info->noa_descriptors[i].interval;
noa_ie.noa_descriptors[i].start_time =
p2p_noa_info->noa_descriptors[i].start_time;
WMA_LOGI("%s: NoA descriptor[%d] type_count %u, "
"duration %u, interval %u, start_time = %u",
__func__, i,
noa_ie.noa_descriptors[i].type_count,
noa_ie.noa_descriptors[i].duration,
noa_ie.noa_descriptors[i].interval,
noa_ie.noa_descriptors[i].start_time);
}
wma_update_noa(bcn, &noa_ie);
/* Send a msg to LIM to update the NoA IE in probe response
* frames transmitted by the host */
wma_update_probe_resp_noa(wma, &noa_ie);
}
if (bcn->dma_mapped) {
adf_nbuf_unmap_single(pdev->osdev, bcn->buf,
ADF_OS_DMA_TO_DEVICE);
bcn->dma_mapped = 0;
}
ret = adf_nbuf_map_single(pdev->osdev, bcn->buf,
ADF_OS_DMA_TO_DEVICE);
if (ret != A_STATUS_OK) {
wmi_buf_free(wmi_buf);
WMA_LOGE("%s: failed map beacon buf to DMA region",
__func__);
adf_os_spin_unlock_bh(&bcn->lock);
return;
}
bcn->dma_mapped = 1;
cmd = (wmi_bcn_send_from_host_cmd_fixed_param *) wmi_buf_data(wmi_buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_bcn_send_from_host_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->data_len = bcn->len;
cmd->frame_ctrl = *((A_UINT16 *)wh->i_fc);
cmd->frag_ptr = adf_nbuf_get_frag_paddr_lo(bcn->buf, 0);
/* Notify Firmware of DTM and mcast/bcast traffic */
if (tim_ie->dtim_count == 0) {
cmd->dtim_flag |= WMI_BCN_SEND_DTIM_ZERO;
/* deliver mcast/bcast traffic in next DTIM beacon */
if (tim_ie->tim_bitctl & 0x01)
cmd->dtim_flag |= WMI_BCN_SEND_DTIM_BITCTL_SET;
}
status = wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, sizeof(*cmd),
WMI_PDEV_SEND_BCN_CMDID);
if (status != EOK) {
WMA_LOGE("Failed to send WMI_PDEV_SEND_BCN_CMDID command");
wmi_buf_free(wmi_buf);
}
adf_os_spin_unlock_bh(&bcn->lock);
}
static int wma_beacon_swba_handler(void *handle, u_int8_t *event, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf;
wmi_host_swba_event_fixed_param *swba_event;
u_int32_t vdev_map;
ol_txrx_pdev_handle pdev;
u_int8_t vdev_id = 0;
param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("Invalid swba event buffer");
return -EINVAL;
}
swba_event = param_buf->fixed_param;
vdev_map = swba_event->vdev_map;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (!pdev) {
WMA_LOGE("%s: pdev is NULL", __func__);
return -EINVAL;
}
WMA_LOGD("vdev_map = %d", vdev_map);
for (; vdev_map && vdev_id < wma->max_bssid;
vdev_id++, vdev_map >>= 1) {
if (!(vdev_map & 0x1))
continue;
if (!wdi_out_cfg_is_high_latency(pdev->ctrl_pdev))
wma_send_bcn_buf_ll(wma, pdev, vdev_id, param_buf);
break;
}
return 0;
}
static int wma_csa_offload_handler(void *handle, u_int8_t *event, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_CSA_HANDLING_EVENTID_param_tlvs *param_buf;
wmi_csa_event_fixed_param *csa_event;
u_int8_t bssid[IEEE80211_ADDR_LEN];
u_int8_t vdev_id = 0;
u_int8_t cur_chan = 0;
uint8_t cur_sb20_channelwidth = 0;
struct ieee80211_channelswitch_ie *csa_ie;
tpCSAOffloadParams csa_offload_event;
struct ieee80211_extendedchannelswitch_ie *xcsa_ie;
struct ieee80211_ie_wide_bw_switch *wb_ie;
struct wma_txrx_node *intr = wma->interfaces;
param_buf = (WMI_CSA_HANDLING_EVENTID_param_tlvs *) event;
WMA_LOGD("%s: Enter", __func__);
if (!param_buf) {
WMA_LOGE("Invalid csa event buffer");
return -EINVAL;
}
csa_event = param_buf->fixed_param;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->i_addr2, &bssid[0]);
if (wma_find_vdev_by_bssid(wma, bssid, &vdev_id) == NULL) {
WMA_LOGE("Invalid bssid received %s:%d", __func__, __LINE__);
return -EINVAL;
}
csa_offload_event = vos_mem_malloc(sizeof(*csa_offload_event));
if (!csa_offload_event) {
WMA_LOGE("VOS MEM Alloc Failed for csa_offload_event");
return -EINVAL;
}
vos_mem_zero(csa_offload_event, sizeof(*csa_offload_event));
vos_mem_copy(csa_offload_event->bssId, &bssid, ETH_ALEN);
if (csa_event->ies_present_flag & WMI_CSA_IE_PRESENT) {
csa_ie = (struct ieee80211_channelswitch_ie *)(&csa_event->csa_ie[0]);
csa_offload_event->channel = csa_ie->newchannel;
csa_offload_event->switchmode = csa_ie->switchmode;
} else if (csa_event->ies_present_flag & WMI_XCSA_IE_PRESENT) {
xcsa_ie = (struct ieee80211_extendedchannelswitch_ie*)(&csa_event->xcsa_ie[0]);
csa_offload_event->channel = xcsa_ie->newchannel;
csa_offload_event->switchmode = xcsa_ie->switchmode;
csa_offload_event->new_op_class = xcsa_ie->newClass;
} else {
WMA_LOGE("CSA Event error: No CSA IE present");
vos_mem_free(csa_offload_event);
return -EINVAL;
}
if (csa_event->ies_present_flag & WMI_WBW_IE_PRESENT) {
wb_ie = (struct ieee80211_ie_wide_bw_switch*)(&csa_event->wb_ie[0]);
csa_offload_event->new_ch_width = wb_ie->new_ch_width;
csa_offload_event->new_ch_freq_seg1 = wb_ie->new_ch_freq_seg1;
csa_offload_event->new_ch_freq_seg2 = wb_ie->new_ch_freq_seg2;
}
if (csa_event->ies_present_flag & WMI_QSBW_ISE_PRESENT) {
struct vendor_ie_sub20_channelwidth sub20width_ie;
sub20width_ie.elem_id =
WMI_CSA_EVENT_QSBW_ISE_EXTRACT_ID(
csa_event->qsbw_ise);
sub20width_ie.elem_len =
WMI_CSA_EVENT_QSBW_ISE_EXTRACT_LEN(
csa_event->qsbw_ise);
sub20width_ie.sub20_capability =
WMI_CSA_EVENT_QSBW_ISE_EXTRACT_CAP(
csa_event->qsbw_ise);
sub20width_ie.new_sub20_channelwidth =
WMI_CSA_EVENT_QSBW_ISE_EXTRACT_NOTIF(
csa_event->qsbw_ise);
WMA_LOGE("CSA event with sbw_ie capability: %d chwidth:%d",
sub20width_ie.sub20_capability,
sub20width_ie.new_sub20_channelwidth);
csa_offload_event->new_sub20_channelwidth =
sub20width_ie.new_sub20_channelwidth;
}
csa_offload_event->ies_present_flag = csa_event->ies_present_flag;
WMA_LOGD("CSA: New Channel = %d BSSID:%pM",
csa_offload_event->channel,
csa_offload_event->bssId);
cur_chan = vos_freq_to_chan(intr[vdev_id].mhz);
cur_sb20_channelwidth =
vos_phy_channel_width_to_sub20(intr[vdev_id].channelwidth);
/*
* basic sanity check: requested channel should not be 0
* and equal to home channel
*/
if( (0 == csa_offload_event->channel) ||
(cur_chan == csa_offload_event->channel &&
cur_sb20_channelwidth ==
csa_offload_event->new_sub20_channelwidth)) {
WMA_LOGE("CSA Event with channel %d. Ignore !!",
csa_offload_event->channel);
vos_mem_free(csa_offload_event);
return -EINVAL;
}
wma->interfaces[vdev_id].is_channel_switch = VOS_TRUE;
wma_send_msg(wma, WDA_CSA_OFFLOAD_EVENT, (void *)csa_offload_event, 0);
return 0;
}
#ifdef WLAN_FEATURE_GTK_OFFLOAD
static int wma_gtk_offload_status_event(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *status;
WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *param_buf;
tpSirGtkOffloadGetInfoRspParams resp;
vos_msg_t vos_msg;
u_int8_t *bssid;
WMA_LOGD("%s Enter", __func__);
param_buf = (WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *)event;
if (!param_buf) {
WMA_LOGE("param_buf is NULL");
return -EINVAL;
}
status = (WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *)param_buf->fixed_param;
if (len < sizeof(WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param)) {
WMA_LOGE("Invalid length for GTK status");
return -EINVAL;
}
bssid = wma_find_bssid_by_vdev_id(wma, status->vdev_id);
if (!bssid) {
WMA_LOGE("invalid bssid for vdev id %d", status->vdev_id);
return -ENOENT;
}
resp = vos_mem_malloc(sizeof(*resp));
if (!resp) {
WMA_LOGE("%s: Failed to alloc response", __func__);
return -ENOMEM;
}
vos_mem_zero(resp, sizeof(*resp));
resp->mesgType = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP;
resp->mesgLen = sizeof(*resp);
resp->ulStatus = VOS_STATUS_SUCCESS;
resp->ulTotalRekeyCount = status->refresh_cnt;
/* TODO: Is the total rekey count and GTK rekey count same? */
resp->ulGTKRekeyCount = status->refresh_cnt;
vos_mem_copy(&resp->ullKeyReplayCounter, &status->replay_counter,
GTK_REPLAY_COUNTER_BYTES);
vos_mem_copy(resp->bssId, bssid, ETH_ALEN);
#ifdef IGTK_OFFLOAD
/* TODO: Is the refresh count same for GTK and IGTK? */
resp->ulIGTKRekeyCount = status->refresh_cnt;
#endif
vos_msg.type = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP;
vos_msg.bodyptr = (void *)resp;
vos_msg.bodyval = 0;
if (vos_mq_post_message(VOS_MQ_ID_SME, (vos_msg_t*)&vos_msg)
!= VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to post GTK response to SME");
vos_mem_free(resp);
return -EINVAL;
}
WMA_LOGD("GTK: got target status with replay counter "
"%02x%02x%02x%02x%02x%02x%02x%02x. vdev %d "
"Refresh GTK %d times exchanges since last set operation",
status->replay_counter[0],
status->replay_counter[1],
status->replay_counter[2],
status->replay_counter[3],
status->replay_counter[4],
status->replay_counter[5],
status->replay_counter[6],
status->replay_counter[7],
status->vdev_id, status->refresh_cnt);
WMA_LOGD("%s Exit", __func__);
return 0;
}
#endif
#ifdef FEATURE_OEM_DATA_SUPPORT
static int wma_oem_capability_event_callback(void *handle,
u_int8_t *datap, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_OEM_CAPABILITY_EVENTID_param_tlvs *param_buf;
u_int8_t *data;
u_int32_t datalen;
u_int32_t *msg_subtype;
tStartOemDataRsp *pStartOemDataRsp;
param_buf = (WMI_OEM_CAPABILITY_EVENTID_param_tlvs *)datap;
if (!param_buf) {
WMA_LOGE("%s: Received NULL buf ptr from FW", __func__);
return -ENOMEM;
}
data = param_buf->data;
datalen = param_buf->num_data;
if (!data) {
WMA_LOGE("%s: Received NULL data from FW", __func__);
return -EINVAL;
}
/*
* wma puts 4 bytes prefix for msg subtype, so length
* of data received from target should be 4 bytes less
* then max allowed
*/
if (datalen <= 0 ||
datalen > (OEM_DATA_RSP_SIZE - OEM_MESSAGE_SUBTYPE_LEN)) {
WMA_LOGE(FL("Invalid data length: %d"), datalen);
return -EINVAL;
}
pStartOemDataRsp = vos_mem_malloc(sizeof(*pStartOemDataRsp));
if (!pStartOemDataRsp) {
WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__);
return -ENOMEM;
}
pStartOemDataRsp->rsp_len = datalen + OEM_MESSAGE_SUBTYPE_LEN;
pStartOemDataRsp->oem_data_rsp =
vos_mem_malloc(pStartOemDataRsp->rsp_len);
if (!pStartOemDataRsp->oem_data_rsp) {
WMA_LOGE(FL("malloc failed for data"));
vos_mem_free(pStartOemDataRsp);
return -ENOMEM;
}
pStartOemDataRsp->target_rsp = true;
msg_subtype = (uint32_t *) pStartOemDataRsp->oem_data_rsp;
*msg_subtype = WMI_OEM_CAPABILITY_RSP;
/* copy data after msg sub type */
vos_mem_copy(pStartOemDataRsp->oem_data_rsp + OEM_MESSAGE_SUBTYPE_LEN,
data, datalen);
WMA_LOGI(FL("Sending WDA_START_OEM_DATA_RSP, data len (%d)"),
pStartOemDataRsp->rsp_len);
wma_send_msg(wma, WDA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0);
return 0;
}
static int wma_oem_measurement_report_event_callback(void *handle,
u_int8_t *datap, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_OEM_MEASUREMENT_REPORT_EVENTID_param_tlvs *param_buf;
u_int8_t *data;
u_int32_t datalen;
u_int32_t *msg_subtype;
tStartOemDataRsp *pStartOemDataRsp;
param_buf = (WMI_OEM_MEASUREMENT_REPORT_EVENTID_param_tlvs *)datap;
if (!param_buf) {
WMA_LOGE("%s: Received NULL buf ptr from FW", __func__);
return -ENOMEM;
}
data = param_buf->data;
datalen = param_buf->num_data;
if (!data) {
WMA_LOGE("%s: Received NULL data from FW", __func__);
return -EINVAL;
}
/*
* wma puts 4 bytes prefix for msg subtype, so length
* of data received from target should be 4 bytes less
* then max allowed
*/
if (datalen <= 0 ||
datalen > (OEM_DATA_RSP_SIZE - OEM_MESSAGE_SUBTYPE_LEN)) {
WMA_LOGE(FL("Invalid data length: %d"), datalen);
return -EINVAL;
}
pStartOemDataRsp = vos_mem_malloc(sizeof(*pStartOemDataRsp));
if (!pStartOemDataRsp) {
WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__);
return -ENOMEM;
}
pStartOemDataRsp->rsp_len = datalen + OEM_MESSAGE_SUBTYPE_LEN;
pStartOemDataRsp->oem_data_rsp =
vos_mem_malloc(pStartOemDataRsp->rsp_len);
if (!pStartOemDataRsp->oem_data_rsp) {
WMA_LOGE(FL("malloc failed for data"));
vos_mem_free(pStartOemDataRsp);
return -ENOMEM;
}
pStartOemDataRsp->target_rsp = true;
msg_subtype = (uint32_t *) pStartOemDataRsp->oem_data_rsp;
*msg_subtype = WMI_OEM_MEASUREMENT_RSP;
/* copy data after msg sub type */
vos_mem_copy(pStartOemDataRsp->oem_data_rsp + OEM_MESSAGE_SUBTYPE_LEN,
data, datalen);
WMA_LOGI(FL("Sending WDA_START_OEM_DATA_RSP, data len (%d)"),
pStartOemDataRsp->rsp_len);
wma_send_msg(wma, WDA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0);
return 0;
}
static int wma_oem_error_report_event_callback(void *handle,
u_int8_t *datap, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_OEM_ERROR_REPORT_EVENTID_param_tlvs *param_buf;
u_int8_t *data;
u_int32_t datalen;
u_int32_t *msg_subtype;
tStartOemDataRsp *pStartOemDataRsp;
param_buf = (WMI_OEM_ERROR_REPORT_EVENTID_param_tlvs *)datap;
if (!param_buf) {
WMA_LOGE("%s: Received NULL buf ptr from FW", __func__);
return -ENOMEM;
}
data = param_buf->data;
datalen = param_buf->num_data;
if (!data) {
WMA_LOGE("%s: Received NULL data from FW", __func__);
return -EINVAL;
}
/*
* wma puts 4 bytes prefix for msg subtype, so length
* of data received from target should be 4 bytes less
* then max allowed
*/
if (datalen <= 0 ||
datalen > (OEM_DATA_RSP_SIZE - OEM_MESSAGE_SUBTYPE_LEN)) {
WMA_LOGE(FL("Invalid data length: %d"), datalen);
return -EINVAL;
}
pStartOemDataRsp = vos_mem_malloc(sizeof(*pStartOemDataRsp));
if (!pStartOemDataRsp) {
WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__);
return -ENOMEM;
}
pStartOemDataRsp->rsp_len = datalen + OEM_MESSAGE_SUBTYPE_LEN;
pStartOemDataRsp->oem_data_rsp =
vos_mem_malloc(pStartOemDataRsp->rsp_len);
if (!pStartOemDataRsp->oem_data_rsp) {
WMA_LOGE(FL("malloc failed for data"));
vos_mem_free(pStartOemDataRsp);
return -ENOMEM;
}
pStartOemDataRsp->target_rsp = true;
msg_subtype = (uint32_t *) pStartOemDataRsp->oem_data_rsp;
*msg_subtype = WMI_OEM_ERROR_REPORT_RSP;
/* copy data after msg sub type */
vos_mem_copy(pStartOemDataRsp->oem_data_rsp + OEM_MESSAGE_SUBTYPE_LEN,
data, datalen);
WMA_LOGI(FL("Sending WDA_START_OEM_DATA_RSP, data len (%d)"),
pStartOemDataRsp->rsp_len);
wma_send_msg(wma, WDA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0);
return 0;
}
/**
* wma_oem_data_response_handler() - OEM data response event handler
* @handle: wma handle
* @datap: data ptr
* @len: data length
*
* Return: 0 for success or error code
*/
static int wma_oem_data_response_handler(void *handle,
uint8_t *datap, uint32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_OEM_RESPONSE_EVENTID_param_tlvs *param_buf;
uint8_t *data;
uint32_t datalen;
tStartOemDataRsp *oem_rsp;
param_buf = (WMI_OEM_RESPONSE_EVENTID_param_tlvs *) datap;
if (!param_buf) {
WMA_LOGE(FL("Received NULL buf ptr from FW"));
return -ENOMEM;
}
data = param_buf->data;
datalen = param_buf->num_data;
if (!data) {
WMA_LOGE(FL("Received NULL data from FW"));
return -EINVAL;
}
if (datalen <= 0 || datalen > OEM_DATA_RSP_SIZE) {
WMA_LOGE(FL("Invalid data length: %d"), datalen);
return -EINVAL;
}
oem_rsp = vos_mem_malloc(sizeof(*oem_rsp));
if (!oem_rsp) {
WMA_LOGE(FL("Failed to alloc oem_rsp"));
return -ENOMEM;
}
oem_rsp->rsp_len = datalen;
oem_rsp->oem_data_rsp = vos_mem_malloc(oem_rsp->rsp_len);
if (!oem_rsp->rsp_len) {
WMA_LOGE(FL("malloc failed for data"));
vos_mem_free(oem_rsp);
return -ENOMEM;
}
oem_rsp->target_rsp = true;
vos_mem_copy(oem_rsp->oem_data_rsp, data, datalen);
WMA_LOGI(FL("Sending WMA_START_OEM_DATA_RSP, data len %d"), datalen);
wma_send_msg(wma, WDA_START_OEM_DATA_RSP, (void *)oem_rsp, 0);
return 0;
}
#else
static inline int wma_oem_data_response_handler(void *handle,
uint8_t *datap, uint32_t len)
{
return 0;
}
#endif /* FEATURE_OEM_DATA_SUPPORT */
static int wma_p2p_noa_event_handler(void *handle, u_int8_t *event, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_P2P_NOA_EVENTID_param_tlvs *param_buf;
wmi_p2p_noa_event_fixed_param *p2p_noa_event;
u_int8_t vdev_id, i;
wmi_p2p_noa_info *p2p_noa_info;
struct p2p_sub_element_noa noa_ie;
u_int8_t *buf_ptr;
u_int32_t descriptors;
param_buf = (WMI_P2P_NOA_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("Invalid P2P NoA event buffer");
return -EINVAL;
}
p2p_noa_event = param_buf->fixed_param;
buf_ptr = (u_int8_t *) p2p_noa_event;
buf_ptr += sizeof(wmi_p2p_noa_event_fixed_param);
p2p_noa_info = (wmi_p2p_noa_info *) (buf_ptr);
vdev_id = p2p_noa_event->vdev_id;
if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) {
vos_mem_zero(&noa_ie, sizeof(noa_ie));
noa_ie.index = (u_int8_t)WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info);
noa_ie.oppPS = (u_int8_t)WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info);
noa_ie.ctwindow = (u_int8_t)WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info);
descriptors = WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info);
noa_ie.num_descriptors = (u_int8_t)descriptors;
if (noa_ie.num_descriptors > WMA_MAX_NOA_DESCRIPTORS) {
WMA_LOGD("Sizing down the no of desc %d to max",
noa_ie.num_descriptors);
noa_ie.num_descriptors = WMA_MAX_NOA_DESCRIPTORS;
}
WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, "
"num_descriptors = %u", __func__, noa_ie.index,
noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors);
for(i = 0; i < noa_ie.num_descriptors; i++) {
noa_ie.noa_descriptors[i].type_count =
(u_int8_t)p2p_noa_info->noa_descriptors[i].type_count;
noa_ie.noa_descriptors[i].duration =
p2p_noa_info->noa_descriptors[i].duration;
noa_ie.noa_descriptors[i].interval =
p2p_noa_info->noa_descriptors[i].interval;
noa_ie.noa_descriptors[i].start_time =
p2p_noa_info->noa_descriptors[i].start_time;
WMA_LOGI("%s: NoA descriptor[%d] type_count %u, "
"duration %u, interval %u, start_time = %u",
__func__, i,
noa_ie.noa_descriptors[i].type_count,
noa_ie.noa_descriptors[i].duration,
noa_ie.noa_descriptors[i].interval,
noa_ie.noa_descriptors[i].start_time);
}
/* Send a msg to LIM to update the NoA IE in probe response
* frames transmitted by the host */
wma_update_probe_resp_noa(wma, &noa_ie);
}
return 0;
}
#ifdef FEATURE_WLAN_TDLS
static int wma_tdls_event_handler(void *handle, u_int8_t *event, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_TDLS_PEER_EVENTID_param_tlvs *param_buf = NULL;
wmi_tdls_peer_event_fixed_param *peer_event = NULL;
tSirTdlsEventNotify *tdls_event;
if (!event) {
WMA_LOGE("%s: event param null", __func__);
return -1;
}
param_buf = (WMI_TDLS_PEER_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("%s: received null buf from target", __func__);
return -1;
}
peer_event = param_buf->fixed_param;
if (!peer_event) {
WMA_LOGE("%s: received null event data from target", __func__);
return -1;
}
tdls_event = (tSirTdlsEventNotify *)
vos_mem_malloc(sizeof(*tdls_event));
if (!tdls_event) {
WMA_LOGE("%s: failed to allocate memory for tdls_event", __func__);
return -1;
}
tdls_event->sessionId = peer_event->vdev_id;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_event->peer_macaddr, tdls_event->peerMac);
switch(peer_event->peer_status) {
case WMI_TDLS_SHOULD_DISCOVER:
tdls_event->messageType = WDA_TDLS_SHOULD_DISCOVER;
break;
case WMI_TDLS_SHOULD_TEARDOWN:
tdls_event->messageType = WDA_TDLS_SHOULD_TEARDOWN;
break;
case WMI_TDLS_PEER_DISCONNECTED:
tdls_event->messageType = WDA_TDLS_PEER_DISCONNECTED;
break;
default:
vos_mem_free(tdls_event);
WMA_LOGE("%s: Discarding unknown tdls event(%d) from target",
__func__, peer_event->peer_status);
return -1;
}
switch (peer_event->peer_reason) {
case WMI_TDLS_TEARDOWN_REASON_TX:
tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_TX;
break;
case WMI_TDLS_TEARDOWN_REASON_RSSI:
tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_RSSI;
break;
case WMI_TDLS_TEARDOWN_REASON_SCAN:
tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_SCAN;
break;
case WMI_TDLS_DISCONNECTED_REASON_PEER_DELETE:
tdls_event->peer_reason = eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE;
break;
case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT:
tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT;
break;
case WMI_TDLS_TEARDOWN_REASON_BAD_PTR:
tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_BAD_PTR;
break;
case WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE:
tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE;
break;
default:
vos_mem_free(tdls_event);
WMA_LOGE("%s: unknown reason(%d) in tdls event(%d) from target",
__func__, peer_event->peer_reason, peer_event->peer_status);
return -1;
}
WMA_LOGD("%s: sending msg to umac, messageType: 0x%x, "
"for peer: %pM, reason: %d, smesessionId: %d",
__func__, tdls_event->messageType, tdls_event->peerMac,
tdls_event->peer_reason, tdls_event->sessionId);
wma_send_msg(wma, tdls_event->messageType, (void *)tdls_event, 0);
return 0;
}
#endif /* FEATURE_WLAN_TDLS */
/*
* WMI Handler for WMI_PHYERR_EVENTID event from firmware.
* This handler is currently handling only DFS phy errors.
* This handler will be invoked only when the DFS phyerror
* filtering offload is disabled.
* Return- 1:Success, 0:Failure
*/
static int wma_unified_phyerr_rx_event_handler(void * handle,
u_int8_t *data, u_int32_t datalen)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_PHYERR_EVENTID_param_tlvs *param_tlvs;
wmi_comb_phyerr_rx_hdr *pe_hdr;
u_int8_t *bufp;
wmi_single_phyerr_rx_event *ev;
struct ieee80211com *ic = wma->dfs_ic;
adf_os_size_t n;
A_UINT64 tsf64 = 0;
int phy_err_code = 0;
int error = 0;
tpAniSirGlobal mac_ctx = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
bool enable_log = false;
if (NULL == mac_ctx) {
WMA_LOGE("%s: mac_ctx is NULL", __func__);
return 0;
}
enable_log = mac_ctx->sap.enable_dfs_phy_error_logs;
param_tlvs = (WMI_PHYERR_EVENTID_param_tlvs *)data;
if (!param_tlvs)
{
WMA_LOGE("%s: Received NULL data from FW", __func__);
return 0;
}
pe_hdr = param_tlvs->hdr;
if (pe_hdr == NULL)
{
WMA_LOGE("%s: Received Data PE Header is NULL", __func__);
return 0;
}
/* Ensure it's at least the size of the header */
if (datalen < sizeof(*pe_hdr))
{
WMA_LOGE("%s: Expected minimum size %zu, received %d",
__func__, sizeof(*pe_hdr), datalen);
return 0;
}
if (pe_hdr->buf_len > DFS_MAX_BUF_LENGHT)
{
WMA_LOGE("%s: Received Invalid Phyerror event buffer length = %d"
"Maximum allowed buf length = %d",
__func__, pe_hdr->buf_len, DFS_MAX_BUF_LENGHT);
return 0;
}
/*
* Reconstruct the 64 bit event TSF. This isn't from the MAC, it's
* at the time the event was sent to us, the TSF value will be
* in the future.
*/
tsf64 = pe_hdr->tsf_l32;
tsf64 |= (((uint64_t) pe_hdr->tsf_u32) << 32);
/*
* Loop over the bufp, extracting out phyerrors
* wmi_unified_comb_phyerr_rx_event.bufp is a char pointer,
* which isn't correct here - what we have received here
* is an array of TLV-style PHY errors.
*/
n = 0;/* Start just after the header */
bufp = param_tlvs->bufp;
while (n < pe_hdr->buf_len)
{
/* ensure there's at least space for the header */
if ((pe_hdr->buf_len - n) < sizeof(ev->hdr))
{
WMA_LOGE("%s: Not enough space.(datalen=%d, n=%zu, hdr=%zu bytes",
__func__,pe_hdr->buf_len,n,sizeof(ev->hdr));
error = 1;
break;
}
/*
* Obtain a pointer to the beginning of the current event.
* data[0] is the beginning of the WMI payload.
*/
ev = (wmi_single_phyerr_rx_event *) &bufp[n];
/*
* Sanity check the buffer length of the event against
* what we currently have.
* Since buf_len is 32 bits, we check if it overflows
* a large 32 bit value. It's not 0x7fffffff because
* we increase n by (buf_len + sizeof(hdr)), which would
* in itself cause n to overflow.
* If "int" is 64 bits then this becomes a moot point.
*/
if (ev->hdr.buf_len > 0x7f000000)
{
WMA_LOGE("%s:buf_len is garbage (0x%x)",__func__,
ev->hdr.buf_len);
error = 1;
break;
}
if (n + ev->hdr.buf_len > pe_hdr->buf_len)
{
WMA_LOGE("%s: buf_len exceeds available space n=%zu,"
"buf_len=%d, datalen=%d",
__func__,n,ev->hdr.buf_len,pe_hdr->buf_len);
error = 1;
break;
}
phy_err_code = WMI_UNIFIED_PHYERRCODE_GET(&ev->hdr);
/*
* If the phyerror category matches,
* pass radar events to the dfs pattern matching code.
* Don't pass radar events with no buffer payload.
*/
if (phy_err_code == 0x5 || phy_err_code == 0x24)
{
if (ev->hdr.buf_len > 0)
{
/* Calling in to the DFS module to process the phyerr */
dfs_process_phyerr(ic, &ev->bufp[0], ev->hdr.buf_len,
WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr) & 0xff,
/* Extension RSSI */
WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr) & 0xff,
ev->hdr.tsf_timestamp,
tsf64, enable_log);
}
}
/*
* Advance the buffer pointer to the next PHY error.
* buflen is the length of this payload, so we need to
* advance past the current header _AND_ the payload.
*/
n += sizeof(*ev) + ev->hdr.buf_len;
}/*end while()*/
if (error)
{
return (0);
}
else
{
return (1);
}
}
#ifdef WLAN_FEATURE_NAN
/* function : wma_nan_rsp_event_handler
* Descriptin : Function is used to handle nan response
* Args : wma_handle, event buffer and its length
* Returns : SUCCESS or FAILURE
*/
static int wma_nan_rsp_event_handler(void *handle, u_int8_t *event_buf,
u_int32_t len)
{
WMI_NAN_EVENTID_param_tlvs *param_buf;
tSirNanEvent *nan_rsp_event;
wmi_nan_event_hdr *nan_rsp_event_hdr;
VOS_STATUS status;
vos_msg_t vos_msg;
u_int8_t *buf_ptr;
u_int32_t alloc_len;
/*
* This is how received event_buf looks like
*
* <-------------------- event_buf ----------------------------------->
*
* <--wmi_nan_event_hdr--><---WMI_TLV_HDR_SIZE---><----- data -------->
*
* +-----------+---------+-----------------------+--------------------+
* | tlv_header| data_len| WMITLV_TAG_ARRAY_BYTE | nan_rsp_event_data |
* +-----------+---------+-----------------------+--------------------+
*/
WMA_LOGD("%s: Posting NaN response event to SME", __func__);
param_buf = (WMI_NAN_EVENTID_param_tlvs *)event_buf;
if (!param_buf) {
WMA_LOGE("%s: Invalid nan response event buf", __func__);
return -EINVAL;
}
nan_rsp_event_hdr = param_buf->fixed_param;
buf_ptr = (u_int8_t *)nan_rsp_event_hdr;
alloc_len = sizeof(tSirNanEvent);
alloc_len += nan_rsp_event_hdr->data_len;
if (nan_rsp_event_hdr->data_len > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*nan_rsp_event_hdr)) / sizeof(u_int8_t))) {
WMA_LOGE("excess data length:%d", nan_rsp_event_hdr->data_len);
VOS_ASSERT(0);
return -EINVAL;
}
nan_rsp_event = (tSirNanEvent *) vos_mem_malloc(alloc_len);
if (NULL == nan_rsp_event) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return -ENOMEM;
}
nan_rsp_event->event_data_len = nan_rsp_event_hdr->data_len;
vos_mem_copy(nan_rsp_event->event_data, buf_ptr +
sizeof(wmi_nan_event_hdr) + WMI_TLV_HDR_SIZE,
nan_rsp_event->event_data_len);
vos_msg.type = eWNI_SME_NAN_EVENT;
vos_msg.bodyptr = (void *)nan_rsp_event;
vos_msg.bodyval = 0;
status = vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to post NaN response event to SME", __func__);
vos_mem_free(nan_rsp_event);
return -1;
}
WMA_LOGD("%s: NaN response event Posted to SME", __func__);
return 0;
}
#endif
/*
* WMI handler for WMI_DFS_RADAR_EVENTID
* This handler is registered for handling
* filtered DFS Phyerror. This handler is
* will be invoked only when DFS Phyerr
* filtering offload is enabled.
* Return- 1:Success, 0:Failure
*/
static int wma_unified_dfs_radar_rx_event_handler(void *handle,
u_int8_t *data, u_int32_t datalen)
{
tp_wma_handle wma = (tp_wma_handle) handle;
struct ieee80211com *ic;
struct ath_dfs *dfs;
struct dfs_event *event;
struct ieee80211_channel *chan;
int empty;
int do_check_chirp = 0;
int is_hw_chirp = 0;
int is_sw_chirp = 0;
int is_pri = 0;
WMI_DFS_RADAR_EVENTID_param_tlvs *param_tlvs;
wmi_dfs_radar_event_fixed_param *radar_event;
adf_os_atomic_dec(&wma->dfs_wmi_event_pending);
ic = wma->dfs_ic;
if (NULL == ic) {
WMA_LOGE("%s: dfs_ic is NULL ", __func__);
return 0;
}
dfs = (struct ath_dfs *)ic->ic_dfs;
param_tlvs = (WMI_DFS_RADAR_EVENTID_param_tlvs *) data;
if (NULL == dfs) {
WMA_LOGE("%s: dfs is NULL ", __func__);
return 0;
}
/*
* This parameter holds the number
* of phyerror interrupts to the host
* after the phyerrors have passed through
* false detect filters in the firmware.
*/
dfs->dfs_phyerr_count++;
if (!param_tlvs) {
WMA_LOGE("%s: Received NULL data from FW", __func__);
return 0;
}
radar_event = param_tlvs->fixed_param;
adf_os_spin_lock_bh(&ic->chan_lock);
chan = ic->ic_curchan;
if (ic->disable_phy_err_processing) {
WMA_LOGD("%s: radar indication done,drop phyerror event",
__func__);
adf_os_spin_unlock_bh(&ic->chan_lock);
return 0;
}
if (NV_CHANNEL_DFS != vos_nv_getChannelEnabledState(chan->ic_ieee)) {
WMA_LOGE("%s: Invalid DFS Phyerror event. Channel=%d is Non-DFS",
__func__, chan->ic_ieee);
adf_os_spin_unlock_bh(&ic->chan_lock);
return 0;
}
adf_os_spin_unlock_bh(&ic->chan_lock);
dfs->ath_dfs_stats.total_phy_errors++;
if (dfs->dfs_caps.ath_chip_is_bb_tlv) {
do_check_chirp = 1;
is_pri = 1;
is_hw_chirp = radar_event->pulse_is_chirp;
if ((u_int32_t)dfs->dfs_phyerr_freq_min >
radar_event->pulse_center_freq) {
dfs->dfs_phyerr_freq_min =
(int)radar_event->pulse_center_freq;
}
if (dfs->dfs_phyerr_freq_max <
(int)radar_event->pulse_center_freq) {
dfs->dfs_phyerr_freq_max =
(int)radar_event->pulse_center_freq;
}
}
/*
* Now, add the parsed, checked and filtered
* radar phyerror event radar pulse event list.
* This event will then be processed by
* dfs_radar_processevent() to see if the pattern
* of pulses in radar pulse list match any radar
* singnature in the current regulatory domain.
*/
ATH_DFSEVENTQ_LOCK(dfs);
empty = STAILQ_EMPTY(&(dfs->dfs_eventq));
ATH_DFSEVENTQ_UNLOCK(dfs);
if (empty) {
return 0;
}
/*
* Add the event to the list, if there's space.
*/
ATH_DFSEVENTQ_LOCK(dfs);
event = STAILQ_FIRST(&(dfs->dfs_eventq));
if (event == NULL) {
ATH_DFSEVENTQ_UNLOCK(dfs);
WMA_LOGE("%s: No more space left for queuing DFS Phyerror events",
__func__);
return 0;
}
STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list);
ATH_DFSEVENTQ_UNLOCK(dfs);
dfs->dfs_phyerr_queued_count++;
dfs->dfs_phyerr_w53_counter++;
event->re_dur = (u_int8_t)radar_event->pulse_duration;
event->re_rssi = radar_event->rssi;
event->re_ts = radar_event->pulse_detect_ts & DFS_TSMASK;
event->re_full_ts = (((uint64_t)radar_event->upload_fullts_high) << 32)
| radar_event->upload_fullts_low;
/**
* Index of peak magnitude
* To do
* Need change interface of WMI_DFS_RADAR_EVENTID to get delta_diff and
* delta_peak when DFS Phyerr filtering offload is enabled.
*/
event->sidx = radar_event->peak_sidx & 0x0000ffff;
event->re_delta_diff = 0;
event->re_delta_peak = 0;
event->re_flags = 0;
/*
* Handle chirp flags.
*/
if (do_check_chirp) {
event->re_flags |= DFS_EVENT_CHECKCHIRP;
if (is_hw_chirp) {
event->re_flags |= DFS_EVENT_HW_CHIRP;
}
if (is_sw_chirp) {
event->re_flags |= DFS_EVENT_SW_CHIRP;
}
}
/*
* Correctly set which channel is being reported on
*/
if (is_pri) {
event->re_chanindex = (u_int8_t)dfs->dfs_curchan_radindex;
} else {
if (dfs->dfs_extchan_radindex == -1) {
WMA_LOGI("%s phyerr on ext channel", __func__);
}
event->re_chanindex = (u_int8_t)dfs->dfs_extchan_radindex;
WMA_LOGI("%s:New extension channel event is added to queue",
__func__);
}
ATH_DFSQ_LOCK(dfs);
STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list);
empty = STAILQ_EMPTY(&dfs->dfs_radarq);
ATH_DFSQ_UNLOCK(dfs);
if (!empty && !dfs->ath_radar_tasksched) {
dfs->ath_radar_tasksched = 1;
OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0);
}
return 1;
}
/*
* Register appropriate dfs phyerror event handler
* based on phyerror filtering offload is enabled
* or disabled.
*/
static void
wma_register_dfs_event_handler(tp_wma_handle wma_handle)
{
if (NULL == wma_handle) {
WMA_LOGE("%s:wma_handle is NULL", __func__);
return;
}
if (VOS_FALSE == wma_handle->dfs_phyerr_filter_offload) {
/*
* Register the wma_unified_phyerr_rx_event_handler
* for filtering offload disabled case to handle
* the DFS phyerrors.
*/
WMA_LOGD("%s:Phyerror Filtering offload is Disabled in ini",
__func__);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PHYERR_EVENTID, wma_unified_phyerr_rx_event_handler);
WMA_LOGD("%s: WMI_PHYERR_EVENTID event handler registered",
__func__);
} else {
WMA_LOGD("%s:Phyerror Filtering offload is Enabled in ini",
__func__);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_DFS_RADAR_EVENTID,
wma_unified_dfs_radar_rx_event_handler);
WMA_LOGD("%s:WMI_DFS_RADAR_EVENTID event handler registered",
__func__);
}
return;
}
static int wma_peer_state_change_event_handler(void *handle,
u_int8_t *event_buff,
u_int32_t len)
{
WMI_PEER_STATE_EVENTID_param_tlvs *param_buf;
wmi_peer_state_event_fixed_param *event;
ol_txrx_vdev_handle vdev;
tp_wma_handle wma_handle = (tp_wma_handle)handle;
if (!event_buff) {
WMA_LOGE("%s: event param null", __func__);
return -EINVAL;
}
param_buf = (WMI_PEER_STATE_EVENTID_param_tlvs *)event_buff;
if (!param_buf) {
WMA_LOGE("%s: Received NULL buf ptr from FW", __func__);
return -ENOMEM;
}
event = param_buf->fixed_param;
vdev = wma_find_vdev_by_id( wma_handle, event->vdev_id);
if (NULL == vdev) {
WMA_LOGP("%s: Couldn't find vdev for vdev_id: %d",
__func__, event->vdev_id);
return -EINVAL;
}
if (vdev->opmode == wlan_op_mode_sta
&& event->state == WMI_PEER_STATE_AUTHORIZED) {
/*
* set event so that WLANTL_ChangeSTAState
* can procced and unpause tx queue
*/
tl_shim_set_peer_authorized_event(wma_handle->vos_context,
event->vdev_id);
}
return 0;
}
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
/*
* Register all the Link Layer Stats related event
* handler
*/
static void
wma_register_ll_stats_event_handler(tp_wma_handle wma_handle)
{
if (NULL == wma_handle) {
WMA_LOGE("%s: wma_handle is NULL", __func__);
return;
}
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_IFACE_LINK_STATS_EVENTID,
wma_unified_link_iface_stats_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_LINK_STATS_EVENTID,
wma_unified_link_peer_stats_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_RADIO_LINK_STATS_EVENTID,
wma_unified_link_radio_stats_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID,
wma_unified_radio_tx_power_level_stats_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_STA_PS_STATECHG_EVENTID,
wma_peer_ps_evt_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_REPORT_STATS_EVENTID,
wma_ll_stats_evt_handler);
return;
}
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
static int wma_roam_synch_event_handler(void *handle, u_int8_t *event, u_int32_t len)
{
WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL;
wmi_roam_synch_event_fixed_param *synch_event = NULL;
u_int8_t *bcn_probersp_ptr = NULL;
u_int8_t *reassoc_rsp_ptr = NULL;
tp_wma_handle wma = (tp_wma_handle)handle;
wmi_channel *chan = NULL;
wmi_key_material *key = NULL;
int size=0;
tSirRoamOffloadSynchInd *pRoamOffloadSynchInd;
uint32_t roam_synch_data_len;
WMA_LOGD("LFR3:%s", __func__);
if (!event) {
WMA_LOGE("%s: event param null", __func__);
return -EINVAL;
}
param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("%s: received null buf from target", __func__);
return -EINVAL;
}
synch_event = param_buf->fixed_param;
if (!synch_event) {
WMA_LOGE("%s: received null event data from target", __func__);
return -EINVAL;
}
if (synch_event->vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: received invalid vdev_id %d",
__func__, synch_event->vdev_id);
return -EINVAL;
}
DPTRACE(adf_dp_trace_record_event(ADF_DP_TRACE_EVENT_RECORD,
synch_event->vdev_id, ADF_PROTO_TYPE_EVENT, ADF_ROAM_SYNCH));
if(wma->interfaces[synch_event->vdev_id].roam_synch_in_progress ==
VOS_TRUE) {
WMA_LOGE("%s: Ignoring RSI since one is already in progress",
__func__);
return -EINVAL;
}
WMA_LOGD("synch payload: LEN bcn:%d, req:%d, rsp:%d",
synch_event->bcn_probe_rsp_len,
synch_event->reassoc_req_len,
synch_event->reassoc_rsp_len);
if (synch_event->bcn_probe_rsp_len > WMA_SVC_MSG_MAX_SIZE)
return -EINVAL;
if (synch_event->reassoc_rsp_len >
(WMA_SVC_MSG_MAX_SIZE - synch_event->bcn_probe_rsp_len))
return -EINVAL;
if (synch_event->reassoc_req_len >
WMA_SVC_MSG_MAX_SIZE - (synch_event->bcn_probe_rsp_len +
synch_event->reassoc_rsp_len))
return -EINVAL;
roam_synch_data_len = synch_event->bcn_probe_rsp_len +
synch_event->reassoc_rsp_len +
synch_event->reassoc_req_len;
/*
* Below is the check for the entire size of the message received from'
* the firmware.
*/
if (roam_synch_data_len > WMA_SVC_MSG_MAX_SIZE -
(sizeof(*synch_event) + sizeof(wmi_channel) +
sizeof(wmi_key_material) + sizeof(uint32_t)))
return -EINVAL;
if (sizeof(tSirRoamOffloadSynchInd) >
(WMA_SVC_MSG_MAX_SIZE - roam_synch_data_len))
return -EINVAL;
roam_synch_data_len += sizeof(tSirRoamOffloadSynchInd);
adf_os_spin_lock_bh(&wma->roam_synch_lock);
wma->interfaces[synch_event->vdev_id].roam_synch_in_progress = VOS_TRUE;
adf_os_spin_unlock_bh(&wma->roam_synch_lock);
pRoamOffloadSynchInd =
(tSirRoamOffloadSynchInd *)vos_mem_malloc(roam_synch_data_len);
if (!pRoamOffloadSynchInd) {
WMA_LOGE("%s: failed to allocate memory for roam_synch_event", __func__);
return -ENOMEM;
}
/* abort existing scan if any */
if (wma->interfaces[synch_event->vdev_id].scan_info.scan_id != 0) {
tAbortScanParams abortScan;
WMA_LOGD("LFR3: Aborting Scan with scan_id=%d\n",
wma->interfaces[synch_event->vdev_id].scan_info.scan_id);
abortScan.SessionId = synch_event->vdev_id;
wma_stop_scan(wma, &abortScan);
}
pRoamOffloadSynchInd->messageType = eWNI_SME_ROAM_OFFLOAD_SYNCH_IND;
pRoamOffloadSynchInd->length = size;
pRoamOffloadSynchInd->roamedVdevId = synch_event->vdev_id;
pRoamOffloadSynchInd->authStatus = synch_event->auth_status;
pRoamOffloadSynchInd->roamReason = synch_event->roam_reason;
pRoamOffloadSynchInd->rssi = synch_event->rssi;
pRoamOffloadSynchInd->isBeacon = synch_event->is_beacon;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid, pRoamOffloadSynchInd->bssId);
pRoamOffloadSynchInd->beaconProbeRespOffset = sizeof(tSirRoamOffloadSynchInd);
bcn_probersp_ptr = (tANI_U8 *)pRoamOffloadSynchInd +
pRoamOffloadSynchInd->beaconProbeRespOffset;
pRoamOffloadSynchInd->beaconProbeRespLength = synch_event->bcn_probe_rsp_len;
vos_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame,
pRoamOffloadSynchInd->beaconProbeRespLength);
pRoamOffloadSynchInd->reassocRespOffset = sizeof(tSirRoamOffloadSynchInd) +
pRoamOffloadSynchInd->beaconProbeRespLength;
pRoamOffloadSynchInd->reassocRespLength = synch_event->reassoc_rsp_len;
reassoc_rsp_ptr = (tANI_U8 *)pRoamOffloadSynchInd +
pRoamOffloadSynchInd->reassocRespOffset;
vos_mem_copy(reassoc_rsp_ptr,
param_buf->reassoc_rsp_frame,
pRoamOffloadSynchInd->reassocRespLength);
chan = (wmi_channel *) param_buf->chan;
pRoamOffloadSynchInd->chan_freq = chan->mhz;
key = (wmi_key_material *) param_buf->key;
if (key != NULL)
{
VOS_TRACE_HEX_DUMP(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_DEBUG,
key->replay_counter,
SIR_REPLAY_CTR_LEN);
vos_mem_copy(pRoamOffloadSynchInd->kck, key->kck,
SIR_KCK_KEY_LEN);
vos_mem_copy(pRoamOffloadSynchInd->kek, key->kek,
SIR_KEK_KEY_LEN);
vos_mem_copy(pRoamOffloadSynchInd->replay_ctr, key->replay_counter,
SIR_REPLAY_CTR_LEN);
}
wma_send_msg(wma, WDA_ROAM_OFFLOAD_SYNCH_IND,
(void *) pRoamOffloadSynchInd, 0);
return 0;
}
#endif
/**
* wma_rssi_breached_event_handler() - rssi breached event handler
* @handle: wma handle
* @cmd_param_info: event handler data
* @len: length of @cmd_param_info
*
* Return: 0 on success; error number otherwise
*/
static int wma_rssi_breached_event_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf;
wmi_rssi_breach_event_fixed_param *event;
struct rssi_breach_event rssi;
tpAniSirGlobal mac = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!mac) {
WMA_LOGE("%s: Invalid mac context", __func__);
return -EINVAL;
}
if (!mac->sme.rssi_threshold_breached_cb) {
WMA_LOGE("%s: Callback not registered", __func__);
return -EINVAL;
}
param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid rssi breached event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
rssi.request_id = event->request_id;
rssi.session_id = event->vdev_id;
rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes);
WMA_LOGD("%s: req_id: %u vdev_id: %d curr_rssi: %d", __func__,
rssi.request_id, rssi.session_id, rssi.curr_rssi);
WMA_LOGI("%s: curr_bssid: %pM", __func__, rssi.curr_bssid.bytes);
mac->sme.rssi_threshold_breached_cb(mac->hHdd, &rssi);
WMA_LOGD("%s: Invoke HDD rssi breached callback", __func__);
return 0;
}
/**
* wma_chip_power_save_failure_detected_handler() - chip pwr save fail detected
* event handler
* @handle: wma handle
* @cmd_param_info: event handler data
* @len: length of @cmd_param_info
*
* Return: VOS_STATUS_SUCCESS on success; error code otherwise
*/
static int wma_chip_power_save_failure_detected_handler(void *handle,
u_int8_t *cmd_param_info, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *param_buf;
wmi_chip_power_save_failure_detected_fixed_param *event;
struct chip_pwr_save_fail_detected_params pwr_save_fail_params;
tpAniSirGlobal mac;
if (NULL == wma) {
WMA_LOGE("%s: wma_handle is NULL", __func__);
return VOS_STATUS_E_INVAL;
}
mac = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
if (!mac) {
WMA_LOGE("%s: Invalid mac context", __func__);
return VOS_STATUS_E_INVAL;
}
if (!mac->sme.chip_power_save_fail_cb) {
WMA_LOGE("%s: Callback not registered", __func__);
return VOS_STATUS_E_INVAL;
}
param_buf =
(WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *)
cmd_param_info;
if (!param_buf) {
WMA_LOGE("%s: Invalid pwr_save_fail_params breached event",
__func__);
return VOS_STATUS_E_INVAL;
}
event = param_buf->fixed_param;
pwr_save_fail_params.failure_reason_code =
event->power_save_failure_reason_code;
pwr_save_fail_params.wake_lock_bitmap[0] =
event->protocol_wake_lock_bitmap[0];
pwr_save_fail_params.wake_lock_bitmap[1] =
event->protocol_wake_lock_bitmap[1];
pwr_save_fail_params.wake_lock_bitmap[2] =
event->protocol_wake_lock_bitmap[2];
pwr_save_fail_params.wake_lock_bitmap[3] =
event->protocol_wake_lock_bitmap[3];
mac->sme.chip_power_save_fail_cb(mac->hHdd,
&pwr_save_fail_params);
WMA_LOGD("%s: Invoke HDD pwr_save_fail callback", __func__);
return VOS_STATUS_SUCCESS;
}
/*
* Send WMI_DFS_PHYERR_FILTER_ENA_CMDID or
* WMI_DFS_PHYERR_FILTER_DIS_CMDID command
* to firmware based on phyerr filtering
* offload status.
*/
static int
wma_unified_dfs_phyerr_filter_offload_enable(tp_wma_handle wma_handle)
{
wmi_dfs_phyerr_filter_ena_cmd_fixed_param* enable_phyerr_offload_cmd;
wmi_dfs_phyerr_filter_dis_cmd_fixed_param* disable_phyerr_offload_cmd;
wmi_buf_t buf;
u_int16_t len;
int ret;
if (NULL == wma_handle) {
WMA_LOGE("%s:wma_handle is NULL", __func__);
return 0;
}
if (VOS_FALSE == wma_handle->dfs_phyerr_filter_offload) {
WMA_LOGD("%s:Phyerror Filtering offload is Disabled in ini",
__func__);
len = sizeof(*disable_phyerr_offload_cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return 0;
}
disable_phyerr_offload_cmd =
(wmi_dfs_phyerr_filter_dis_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&disable_phyerr_offload_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_dfs_phyerr_filter_dis_cmd_fixed_param));
/*
* Send WMI_DFS_PHYERR_FILTER_DIS_CMDID
* to the firmware to disable the phyerror
* filtering offload.
*/
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_DFS_PHYERR_FILTER_DIS_CMDID);
if (ret < 0) {
WMA_LOGE("%s: Failed to send WMI_DFS_PHYERR_FILTER_DIS_CMDID ret=%d",
__func__, ret);
wmi_buf_free(buf);
return 0;
}
WMA_LOGD("%s: WMI_DFS_PHYERR_FILTER_DIS_CMDID Send Success",
__func__);
} else {
WMA_LOGD("%s:Phyerror Filtering offload is Enabled in ini",
__func__);
len = sizeof(*enable_phyerr_offload_cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return 0;
}
enable_phyerr_offload_cmd =
(wmi_dfs_phyerr_filter_ena_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&enable_phyerr_offload_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_dfs_phyerr_filter_ena_cmd_fixed_param));
/*
* Send a WMI_DFS_PHYERR_FILTER_ENA_CMDID
* to the firmware to enable the phyerror
* filtering offload.
*/
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_DFS_PHYERR_FILTER_ENA_CMDID);
if (ret < 0) {
WMA_LOGE("%s: Failed to send WMI_DFS_PHYERR_FILTER_ENA_CMDID ret=%d",
__func__, ret);
wmi_buf_free(buf);
return 0;
}
WMA_LOGD("%s: WMI_DFS_PHYERR_FILTER_ENA_CMDID Send Success",
__func__);
}
return 1;
}
/*
* WMI Handler for WMI_OFFLOAD_BCN_TX_STATUS_EVENTID event from firmware.
* This event is generated by FW when the beacon transmission is offloaded
* and the host performs beacon template modification using WMI_BCN_TMPL_CMDID
* The FW generates this event when the first successful beacon transmission
* after template update
* Return- 1:Success, 0:Failure
*/
static int wma_unified_bcntx_status_event_handler(void *handle, u_int8_t *cmd_param_info,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *param_buf;
wmi_offload_bcn_tx_status_event_fixed_param *resp_event;
tSirFirstBeaconTxCompleteInd *beacon_tx_complete_ind;
param_buf = (WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *) cmd_param_info;
if (!param_buf) {
WMA_LOGE("Invalid bcn tx response event buffer");
return -EINVAL;
}
resp_event = param_buf->fixed_param;
if (resp_event->vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: received invalid vdev_id %d",
__func__, resp_event->vdev_id);
return -EINVAL;
}
/* Check for valid handle to ensure session is not deleted in any race */
if (!wma->interfaces[resp_event->vdev_id].handle) {
WMA_LOGE("%s: The session does not exist", __func__);
return -EINVAL;
}
/* Beacon Tx Indication supports only AP mode. Ignore in other modes */
if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == false) {
WMA_LOGI("%s: Beacon Tx Indication does not support type %d and sub_type %d",
__func__, wma->interfaces[resp_event->vdev_id].type,
wma->interfaces[resp_event->vdev_id].sub_type);
return 0;
}
beacon_tx_complete_ind = (tSirFirstBeaconTxCompleteInd *)
vos_mem_malloc(sizeof(tSirFirstBeaconTxCompleteInd));
if (!beacon_tx_complete_ind) {
WMA_LOGE("%s: Failed to alloc beacon_tx_complete_ind", __func__);
return -ENOMEM;
}
beacon_tx_complete_ind->messageType = WDA_DFS_BEACON_TX_SUCCESS_IND;
beacon_tx_complete_ind->length = sizeof(tSirFirstBeaconTxCompleteInd);
beacon_tx_complete_ind->bssIdx = resp_event->vdev_id;
wma_send_msg(wma, WDA_DFS_BEACON_TX_SUCCESS_IND, (void *)beacon_tx_complete_ind, 0);
return 0;
}
static int wma_vdev_install_key_complete_event_handler(void *handle, u_int8_t *event, u_int32_t len)
{
WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *param_buf = NULL;
wmi_vdev_install_key_complete_event_fixed_param *key_fp = NULL;
if (!event) {
WMA_LOGE("%s: event param null", __func__);
return -1;
}
param_buf = (WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("%s: received null buf from target", __func__);
return -1;
}
key_fp = param_buf->fixed_param;
if (!key_fp) {
WMA_LOGE("%s: received null event data from target", __func__);
return -1;
}
/*
* Do nothing for now. Completion of set key is already indicated to lim
*/
WMA_LOGI("%s: WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID", __func__);
return 0;
}
#ifdef WLAN_FEATURE_STATS_EXT
static int wma_stats_ext_event_handler(void *handle, u_int8_t *event_buf,
u_int32_t len)
{
WMI_STATS_EXT_EVENTID_param_tlvs *param_buf;
tSirStatsExtEvent *stats_ext_event;
wmi_stats_ext_event_fixed_param *stats_ext_info;
VOS_STATUS status;
vos_msg_t vos_msg;
u_int8_t *buf_ptr;
u_int32_t alloc_len;
WMA_LOGD("%s: Posting stats ext event to SME", __func__);
param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *)event_buf;
if (!param_buf) {
WMA_LOGE("%s: Invalid stats ext event buf", __func__);
return -EINVAL;
}
stats_ext_info = param_buf->fixed_param;
buf_ptr = (u_int8_t *)stats_ext_info;
alloc_len = sizeof(tSirStatsExtEvent);
alloc_len += stats_ext_info->data_len;
if (stats_ext_info->data_len > (WMA_SVC_MSG_MAX_SIZE -
sizeof(*stats_ext_info))) {
WMA_LOGE("Excess data_len:%d", stats_ext_info->data_len);
VOS_ASSERT(0);
return -EINVAL;
}
stats_ext_event = (tSirStatsExtEvent *) vos_mem_malloc(alloc_len);
if (NULL == stats_ext_event) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return -ENOMEM;
}
buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE ;
stats_ext_event->vdev_id = stats_ext_info->vdev_id;
stats_ext_event->event_data_len = stats_ext_info->data_len;
vos_mem_copy(stats_ext_event->event_data,
buf_ptr,
stats_ext_event->event_data_len);
vos_msg.type = eWNI_SME_STATS_EXT_EVENT;
vos_msg.bodyptr = (void *)stats_ext_event;
vos_msg.bodyval = 0;
status = vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to post stats ext event to SME", __func__);
vos_mem_free(stats_ext_event);
return -1;
}
WMA_LOGD("%s: stats ext event Posted to SME", __func__);
return 0;
}
static int wma_rx_aggr_failure_event_handler(void *handle, u_int8_t *event_buf,
u_int32_t len)
{
WMI_REPORT_RX_AGGR_FAILURE_EVENTID_param_tlvs *param_buf;
struct sir_sme_rx_aggr_hole_ind *rx_aggr_hole_event;
wmi_rx_aggr_failure_event_fixed_param *rx_aggr_failure_info;
wmi_rx_aggr_failure_info *hole_info;
u_int32_t i, alloc_len;
VOS_STATUS status;
vos_msg_t vos_msg;
WMA_LOGD("%s: Posting stats ext event to SME", __func__);
param_buf = (WMI_REPORT_RX_AGGR_FAILURE_EVENTID_param_tlvs *)event_buf;
if (!param_buf) {
WMA_LOGE("%s: Invalid stats ext event buf", __func__);
return -EINVAL;
}
rx_aggr_failure_info = param_buf->fixed_param;
hole_info = param_buf->failure_info;
if (rx_aggr_failure_info->num_failure_info > ((WMA_SVC_MSG_MAX_SIZE -
sizeof(*rx_aggr_hole_event)) /
sizeof(rx_aggr_hole_event->hole_info_array[0]))) {
WMA_LOGE("%s: Excess data from WMI num_failure_info %d",
__func__, rx_aggr_failure_info->num_failure_info);
return -EINVAL;
}
alloc_len = sizeof(*rx_aggr_hole_event) +
(rx_aggr_failure_info->num_failure_info)*
sizeof(rx_aggr_hole_event->hole_info_array[0]);
rx_aggr_hole_event = vos_mem_malloc(alloc_len);
if (NULL == rx_aggr_hole_event) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return -ENOMEM;
}
rx_aggr_hole_event->hole_cnt = rx_aggr_failure_info->num_failure_info;
WMA_LOGD("aggr holes_sum: %d\n",
rx_aggr_failure_info->num_failure_info);
for (i = 0; i < rx_aggr_hole_event->hole_cnt; i++) {
rx_aggr_hole_event->hole_info_array[i] =
hole_info->end_seq - hole_info->start_seq + 1;
WMA_LOGD("aggr_index: %d\tstart_seq: %d\tend_seq: %d\t"
"hole_info: %d mpdu lost",
i, hole_info->start_seq, hole_info->end_seq,
rx_aggr_hole_event->hole_info_array[i]);
hole_info++;
}
vos_msg.type = eWNI_SME_RX_AGGR_HOLE_IND;
vos_msg.bodyptr = rx_aggr_hole_event;
vos_msg.bodyval = 0;
status = vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to post stats ext event to SME", __func__);
vos_mem_free(rx_aggr_hole_event);
return -EINVAL;
}
WMA_LOGD("%s: stats ext event Posted to SME", __func__);
return 0;
}
#endif
/**
* wma_chan_info_event_handler() - chan info event handler
* @handle: wma handle
* @event_buf: event handler data
* @len: length of @event_buf
*
* this function will handle the WMI_CHAN_INFO_EVENTID
*
* Return: int
*/
static int
wma_chan_info_event_handler(void *handle, u_int8_t *event_buf,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_CHAN_INFO_EVENTID_param_tlvs *param_buf;
wmi_chan_info_event_fixed_param *event;
struct scan_chan_info buf;
tpAniSirGlobal mac = NULL;
struct lim_channel_status *channel_status;
WMA_LOGD("%s: Enter", __func__);
if (wma != NULL && wma->vos_context != NULL) {
mac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
}
if (!mac) {
WMA_LOGE("%s: Invalid mac context", __func__);
return -EINVAL;
}
WMA_LOGD("%s: monitor:%d", __func__, mac->snr_monitor_enabled);
if (mac->snr_monitor_enabled && mac->chan_info_cb) {
param_buf =
(WMI_CHAN_INFO_EVENTID_param_tlvs *)event_buf;
if (!param_buf) {
WMA_LOGA("%s: Invalid chan info event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
if (!event) {
WMA_LOGA("%s: Invalid fixed param", __func__);
return -EINVAL;
}
buf.tx_frame_count = event->tx_frame_cnt;
buf.clock_freq = event->mac_clk_mhz;
buf.cmd_flag = event->cmd_flags;
buf.freq = event->freq;
buf.noise_floor = event->noise_floor;
buf.cycle_count = event->cycle_count;
buf.rx_clear_count = event->rx_clear_count;
mac->chan_info_cb(&buf);
}
if (ACS_FW_REPORT_PARAM_CONFIGURED &&
mac->sme.currDeviceMode == VOS_STA_SAP_MODE) {
param_buf = (WMI_CHAN_INFO_EVENTID_param_tlvs *) event_buf;
if (!param_buf) {
WMA_LOGE("Invalid chan info event buffer");
return -EINVAL;
}
event = param_buf->fixed_param;
channel_status =
vos_mem_malloc(sizeof(*channel_status));
if (!channel_status) {
WMA_LOGE(FL("Mem alloc fail"));
return -ENOMEM;
}
WMA_LOGI(FL("freq=%d nf=%d rx_cnt=%u cycle_count=%u "
"tx_pwr_range=%d tx_pwr_tput=%d "
"rx_frame_count=%u my_bss_rx_cycle_count=%u "
"rx_11b_mode_data_duration=%d "
"tx_frame_cnt=%d mac_clk_mhz=%d cmd_flags=%d"),
event->freq,
event->noise_floor,
event->rx_clear_count,
event->cycle_count,
event->chan_tx_pwr_range,
event->chan_tx_pwr_tp,
event->rx_frame_count,
event->my_bss_rx_cycle_count,
event->rx_11b_mode_data_duration,
event->tx_frame_cnt,
event->mac_clk_mhz,
event->cmd_flags
);
channel_status->channelfreq = event->freq;
channel_status->noise_floor = event->noise_floor;
channel_status->rx_clear_count =
event->rx_clear_count;
channel_status->cycle_count = event->cycle_count;
channel_status->chan_tx_pwr_range =
event->chan_tx_pwr_range;
channel_status->chan_tx_pwr_throughput =
event->chan_tx_pwr_tp;
channel_status->rx_frame_count =
event->rx_frame_count;
channel_status->bss_rx_cycle_count =
event->my_bss_rx_cycle_count;
channel_status->rx_11b_mode_data_duration =
event->rx_11b_mode_data_duration;
channel_status->tx_frame_count =
event->tx_frame_cnt;
channel_status->mac_clk_mhz =
event->mac_clk_mhz;
channel_status->channel_id =
vos_freq_to_chan(event->freq);
channel_status->cmd_flags =
event->cmd_flags;
wma_send_msg(handle,
WDA_RX_CHN_STATUS_EVENT,
(void *) channel_status, 0);
}
return 0;
}
static void
wma_register_extscan_event_handler(tp_wma_handle wma_handle)
{
if (!wma_handle) {
WMA_LOGE("%s: extscan wma_handle is NULL", __func__);
return;
}
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_EXTSCAN_START_STOP_EVENTID,
wma_extscan_start_stop_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_EXTSCAN_CAPABILITIES_EVENTID,
wma_extscan_capabilities_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_EXTSCAN_HOTLIST_MATCH_EVENTID,
wma_extscan_hotlist_match_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID,
wma_extscan_change_results_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_EXTSCAN_OPERATION_EVENTID,
wma_extscan_operations_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_EXTSCAN_TABLE_USAGE_EVENTID,
wma_extscan_table_usage_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_EXTSCAN_CACHED_RESULTS_EVENTID,
wma_extscan_cached_results_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PASSPOINT_MATCH_EVENTID,
wma_passpoint_match_event_handler);
return;
}
static int wma_antenna_isolation_event_handler(void *handle,
u_int8_t *param, u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
wmi_coex_report_isolation_event_fixed_param *event;
WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID_param_tlvs *param_buf;
struct sir_isolation_resp isolation;
tpAniSirGlobal mac = NULL;
WMA_LOGE("%s: handle %pK param %pK len %d", __func__, handle, param, len);
if(wma != NULL && wma->vos_context != NULL) {
mac = (tpAniSirGlobal)vos_get_context(
VOS_MODULE_ID_PE, wma->vos_context);
}
if (!mac) {
WMA_LOGE("%s: Invalid mac context", __func__);
return -EINVAL;
}
param_buf =
(WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID_param_tlvs *)param;
if (!param_buf) {
WMA_LOGE("%s: Invalid isolation event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
isolation.isolation_chain0 = event->isolation_chain0;
isolation.isolation_chain1 = event->isolation_chain1;
isolation.isolation_chain2 = event->isolation_chain2;
isolation.isolation_chain3 = event->isolation_chain3;
printk("\n*********************ANTENNA ISOLATION********************\n");
WMA_LOGD("%s: chain1 %d chain2 %d chain3 %d chain4 %d", __func__,
isolation.isolation_chain0, isolation.isolation_chain1,
isolation.isolation_chain2, isolation.isolation_chain3);
mac->sme.get_isolation(&isolation, mac->sme.get_isolation_cb_context);
return 0;
}
void wma_wow_tx_complete(void *wma)
{
tp_wma_handle wma_handle = (tp_wma_handle)wma;
WMA_LOGD("WOW_TX_COMPLETE DONE");
vos_event_set(&wma_handle->wow_tx_complete);
}
#ifdef WLAN_FEATURE_NAN
/**
* wma_set_nan_enable() - set nan enable flag in WMA handle
* @wma_handle: Pointer to wma handle
* @mac_param: Pointer to mac_param
*
* Return: none
*/
static void wma_set_nan_enable(tp_wma_handle wma_handle,
tMacOpenParameters *mac_param)
{
wma_handle->is_nan_enabled = mac_param->is_nan_enabled;
}
#else
static void wma_set_nan_enable(tp_wma_handle wma_handle,
tMacOpenParameters *mac_param)
{
}
#endif
#ifdef WLAN_FEATURE_TSF_PLUS
/**
* wma_update_ptp_params() - update bundle params
* @olCfg: cfg handle
* @mac_params: mac params
*
* Return: none
*/
static
void wma_update_ptp_params(struct txrx_pdev_cfg_param_t *olCfg,
tMacOpenParameters *mac_params)
{
olCfg->is_ptp_enabled = mac_params->is_ptp_enabled;
}
#else
static
void wma_update_ptp_params(struct txrx_pdev_cfg_param_t *olCfg,
tMacOpenParameters *mac_params)
{
return;
}
#endif
#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK
/**
* cfg_update_del_ack_params() - update del ack parameters
* @olCfg: cfg handle
* @mac_params: mac params
*
* Return: none
*/
static
void cfg_update_del_ack_params(struct txrx_pdev_cfg_param_t *olCfg,
tMacOpenParameters *mac_params)
{
olCfg->del_ack_enable = mac_params->del_ack_enable;
olCfg->del_ack_timer_value = mac_params->del_ack_timer_value;
olCfg->del_ack_pkt_count = mac_params->del_ack_pkt_count;
}
#else
static
void cfg_update_del_ack_params(struct txrx_pdev_cfg_param_t *olCfg,
tMacOpenParameters *mac_params)
{
}
#endif
#ifdef QCA_SUPPORT_TXRX_HL_BUNDLE
/**
* ol_cfg_update_bundle_params() - update bundle params
* @olCfg: cfg handle
* @mac_params: mac params
*
* Return: none
*/
static
void ol_cfg_update_bundle_params(struct txrx_pdev_cfg_param_t *olCfg,
tMacOpenParameters *mac_params)
{
olCfg->pkt_bundle_timer_value = mac_params->pkt_bundle_timer_value;
olCfg->pkt_bundle_size = mac_params->pkt_bundle_size;
}
#else
static
void ol_cfg_update_bundle_params(struct txrx_pdev_cfg_param_t *olCfg,
tMacOpenParameters *mac_params)
{
return;
}
#endif
/**
* ol_cfg_update_ac_specs_params() - update ac_specs params
* @olcfg: cfg handle
* @mac_params: mac params
*
* Return: none
*/
void ol_cfg_update_ac_specs_params(struct txrx_pdev_cfg_param_t *olcfg,
tMacOpenParameters *mac_params)
{
int i;
if (NULL == olcfg)
return;
if (NULL == mac_params)
return;
for (i = 0; i < OL_TX_NUM_WMM_AC; i++) {
olcfg->ac_specs[i].wrr_skip_weight =
mac_params->ac_specs[i].wrr_skip_weight;
olcfg->ac_specs[i].credit_threshold =
mac_params->ac_specs[i].credit_threshold;
olcfg->ac_specs[i].send_limit =
mac_params->ac_specs[i].send_limit;
olcfg->ac_specs[i].credit_reserve =
mac_params->ac_specs[i].credit_reserve;
olcfg->ac_specs[i].discard_weight =
mac_params->ac_specs[i].discard_weight;
}
}
#ifdef FEATURE_RUNTIME_PM
/**
* wma_runtime_context_init() - API to init wma runtime contexts
* @handle: wma handle
*
* The API initializes the wma runtime contexts for beaconing interfaces
* and the context to synchronize runtime suspend/resume.
*
* Return: void
*/
static void wma_runtime_context_init(tp_wma_handle handle)
{
tp_wma_handle wma_handle = handle;
struct wma_runtime_pm_context *runtime_context =
&wma_handle->runtime_context;
runtime_context->ap =
vos_runtime_pm_prevent_suspend_init("wma_runtime_ap");
runtime_context->resume =
vos_runtime_pm_prevent_suspend_init("wma_runtime_resume");
}
/**
* wma_runtime_context_deinit() - API to deinit wma runtime contexts
* @handle: wma handle
*
* The API deinitializes the wma runtime contexts for beaconing interfaces
* and the context to synchronize runtime suspend/resume.
*
* Return: void
*/
static void wma_runtime_context_deinit(tp_wma_handle handle)
{
tp_wma_handle wma_handle = handle;
struct wma_runtime_pm_context *runtime_context =
&wma_handle->runtime_context;
vos_runtime_pm_prevent_suspend_deinit(runtime_context->ap);
runtime_context->ap = NULL;
vos_runtime_pm_prevent_suspend_deinit(
runtime_context->resume);
runtime_context->resume = NULL;
}
#else
static void wma_runtime_context_init(tp_wma_handle handle) { }
static void wma_runtime_context_deinit(tp_wma_handle handle) { }
#endif
/**
* wma_state_info_dump() - prints state information of wma layer
* @buf: buffer pointer
* @size: size of buffer to be filled
*
* This function is used to dump state information of wma layer
*
* Return: None
*/
static void wma_state_info_dump(char **buf_ptr, uint16_t *size)
{
tp_wma_handle wma_handle;
pVosContextType vos_context;
uint16_t len = 0;
char *buf = *buf_ptr;
vos_context = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL);
if (!vos_context) {
VOS_ASSERT(0);
return;
}
wma_handle = (tp_wma_handle)vos_get_context(VOS_MODULE_ID_WDA,
vos_context);
if (!wma_handle) {
WMA_LOGE("%s: WMA context is invald!", __func__);
return;
}
WMA_LOGI("%s: size of buffer: %d", __func__, *size);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_pno_match_wake_up_count %d",
wma_handle->wow_pno_match_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_pno_complete_wake_up_count %d",
wma_handle->wow_pno_complete_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_gscan_wake_up_count %d",
wma_handle->wow_gscan_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_low_rssi_wake_up_count %d",
wma_handle->wow_low_rssi_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_rssi_breach_wake_up_count %d",
wma_handle->wow_rssi_breach_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_ucast_wake_up_count %d",
wma_handle->wow_ucast_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_bcast_wake_up_count %d",
wma_handle->wow_bcast_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_ipv4_mcast_wake_up_count %d",
wma_handle->wow_ipv4_mcast_wake_up_count);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_ipv6_mcast_ra_stats %d",
wma_handle->wow_ipv6_mcast_ra_stats);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_ipv6_mcast_ns_stats %d",
wma_handle->wow_ipv6_mcast_ns_stats);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_ipv6_mcast_na_stats %d",
wma_handle->wow_ipv6_mcast_na_stats);
len += vos_scnprintf(buf + len, *size - len,
"\n wow_oem_response_wake_up_count %d",
wma_handle->wow_oem_response_wake_up_count);
*size -= len;
*buf_ptr += len;
}
/**
* wma_register_debug_callback() - registration function for wma layer
* to print wma state information
*/
static void wma_register_debug_callback(void)
{
vos_register_debug_callback(VOS_MODULE_ID_WDA, &wma_state_info_dump);
}
/**
* wma_action_frame_filter_mac_event_handler() - action frame filter evt handler
* @handle: wma handle
* @event_buf: event handler data
* @len: length of @event_buf
*
* this function will handle the
* WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID
*
* Return: int
*/
static int
wma_action_frame_filter_mac_event_handler(void *handle, u_int8_t *event_buf,
u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID_param_tlvs *param_buf;
wmi_vdev_add_mac_addr_to_rx_filter_status_event_fixed_param *event;
struct action_frame_random_filter *filter;
struct wma_txrx_node *intr;
bool status = false;
WMA_LOGD("%s: Enter", __func__);
param_buf =
(WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID_param_tlvs *)event_buf;
if (!param_buf) {
WMA_LOGA(FL("Invalid action frame filter mac event"));
return -EINVAL;
}
event = param_buf->fixed_param;
if (!event) {
WMA_LOGA(FL("Invalid fixed param"));
return -EINVAL;
}
intr = &wma_handle->interfaces[event->vdev_id];
/* command is in progess */
if(!intr->action_frame_filter) {
WMA_LOGE(FL("no action frame req is pending - invalid event"));
return -1;
}
filter = intr->action_frame_filter;
if (event->status)
status = true;
(filter->callback)(status, filter->context);
intr->action_frame_filter = NULL;
vos_mem_free(filter);
return 0;
}
struct wma_version_info g_wmi_version_info;
/*
* Allocate and init wmi adaptation layer.
*/
VOS_STATUS WDA_open(v_VOID_t *vos_context, v_VOID_t *os_ctx,
wda_tgt_cfg_cb tgt_cfg_cb,
wda_dfs_radar_indication_cb radar_ind_cb,
wda_dfs_block_tx_cb dfs_block_tx_cb,
tMacOpenParameters *mac_params)
{
tp_wma_handle wma_handle;
HTC_HANDLE htc_handle;
adf_os_device_t adf_dev;
v_VOID_t *wmi_handle;
VOS_STATUS vos_status;
struct ol_softc *scn;
struct txrx_pdev_cfg_param_t olCfg = {0};
WMA_LOGD("%s: Enter", __func__);
g_wmi_version_info.major = __WMI_VER_MAJOR_;
g_wmi_version_info.minor = __WMI_VER_MINOR_;
g_wmi_version_info.revision = __WMI_REVISION_;
adf_dev = vos_get_context(VOS_MODULE_ID_ADF, vos_context);
htc_handle = vos_get_context(VOS_MODULE_ID_HTC, vos_context);
if (!htc_handle) {
WMA_LOGP("%s: Invalid HTC handle", __func__);
return VOS_STATUS_E_INVAL;
}
/* Alloc memory for WMA Context */
vos_status = vos_alloc_context(vos_context, VOS_MODULE_ID_WDA,
(v_VOID_t **) &wma_handle,
sizeof (t_wma_handle));
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: Memory allocation failed for wma_handle",
__func__);
return vos_status;
}
vos_mem_zero(wma_handle, sizeof (t_wma_handle));
if (vos_get_conparam() != VOS_FTM_MODE) {
#ifdef FEATURE_WLAN_SCAN_PNO
vos_wake_lock_init(&wma_handle->pno_wake_lock, "wlan_pno_wl");
#endif
#ifdef FEATURE_WLAN_EXTSCAN
vos_wake_lock_init(&wma_handle->extscan_wake_lock,
"wlan_extscan_wl");
#endif
vos_wake_lock_init(&wma_handle->wow_wake_lock,
"wlan_wow_wl");
vos_wake_lock_init(&wma_handle->wow_auth_req_wl,
"wlan_auth_req_wl");
vos_wake_lock_init(&wma_handle->wow_assoc_req_wl,
"wlan_assoc_req_wl");
vos_wake_lock_init(&wma_handle->wow_deauth_rec_wl,
"wlan_deauth_rec_wl");
vos_wake_lock_init(&wma_handle->wow_disassoc_rec_wl,
"wlan_disassoc_rec_wl");
vos_wake_lock_init(&wma_handle->wow_ap_assoc_lost_wl,
"wlan_ap_assoc_lost_wl");
vos_wake_lock_init(&wma_handle->wow_auto_shutdown_wl,
"wlan_auto_shutdown_wl");
}
/* attach the wmi */
wmi_handle = wmi_unified_attach(wma_handle, wma_wow_tx_complete);
if (!wmi_handle) {
WMA_LOGP("%s: failed to attach WMI", __func__);
vos_status = VOS_STATUS_E_NOMEM;
goto err_wma_handle;
}
WMA_LOGA("WMA --> wmi_unified_attach - success");
/* Save the WMI & HTC handle */
wma_handle->wmi_handle = wmi_handle;
wma_handle->htc_handle = htc_handle;
wma_handle->vos_context = vos_context;
wma_handle->adf_dev = adf_dev;
wma_runtime_context_init(wma_handle);
/* initialize default target config */
wma_set_default_tgt_config(wma_handle);
#ifdef IPA_UC_OFFLOAD
olCfg.is_uc_offload_enabled = mac_params->ucOffloadEnabled;
olCfg.uc_tx_buffer_count = mac_params->ucTxBufCount;
olCfg.uc_tx_buffer_size = mac_params->ucTxBufSize;
olCfg.uc_rx_indication_ring_count = mac_params->ucRxIndRingCount;
olCfg.uc_tx_partition_base = mac_params->ucTxPartitionBase;
#endif /* IPA_UC_OFFLOAD*/
wma_handle->tx_chain_mask_cck = mac_params->tx_chain_mask_cck;
wma_handle->self_gen_frm_pwr = mac_params->self_gen_frm_pwr;
wma_handle->max_mgmt_tx_fail_count = mac_params->max_mgmt_tx_fail_count;
/* Allocate cfg handle */
/* RX Full reorder should enable for PCIe, ROME3.X project only now
* MDM should enable later, schedule TBD
* HL also sdould be enabled, schedule TBD */
#ifdef WLAN_FEATURE_RX_FULL_REORDER_OL
olCfg.is_full_reorder_offload = mac_params->reorderOffload;
#else
olCfg.is_full_reorder_offload = 0;
#endif
ol_cfg_update_bundle_params(&olCfg, mac_params);
cfg_update_del_ack_params(&olCfg, mac_params);
ol_cfg_update_ac_specs_params(&olCfg, mac_params);
wma_update_ptp_params(&olCfg, mac_params);
((pVosContextType) vos_context)->cfg_ctx =
ol_pdev_cfg_attach(((pVosContextType) vos_context)->adf_ctx, olCfg);
if (!(((pVosContextType) vos_context)->cfg_ctx)) {
WMA_LOGP("%s: failed to init cfg handle", __func__);
vos_status = VOS_STATUS_E_NOMEM;
goto err_wmi_handle;
}
/* adjust the cfg_ctx default value based on setting */
wdi_in_set_cfg_rx_fwd_disabled((ol_pdev_handle)((pVosContextType)vos_context)->cfg_ctx,
(u_int8_t)mac_params->apDisableIntraBssFwd);
/* adjust the packet log enable default value based on CFG INI setting */
wdi_in_set_cfg_pakcet_log_enabled((ol_pdev_handle)
((pVosContextType)vos_context)->cfg_ctx, (u_int8_t)vos_is_packet_log_enabled());
/* adjust the ptp rx option default value based on CFG INI setting */
wdi_in_set_cfg_ptp_rx_opt_enabled((ol_pdev_handle)
((pVosContextType)
vos_context)->cfg_ctx,
(u_int8_t)
vos_is_ptp_rx_opt_enabled());
/* Allocate dfs_ic and initialize DFS */
wma_handle->dfs_ic = wma_dfs_attach(wma_handle->dfs_ic);
if(wma_handle->dfs_ic == NULL) {
WMA_LOGE("%s: Memory allocation failed for dfs_ic", __func__);
goto err_wmi_handle;
}
#if defined(QCA_WIFI_FTM)
if (vos_get_conparam() == VOS_FTM_MODE)
wma_utf_attach(wma_handle);
#endif
/*TODO: Recheck below parameters */
scn = vos_get_context(VOS_MODULE_ID_HIF, vos_context);
if (NULL == scn) {
WMA_LOGE("%s: Failed to get scn",__func__);
vos_status = VOS_STATUS_E_NOMEM;
goto err_scn_context;
}
mac_params->maxStation = ol_get_number_of_peers_supported(scn);
mac_params->maxBssId = WMA_MAX_SUPPORTED_BSS;
mac_params->frameTransRequired = 0;
#ifdef WLAN_FEATURE_LPSS
wma_handle->is_lpass_enabled = mac_params->is_lpass_enabled;
#endif
wma_set_nan_enable(wma_handle, mac_params);
wma_handle->wlan_resource_config.num_wow_filters = mac_params->maxWoWFilters;
wma_handle->wlan_resource_config.num_keep_alive_pattern = WMA_MAXNUM_PERIODIC_TX_PTRNS;
/* The current firmware implementation requires the number of offload peers
* should be (number of vdevs + 1).
*/
wma_handle->wlan_resource_config.num_offload_peers =
mac_params->apMaxOffloadPeers + 1;
wma_handle->wlan_resource_config.num_offload_reorder_buffs =
mac_params->apMaxOffloadReorderBuffs + 1;
wma_handle->ol_ini_info = mac_params->olIniInfo;
wma_handle->max_station = mac_params->maxStation;
wma_handle->max_bssid = mac_params->maxBssId;
wma_handle->frame_xln_reqd = mac_params->frameTransRequired;
wma_handle->driver_type = mac_params->driverType;
wma_handle->ssdp = mac_params->ssdp;
wma_handle->enable_mc_list = mac_params->enable_mc_list;
wma_handle->enable_bcst_ptrn = mac_params->enable_bcst_ptrn;
wma_handle->bpf_packet_filter_enable =
mac_params->bpf_packet_filter_enable;
#ifdef FEATURE_WLAN_RA_FILTERING
wma_handle->IsRArateLimitEnabled = mac_params->IsRArateLimitEnabled;
wma_handle->RArateLimitInterval = mac_params->RArateLimitInterval;
#endif
/*
* Indicates if DFS Phyerr filtering offload
* is Enabled/Disabed from ini
*/
wma_handle->dfs_phyerr_filter_offload =
mac_params->dfsPhyerrFilterOffload;
wma_handle->dfs_pri_multiplier =
mac_params->dfsRadarPriMultiplier;
wma_handle->interfaces = vos_mem_malloc(sizeof(struct wma_txrx_node) *
wma_handle->max_bssid);
if (!wma_handle->interfaces) {
WMA_LOGP("%s: failed to allocate interface table", __func__);
vos_status = VOS_STATUS_E_NOMEM;
goto err_scn_context;
}
vos_mem_zero(wma_handle->interfaces, sizeof(struct wma_txrx_node) *
wma_handle->max_bssid);
/* Register the debug print event handler */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_DEBUG_PRINT_EVENTID,
wma_unified_debug_print_event_handler);
wma_handle->tgt_cfg_update_cb = tgt_cfg_cb;
wma_handle->dfs_radar_indication_cb = radar_ind_cb;
wma_handle->dfs_block_tx_cb = dfs_block_tx_cb;
vos_status = vos_event_init(&wma_handle->wma_ready_event);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: wma_ready_event initialization failed", __func__);
goto err_event_init;
}
vos_status = vos_event_init(&wma_handle->target_suspend);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: target suspend event initialization failed",
__func__);
goto err_event_init;
}
vos_status = vos_event_init(&wma_handle->wow_tx_complete);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: wow_tx_complete event initialization failed",
__func__);
goto err_event_init;
}
/* Init Tx Frame Complete event */
vos_status = vos_event_init(&wma_handle->tx_frm_download_comp_event);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGP("%s: failed to init tx_frm_download_comp_event",
__func__);
goto err_event_init;
}
/* Init tx queue empty check event */
vos_status = vos_event_init(&wma_handle->tx_queue_empty_event);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGP("%s: failed to init tx_queue_empty_event",
__func__);
goto err_event_init;
}
vos_status = vos_event_init(&wma_handle->wma_resume_event);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: wma_resume_event initialization failed", __func__);
goto err_event_init;
}
vos_status = vos_event_init(&wma_handle->runtime_suspend);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: runtime suspend event initialization failed",
__func__);
goto err_event_init;
}
vos_status = vos_event_init(&wma_handle->recovery_event);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: recovery event initialization failed", __func__);
goto err_event_init;
}
INIT_LIST_HEAD(&wma_handle->vdev_resp_queue);
adf_os_spinlock_init(&wma_handle->vdev_respq_lock);
adf_os_spinlock_init(&wma_handle->vdev_detach_lock);
adf_os_spinlock_init(&wma_handle->roam_preauth_lock);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
adf_os_spinlock_init(&wma_handle->roam_synch_lock);
#endif
adf_os_atomic_init(&wma_handle->is_wow_bus_suspended);
adf_os_atomic_init(&wma_handle->dfs_wmi_event_pending);
adf_os_atomic_init(&wma_handle->dfs_wmi_event_dropped);
/* Register vdev start response event handler */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_VDEV_START_RESP_EVENTID,
wma_vdev_start_resp_handler);
/* Register vdev stop response event handler */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_VDEV_STOPPED_EVENTID,
wma_vdev_stop_resp_handler);
/* register for STA kickout function */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_STA_KICKOUT_EVENTID,
wma_peer_sta_kickout_event_handler);
/* register for stats response event */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_UPDATE_STATS_EVENTID,
wma_stats_event_handler);
/* register for peer info response event */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_STATS_INFO_EVENTID,
wma_peer_info_event_handler);
/* register for linkspeed response event */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_ESTIMATED_LINKSPEED_EVENTID,
wma_link_speed_event_handler);
#ifdef FEATURE_OEM_DATA_SUPPORT
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_OEM_CAPABILITY_EVENTID,
wma_oem_capability_event_callback);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_OEM_MEASUREMENT_REPORT_EVENTID,
wma_oem_measurement_report_event_callback);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_OEM_ERROR_REPORT_EVENTID,
wma_oem_error_report_event_callback);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_OEM_RESPONSE_EVENTID,
wma_oem_data_response_handler);
#endif
/*
* Register appropriate DFS phyerr event handler for
* Phyerror events. Handlers differ for phyerr filtering
* offload enable and disable cases.
*/
wma_register_dfs_event_handler(wma_handle);
/* Register peer change event handler */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_STATE_EVENTID,
wma_peer_state_change_event_handler);
/* Register beacon tx complete event id. The event is required
* for sending channel switch announcement frames
*/
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_OFFLOAD_BCN_TX_STATUS_EVENTID,
wma_unified_bcntx_status_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_UPDATE_VDEV_RATE_STATS_EVENTID,
wma_link_status_event_handler);
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
/* Register event handler for processing Link Layer Stats
* response from the FW
*/
wma_register_ll_stats_event_handler(wma_handle);
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
wmi_set_tgt_assert(wma_handle->wmi_handle,
mac_params->force_target_assert_enabled);
/* Firmware debug log */
vos_status = dbglog_init(wma_handle->wmi_handle);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: Firmware Dbglog initialization failed", __func__);
goto err_dbglog_init;
}
/*
* Update Powersave mode
* 1 - Legacy Powersave + Deepsleep Disabled
* 2 - QPower + Deepsleep Disabled
* 3 - Legacy Powersave + Deepsleep Enabled
* 4 - QPower + Deepsleep Enabled
*/
wma_handle->powersave_mode = mac_params->powersaveOffloadEnabled;
wma_handle->staMaxLIModDtim = mac_params->staMaxLIModDtim;
wma_handle->staModDtim = mac_params->staModDtim;
wma_handle->staDynamicDtim = mac_params->staDynamicDtim;
/*
* Value of mac_params->wowEnable can be,
* 0 - Disable both magic pattern match and pattern byte match.
* 1 - Enable magic pattern match on all interfaces.
* 2 - Enable pattern byte match on all interfaces.
* 3 - Enable both magic patter and pattern byte match on
* all interfaces.
*/
wma_handle->wow.magic_ptrn_enable =
(mac_params->wowEnable & 0x01) ? TRUE : FALSE;
wma_handle->ptrn_match_enable_all_vdev =
(mac_params->wowEnable & 0x02) ? TRUE : FALSE;
#ifdef FEATURE_WLAN_TDLS
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_TDLS_PEER_EVENTID,
wma_tdls_event_handler);
#endif /* FEATURE_WLAN_TDLS */
/* register for install key completion event */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
wma_vdev_install_key_complete_event_handler);
#ifdef WLAN_FEATURE_NAN
/* register for nan response event */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_NAN_EVENTID,
wma_nan_rsp_event_handler);
#endif
#ifdef WLAN_FEATURE_STATS_EXT
/* register for extended stats event */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_STATS_EXT_EVENTID,
wma_stats_ext_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_REPORT_RX_AGGR_FAILURE_EVENTID,
wma_rx_aggr_failure_event_handler);
#endif
#ifdef FEATURE_WLAN_EXTSCAN
wma_register_extscan_event_handler(wma_handle);
#endif
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PDEV_DIV_RSSI_ANTID_EVENTID,
wma_pdev_div_info_evt_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_BPF_CAPABILIY_INFO_EVENTID,
wma_get_bpf_caps_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PDEV_CHIP_POWER_STATS_EVENTID,
wma_unified_power_debug_stats_event_handler);
WMA_LOGD("%s: Exit", __func__);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_ROAM_SYNCH_EVENTID,
wma_roam_synch_event_handler);
#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_RSSI_BREACH_EVENTID,
wma_rssi_breached_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_CHAN_INFO_EVENTID,
wma_chan_info_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID,
wma_action_frame_filter_mac_event_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID,
wma_chip_power_save_failure_detected_handler);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID,
wma_antenna_isolation_event_handler);
wma_register_debug_callback();
wma_ndp_register_all_event_handlers(wma_handle);
return VOS_STATUS_SUCCESS;
err_dbglog_init:
adf_os_spinlock_destroy(&wma_handle->vdev_respq_lock);
adf_os_spinlock_destroy(&wma_handle->vdev_detach_lock);
adf_os_spinlock_destroy(&wma_handle->roam_preauth_lock);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
adf_os_spinlock_destroy(&wma_handle->roam_synch_lock);
#endif
err_event_init:
wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
WMI_DEBUG_PRINT_EVENTID);
vos_mem_free(wma_handle->interfaces);
err_scn_context:
wma_dfs_detach(wma_handle->dfs_ic);
#if defined(QCA_WIFI_FTM)
wma_utf_detach(wma_handle);
#endif
err_wmi_handle:
adf_os_mem_free(((pVosContextType) vos_context)->cfg_ctx);
OS_FREE(wmi_handle);
err_wma_handle:
if (vos_get_conparam() != VOS_FTM_MODE) {
#ifdef FEATURE_WLAN_SCAN_PNO
vos_wake_lock_destroy(&wma_handle->pno_wake_lock);
#endif
#ifdef FEATURE_WLAN_EXTSCAN
vos_wake_lock_destroy(&wma_handle->extscan_wake_lock);
#endif
vos_wake_lock_destroy(&wma_handle->wow_wake_lock);
vos_wake_lock_destroy(&wma_handle->wow_auth_req_wl);
vos_wake_lock_destroy(&wma_handle->wow_assoc_req_wl);
vos_wake_lock_destroy(&wma_handle->wow_deauth_rec_wl);
vos_wake_lock_destroy(&wma_handle->wow_disassoc_rec_wl);
vos_wake_lock_destroy(&wma_handle->wow_ap_assoc_lost_wl);
vos_wake_lock_destroy(&wma_handle->wow_auto_shutdown_wl);
}
wma_runtime_context_deinit(wma_handle);
vos_free_context(vos_context, VOS_MODULE_ID_WDA, wma_handle);
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
/* function : wma_pre_start
* Description :
* Args :
* Returns :
*/
VOS_STATUS wma_pre_start(v_VOID_t *vos_ctx)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
A_STATUS status = A_OK;
tp_wma_handle wma_handle;
vos_msg_t wma_msg = {0} ;
WMA_LOGD("%s: Enter", __func__);
wma_handle = vos_get_context(VOS_MODULE_ID_WDA, vos_ctx);
/* Validate the wma_handle */
if (NULL == wma_handle) {
WMA_LOGP("%s: invalid argument", __func__);
vos_status = VOS_STATUS_E_INVAL;
goto end;
}
/* Open endpoint for ctrl path - WMI <--> HTC */
status = wmi_unified_connect_htc_service(
wma_handle->wmi_handle,
wma_handle->htc_handle);
if (A_OK != status) {
WMA_LOGP("%s: wmi_unified_connect_htc_service", __func__);
vos_status = VOS_STATUS_E_FAULT;
goto end;
}
WMA_LOGA("WMA --> wmi_unified_connect_htc_service - success");
/* Trigger the CFG DOWNLOAD */
wma_msg.type = WNI_CFG_DNLD_REQ ;
wma_msg.bodyptr = NULL;
wma_msg.bodyval = 0;
vos_status = vos_mq_post_message( VOS_MQ_ID_WDA, &wma_msg );
if (VOS_STATUS_SUCCESS !=vos_status) {
WMA_LOGP("%s: Failed to post WNI_CFG_DNLD_REQ msg", __func__);
VOS_ASSERT(0);
vos_status = VOS_STATUS_E_FAILURE;
}
end:
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
/* function : wma_send_msg
* Description :
* Args :
* Returns :
*/
void wma_send_msg(tp_wma_handle wma_handle, u_int16_t msg_type,
void *body_ptr, u_int32_t body_val)
{
tSirMsgQ msg = {0} ;
tANI_U32 status = VOS_STATUS_SUCCESS ;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
msg.type = msg_type;
msg.bodyval = body_val;
msg.bodyptr = body_ptr;
status = limPostMsgApi(pMac, &msg);
if (VOS_STATUS_SUCCESS != status) {
if(NULL != body_ptr)
vos_mem_free(body_ptr);
VOS_ASSERT(0) ;
}
return ;
}
/* function : wma_get_txrx_vdev_type
* Description :
* Args :
* Returns :
*/
enum wlan_op_mode wma_get_txrx_vdev_type(u_int32_t type)
{
enum wlan_op_mode vdev_type = wlan_op_mode_unknown;
switch (type) {
case WMI_VDEV_TYPE_AP:
vdev_type = wlan_op_mode_ap;
break;
case WMI_VDEV_TYPE_STA:
vdev_type = wlan_op_mode_sta;
break;
#ifdef QCA_IBSS_SUPPORT
case WMI_VDEV_TYPE_IBSS:
vdev_type = wlan_op_mode_ibss;
break;
#endif
case WMI_VDEV_TYPE_OCB:
vdev_type = wlan_op_mode_ocb;
break;
case WMI_VDEV_TYPE_NDI:
vdev_type = wlan_op_mode_ndi;
break;
case WMI_VDEV_TYPE_MONITOR:
vdev_type = wlan_op_mode_monitor;
break;
default:
WMA_LOGE("Invalid vdev type %u", type);
vdev_type = wlan_op_mode_unknown;
}
return vdev_type;
}
/* function : wma_unified_vdev_create_send
* Description :
* Args :
* Returns :
*/
int wma_unified_vdev_create_send(wmi_unified_t wmi_handle, u_int8_t if_id,
u_int32_t type, u_int32_t subtype,
u_int8_t macaddr[IEEE80211_ADDR_LEN],
u_int8_t nss_2g, u_int8_t nss_5g)
{
wmi_vdev_create_cmd_fixed_param* cmd;
wmi_buf_t buf;
int len = sizeof(*cmd);
int ret;
int num_bands = 2;
u_int8_t *buf_ptr;
wmi_vdev_txrx_streams *txrx_streams;
len += (num_bands * sizeof(wmi_vdev_txrx_streams) + WMI_TLV_HDR_SIZE);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
WMA_LOGP("%s:wmi_buf_alloc failed", __FUNCTION__);
return ENOMEM;
}
cmd = (wmi_vdev_create_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_create_cmd_fixed_param));
cmd->vdev_id = if_id;
cmd->vdev_type = type;
cmd->vdev_subtype = subtype;
cmd->num_cfg_txrx_streams = num_bands;
WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->vdev_macaddr);
WMA_LOGE("%s: ID = %d VAP Addr = %02x:%02x:%02x:%02x:%02x:%02x",
__func__, if_id,
macaddr[0], macaddr[1], macaddr[2],
macaddr[3], macaddr[4], macaddr[5]);
buf_ptr = (u_int8_t *)cmd + sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
(num_bands * sizeof(wmi_vdev_txrx_streams)));
buf_ptr += WMI_TLV_HDR_SIZE;
WMA_LOGD("%s: type %d, subtype %d, nss_2g %d, nss_5g %d", __func__,
type, subtype, nss_2g, nss_5g);
txrx_streams = (wmi_vdev_txrx_streams *)buf_ptr;
txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G;
txrx_streams->supported_tx_streams = nss_2g;
txrx_streams->supported_rx_streams = nss_2g;
WMITLV_SET_HDR(&txrx_streams->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_txrx_streams,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_txrx_streams));
buf_ptr += sizeof(wmi_vdev_txrx_streams);
txrx_streams = (wmi_vdev_txrx_streams *)buf_ptr;
txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G;
txrx_streams->supported_tx_streams = nss_5g;
txrx_streams->supported_rx_streams = nss_5g;
WMITLV_SET_HDR(&txrx_streams->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_txrx_streams,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_txrx_streams));
ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_VDEV_CREATE_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send WMI_VDEV_CREATE_CMDID");
wmi_buf_free(buf);
}
return ret;
}
/* function : wma_unified_vdev_delete_send
* Description :
* Args :
* Returns :
*/
static int wma_unified_vdev_delete_send(wmi_unified_t wmi_handle, u_int8_t if_id)
{
wmi_vdev_delete_cmd_fixed_param* cmd;
wmi_buf_t buf;
int ret;
buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGP("%s:wmi_buf_alloc failed", __FUNCTION__);
return ENOMEM;
}
cmd = (wmi_vdev_delete_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_delete_cmd_fixed_param));
cmd->vdev_id = if_id;
ret = wmi_unified_cmd_send(wmi_handle, buf, sizeof(wmi_vdev_delete_cmd_fixed_param),
WMI_VDEV_DELETE_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send WMI_VDEV_DELETE_CMDID");
wmi_buf_free(buf);
}
return ret;
}
void wma_vdev_detach_callback(void *ctx)
{
tp_wma_handle wma;
struct wma_txrx_node *iface = (struct wma_txrx_node *)ctx;
tpDelStaSelfParams param;
struct wma_target_req *req_msg;
wma = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
if (!wma || !iface->del_staself_req) {
WMA_LOGP("%s: wma %pK iface %pK", __func__, wma,
iface->del_staself_req);
return;
}
param = (tpDelStaSelfParams) iface->del_staself_req;
WMA_LOGD("%s: sending WDA_DEL_STA_SELF_RSP for vdev %d",
__func__, param->sessionId);
req_msg = wma_find_vdev_req(wma, param->sessionId,
WMA_TARGET_REQ_TYPE_VDEV_DEL);
if (req_msg) {
WMA_LOGD("%s: Found vdev request for vdev id %d",
__func__, param->sessionId);
vos_timer_stop(&req_msg->event_timeout);
vos_timer_destroy(&req_msg->event_timeout);
adf_os_mem_free(req_msg);
}
if(iface->addBssStaContext)
adf_os_mem_free(iface->addBssStaContext);
#if defined WLAN_FEATURE_VOWIFI_11R
if (iface->staKeyParams)
adf_os_mem_free(iface->staKeyParams);
#endif
vos_mem_zero(iface, sizeof(*iface));
param->status = VOS_STATUS_SUCCESS;
wma_send_msg(wma, WDA_DEL_STA_SELF_RSP, (void *)param, 0);
}
/* function : wma_vdev_detach
* Description :
* Args :
* Returns :
*/
static VOS_STATUS wma_vdev_detach(tp_wma_handle wma_handle,
tpDelStaSelfParams pdel_sta_self_req_param,
u_int8_t generateRsp)
{
VOS_STATUS status = VOS_STATUS_SUCCESS;
ol_txrx_peer_handle peer;
ol_txrx_pdev_handle pdev;
u_int8_t peer_id;
u_int8_t vdev_id = pdel_sta_self_req_param->sessionId;
struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id];
struct wma_target_req *msg;
if (((iface->type == WMI_VDEV_TYPE_AP) &&
(iface->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) ||
(iface->type == WMI_VDEV_TYPE_MONITOR)) {
WMA_LOGA("P2P Device: removing self peer %pM",
pdel_sta_self_req_param->selfMacAddr);
pdev = vos_get_context(VOS_MODULE_ID_TXRX,
wma_handle->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev",__func__);
return VOS_STATUS_E_FAULT;
}
peer = ol_txrx_find_peer_by_addr(pdev,
pdel_sta_self_req_param->selfMacAddr,
&peer_id);
if (!peer) {
WMA_LOGE("%s Failed to find peer %pM", __func__,
pdel_sta_self_req_param->selfMacAddr);
}
wma_remove_peer(wma_handle,
pdel_sta_self_req_param->selfMacAddr,
vdev_id, peer, VOS_FALSE);
}
if (adf_os_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) {
WMA_LOGA("BSS is not yet stopped. Defering vdev(vdev id %x) deletion",
vdev_id);
iface->del_staself_req = pdel_sta_self_req_param;
return status;
}
adf_os_spin_lock_bh(&wma_handle->vdev_detach_lock);
if(!iface->handle) {
WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed",
vdev_id);
adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
vos_mem_free(pdel_sta_self_req_param);
pdel_sta_self_req_param = NULL;
return status;
}
/* Unregister vdev from TL shim before vdev delete
* Will protect from invalid vdev access */
WLANTL_UnRegisterVdev(wma_handle->vos_context, vdev_id);
/* remove the interface from ath_dev */
if (wma_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id)) {
WMA_LOGE("Unable to remove an interface for ath_dev.");
status = VOS_STATUS_E_FAILURE;
adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
goto out;
}
WMA_LOGD("vdev_id:%hu vdev_hdl:%pK", vdev_id, iface->handle);
if (!generateRsp) {
WMA_LOGE("Call txrx detach w/o callback for vdev %d", vdev_id);
ol_txrx_vdev_detach(iface->handle, NULL, NULL);
iface->handle = NULL;
wma_handle->interfaces[vdev_id].is_vdev_valid = false;
adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
goto out;
}
iface->del_staself_req = pdel_sta_self_req_param;
msg = wma_fill_vdev_req(wma_handle, vdev_id, WDA_DEL_STA_SELF_REQ,
WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 2000);
if (!msg) {
WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d",
__func__, vdev_id);
status = VOS_STATUS_E_NOMEM;
adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
goto out;
}
WMA_LOGD("Call txrx detach with callback for vdev %d", vdev_id);
ol_txrx_vdev_detach(iface->handle, NULL, NULL);
iface->handle = NULL;
wma_handle->interfaces[vdev_id].is_vdev_valid = false;
wma_vdev_detach_callback(iface);
adf_os_spin_unlock_bh(&wma_handle->vdev_detach_lock);
return status;
out:
if(iface->addBssStaContext)
adf_os_mem_free(iface->addBssStaContext);
#if defined WLAN_FEATURE_VOWIFI_11R
if (iface->staKeyParams)
adf_os_mem_free(iface->staKeyParams);
#endif
vos_mem_zero(iface, sizeof(*iface));
pdel_sta_self_req_param->status = status;
if (generateRsp)
wma_send_msg(wma_handle, WDA_DEL_STA_SELF_RSP, (void *)pdel_sta_self_req_param, 0);
return status;
}
static int wmi_unified_peer_create_send(wmi_unified_t wmi,
const u_int8_t *peer_addr, u_int32_t peer_type,
u_int32_t vdev_id)
{
wmi_peer_create_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wmi, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_peer_create_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_peer_create_cmd_fixed_param));
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
cmd->peer_type = peer_type;
cmd->vdev_id = vdev_id;
if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_CREATE_CMDID)) {
WMA_LOGP("%s: failed to send WMI_PEER_CREATE_CMDID", __func__);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
VOS_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev,
ol_txrx_vdev_handle vdev, u8 peer_addr[6],
u_int32_t peer_type, u_int8_t vdev_id,
v_BOOL_t roam_synch_in_progress)
{
ol_txrx_peer_handle peer;
if (++wma->interfaces[vdev_id].peer_count > wma->wlan_resource_config.num_peers) {
WMA_LOGP("%s, the peer count exceeds the limit %d",
__func__, wma->interfaces[vdev_id].peer_count - 1);
goto err;
}
peer = ol_txrx_peer_attach(pdev, vdev, peer_addr);
if (!peer) {
WMA_LOGE("%s : Unable to attach peer %pM", __func__, peer_addr);
goto err;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (roam_synch_in_progress) {
WMA_LOGD("%s: Created peer with peer_addr %pM vdev_id %d,"
"peer_count - %d",__func__, peer_addr, vdev_id,
wma->interfaces[vdev_id].peer_count);
return VOS_STATUS_SUCCESS;
}
#endif
if (wmi_unified_peer_create_send(wma->wmi_handle, peer_addr,
peer_type, vdev_id) < 0) {
WMA_LOGP("%s : Unable to create peer in Target", __func__);
ol_txrx_peer_detach(peer);
goto err;
}
WMA_LOGE("%s: Created peer with peer_addr %pM vdev_id %d, peer_count - %d",
__func__, peer_addr, vdev_id, wma->interfaces[vdev_id].peer_count);
#ifdef QCA_IBSS_SUPPORT
/* for each remote ibss peer, clear its keys */
if (wma_is_vdev_in_ibss_mode(wma, vdev_id)
&& !vos_mem_compare(peer_addr, vdev->mac_addr.raw, ETH_ALEN)) {
tSetStaKeyParams key_info;
WMA_LOGD("%s: remote ibss peer %pM key clearing\n", __func__,
peer_addr);
vos_mem_set(&key_info, sizeof(key_info), 0);
key_info.smesessionId= vdev_id;
vos_mem_copy(key_info.peerMacAddr, peer_addr, ETH_ALEN);
key_info.sendRsp = FALSE;
wma_set_stakey(wma, &key_info);
}
#endif
return VOS_STATUS_SUCCESS;
err:
wma->interfaces[vdev_id].peer_count--;
return VOS_STATUS_E_FAILURE;
}
static void wma_set_sta_keep_alive(tp_wma_handle wma, u_int8_t vdev_id,
v_U32_t method, v_U32_t timeperiod,
u_int8_t *hostv4addr, u_int8_t *destv4addr,
u_int8_t *destmac)
{
wmi_buf_t buf;
WMI_STA_KEEPALIVE_CMD_fixed_param *cmd;
WMI_STA_KEEPALVE_ARP_RESPONSE *arp_rsp;
u_int8_t *buf_ptr;
int len;
WMA_LOGD("%s: Enter", __func__);
if (timeperiod > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) {
WMA_LOGE("Invalid period %d Max limit %d", timeperiod,
WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX);
return;
}
len = sizeof(*cmd) + sizeof(*arp_rsp);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("wmi_buf_alloc failed");
return;
}
cmd = (WMI_STA_KEEPALIVE_CMD_fixed_param *) wmi_buf_data(buf);
buf_ptr = (u_int8_t *)cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_STA_KEEPALIVE_CMD_fixed_param));
cmd->interval = timeperiod;
cmd->enable = (timeperiod)? 1:0;
cmd->vdev_id = vdev_id;
WMA_LOGD("Keep Alive: vdev_id:%d interval:%u method:%d", vdev_id,
timeperiod, method);
arp_rsp = (WMI_STA_KEEPALVE_ARP_RESPONSE *)(buf_ptr + sizeof(*cmd));
WMITLV_SET_HDR(&arp_rsp->tlv_header,
WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE,
WMITLV_GET_STRUCT_TLVLEN(WMI_STA_KEEPALVE_ARP_RESPONSE));
if (method == SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP) {
if ((NULL == hostv4addr) ||
(NULL == destv4addr) ||
(NULL == destmac)) {
WMA_LOGE("%s: received null pointer, hostv4addr:%pK "
"destv4addr:%pK destmac:%pK ", __func__,
hostv4addr, destv4addr, destmac);
wmi_buf_free(buf);
return;
}
cmd->method = WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE;
vos_mem_copy(&arp_rsp->sender_prot_addr, hostv4addr,
SIR_IPV4_ADDR_LEN);
vos_mem_copy(&arp_rsp->target_prot_addr, destv4addr,
SIR_IPV4_ADDR_LEN);
WMI_CHAR_ARRAY_TO_MAC_ADDR(destmac,&arp_rsp->dest_mac_addr);
} else {
cmd->method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME;
}
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_STA_KEEPALIVE_CMDID)) {
WMA_LOGE("Failed to set KeepAlive");
wmi_buf_free(buf);
}
WMA_LOGD("%s: Exit", __func__);
return;
}
static inline void wma_get_link_probe_timeout(struct sAniSirGlobal *mac,
tANI_U32 sub_type,
tANI_U32 *max_inactive_time,
tANI_U32 *max_unresponsive_time)
{
tANI_U32 keep_alive;
tANI_U16 lm_id, ka_id;
switch (sub_type) {
case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO:
lm_id = WNI_CFG_GO_LINK_MONITOR_TIMEOUT;
ka_id = WNI_CFG_GO_KEEP_ALIVE_TIMEOUT;
break;
default:
/*For softAp the subtype value will be zero*/
lm_id = WNI_CFG_AP_LINK_MONITOR_TIMEOUT;
ka_id = WNI_CFG_AP_KEEP_ALIVE_TIMEOUT;
}
if(wlan_cfgGetInt(mac, lm_id, max_inactive_time) != eSIR_SUCCESS) {
WMA_LOGE("Failed to read link monitor for subtype %d", sub_type);
*max_inactive_time = WMA_LINK_MONITOR_DEFAULT_TIME_SECS;
}
if(wlan_cfgGetInt(mac, ka_id, &keep_alive) != eSIR_SUCCESS) {
WMA_LOGE("Failed to read keep alive for subtype %d", sub_type);
keep_alive = WMA_KEEP_ALIVE_DEFAULT_TIME_SECS;
}
*max_unresponsive_time = *max_inactive_time + keep_alive;
}
/**
* wma_verify_rate_code() - verify if rate code is valid.
* @rate_code: rate code
*
* Return: verify result
*/
static bool wma_verify_rate_code(u_int32_t rate_code)
{
uint8_t preamble, nss, rate;
bool valid = true;
preamble = (rate_code & 0xc0) >> 6;
nss = (rate_code & 0x30) >> 4;
rate = rate_code & 0xf;
switch (preamble) {
case WMI_RATE_PREAMBLE_CCK:
if (nss != 0 || rate > 3)
valid = false;
break;
case WMI_RATE_PREAMBLE_OFDM:
if (nss != 0 || rate > 7)
valid = false;
break;
case WMI_RATE_PREAMBLE_HT:
if (nss > 1 || rate > 7)
valid = false;
break;
case WMI_RATE_PREAMBLE_VHT:
if (nss > 1 || rate > 9)
valid = false;
break;
default:
break;
}
return valid;
}
#define TX_MGMT_RATE_2G_ENABLE_OFFSET 30
#define TX_MGMT_RATE_5G_ENABLE_OFFSET 31
#define TX_MGMT_RATE_2G_OFFSET 0
#define TX_MGMT_RATE_5G_OFFSET 12
/**
* wma_set_mgmt_rate() - set vdev mgmt rate.
* @wma: wma handle
* @vdev_id: vdev id
*
* Return: None
*/
static void wma_set_vdev_mgmt_rate(tp_wma_handle wma, u_int8_t vdev_id)
{
uint32_t cfg_val;
int ret;
uint32_t per_band_mgmt_tx_rate = 0;
struct sAniSirGlobal *mac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == mac) {
WMA_LOGE("%s: Failed to get mac", __func__);
return;
}
if (wlan_cfgGetInt(mac, WNI_CFG_RATE_FOR_TX_MGMT,
&cfg_val) == eSIR_SUCCESS) {
if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_STADEF) ||
!wma_verify_rate_code(cfg_val)) {
WMA_LOGE("invalid rate code, ignore.");
} else {
ret = wmi_unified_vdev_set_param_send(
wma->wmi_handle,
vdev_id,
WMI_VDEV_PARAM_MGMT_TX_RATE,
cfg_val);
if (ret)
WMA_LOGE("Failed to set "
"WMI_VDEV_PARAM_MGMT_TX_RATE");
}
} else {
WMA_LOGE("Failed to get value of "
"WNI_CFG_RATE_FOR_TX_MGMT");
}
if (wlan_cfgGetInt(mac, WNI_CFG_RATE_FOR_TX_MGMT_2G,
&cfg_val) == eSIR_SUCCESS) {
if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_2G_STADEF) ||
!wma_verify_rate_code(cfg_val)) {
per_band_mgmt_tx_rate &=
~(1 << TX_MGMT_RATE_2G_ENABLE_OFFSET);
} else {
per_band_mgmt_tx_rate |=
(1 << TX_MGMT_RATE_2G_ENABLE_OFFSET);
per_band_mgmt_tx_rate |=
((cfg_val & 0x7FF) << TX_MGMT_RATE_2G_OFFSET);
}
} else {
WMA_LOGE("Failed to get value of WNI_CFG_RATE_FOR_TX_MGMT_2G");
}
if (wlan_cfgGetInt(mac, WNI_CFG_RATE_FOR_TX_MGMT_5G,
&cfg_val) == eSIR_SUCCESS) {
if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_5G_STADEF) ||
!wma_verify_rate_code(cfg_val)) {
per_band_mgmt_tx_rate &=
~(1 << TX_MGMT_RATE_5G_ENABLE_OFFSET);
} else {
per_band_mgmt_tx_rate |=
(1 << TX_MGMT_RATE_5G_ENABLE_OFFSET);
per_band_mgmt_tx_rate |=
((cfg_val & 0x7FF) << TX_MGMT_RATE_5G_OFFSET);
}
} else {
WMA_LOGE("Failed to get value of WNI_CFG_RATE_FOR_TX_MGMT_5G");
}
ret = wmi_unified_vdev_set_param_send(
wma->wmi_handle,
vdev_id,
WMI_VDEV_PARAM_PER_BAND_MGMT_TX_RATE,
per_band_mgmt_tx_rate);
if (ret)
WMA_LOGE("Failed to set WMI_VDEV_PARAM_PER_BAND_MGMT_TX_RATE");
}
static void wma_set_sap_keepalive(tp_wma_handle wma, u_int8_t vdev_id)
{
tANI_U32 min_inactive_time, max_inactive_time, max_unresponsive_time;
struct sAniSirGlobal *mac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == mac) {
WMA_LOGE("%s: Failed to get mac", __func__);
return;
}
wma_get_link_probe_timeout(mac, wma->interfaces[vdev_id].sub_type,
&max_inactive_time, &max_unresponsive_time);
min_inactive_time = max_inactive_time / 2;
if (wmi_unified_vdev_set_param_send(wma->wmi_handle,
vdev_id,
WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
min_inactive_time))
WMA_LOGE("Failed to Set AP MIN IDLE INACTIVE TIME");
if (wmi_unified_vdev_set_param_send(wma->wmi_handle,
vdev_id,
WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
max_inactive_time))
WMA_LOGE("Failed to Set AP MAX IDLE INACTIVE TIME");
if (wmi_unified_vdev_set_param_send(wma->wmi_handle,
vdev_id,
WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
max_unresponsive_time))
WMA_LOGE("Failed to Set MAX UNRESPONSIVE TIME");
WMA_LOGD("%s:vdev_id:%d min_inactive_time: %u max_inactive_time: %u"
" max_unresponsive_time: %u", __func__, vdev_id,
min_inactive_time, max_inactive_time, max_unresponsive_time);
}
static VOS_STATUS wma_set_enable_disable_mcc_adaptive_scheduler(tANI_U32 mcc_adaptive_scheduler)
{
int ret = -1;
wmi_buf_t buf = 0;
wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *cmd = NULL;
tp_wma_handle wma = NULL;
void *vos_context = NULL;
u_int16_t len = sizeof(wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param);
vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
wma = vos_get_context(VOS_MODULE_ID_WDA, vos_context);
if (NULL == wma) {
WMA_LOGE("%s : Failed to get wma", __func__);
return VOS_STATUS_E_FAULT;
}
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param));
cmd->enable = mcc_adaptive_scheduler;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID);
if (ret) {
WMA_LOGP("%s: Failed to send enable/disable MCC"
" adaptive scheduler command", __func__);
wmi_buf_free(buf);
}
return VOS_STATUS_SUCCESS;
}
/**
* Currently used to set time latency for an MCC vdev/adapter using operating
* channel of it and channel number. The info is provided run time using
* iwpriv command: iwpriv <wlan0 | p2p0> setMccLatency <latency in ms>.
*/
static VOS_STATUS wma_set_mcc_channel_time_latency
(
tp_wma_handle wma,
tANI_U32 mcc_channel,
tANI_U32 mcc_channel_time_latency
)
{
int ret = -1;
wmi_buf_t buf = 0;
wmi_resmgr_set_chan_latency_cmd_fixed_param *cmdTL = NULL;
u_int16_t len = 0;
u_int8_t *buf_ptr = NULL;
tANI_U32 cfg_val = 0;
wmi_resmgr_chan_latency chan_latency;
struct sAniSirGlobal *pMac = NULL;
/* Note: we only support MCC time latency for a single channel */
u_int32_t num_channels = 1;
u_int32_t channel1 = mcc_channel;
u_int32_t chan1_freq = vos_chan_to_freq( channel1 );
u_int32_t latency_chan1 = mcc_channel_time_latency;
if (!wma) {
WMA_LOGE("%s:NULL wma ptr. Exiting", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
pMac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (!pMac) {
WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
/* First step is to confirm if MCC is active */
if (!limIsInMCC(pMac)) {
WMA_LOGE("%s: MCC is not active. Exiting", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
/* Confirm MCC adaptive scheduler feature is disabled */
if (wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED,
&cfg_val) == eSIR_SUCCESS) {
if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) {
WMA_LOGD("%s: Can't set channel latency while MCC "
"ADAPTIVE SCHED is enabled. Exit", __func__);
return VOS_STATUS_SUCCESS;
}
} else {
WMA_LOGE("%s: Failed to get value for MCC_ADAPTIVE_SCHED, "
"Exit w/o setting latency", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
/* If 0ms latency is provided, then FW will set to a default.
* Otherwise, latency must be at least 30ms.
*/
if ((latency_chan1 > 0) &&
(latency_chan1 < WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY)) {
WMA_LOGE("%s: Invalid time latency for Channel #1 = %dms "
"Minimum is 30ms (or 0 to use default value by "
"firmware)", __func__, latency_chan1);
return VOS_STATUS_E_INVAL;
}
/* Set WMI CMD for channel time latency here */
len = sizeof(wmi_resmgr_set_chan_latency_cmd_fixed_param) +
WMI_TLV_HDR_SIZE + /*Place holder for chan_time_latency array*/
num_channels * sizeof(wmi_resmgr_chan_latency);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmdTL = (wmi_resmgr_set_chan_latency_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmdTL->tlv_header,
WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_resmgr_set_chan_latency_cmd_fixed_param));
cmdTL->num_chans = num_channels;
/* Update channel time latency information for home channel(s) */
buf_ptr += sizeof(*cmdTL);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
num_channels * sizeof(wmi_resmgr_chan_latency));
buf_ptr += WMI_TLV_HDR_SIZE;
chan_latency.chan_mhz = chan1_freq;
chan_latency.latency = latency_chan1;
vos_mem_copy(buf_ptr, &chan_latency, sizeof(chan_latency));
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RESMGR_SET_CHAN_LATENCY_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send MCC Channel Time Latency command",
__func__);
wmi_buf_free(buf);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* Currently used to set time quota for 2 MCC vdevs/adapters using (operating
* channel, quota) for each mode . The info is provided run time using
* iwpriv command: iwpriv <wlan0 | p2p0> setMccQuota <quota in ms>.
* Note: the quota provided in command is for the same mode in cmd. HDD
* checks if MCC mode is active, gets the second mode and its operating chan.
* Quota for the 2nd role is calculated as 100 - quota of first mode.
*/
static VOS_STATUS wma_set_mcc_channel_time_quota
(
tp_wma_handle wma,
tANI_U32 adapter_1_chan_number,
tANI_U32 adapter_1_quota,
tANI_U32 adapter_2_chan_number
)
{
int ret = -1;
wmi_buf_t buf = 0;
u_int16_t len = 0;
u_int8_t *buf_ptr = NULL;
tANI_U32 cfg_val = 0;
struct sAniSirGlobal *pMac = NULL;
wmi_resmgr_set_chan_time_quota_cmd_fixed_param *cmdTQ = NULL;
wmi_resmgr_chan_time_quota chan_quota;
u_int32_t channel1 = adapter_1_chan_number;
u_int32_t channel2 = adapter_2_chan_number;
u_int32_t quota_chan1 = adapter_1_quota;
/* Knowing quota of 1st chan., derive quota for 2nd chan. */
u_int32_t quota_chan2 = 100 - quota_chan1;
/* Note: setting time quota for MCC requires info for 2 channels */
u_int32_t num_channels = 2;
u_int32_t chan1_freq = vos_chan_to_freq(adapter_1_chan_number);
u_int32_t chan2_freq = vos_chan_to_freq(adapter_2_chan_number);
WMA_LOGD("%s: Channel1:%d, freq1:%dMHz, Quota1:%dms, "
"Channel2:%d, freq2:%dMHz, Quota2:%dms", __func__,
channel1, chan1_freq, quota_chan1, channel2, chan2_freq,
quota_chan2);
if (!wma) {
WMA_LOGE("%s:NULL wma ptr. Exiting", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
pMac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (!pMac) {
WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
/* First step is to confirm if MCC is active */
if (!limIsInMCC(pMac)) {
WMA_LOGD("%s: MCC is not active. Exiting", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
/* Confirm MCC adaptive scheduler feature is disabled */
if (wlan_cfgGetInt(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED,
&cfg_val) == eSIR_SUCCESS) {
if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) {
WMA_LOGD("%s: Can't set channel quota while "
"MCC_ADAPTIVE_SCHED is enabled. Exit",
__func__);
return VOS_STATUS_SUCCESS;
}
} else {
WMA_LOGE("%s: Failed to retrieve "
"WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED. Exit",
__func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
/**
* Perform sanity check on time quota values provided.
*/
if (quota_chan1 < WMI_MCC_MIN_CHANNEL_QUOTA ||
quota_chan1 > WMI_MCC_MAX_CHANNEL_QUOTA) {
WMA_LOGE("%s: Invalid time quota for Channel #1=%dms. Minimum "
"is 20ms & maximum is 80ms", __func__, quota_chan1);
return VOS_STATUS_E_INVAL;
}
/* Set WMI CMD for channel time quota here */
len = sizeof(wmi_resmgr_set_chan_time_quota_cmd_fixed_param) +
WMI_TLV_HDR_SIZE + /* Place holder for chan_time_quota array */
num_channels * sizeof(wmi_resmgr_chan_time_quota);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmdTQ = (wmi_resmgr_set_chan_time_quota_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmdTQ->tlv_header,
WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_resmgr_set_chan_time_quota_cmd_fixed_param));
cmdTQ->num_chans = num_channels;
/* Update channel time quota information for home channel(s) */
buf_ptr += sizeof(*cmdTQ);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
num_channels * sizeof(wmi_resmgr_chan_time_quota));
buf_ptr += WMI_TLV_HDR_SIZE;
chan_quota.chan_mhz = chan1_freq;
chan_quota.channel_time_quota = quota_chan1;
vos_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota));
/* Construct channel and quota record for the 2nd MCC mode. */
buf_ptr += sizeof(chan_quota);
chan_quota.chan_mhz = chan2_freq;
chan_quota.channel_time_quota = quota_chan2;
vos_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota));
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID);
if (ret) {
WMA_LOGE("Failed to send MCC Channel Time Quota command");
wmi_buf_free(buf);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/* function : wma_vdev_attach
* Description :
* Args :
* Returns :
*/
static ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle,
tpAddStaSelfParams self_sta_req,
u_int8_t generateRsp)
{
ol_txrx_vdev_handle txrx_vdev_handle = NULL;
ol_txrx_pdev_handle txrx_pdev = vos_get_context(VOS_MODULE_ID_TXRX,
wma_handle->vos_context);
enum wlan_op_mode txrx_vdev_type;
VOS_STATUS status = VOS_STATUS_SUCCESS;
struct sAniSirGlobal *mac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
tANI_U32 cfg_val;
tANI_U16 val16;
int ret;
tSirMacHTCapabilityInfo *phtCapInfo;
u_int8_t vdev_id;
struct sir_set_tx_rx_aggregation_size tx_rx_aggregation_size;
if (NULL == mac) {
WMA_LOGE("%s: Failed to get mac",__func__);
goto end;
}
if (VOS_MONITOR_MODE == vos_get_conparam())
self_sta_req->type = WMI_VDEV_TYPE_MONITOR;
/* Create a vdev in target */
if (wma_unified_vdev_create_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
self_sta_req->type,
self_sta_req->subType,
self_sta_req->selfMacAddr,
self_sta_req->nss_2g,
self_sta_req->nss_5g))
{
WMA_LOGP("%s: Unable to add an interface for ath_dev", __func__);
status = VOS_STATUS_E_RESOURCES;
goto end;
}
vdev_id = self_sta_req->sessionId;
txrx_vdev_type = wma_get_txrx_vdev_type(self_sta_req->type);
if (wlan_op_mode_unknown == txrx_vdev_type) {
WMA_LOGE("Failed to get txrx vdev type");
wma_unified_vdev_delete_send(wma_handle->wmi_handle,
self_sta_req->sessionId);
goto end;
}
txrx_vdev_handle = ol_txrx_vdev_attach(txrx_pdev,
self_sta_req->selfMacAddr,
self_sta_req->sessionId,
txrx_vdev_type);
wma_handle->interfaces[self_sta_req->sessionId].pause_bitmap = 0;
WMA_LOGD("vdev_id %hu, txrx_vdev_handle = %pK", self_sta_req->sessionId,
txrx_vdev_handle);
if (NULL == txrx_vdev_handle) {
WMA_LOGP("%s: ol_txrx_vdev_attach failed", __func__);
status = VOS_STATUS_E_FAILURE;
wma_unified_vdev_delete_send(wma_handle->wmi_handle,
self_sta_req->sessionId);
goto end;
}
wma_handle->interfaces[self_sta_req->sessionId].vdev_active = TRUE;
wma_handle->interfaces[self_sta_req->sessionId].handle = txrx_vdev_handle;
wma_handle->interfaces[self_sta_req->sessionId].ptrn_match_enable =
wma_handle->ptrn_match_enable_all_vdev ? TRUE : FALSE;
if (wlan_cfgGetInt(mac, WNI_CFG_WOWLAN_DEAUTH_ENABLE, &cfg_val)
!= eSIR_SUCCESS)
wma_handle->wow.deauth_enable = TRUE;
else
wma_handle->wow.deauth_enable = cfg_val ? TRUE : FALSE;
if (wlan_cfgGetInt(mac, WNI_CFG_WOWLAN_DISASSOC_ENABLE, &cfg_val)
!= eSIR_SUCCESS)
wma_handle->wow.disassoc_enable = TRUE;
else
wma_handle->wow.disassoc_enable = cfg_val ? TRUE : FALSE;
if (wlan_cfgGetInt(mac, WNI_CFG_WOWLAN_MAX_MISSED_BEACON, &cfg_val)
!= eSIR_SUCCESS)
wma_handle->wow.bmiss_enable = TRUE;
else
wma_handle->wow.bmiss_enable = cfg_val ? TRUE : FALSE;
vos_mem_copy(wma_handle->interfaces[self_sta_req->sessionId].addr,
self_sta_req->selfMacAddr,
sizeof(wma_handle->interfaces[self_sta_req->sessionId].addr));
tx_rx_aggregation_size.tx_aggregation_size =
self_sta_req->tx_aggregation_size;
tx_rx_aggregation_size.rx_aggregation_size =
self_sta_req->rx_aggregation_size;
tx_rx_aggregation_size.vdev_id = self_sta_req->sessionId;
status = wma_set_tx_rx_aggregation_size(&tx_rx_aggregation_size);
if (status != VOS_STATUS_SUCCESS)
WMA_LOGE("failed to set aggregation sizes(err=%d)", status);
switch (self_sta_req->type) {
case WMI_VDEV_TYPE_STA:
if(wlan_cfgGetInt(mac, WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD,
&cfg_val ) != eSIR_SUCCESS) {
WMA_LOGE("Failed to get value for "
"WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD");
cfg_val = DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD;
}
wma_set_sta_keep_alive(wma_handle,
self_sta_req->sessionId,
SIR_KEEP_ALIVE_NULL_PKT,
cfg_val,
NULL,
NULL,
NULL);
break;
}
wma_handle->interfaces[self_sta_req->sessionId].type =
self_sta_req->type;
wma_handle->interfaces[self_sta_req->sessionId].sub_type =
self_sta_req->subType;
wma_handle->interfaces[self_sta_req->sessionId].nss_2g =
self_sta_req->nss_2g;
wma_handle->interfaces[self_sta_req->sessionId].nss_5g =
self_sta_req->nss_5g;
adf_os_atomic_init(&wma_handle->interfaces
[self_sta_req->sessionId].bss_status);
if (((self_sta_req->type == WMI_VDEV_TYPE_AP) &&
(self_sta_req->subType ==
WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) ||
(self_sta_req->type == WMI_VDEV_TYPE_OCB) ||
(self_sta_req->type == WMI_VDEV_TYPE_MONITOR) ||
(self_sta_req->type == WMI_VDEV_TYPE_NDI)) {
WMA_LOGA("Creating self peer %pM, vdev_id %hu",
self_sta_req->selfMacAddr,
self_sta_req->sessionId);
status = wma_create_peer(wma_handle, txrx_pdev,
txrx_vdev_handle, self_sta_req->selfMacAddr,
WMI_PEER_TYPE_DEFAULT,self_sta_req->sessionId,
VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to create peer", __func__);
status = VOS_STATUS_E_FAILURE;
wma_unified_vdev_delete_send(wma_handle->wmi_handle,
self_sta_req->sessionId);
}
}
wma_handle->interfaces[vdev_id].is_vdev_valid = true;
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
WMI_VDEV_PARAM_DISCONNECT_TH,
self_sta_req->pkt_err_disconn_th);
if (ret)
WMA_LOGE("Failed to set WMI_VDEV_PARAM_DISCONNECT_TH");
WMA_LOGD("%s %d vdev_id %d mcc_rts_cts_prot_enable %d\n",
__func__, __LINE__, self_sta_req->sessionId,
mac->roam.configParam.mcc_rts_cts_prot_enable);
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE,
mac->roam.configParam.mcc_rts_cts_prot_enable);
if (ret)
WMA_LOGE("Failed to set WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE");
WMA_LOGD("%s %d vdev_id %d mcc_bcast_prob_resp_enable %d\n",
__func__, __LINE__, self_sta_req->sessionId,
mac->roam.configParam.mcc_bcast_prob_resp_enable);
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE,
mac->roam.configParam.mcc_bcast_prob_resp_enable);
if (ret)
WMA_LOGE("Failed to set WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE");
if (wlan_cfgGetInt(mac, WNI_CFG_RTS_THRESHOLD,
&cfg_val) == eSIR_SUCCESS) {
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
WMI_VDEV_PARAM_RTS_THRESHOLD,
cfg_val);
if (ret)
WMA_LOGE("Failed to set WMI_VDEV_PARAM_RTS_THRESHOLD");
} else {
WMA_LOGE("Failed to get value for WNI_CFG_RTS_THRESHOLD, leaving unchanged");
}
if (wlan_cfgGetInt(mac, WNI_CFG_FRAGMENTATION_THRESHOLD,
&cfg_val) == eSIR_SUCCESS) {
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
cfg_val);
if (ret)
WMA_LOGE("Failed to set WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD");
} else {
WMA_LOGE("Failed to get value for WNI_CFG_FRAGMENTATION_THRESHOLD, leaving unchanged");
}
if (wlan_cfgGetInt(mac, WNI_CFG_HT_CAP_INFO,
&cfg_val) == eSIR_SUCCESS) {
val16 = (tANI_U16)cfg_val;
phtCapInfo = (tSirMacHTCapabilityInfo *)&cfg_val;
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
WMI_VDEV_PARAM_TX_STBC,
phtCapInfo->txSTBC);
if (ret)
WMA_LOGE("Failed to set WMI_VDEV_PARAM_TX_STBC");
} else {
WMA_LOGE("Failed to get value of HT_CAP, TX STBC unchanged");
}
wma_set_vdev_mgmt_rate(wma_handle, self_sta_req->sessionId);
/* Initialize roaming offload state */
if ((self_sta_req->type == WMI_VDEV_TYPE_STA) &&
(self_sta_req->subType == 0)) {
wma_handle->roam_offload_enabled = TRUE;
wmi_unified_vdev_set_param_send(wma_handle->wmi_handle,
self_sta_req->sessionId,
WMI_VDEV_PARAM_ROAM_FW_OFFLOAD,
(WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG |
WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG));
}
/* Initialize BMISS parameters */
if ((self_sta_req->type == WMI_VDEV_TYPE_STA) &&
(self_sta_req->subType == 0)) {
wma_roam_scan_bmiss_cnt(wma_handle,
mac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt,
mac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt,
self_sta_req->sessionId);
}
if (wlan_cfgGetInt(mac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED,
&cfg_val) == eSIR_SUCCESS) {
WMA_LOGD("%s: setting ini value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED: %d",
__func__, cfg_val);
ret = wma_set_enable_disable_mcc_adaptive_scheduler(cfg_val);
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to set WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED");
}
} else {
WMA_LOGE("Failed to get value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, leaving unchanged");
}
end:
self_sta_req->status = status;
#ifdef QCA_IBSS_SUPPORT
if (generateRsp)
#endif
wma_send_msg(wma_handle, WDA_ADD_STA_SELF_RSP, (void *)self_sta_req, 0);
return txrx_vdev_handle;
}
static VOS_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
v_VOID_t *mac = vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
WMA_LOGD("%s: Enter", __func__);
if (NULL == mac) {
WMA_LOGP("%s: Invalid context", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
processCfgDownloadReq(mac);
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
/* function : wma_set_scan_info
* Description : function to save current ongoing scan info
* Args : wma handle, scan id, scan requestor id, vdev id
* Returns : None
*/
static inline void wma_set_scan_info(tp_wma_handle wma_handle,
u_int32_t scan_id,
u_int32_t requestor,
u_int32_t vdev_id,
tSirP2pScanType p2p_scan_type)
{
wma_handle->interfaces[vdev_id].scan_info.scan_id = scan_id;
wma_handle->interfaces[vdev_id].scan_info.scan_requestor_id =
requestor;
wma_handle->interfaces[vdev_id].scan_info.p2p_scan_type = p2p_scan_type;
}
/* function : wma_reset_scan_info
* Description : function to reset the current ongoing scan info
* Args : wma handle, vdev_id
* Returns : None
*/
static inline void wma_reset_scan_info(tp_wma_handle wma_handle,
u_int8_t vdev_id)
{
vos_mem_zero((void *) &(wma_handle->interfaces[vdev_id].scan_info),
sizeof(struct scan_param));
}
bool wma_check_scan_in_progress(WMA_HANDLE handle)
{
tp_wma_handle wma_handle = handle;
int i;
for (i = 0; i < wma_handle->max_bssid; i++){
if (wma_handle->interfaces[i].scan_info.scan_id){
WMA_LOGE("%s: scan in progress on interface[%d],scanid = %d",
__func__, i, wma_handle->interfaces[i].scan_info.scan_id );
return true;
}
}
return false;
}
v_BOOL_t wma_is_SAP_active(tp_wma_handle wma_handle)
{
int i;
for (i = 0; i < wma_handle->max_bssid; i++) {
if (!wma_handle->interfaces[i].vdev_up)
continue;
if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
wma_handle->interfaces[i].sub_type == 0)
return TRUE;
}
return FALSE;
}
v_BOOL_t wma_is_P2P_GO_active(tp_wma_handle wma_handle)
{
int i;
for (i = 0; i < wma_handle->max_bssid; i++) {
if (!wma_handle->interfaces[i].vdev_up)
continue;
if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP &&
wma_handle->interfaces[i].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO)
return TRUE;
}
return FALSE;
}
v_BOOL_t wma_is_P2P_CLI_active(tp_wma_handle wma_handle)
{
int i;
for (i = 0; i < wma_handle->max_bssid; i++) {
if (!wma_handle->interfaces[i].vdev_up)
continue;
if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
wma_handle->interfaces[i].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT)
return TRUE;
}
return FALSE;
}
v_BOOL_t wma_is_STA_active(tp_wma_handle wma_handle)
{
int i;
for (i = 0; i < wma_handle->max_bssid; i++) {
if (!wma_handle->interfaces[i].vdev_up)
continue;
if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA &&
wma_handle->interfaces[i].sub_type == 0)
return TRUE;
if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS)
return TRUE;
}
return FALSE;
}
/**
* wma_is_mcc_24G() - Function to check MCC in 2.4GHz band
* @handle: WMA handle
*
* This function is used to check MCC in 2.4GHz band
*
* Return: True if WMA is in MCC in 2.4GHz band
*
*/
static bool wma_is_mcc_24G(WMA_HANDLE handle)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
int32_t prev_chan = 0;
int32_t i;
if (NULL == wma_handle) {
WMA_LOGE("%s: wma_handle is NULL", __func__);
return false;
}
for (i = 0; i < wma_handle->max_bssid; i++) {
if (wma_handle->interfaces[i].handle &&
wma_handle->interfaces[i].vdev_up) {
if ((prev_chan != 0 &&
prev_chan != wma_handle->interfaces[i].mhz) &&
(wma_handle->interfaces[i].mhz <=
VOS_CHAN_14_FREQ))
return true;
else
prev_chan = wma_handle->interfaces[i].mhz;
}
}
return false;
}
/**
* wma_is_mcc_starting() - Function to check MCC will start or already started
* @handle: WMA handle
*
* This function is used to check MCC will start or already started
*
* Return: True if WMA is in MCC will or already started
*
*/
static bool wma_is_mcc_starting(WMA_HANDLE handle, A_UINT32 starting_mhz)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
int32_t prev_chan = starting_mhz;
int32_t i;
if (NULL == wma_handle) {
WMA_LOGE("%s: wma_handle is NULL", __func__);
return false;
}
for (i = 0; i < wma_handle->max_bssid; i++) {
if (wma_handle->interfaces[i].handle &&
wma_handle->interfaces[i].vdev_up) {
if ((prev_chan != 0 &&
prev_chan != wma_handle->interfaces[i].mhz))
return true;
else
prev_chan = wma_handle->interfaces[i].mhz;
}
}
return false;
}
/* function : wma_get_buf_start_scan_cmd
* Description :
* Args :
* Returns :
*/
VOS_STATUS wma_get_buf_start_scan_cmd(tp_wma_handle wma_handle,
tSirScanOffloadReq *scan_req,
wmi_buf_t *buf,
int *buf_len)
{
wmi_start_scan_cmd_fixed_param *cmd;
wmi_chan_list *chan_list = NULL;
wmi_mac_addr *bssid;
wmi_ssid *ssid = NULL;
u_int32_t *tmp_ptr, ie_len_with_pad;
VOS_STATUS vos_status = VOS_STATUS_E_FAILURE;
u_int8_t *buf_ptr;
u_int32_t dwell_time;
u_int8_t SSID_num;
int i;
int len = sizeof(*cmd);
wmi_vendor_oui *voui = NULL;
struct vendor_oui *pvoui = NULL;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!pMac) {
WMA_LOGP("%s: pMac is NULL!", __func__);
return VOS_STATUS_E_FAILURE;
}
len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of uint32 */
/* calculate the length of buffer required */
if (scan_req->channelList.numChannels)
len += scan_req->channelList.numChannels * sizeof(u_int32_t);
len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of wmi_ssid structures */
if (scan_req->numSsid)
len += scan_req->numSsid * sizeof(wmi_ssid);
len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of wmi_mac_addr structures */
len += sizeof(wmi_mac_addr);
len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of bytes */
if (scan_req->uIEFieldLen)
len += roundup(scan_req->uIEFieldLen, sizeof(u_int32_t));
len += WMI_TLV_HDR_SIZE; /* Length of TLV for array of wmi_vendor_oui */
if (scan_req->num_vendor_oui)
len += scan_req->num_vendor_oui * sizeof(wmi_vendor_oui);
/* Allocate the memory */
*buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!*buf) {
WMA_LOGP("%s: failed to allocate memory for start scan cmd",
__func__);
return VOS_STATUS_E_FAILURE;
}
buf_ptr = (u_int8_t *) wmi_buf_data(*buf);
cmd = (wmi_start_scan_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_start_scan_cmd_fixed_param));
if (wma_handle->scan_id >= WMA_MAX_SCAN_ID)
wma_handle->scan_id = 0;
cmd->vdev_id = scan_req->sessionId;
/* host cycles through the lower 12 bits of
wma_handle->scan_id to generate ids */
cmd->scan_id = WMA_HOST_SCAN_REQID_PREFIX | ++wma_handle->scan_id;
cmd->scan_priority = WMI_SCAN_PRIORITY_LOW;
cmd->scan_req_id = WMA_HOST_SCAN_REQUESTOR_ID_PREFIX |
WMA_DEFAULT_SCAN_REQUESTER_ID;
/* Set the scan events which the driver is intereseted to receive */
/* TODO: handle all the other flags also */
cmd->notify_scan_events = WMI_SCAN_EVENT_STARTED |
WMI_SCAN_EVENT_START_FAILED |
WMI_SCAN_EVENT_FOREIGN_CHANNEL |
WMI_SCAN_EVENT_COMPLETED |
WMI_SCAN_EVENT_DEQUEUED |
WMI_SCAN_EVENT_PREEMPTED |
WMI_SCAN_EVENT_RESTARTED;
cmd->dwell_time_active = scan_req->maxChannelTime;
if (scan_req->scanType == eSIR_ACTIVE_SCAN) {
/* In Active scan case, the firmware has to do passive scan on DFS channels
* So the passive scan duration should be updated properly so that the duration
* will be sufficient enough to receive the beacon from AP */
if (wlan_cfgGetInt(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME,
&dwell_time) != eSIR_SUCCESS) {
WMA_LOGE("Failed to get passive max channel value"
"using default value");
dwell_time = WMA_DWELL_TIME_PASSIVE_DEFAULT;
}
cmd->dwell_time_passive = dwell_time;
}
else
cmd->dwell_time_passive = scan_req->maxChannelTime;
/* Ensure correct number of probes are sent on active channel */
cmd->repeat_probe_time = cmd->dwell_time_active / WMA_SCAN_NPROBES_DEFAULT;
/* CSR sends min_rest_Time, max_rest_time and idle_time
* for staying on home channel to continue data traffic.
* Rome fw has facility to monitor the traffic
* and move to next channel. Stay on the channel for min_rest_time
* and then leave if there is no traffic.
*/
cmd->min_rest_time = scan_req->min_rest_time;
cmd->max_rest_time = scan_req->restTime;
/* Check for traffic at idle_time interval after min_rest_time.
* Default value is 25 ms to allow full use of max_rest_time
* when voice packets are running at 20 ms interval.
*/
cmd->idle_time = scan_req->idle_time;
/* Large timeout value for full scan cycle, 30 seconds */
cmd->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION;
/* add DS param IE in probe req frame */
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ;
/* set flag to get chan stats */
if (pMac->snr_monitor_enabled)
cmd->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT;
/* do not add OFDM rates in 11B mode */
if (scan_req->dot11mode != WNI_CFG_DOT11_MODE_11B)
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES;
else
WMA_LOGD("OFDM_RATES not included in 11B mode");
/* Do not combine multiple channels in a single burst. Come back
* to home channel for data traffic after every foreign channel.
* By default, prefer throughput performance over scan cycle time.
*/
cmd->burst_duration = 0;
/* mac randomization attributes */
if (scan_req->enable_scan_randomization) {
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ |
WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ;
WMI_CHAR_ARRAY_TO_MAC_ADDR(scan_req->mac_addr, &cmd->mac_addr);
WMI_CHAR_ARRAY_TO_MAC_ADDR(scan_req->mac_addr_mask,
&cmd->mac_mask);
}
if (!scan_req->p2pScanType) {
WMA_LOGD("Normal Scan request");
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES;
if (!scan_req->numSsid)
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_BCAST_PROBE_REQ;
if (scan_req->scanType == eSIR_PASSIVE_SCAN)
cmd->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
if (ACS_FW_REPORT_PARAM_CONFIGURED) {
/* add chan stat info report tag */
if (scan_req->bssType == eSIR_INFRA_AP_MODE) {
cmd->scan_ctrl_flags |=
WMI_SCAN_CHAN_STAT_EVENT;
WMA_LOGI("set ACS ctrl BIT");
}
}
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ;
cmd->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ;
if (scan_req->ie_whitelist) {
cmd->scan_ctrl_flags |=
WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ;
for (i = 0; i < PROBE_REQ_BITMAP_LEN; i++)
cmd->ie_bitmap[i] =
scan_req->probe_req_ie_bitmap[i];
}
cmd->num_vendor_oui = scan_req->num_vendor_oui;
/*
* Decide burst_duration and dwell_time_active based on
* what type of devices are active.
*/
do {
if (wma_is_SAP_active(wma_handle) &&
wma_is_P2P_GO_active(wma_handle) &&
wma_is_STA_active(wma_handle)) {
if (scan_req->maxChannelTime <=
WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION)
cmd->burst_duration = scan_req->maxChannelTime;
else
cmd->burst_duration =
WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION;
break;
}
if (wma_is_SAP_active(wma_handle)) {
/* Background scan while SoftAP is sending beacons.
* Max duration of CTS2self is 32 ms, which limits
* the dwell time.
*/
cmd->dwell_time_active = MIN(scan_req->maxChannelTime,
(WMA_CTS_DURATION_MS_MAX - WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME));
cmd->dwell_time_passive = cmd->dwell_time_active;
cmd->burst_duration = 0;
break;
}
if (wma_handle->miracast_value &&
wma_is_mcc_24G(wma_handle)) {
cmd->max_rest_time =
pMac->f_sta_miracast_mcc_rest_time_val;
}
if (wma_is_P2P_GO_active(wma_handle)) {
/* Background scan while GO is sending beacons.
* Every off-channel transition has overhead of 2 beacon
* intervals for NOA. Maximize number of channels in
* every transition by using burst scan.
*/
if (wma_handle->miracast_value) {
/* When miracast is running, burst duration
* needs to be minimum to avoid any stutter
* or glitch in miracast during station scan
*/
if (scan_req->maxChannelTime <=
WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION)
cmd->burst_duration =
scan_req->maxChannelTime;
else
cmd->burst_duration =
WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION;
}
else {
/* If miracast is not running, accomodate max
* stations to make the scans faster
*/
cmd->burst_duration =
WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS *
scan_req->maxChannelTime;
if (cmd->burst_duration >
WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION) {
u_int8_t channels =
WMA_P2P_SCAN_MAX_BURST_DURATION
/ scan_req->maxChannelTime;
if (channels)
cmd->burst_duration = channels *
scan_req->maxChannelTime;
else
cmd->burst_duration =
WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION;
}
}
break;
}
if (wma_is_STA_active(wma_handle) ||
wma_is_P2P_CLI_active(wma_handle)) {
if (scan_req->burst_scan_duration)
cmd->burst_duration =
scan_req->burst_scan_duration;
else
/* Typical background scan.
* Disable burst scan for now.
*/
cmd->burst_duration = 0;
break;
}
} while (0);
}
else {
WMA_LOGD("P2P Scan");
switch (scan_req->p2pScanType) {
case P2P_SCAN_TYPE_LISTEN:
WMA_LOGD("P2P_SCAN_TYPE_LISTEN");
cmd->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
cmd->notify_scan_events |=
WMI_SCAN_EVENT_FOREIGN_CHANNEL;
cmd->repeat_probe_time = 0;
break;
case P2P_SCAN_TYPE_SEARCH:
WMA_LOGD("P2P_SCAN_TYPE_SEARCH");
cmd->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ;
/* Default P2P burst duration of 120 ms will cover
* 3 channels with default max dwell time 40 ms.
* Cap limit will be set by
* WMA_P2P_SCAN_MAX_BURST_DURATION. Burst duration
* should be such that no channel is scanned less
* than the dwell time in normal scenarios.
*/
if (scan_req->channelList.numChannels == P2P_SOCIAL_CHANNELS
&& (!(wma_handle->miracast_value)))
cmd->repeat_probe_time = scan_req->maxChannelTime/5;
else
cmd->repeat_probe_time = scan_req->maxChannelTime/3;
cmd->burst_duration = WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS * scan_req->maxChannelTime;
if (cmd->burst_duration > WMA_P2P_SCAN_MAX_BURST_DURATION) {
u_int8_t channels = WMA_P2P_SCAN_MAX_BURST_DURATION / scan_req->maxChannelTime;
if (channels)
cmd->burst_duration = channels * scan_req->maxChannelTime;
else
cmd->burst_duration = WMA_P2P_SCAN_MAX_BURST_DURATION;
}
break;
default:
WMA_LOGE("Invalid scan type");
goto error;
}
}
cmd->n_probes = (cmd->repeat_probe_time > 0) ?
cmd->dwell_time_active/cmd->repeat_probe_time : 0;
buf_ptr += sizeof(*cmd);
tmp_ptr = (u_int32_t *) (buf_ptr + WMI_TLV_HDR_SIZE);
if (scan_req->channelList.numChannels) {
chan_list = (wmi_chan_list *) tmp_ptr;
cmd->num_chan = scan_req->channelList.numChannels;
for (i = 0; i < scan_req->channelList.numChannels; ++i) {
tmp_ptr[i] = vos_chan_to_freq(
scan_req->channelList.channelNumber[i]);
}
}
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_UINT32,
(cmd->num_chan * sizeof(u_int32_t)));
buf_ptr += WMI_TLV_HDR_SIZE + (cmd->num_chan * sizeof(u_int32_t));
if (scan_req->numSsid > SIR_SCAN_MAX_NUM_SSID) {
WMA_LOGE("Invalid value for numSsid");
goto error;
}
cmd->num_ssids = scan_req->numSsid;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC,
(cmd->num_ssids * sizeof(wmi_ssid)));
if (scan_req->numSsid) {
ssid = (wmi_ssid *) (buf_ptr + WMI_TLV_HDR_SIZE);
for (i = 0; i < scan_req->numSsid; ++i) {
ssid->ssid_len = scan_req->ssId[i].length;
vos_mem_copy(ssid->ssid, scan_req->ssId[i].ssId,
scan_req->ssId[i].length);
ssid++;
}
}
buf_ptr += WMI_TLV_HDR_SIZE + (cmd->num_ssids * sizeof(wmi_ssid));
cmd->num_bssid = 1;
if (!scan_req->p2pScanType) {
if (wma_is_SAP_active(wma_handle)) {
SSID_num = cmd->num_ssids * cmd->num_bssid;
cmd->repeat_probe_time =
probeTime_dwellTime_map[MIN(SSID_num,
WMA_DWELL_TIME_PROBE_TIME_MAP_SIZE - 1)].
probe_time;
cmd->n_probes = (cmd->repeat_probe_time > 0) ?
cmd->dwell_time_active/
cmd->repeat_probe_time : 0;
}
}
WMA_LOGI("Scan Type 0x%x, Active dwell time %u, Passive dwell time %u",
scan_req->scanType, cmd->dwell_time_active,
cmd->dwell_time_passive);
WMA_LOGI("Scan repeat_probe_time %u n_probes %u num_ssids %u num_bssid %u",
cmd->repeat_probe_time,
cmd->n_probes,
cmd->num_ssids,
cmd->num_bssid);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC,
(cmd->num_bssid * sizeof(wmi_mac_addr)));
bssid = (wmi_mac_addr *) (buf_ptr + WMI_TLV_HDR_SIZE);
WMI_CHAR_ARRAY_TO_MAC_ADDR(scan_req->bssId, bssid);
buf_ptr += WMI_TLV_HDR_SIZE + (cmd->num_bssid * sizeof(wmi_mac_addr));
cmd->ie_len = scan_req->uIEFieldLen;
ie_len_with_pad = roundup(scan_req->uIEFieldLen, sizeof(u_int32_t));
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_with_pad);
if (scan_req->uIEFieldLen) {
vos_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
(u_int8_t *)scan_req +
(scan_req->uIEFieldOffset),
scan_req->uIEFieldLen);
}
buf_ptr += WMI_TLV_HDR_SIZE + ie_len_with_pad;
/* mac randomization */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
scan_req->num_vendor_oui *
sizeof(wmi_vendor_oui));
buf_ptr += WMI_TLV_HDR_SIZE;
if (cmd->num_vendor_oui != 0) {
voui = (wmi_vendor_oui *)buf_ptr;
pvoui = (struct vendor_oui *)((u_int8_t *)scan_req +
(scan_req->oui_field_offset));
for (i = 0; i < cmd->num_vendor_oui; i++) {
WMITLV_SET_HDR(&voui[i].tlv_header,
WMITLV_TAG_STRUC_wmi_vendor_oui,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vendor_oui));
voui[i].oui_type_subtype = pvoui[i].oui_type |
(pvoui[i].oui_subtype << 24);
}
buf_ptr += cmd->num_vendor_oui *
sizeof(wmi_vendor_oui);
}
*buf_len = len;
return VOS_STATUS_SUCCESS;
error:
vos_mem_free(*buf);
*buf = NULL;
return vos_status;
}
/* function : wma_get_buf_stop_scan_cmd
* Description : function to fill the args for wmi_stop_scan_cmd
* Args : wma handle, wmi command buffer, buffer length, vdev_id
* Returns : failure or success
*/
VOS_STATUS wma_get_buf_stop_scan_cmd(tp_wma_handle wma_handle,
wmi_buf_t *buf,
int *buf_len,
tAbortScanParams *abort_scan_req)
{
wmi_stop_scan_cmd_fixed_param *cmd;
VOS_STATUS vos_status;
int len = sizeof(*cmd);
/* Allocate the memory */
*buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!*buf) {
WMA_LOGP("%s: failed to allocate memory for stop scan cmd",
__func__);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
cmd = (wmi_stop_scan_cmd_fixed_param *) wmi_buf_data(*buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_stop_scan_cmd_fixed_param));
cmd->vdev_id = abort_scan_req->SessionId;
cmd->requestor =
wma_handle->interfaces[cmd->vdev_id].scan_info.scan_requestor_id;
cmd->scan_id = wma_handle->interfaces[cmd->vdev_id].scan_info.scan_id;
/* stop the scan with the corresponding scan_id */
cmd->req_type = WMI_SCAN_STOP_ONE;
*buf_len = len;
vos_status = VOS_STATUS_SUCCESS;
error:
return vos_status;
}
void wma_process_link_status_req(tp_wma_handle wma,
tAniGetLinkStatus *pGetLinkStatus)
{
wmi_buf_t buf;
wmi_request_stats_cmd_fixed_param *cmd;
u_int8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
struct wma_txrx_node *iface = &wma->interfaces[pGetLinkStatus->sessionId];
if (iface->plink_status_req) {
WMA_LOGE(
"%s:previous link status request is pending,deleting the new request",
__func__);
vos_mem_free(pGetLinkStatus);
return;
}
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
goto end;
}
iface->plink_status_req = pGetLinkStatus;
cmd = (wmi_request_stats_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_request_stats_cmd_fixed_param));
cmd->stats_id = WMI_REQUEST_VDEV_RATE_STAT;
cmd->vdev_id = pGetLinkStatus->sessionId;
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_REQUEST_STATS_CMDID)) {
WMA_LOGE("Failed to send WMI link status request to fw");
wmi_buf_free(buf);
iface->plink_status_req = NULL;
goto end;
}
return;
end:
wma_post_link_status(pGetLinkStatus, LINK_STATUS_LEGACY);
}
VOS_STATUS wma_send_snr_request(tp_wma_handle wma_handle, void *pGetRssiReq,
v_S7_t first_rssi)
{
wmi_buf_t buf;
wmi_request_stats_cmd_fixed_param *cmd;
u_int8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
tAniGetRssiReq *pRssiBkUp = NULL;
/* command is in progess */
if(NULL != wma_handle->pGetRssiReq)
return VOS_STATUS_SUCCESS;
wma_handle->first_rssi = first_rssi;
/* create a copy of csrRssiCallback to send rssi value
* after wmi event
*/
if(pGetRssiReq) {
pRssiBkUp = adf_os_mem_alloc(NULL, sizeof(tAniGetRssiReq));
if(!pRssiBkUp) {
WMA_LOGE("Failed to allocate memory for tAniGetRssiReq");
wma_handle->pGetRssiReq = NULL;
return VOS_STATUS_E_FAILURE;
}
adf_os_mem_set(pRssiBkUp, 0, sizeof(tAniGetRssiReq));
pRssiBkUp->sessionId = ((tAniGetRssiReq*)pGetRssiReq)->sessionId;
pRssiBkUp->rssiCallback = ((tAniGetRssiReq*)pGetRssiReq)->rssiCallback;
pRssiBkUp->pDevContext = ((tAniGetRssiReq*)pGetRssiReq)->pDevContext;
wma_handle->pGetRssiReq = (void*)pRssiBkUp;
}
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
adf_os_mem_free(pRssiBkUp);
wma_handle->pGetRssiReq = NULL;
return VOS_STATUS_E_FAILURE;
}
cmd = (wmi_request_stats_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header, WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_request_stats_cmd_fixed_param));
cmd->stats_id = WMI_REQUEST_VDEV_STAT;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,WMI_REQUEST_STATS_CMDID)) {
WMA_LOGE("Failed to send host stats request to fw");
wmi_buf_free(buf);
adf_os_mem_free(pRssiBkUp);
wma_handle->pGetRssiReq = NULL;
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS WDA_GetSnr(tAniGetSnrReq *psnr_req)
{
wmi_buf_t buf;
wmi_request_stats_cmd_fixed_param *cmd;
tAniGetSnrReq *psnr_req_bkp;
u_int8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tp_wma_handle wma_handle = NULL;
struct wma_txrx_node *intr;
wma_handle = vos_get_context(VOS_MODULE_ID_WDA, vos_context);
if (NULL == wma_handle) {
WMA_LOGE("%s : Failed to get wma_handle", __func__);
return VOS_STATUS_E_FAULT;
}
intr = &wma_handle->interfaces[psnr_req->sessionId];
/* command is in progess */
if(NULL != intr->psnr_req) {
WMA_LOGE("%s : previous snr request is pending", __func__);
return VOS_STATUS_SUCCESS;
}
psnr_req_bkp = adf_os_mem_alloc(NULL, sizeof(tAniGetSnrReq));
if (!psnr_req_bkp) {
WMA_LOGE("Failed to allocate memory for tAniGetSnrReq");
return VOS_STATUS_E_FAILURE;
}
adf_os_mem_set(psnr_req_bkp, 0, sizeof(tAniGetSnrReq));
psnr_req_bkp->staId = psnr_req->staId;
psnr_req_bkp->pDevContext = psnr_req->pDevContext;
psnr_req_bkp->snrCallback = psnr_req->snrCallback;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
adf_os_mem_free(psnr_req_bkp);
return VOS_STATUS_E_FAILURE;
}
cmd = (wmi_request_stats_cmd_fixed_param *)wmi_buf_data(buf);
cmd->vdev_id = psnr_req->sessionId;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_request_stats_cmd_fixed_param));
cmd->stats_id = WMI_REQUEST_VDEV_STAT;
intr->psnr_req = (void *)psnr_req_bkp;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_REQUEST_STATS_CMDID)) {
WMA_LOGE("Failed to send host stats request to fw");
wmi_buf_free(buf);
adf_os_mem_free(psnr_req_bkp);
intr->psnr_req = NULL;
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_TSF
/**
* wma_capture_tsf() - send wmi to fw to capture tsf
*
* @wma_handle: wma handler
* @vdev_id: vdev id
*
* Return: wmi send state
*/
static VOS_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf;
wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd;
int status;
int len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: failed to allocate memory for cap tsf cmd",
__func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) wmi_buf_data(buf);
cmd->vdev_id = vdev_id;
cmd->tsf_action = TSF_TSTAMP_CAPTURE_REQ;
WMA_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_REQ",
__func__, cmd->vdev_id);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_tsf_tstamp_action_cmd_fixed_param));
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_VDEV_TSF_TSTAMP_ACTION_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send returned Error %d", status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
return VOS_STATUS_SUCCESS;
error:
if (buf)
wmi_buf_free(buf);
return vos_status;
}
/**
* wma_reset_tsf_gpio() - send wmi to fw to reset GPIO
*
* @wma_handle: wma handler
* @vdev_id: vdev id
*
* Return: wmi send state
*/
static VOS_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf;
wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd;
int status;
int len = sizeof(*cmd);
uint8_t *buf_ptr;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: failed to allocate memory for reset tsf gpio",
__func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) buf_ptr;
cmd->vdev_id = vdev_id;
cmd->tsf_action = TSF_TSTAMP_CAPTURE_RESET;
WMA_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_RESET",
__func__, cmd->vdev_id);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_tsf_tstamp_action_cmd_fixed_param));
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_VDEV_TSF_TSTAMP_ACTION_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send returned Error %d", status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
return VOS_STATUS_SUCCESS;
error:
if (buf)
wmi_buf_free(buf);
return vos_status;
}
#else
static VOS_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id)
{
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id)
{
return VOS_STATUS_SUCCESS;
}
#endif
/* function : wma_start_scan
* Description :
* Args :
* Returns :
*/
VOS_STATUS wma_start_scan(tp_wma_handle wma_handle,
tSirScanOffloadReq *scan_req, v_U16_t msg_type)
{
uint32_t vdev_id, scan_id;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf = NULL;
wmi_start_scan_cmd_fixed_param *cmd;
int status = 0;
int len;
tSirScanOffloadEvent *scan_event;
if (scan_req->sessionId >= wma_handle->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %d, msg_type : 0x%x", __func__,
scan_req->sessionId, msg_type);
vos_status = VOS_STATUS_E_FAILURE;
goto error1;
}
/* Sanity check to find whether vdev id active or not */
if (!wma_handle->interfaces[scan_req->sessionId].handle) {
WMA_LOGE("vdev id [%d] is not active", scan_req->sessionId);
vos_status = VOS_STATUS_E_FAILURE;
goto error1;
}
if (msg_type == WDA_START_SCAN_OFFLOAD_REQ) {
/* Start the timer for scan completion */
vos_status = vos_timer_start(&wma_handle->wma_scan_comp_timer,
WMA_HW_DEF_SCAN_MAX_DURATION);
if (vos_status != VOS_STATUS_SUCCESS ) {
WMA_LOGE("Failed to start the scan completion timer");
vos_status = VOS_STATUS_E_FAILURE;
goto error1;
}
}
/* Fill individual elements of wmi_start_scan_req and
* TLV for channel list, bssid, ssid etc ... */
vos_status = wma_get_buf_start_scan_cmd(wma_handle, scan_req,
&buf, &len);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to get buffer for start scan cmd");
goto error0;
}
if (NULL == buf) {
WMA_LOGE("Failed to get buffer for saving current scan info");
vos_status = VOS_STATUS_E_NOMEM;
goto error0;
}
/* Save current scan info */
cmd = (wmi_start_scan_cmd_fixed_param *) wmi_buf_data(buf);
if (msg_type == WDA_CHNL_SWITCH_REQ) {
/* Adjust parameters for channel switch scan */
cmd->min_rest_time = WMA_ROAM_PREAUTH_REST_TIME;
cmd->max_rest_time = WMA_ROAM_PREAUTH_REST_TIME;
cmd->max_scan_time = WMA_ROAM_PREAUTH_MAX_SCAN_TIME;
cmd->scan_priority = WMI_SCAN_PRIORITY_VERY_HIGH;
adf_os_spin_lock_bh(&wma_handle->roam_preauth_lock);
cmd->scan_id = ( (cmd->scan_id & WMA_MAX_SCAN_ID) |
WMA_HOST_ROAM_SCAN_REQID_PREFIX);
wma_handle->roam_preauth_scan_id = cmd->scan_id;
adf_os_spin_unlock_bh(&wma_handle->roam_preauth_lock);
}
wma_set_scan_info(wma_handle, cmd->scan_id,
cmd->scan_req_id, cmd->vdev_id,
scan_req->p2pScanType);
if (scan_req->p2pScanType)
cmd->scan_priority = WMI_SCAN_PRIORITY_MEDIUM;
WMA_LOGD("scan_id %x, vdev_id %x, scan type %x, msg_type %x",
cmd->scan_id, cmd->vdev_id, scan_req->p2pScanType,
msg_type);
/*
* Cache vdev_id and scan_id because cmd is freed after calling
* wmi_unified_cmd_send cmd. WMI internally frees cmd buffer after
* getting TX complete from CE
*/
vdev_id = cmd->vdev_id;
scan_id = cmd->scan_id;
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_START_SCAN_CMDID);
/* Call the wmi api to request the scan */
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
/* Update the scan parameters for handler */
wma_handle->wma_scan_timer_info.vdev_id = vdev_id;
wma_handle->wma_scan_timer_info.scan_id = scan_id;
return VOS_STATUS_SUCCESS;
error:
wma_reset_scan_info(wma_handle, cmd->vdev_id);
if (buf)
wmi_buf_free(buf);
error0:
/* Stop the timer for scan completion */
if (vos_timer_stop(&wma_handle->wma_scan_comp_timer)
!= VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to stop the scan completion timer");
}
error1:
/* Send completion event for only for start scan request */
if (msg_type == WDA_START_SCAN_OFFLOAD_REQ) {
scan_event =
(tSirScanOffloadEvent *) vos_mem_malloc(sizeof(tSirScanOffloadEvent));
if (!scan_event) {
WMA_LOGP("%s: Failed to allocate memory for scan rsp",
__func__);
return VOS_STATUS_E_NOMEM;
}
memset(scan_event, 0x00, sizeof(*scan_event));
scan_event->event = WMI_SCAN_EVENT_COMPLETED;
scan_event->reasonCode = eSIR_SME_SCAN_FAILED;
scan_event->p2pScanType = scan_req->p2pScanType;
scan_event->sessionId = scan_req->sessionId;
wma_send_msg(wma_handle, WDA_RX_SCAN_EVENT, (void *) scan_event, 0) ;
}
return vos_status;
}
/* function : wma_stop_scan
* Description : function to send the stop scan command
* Args : wma_handle
* Returns : failure or success
*/
static VOS_STATUS wma_stop_scan(tp_wma_handle wma_handle,
tAbortScanParams *abort_scan_req)
{
VOS_STATUS vos_status;
wmi_buf_t buf;
int status = 0;
int len;
vos_status = wma_get_buf_stop_scan_cmd(wma_handle, &buf, &len,
abort_scan_req);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to get buffer for stop scan cmd");
goto error1;
}
if (NULL == buf) {
WMA_LOGE("Failed to get buffer for stop scan cmd");
vos_status = VOS_STATUS_E_FAULT;
goto error1;
}
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_STOP_SCAN_CMDID);
/* Call the wmi api to request the scan */
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_STOP_SCAN_CMDID returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI("WMA --> WMI_STOP_SCAN_CMDID");
return VOS_STATUS_SUCCESS;
error:
if (buf)
wmi_buf_free(buf);
error1:
return vos_status;
}
/* function : wma_update_channel_list
* Description : Function is used to update the support channel list
* Args : wma_handle, list of supported channels and power
* Returns : SUCCESS or FAILURE
*/
VOS_STATUS wma_update_channel_list(WMA_HANDLE handle,
tSirUpdateChanList *chan_list)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_buf_t buf;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_scan_chan_list_cmd_fixed_param *cmd;
int status, i;
u_int8_t *buf_ptr;
wmi_channel *chan_info;
u_int16_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
len += sizeof(wmi_channel) * chan_list->numChan;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate memory");
vos_status = VOS_STATUS_E_NOMEM;
goto end;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_scan_chan_list_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_scan_chan_list_cmd_fixed_param));
WMA_LOGD("no of channels = %d, len = %d", chan_list->numChan, len);
cmd->num_scan_chans = chan_list->numChan;
WMITLV_SET_HDR((buf_ptr + sizeof(wmi_scan_chan_list_cmd_fixed_param)),
WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_channel) * chan_list->numChan);
chan_info = (wmi_channel *) (buf_ptr + sizeof(*cmd) + WMI_TLV_HDR_SIZE);
WMA_LOGD("ht %d, vht %d, vht_24 %d", chan_list->ht_en,
chan_list->vht_en, chan_list->vht_24_en);
for (i = 0; i < chan_list->numChan; ++i) {
WMITLV_SET_HDR(&chan_info->tlv_header,
WMITLV_TAG_STRUC_wmi_channel,
WMITLV_GET_STRUCT_TLVLEN(wmi_channel));
chan_info->mhz =
vos_chan_to_freq(chan_list->chanParam[i].chanId);
chan_info->band_center_freq1 = chan_info->mhz;
chan_info->band_center_freq2 = 0;
if (chan_list->chanParam[i].dfsSet) {
WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_PASSIVE);
}
if (chan_list->chanParam[i].half_rate) {
WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_HALF_RATE);
} else if (chan_list->chanParam[i].quarter_rate) {
WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_QUARTER_RATE);
}
if (chan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) {
WMI_SET_CHANNEL_MODE(chan_info, MODE_11G);
if (chan_list->vht_en && chan_list->vht_24_en)
WMI_SET_CHANNEL_FLAG(chan_info,
WMI_CHAN_FLAG_ALLOW_VHT);
} else {
WMI_SET_CHANNEL_MODE(chan_info, MODE_11A);
if (chan_list->vht_en)
WMI_SET_CHANNEL_FLAG(chan_info,
WMI_CHAN_FLAG_ALLOW_VHT);
}
if (chan_list->ht_en)
WMI_SET_CHANNEL_FLAG(chan_info,
WMI_CHAN_FLAG_ALLOW_HT);
WMI_SET_CHANNEL_MAX_TX_POWER(chan_info,
chan_list->chanParam[i].pwr);
WMI_SET_CHANNEL_REG_POWER(chan_info,
chan_list->chanParam[i].pwr);
WMA_LOGI(FL("Channel %u[%d] DFS[%d] TX pwr = %d "),
chan_info->mhz, i, chan_list->chanParam[i].dfsSet,
chan_list->chanParam[i].pwr);
/*TODO: Set WMI_SET_CHANNEL_MIN_POWER */
/*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */
/*TODO: WMI_SET_CHANNEL_REG_CLASSID*/
chan_info++;
}
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_SCAN_CHAN_LIST_CMDID);
if (status != EOK) {
vos_status = VOS_STATUS_E_FAILURE;
WMA_LOGE("Failed to send WMI_SCAN_CHAN_LIST_CMDID");
wmi_buf_free(buf);
}
end:
return vos_status;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
VOS_STATUS wma_roam_scan_fill_self_caps(tp_wma_handle wma_handle,
wmi_roam_offload_tlv_param *roam_offload_params,
tSirRoamOffloadScanReq *roam_req)
{
struct sAniSirGlobal *pMac = NULL;
tSirMacCapabilityInfo selfCaps;
tANI_U32 val = 0;
tANI_U32 nCfgValue;
tANI_U16 *pCfgValue16;
tANI_U8 nCfgValue8, *pCfgValue8;
tSirMacQosInfoStation macQosInfoSta;
union {
tANI_U16 nCfgValue16;
tSirMacHTCapabilityInfo htCapInfo;
tSirMacExtendedHTCapabilityInfo extHtCapInfo;
} uHTCapabilityInfo;
vos_mem_set(&macQosInfoSta, 0, sizeof(tSirMacQosInfoStation));
/* Roaming is done only for INFRA STA type.
* So, ess will be one and ibss will be Zero */
pMac = (struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
if (!pMac) {
WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
}
if (wlan_cfgGetInt(pMac, WNI_CFG_PRIVACY_ENABLED, &val) !=
eSIR_SUCCESS){
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_PRIVACY_ENABLED");
return VOS_STATUS_E_FAILURE;
}
selfCaps.ess = 1;
selfCaps.ibss = 0;
if (val)
selfCaps.privacy = 1;
if (wlan_cfgGetInt(pMac, WNI_CFG_SHORT_PREAMBLE, &val) !=
eSIR_SUCCESS){
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_SHORT_PREAMBLE");
return VOS_STATUS_E_FAILURE;
}
if (val)
selfCaps.shortPreamble = 1;
selfCaps.pbcc = 0;
selfCaps.channelAgility = 0;
if (wlan_cfgGetInt(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED,
&val) != eSIR_SUCCESS){
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED");
return VOS_STATUS_E_FAILURE;
}
if (val)
selfCaps.shortSlotTime = 1;
if (wlan_cfgGetInt(pMac, WNI_CFG_11H_ENABLED, &val) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_11H_ENABLED");
return VOS_STATUS_E_FAILURE;
}
if (val)
selfCaps.spectrumMgt = 1;
if (wlan_cfgGetInt(pMac, WNI_CFG_QOS_ENABLED, &val) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_QOS_ENABLED");
return VOS_STATUS_E_FAILURE;
}
if (val)
selfCaps.qos = 1;
if (wlan_cfgGetInt(pMac, WNI_CFG_APSD_ENABLED, &val) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_APSD_ENABLED");
return VOS_STATUS_E_FAILURE;
}
if (val)
selfCaps.apsd = 1;
selfCaps.rrm = pMac->rrm.rrmSmeContext.rrmConfig.rrm_enabled;
if (wlan_cfgGetInt(pMac, WNI_CFG_BLOCK_ACK_ENABLED, &val) !=
eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_BLOCK_ACK_ENABLED");
return VOS_STATUS_E_FAILURE;
}
selfCaps.delayedBA =
(tANI_U16)((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1);
selfCaps.immediateBA =
(tANI_U16)((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1);
pCfgValue16 = (tANI_U16 *)&selfCaps;
roam_offload_params->capability = (*pCfgValue16) & 0xFFFF;
if (wlan_cfgGetInt(pMac, WNI_CFG_HT_CAP_INFO, &nCfgValue) !=
eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_HT_CAP_INFO");
return VOS_STATUS_E_FAILURE;
}
uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF;
roam_offload_params->ht_caps_info =
uHTCapabilityInfo.nCfgValue16 & 0xFFFF;
if (wlan_cfgGetInt(pMac, WNI_CFG_HT_AMPDU_PARAMS, &nCfgValue) !=
eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_HT_AMPDU_PARAMS");
return VOS_STATUS_E_FAILURE;
}
/* tSirMacHTParametersInfo */
nCfgValue8 = ( tANI_U8 ) nCfgValue;
roam_offload_params->ampdu_param = (nCfgValue8) & 0xFF;
val = ROAM_OFFLOAD_NUM_MCS_SET;
if (wlan_cfgGetStr(pMac, WNI_CFG_SUPPORTED_MCS_SET,
(tANI_U8*)roam_offload_params->mcsset,
&val) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_SUPPORTED_MCS_SET");
return VOS_STATUS_E_FAILURE;
}
if (wlan_cfgGetInt(pMac, WNI_CFG_EXT_HT_CAP_INFO, &nCfgValue) !=
eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_EXT_HT_CAP_INFO");
return VOS_STATUS_E_FAILURE;
}
/* uHTCapabilityInfo.extHtCapInfo */
uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF;
roam_offload_params->ht_ext_cap =
uHTCapabilityInfo.nCfgValue16 & 0xFFFF;
if (wlan_cfgGetInt(pMac, WNI_CFG_TX_BF_CAP, &nCfgValue) !=
eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_TX_BF_CAP");
return VOS_STATUS_E_FAILURE;
}
/* tSirMacTxBFCapabilityInfo */
nCfgValue8 = ( tANI_U8 ) nCfgValue;
roam_offload_params->ht_txbf = nCfgValue8 & 0xFF;
if (wlan_cfgGetInt(pMac, WNI_CFG_AS_CAP, &nCfgValue) !=
eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_AS_CAP");
return VOS_STATUS_E_FAILURE;
}
/* tSirMacASCapabilityInfo */
nCfgValue8 = ( tANI_U8 ) nCfgValue;
roam_offload_params->asel_cap = nCfgValue8 & 0xFF;
/* QOS Info */
if (wlan_cfgGetInt(pMac, WNI_CFG_MAX_SP_LENGTH, &nCfgValue) !=
eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_MAX_SP_LENGTH");
return VOS_STATUS_E_FAILURE;
}
nCfgValue8 = ( tANI_U8 ) nCfgValue;
macQosInfoSta.maxSpLen = nCfgValue8;
macQosInfoSta.moreDataAck = 0;
macQosInfoSta.qack = 0;
macQosInfoSta.acbe_uapsd = roam_req->AcUapsd.acbe_uapsd;
macQosInfoSta.acbk_uapsd = roam_req->AcUapsd.acbk_uapsd;
macQosInfoSta.acvi_uapsd = roam_req->AcUapsd.acvi_uapsd;
macQosInfoSta.acvo_uapsd = roam_req->AcUapsd.acvo_uapsd;
pCfgValue8 = (tANI_U8 *)&macQosInfoSta;
/* macQosInfoSta Only queue_request is set.Refer to
* PopulateDot11fWMMCaps for more details
*/
roam_offload_params->qos_caps = (*pCfgValue8) & 0xFF;
roam_offload_params->wmm_caps = 0x4 & 0xFF;
return VOS_STATUS_SUCCESS;
}
#endif
/* function : wma_roam_scan_offload_mode
* Description : send WMI_ROAM_SCAN_MODE TLV to firmware. It has a piggyback
* : of WMI_ROAM_SCAN_MODE.
* Args : scan_cmd_fp contains the scan parameters.
* : mode controls rssi based and periodic scans by roam engine.
* Returns :
*/
VOS_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle,
wmi_start_scan_cmd_fixed_param *scan_cmd_fp,
tSirRoamOffloadScanReq *roam_req,
u_int32_t mode,
u_int32_t vdev_id)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf = NULL;
int status = 0;
int len;
u_int8_t *buf_ptr;
wmi_roam_scan_mode_fixed_param *roam_scan_mode_fp;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
int auth_mode = WMI_AUTH_NONE;
wmi_roam_offload_tlv_param *roam_offload_params;
wmi_roam_11i_offload_tlv_param *roam_offload_11i;
wmi_roam_11r_offload_tlv_param *roam_offload_11r;
wmi_roam_ese_offload_tlv_param *roam_offload_ese;
if (roam_req)
auth_mode = eCsrAuthType_to_rsn_authmode
(roam_req->ConnectedNetwork.authentication,
roam_req->ConnectedNetwork.encryption);
WMA_LOGD("%s : auth mode = %d",__func__, auth_mode);
#endif
/* Need to create a buf with roam_scan command at
* front and piggyback with scan command */
len = sizeof(wmi_roam_scan_mode_fixed_param) +
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
(2 * WMI_TLV_HDR_SIZE) +
#endif
sizeof(wmi_start_scan_cmd_fixed_param);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (roam_req && roam_req->RoamOffloadEnabled) {
len += sizeof(wmi_roam_offload_tlv_param);
len += WMI_TLV_HDR_SIZE;
if((auth_mode != WMI_AUTH_NONE) &&
((auth_mode != WMI_AUTH_OPEN) ||
(auth_mode == WMI_AUTH_OPEN &&
roam_req->MDID.mdiePresent) || roam_req->IsESEAssoc)){
len += WMI_TLV_HDR_SIZE;
if(roam_req->IsESEAssoc)
len += sizeof(wmi_roam_ese_offload_tlv_param);
else if (auth_mode == WMI_AUTH_FT_RSNA ||
auth_mode == WMI_AUTH_FT_RSNA_PSK ||
(auth_mode == WMI_AUTH_OPEN &&
roam_req->MDID.mdiePresent))
len += sizeof(wmi_roam_11r_offload_tlv_param);
else
len += sizeof(wmi_roam_11i_offload_tlv_param);
} else {
len += WMI_TLV_HDR_SIZE;
}
} else {
if (roam_req)
WMA_LOGD("%s : roam offload = %d",
__func__, roam_req->RoamOffloadEnabled);
else
WMA_LOGD("%s : roam_req is NULL",__func__);
len += (2 * WMI_TLV_HDR_SIZE);
}
if (roam_req && roam_req->RoamOffloadEnabled) {
mode = mode | WMI_ROAM_SCAN_MODE_ROAMOFFLOAD;
}
#endif
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
roam_scan_mode_fp = (wmi_roam_scan_mode_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&roam_scan_mode_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_roam_scan_mode_fixed_param));
roam_scan_mode_fp->roam_scan_mode = mode;
roam_scan_mode_fp->vdev_id = vdev_id;
/* Fill in scan parameters suitable for roaming scan */
buf_ptr += sizeof(wmi_roam_scan_mode_fixed_param);
vos_mem_copy(buf_ptr, scan_cmd_fp, sizeof(wmi_start_scan_cmd_fixed_param));
/* Ensure there is no additional IEs */
scan_cmd_fp->ie_len = 0;
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_start_scan_cmd_fixed_param));
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
buf_ptr += sizeof(wmi_start_scan_cmd_fixed_param);
if (roam_req && roam_req->RoamOffloadEnabled) {
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_roam_offload_tlv_param));
buf_ptr += WMI_TLV_HDR_SIZE;
roam_offload_params = (wmi_roam_offload_tlv_param *) buf_ptr;
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_STRUC_wmi_roam_offload_tlv_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_roam_offload_tlv_param));
roam_offload_params->prefer_5g = roam_req->Prefer5GHz;
roam_offload_params->rssi_cat_gap = roam_req->RoamRssiCatGap;
roam_offload_params->select_5g_margin = roam_req->Select5GHzMargin;
roam_offload_params->reassoc_failure_timeout =
roam_req->ReassocFailureTimeout;
/* Fill the capabilities */
wma_roam_scan_fill_self_caps(wma_handle, roam_offload_params, roam_req);
buf_ptr += sizeof(wmi_roam_offload_tlv_param);
/* The TLV's are in the order of 11i, 11R, ESE. Hence,
* they are filled in the same order.Depending on the
* authentication type, the other mode TLV's are nullified
* and only headers are filled.*/
if ((auth_mode != WMI_AUTH_NONE) &&
((auth_mode != WMI_AUTH_OPEN) ||
(auth_mode == WMI_AUTH_OPEN && roam_req->MDID.mdiePresent) ||
(roam_req->IsESEAssoc))) {
if (roam_req->IsESEAssoc){
WMITLV_SET_HDR(buf_ptr,WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_roam_ese_offload_tlv_param));
buf_ptr += WMI_TLV_HDR_SIZE;
roam_offload_ese =
(wmi_roam_ese_offload_tlv_param *) buf_ptr;
vos_mem_copy (roam_offload_ese->krk, roam_req->KRK,
sizeof(roam_req->KRK));
vos_mem_copy (roam_offload_ese->btk, roam_req->BTK,
sizeof(roam_req->BTK));
WMITLV_SET_HDR(&roam_offload_ese->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_ese_offload_tlv_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_roam_ese_offload_tlv_param));
buf_ptr += sizeof(wmi_roam_ese_offload_tlv_param);
} else if (auth_mode == WMI_AUTH_FT_RSNA ||
auth_mode == WMI_AUTH_FT_RSNA_PSK ||
(auth_mode == WMI_AUTH_OPEN &&
roam_req->MDID.mdiePresent)){
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_roam_11r_offload_tlv_param));
buf_ptr += WMI_TLV_HDR_SIZE;
roam_offload_11r =
(wmi_roam_11r_offload_tlv_param *) buf_ptr;
roam_offload_11r->r0kh_id_len = roam_req->R0KH_ID_Length;
vos_mem_copy (roam_offload_11r->r0kh_id, roam_req->R0KH_ID,
roam_offload_11r->r0kh_id_len);
vos_mem_copy (roam_offload_11r->psk_msk, roam_req->PSK_PMK,
sizeof(roam_req->PSK_PMK));
roam_offload_11r->psk_msk_len = roam_req->pmk_len;
roam_offload_11r->mdie_present = roam_req->MDID.mdiePresent;
roam_offload_11r->mdid = roam_req->MDID.mobilityDomain;
if(auth_mode == WMI_AUTH_OPEN) {
/* If FT-Open ensure pmk length
and r0khid len are zero */
roam_offload_11r->r0kh_id_len = 0;
roam_offload_11r->psk_msk_len = 0;
}
WMITLV_SET_HDR(&roam_offload_11r->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_11r_offload_tlv_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_roam_11r_offload_tlv_param));
buf_ptr += sizeof(wmi_roam_11r_offload_tlv_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
} else {
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_roam_11i_offload_tlv_param));
buf_ptr += WMI_TLV_HDR_SIZE;
roam_offload_11i =
(wmi_roam_11i_offload_tlv_param *) buf_ptr;
if (roam_req->RoamKeyMgmtOffloadEnabled) {
WMI_SET_ROAM_OFFLOAD_OKC_ENABLED(
roam_offload_11i->flags);
WMA_LOGE("LFR3:OKC Enabled");
} else {
WMI_SET_ROAM_OFFLOAD_OKC_DISABLED(
roam_offload_11i->flags);
WMA_LOGE("LFR3:OKC Disabled");
}
vos_mem_copy (roam_offload_11i->pmk, roam_req->PSK_PMK,
sizeof(roam_req->PSK_PMK));
roam_offload_11i->pmk_len = roam_req->pmk_len;
WMITLV_SET_HDR(&roam_offload_11i->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_11i_offload_tlv_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_roam_11i_offload_tlv_param) );
buf_ptr += sizeof(wmi_roam_11i_offload_tlv_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,0);
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,0);
buf_ptr += WMI_TLV_HDR_SIZE;
}
} else {
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
}
} else {
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
WMITLV_GET_STRUCT_TLVLEN(0));
}
#endif
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_SCAN_MODE);
if (status != EOK) {
WMA_LOGE
("wmi_unified_cmd_send WMI_ROAM_SCAN_MODE returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_MODE", __func__);
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return vos_status;
}
/* function : wma_roam_scan_offload_rssi_threshold
* Description : Send WMI_ROAM_SCAN_RSSI_THRESHOLD TLV to firmware
* Args :
* Returns :
*/
VOS_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle,
tSirRoamOffloadScanReq *roam_req)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf = NULL;
int status = 0;
int len, rssi_thresh, rssi_thresh_diff;
u_int8_t *buf_ptr;
wmi_roam_scan_rssi_threshold_fixed_param *rssi_threshold_fp;
wmi_roam_scan_extended_threshold_param *ext_thresholds = NULL;
struct roam_ext_params *roam_params;
uint32_t hirssi_scan_max_count;
uint32_t hirssi_scan_delta;
int32_t hirssi_upper_bound;
int32_t good_rssi_threshold;
/* Send rssi threshold */
roam_params = &roam_req->roam_params;
rssi_thresh = roam_req->LookupThreshold - WMA_NOISE_FLOOR_DBM_DEFAULT;
rssi_thresh_diff = roam_req->OpportunisticScanThresholdDiff;
hirssi_scan_max_count = roam_req->hi_rssi_scan_max_count;
hirssi_scan_delta = roam_req->hi_rssi_scan_rssi_delta;
hirssi_upper_bound = roam_req->hi_rssi_scan_rssi_ub -
WMA_NOISE_FLOOR_DBM_DEFAULT;
len = sizeof(wmi_roam_scan_rssi_threshold_fixed_param);
len += WMI_TLV_HDR_SIZE; /* TLV for ext_thresholds*/
len += sizeof(wmi_roam_scan_extended_threshold_param);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
rssi_threshold_fp = (wmi_roam_scan_rssi_threshold_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&rssi_threshold_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_roam_scan_rssi_threshold_fixed_param));
/* fill in threshold values */
rssi_threshold_fp->vdev_id = roam_req->sessionId;
rssi_threshold_fp->roam_scan_rssi_thresh = rssi_thresh & 0x000000ff;
rssi_threshold_fp->roam_rssi_thresh_diff = rssi_thresh_diff & 0x000000ff;
rssi_threshold_fp->hirssi_scan_max_count = hirssi_scan_max_count;
rssi_threshold_fp->hirssi_scan_delta = hirssi_scan_delta;
rssi_threshold_fp->hirssi_upper_bound = hirssi_upper_bound & 0x00000ff;
buf_ptr += sizeof(wmi_roam_scan_rssi_threshold_fixed_param);
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_roam_scan_extended_threshold_param));
buf_ptr += WMI_TLV_HDR_SIZE;
ext_thresholds = (wmi_roam_scan_extended_threshold_param *) buf_ptr;
/* The current Noise floor in firmware is -96dBm. Penalty/Boost threshold is
* applied on a weaker signal to make it even more weaker. So, there
* is a chance that the user may configure a very low Penalty/Boost
* threshold beyond the noise floor. If that is the case, then suppress
* the penalty/boost threshold to the noise floor.
*/
if (roam_params->raise_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT)
ext_thresholds->penalty_threshold_5g = 0;
else
ext_thresholds->boost_threshold_5g =
(roam_params->raise_rssi_thresh_5g - WMA_NOISE_FLOOR_DBM_DEFAULT) &
0x000000ff;
if (roam_params->drop_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT)
ext_thresholds->penalty_threshold_5g = 0;
else
ext_thresholds->penalty_threshold_5g =
(roam_params->drop_rssi_thresh_5g - WMA_NOISE_FLOOR_DBM_DEFAULT) &
0x000000ff;
ext_thresholds->boost_algorithm_5g = WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR;
ext_thresholds->boost_factor_5g = roam_params->raise_factor_5g;
ext_thresholds->penalty_algorithm_5g =
WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR;
ext_thresholds->penalty_factor_5g = roam_params->drop_factor_5g;
ext_thresholds->max_boost_5g = roam_params->max_raise_rssi_5g;
ext_thresholds->max_penalty_5g = roam_params->max_drop_rssi_5g;
if (roam_params->good_rssi_roam)
good_rssi_threshold = WMA_NOISE_FLOOR_DBM_DEFAULT;
else
good_rssi_threshold = 0;
ext_thresholds->good_rssi_threshold =
(good_rssi_threshold - WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff;
WMA_LOGD("WMA --> good_rssi_threshold=%d",
ext_thresholds->good_rssi_threshold);
WMITLV_SET_HDR(&ext_thresholds->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param,
WMITLV_GET_STRUCT_TLVLEN
(wmi_roam_scan_extended_threshold_param));
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_SCAN_RSSI_THRESHOLD);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_RSSI_THRESHOLD returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI(
"%s: WMA --> WMI_ROAM_SCAN_RSSI_THRESHOLD roam_scan_rssi_thresh=%d, roam_rssi_thresh_diff=%d",
__func__, rssi_thresh, rssi_thresh_diff);
WMA_LOGI(
"%s: WMA --> WMI_ROAM_SCAN_RSSI_THRESHOLD hirssi_scan max_count=%d, delta=%d",
__func__, hirssi_scan_max_count, hirssi_scan_delta);
WMA_LOGI(
"%s: WMA --> WMI_ROAM_SCAN_RSSI_THRESHOLD hirssi_upper_bound=%d",
__func__, hirssi_upper_bound);
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return vos_status;
}
/* function : wma_roam_scan_offload_scan_period
* Description : Send WMI_ROAM_SCAN_PERIOD TLV to firmware
* Args :
* Returns :
*/
VOS_STATUS wma_roam_scan_offload_scan_period(tp_wma_handle wma_handle,
A_UINT32 scan_period,
A_UINT32 scan_age,
u_int32_t vdev_id)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf = NULL;
int status = 0;
int len;
u_int8_t *buf_ptr;
wmi_roam_scan_period_fixed_param *scan_period_fp;
/* Send scan period values */
len = sizeof(wmi_roam_scan_period_fixed_param);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
scan_period_fp = (wmi_roam_scan_period_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&scan_period_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_roam_scan_period_fixed_param));
/* fill in scan period values */
scan_period_fp->vdev_id = vdev_id;
scan_period_fp->roam_scan_period = scan_period; /* 20 seconds */
scan_period_fp->roam_scan_age = scan_age;
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_SCAN_PERIOD);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_PERIOD returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_PERIOD roam_scan_period=%d, roam_scan_age=%d",
__func__, scan_period, scan_age);
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return vos_status;
}
/* function : wma_roam_scan_offload_rssi_change
* Description : Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD TLV to firmware
* Args :
* Returns :
*/
VOS_STATUS wma_roam_scan_offload_rssi_change(tp_wma_handle wma_handle,
u_int32_t vdev_id,
A_INT32 rssi_change_thresh,
A_UINT32 bcn_rssi_weight,
A_UINT32 hirssi_delay_btw_scans)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf = NULL;
int status = 0;
int len;
u_int8_t *buf_ptr;
wmi_roam_scan_rssi_change_threshold_fixed_param *rssi_change_fp;
/* Send rssi change parameters */
len = sizeof(wmi_roam_scan_rssi_change_threshold_fixed_param);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
rssi_change_fp = (wmi_roam_scan_rssi_change_threshold_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&rssi_change_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_roam_scan_rssi_change_threshold_fixed_param));
/* fill in rssi change threshold (hysteresis) values */
rssi_change_fp->vdev_id = vdev_id;
rssi_change_fp->roam_scan_rssi_change_thresh = rssi_change_thresh;
rssi_change_fp->bcn_rssi_weight = bcn_rssi_weight;
rssi_change_fp->hirssi_delay_btw_scans = hirssi_delay_btw_scans;
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_RSSI_CHANGE_THERSHOLD roam_scan_rssi_change_thresh=%d, bcn_rssi_weight=%d",
__func__, rssi_change_thresh, bcn_rssi_weight);
WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_RSSI_CHANGE_THERSHOLD hirssi_delay_btw_scans=%d",
__func__, hirssi_delay_btw_scans);
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return vos_status;
}
/* function : wma_roam_scan_offload_chan_list
* Description : Send WMI_ROAM_CHAN_LIST TLV to firmware
* Args :
* Returns :
*/
VOS_STATUS wma_roam_scan_offload_chan_list(tp_wma_handle wma_handle,
u_int8_t chan_count,
u_int8_t *chan_list,
u_int8_t list_type,
u_int32_t vdev_id)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf = NULL;
int status = 0;
int len, list_tlv_len;
int i;
u_int8_t *buf_ptr;
wmi_roam_chan_list_fixed_param *chan_list_fp;
A_UINT32 *roam_chan_list_array;
if (chan_count == 0)
{
WMA_LOGD("%s : invalid number of channels %d", __func__, chan_count);
return VOS_STATUS_E_EMPTY;
}
/* Channel list is a table of 2 TLV's */
list_tlv_len = WMI_TLV_HDR_SIZE + chan_count * sizeof(A_UINT32);
len = sizeof(wmi_roam_chan_list_fixed_param) + list_tlv_len;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
chan_list_fp = (wmi_roam_chan_list_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&chan_list_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_roam_chan_list_fixed_param));
chan_list_fp->vdev_id = vdev_id;
chan_list_fp->num_chan = chan_count;
if (chan_count > 0 && list_type == CHANNEL_LIST_STATIC) {
/* external app is controlling channel list */
chan_list_fp->chan_list_type = WMI_ROAM_SCAN_CHAN_LIST_TYPE_STATIC;
} else {
/* umac supplied occupied channel list in LFR */
chan_list_fp->chan_list_type = WMI_ROAM_SCAN_CHAN_LIST_TYPE_DYNAMIC;
}
buf_ptr += sizeof(wmi_roam_chan_list_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(chan_list_fp->num_chan * sizeof(u_int32_t)));
roam_chan_list_array = (A_UINT32 *)(buf_ptr + WMI_TLV_HDR_SIZE);
WMA_LOGI("%s: %d channels = ", __func__, chan_list_fp->num_chan);
for (i = 0; ((i < chan_list_fp->num_chan) &&
(i < SIR_ROAM_MAX_CHANNELS)); i++) {
roam_chan_list_array[i] = vos_chan_to_freq(chan_list[i]);
WMA_LOGI("%d,",roam_chan_list_array[i]);
}
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_CHAN_LIST);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_CHAN_LIST returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_CHAN_LIST", __func__);
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return vos_status;
}
/* function : eCsrAuthType_to_rsn_authmode
* Description : Map CSR's authentication type into RSN auth mode used by firmware
* Args :
* Returns :
*/
A_UINT32 eCsrAuthType_to_rsn_authmode (eCsrAuthType authtype, eCsrEncryptionType encr) {
switch(authtype) {
case eCSR_AUTH_TYPE_OPEN_SYSTEM:
return (WMI_AUTH_OPEN);
case eCSR_AUTH_TYPE_WPA:
return (WMI_AUTH_WPA);
case eCSR_AUTH_TYPE_WPA_PSK:
return (WMI_AUTH_WPA_PSK);
case eCSR_AUTH_TYPE_RSN:
return (WMI_AUTH_RSNA);
case eCSR_AUTH_TYPE_RSN_PSK:
return (WMI_AUTH_RSNA_PSK);
#if defined WLAN_FEATURE_VOWIFI_11R
case eCSR_AUTH_TYPE_FT_RSN:
return (WMI_AUTH_FT_RSNA);
case eCSR_AUTH_TYPE_FT_RSN_PSK:
return (WMI_AUTH_FT_RSNA_PSK);
#endif
#ifdef FEATURE_WLAN_WAPI
case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE:
return (WMI_AUTH_WAPI);
case eCSR_AUTH_TYPE_WAPI_WAI_PSK:
return(WMI_AUTH_WAPI_PSK);
#endif
#ifdef FEATURE_WLAN_ESE
case eCSR_AUTH_TYPE_CCKM_WPA:
case eCSR_AUTH_TYPE_CCKM_RSN:
return (WMI_AUTH_CCKM);
#endif
#ifdef WLAN_FEATURE_11W
case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
return (WMI_AUTH_RSNA_PSK_SHA256);
case eCSR_AUTH_TYPE_RSN_8021X_SHA256:
return (WMI_AUTH_RSNA_8021X_SHA256);
#endif
case eCSR_AUTH_TYPE_NONE:
case eCSR_AUTH_TYPE_AUTOSWITCH:
/* In case of WEP and other keys, NONE means OPEN auth */
if (encr == eCSR_ENCRYPT_TYPE_WEP40_STATICKEY ||
encr == eCSR_ENCRYPT_TYPE_WEP104_STATICKEY ||
encr == eCSR_ENCRYPT_TYPE_WEP40 ||
encr == eCSR_ENCRYPT_TYPE_WEP104 ||
encr == eCSR_ENCRYPT_TYPE_TKIP ||
encr == eCSR_ENCRYPT_TYPE_AES) {
return (WMI_AUTH_OPEN);
}
return(WMI_AUTH_NONE);
default:
return(WMI_AUTH_NONE);
}
}
/* function : eCsrEncryptionType_to_rsn_cipherset
* Description : Map CSR's encryption type into RSN cipher types used by firmware
* Args :
* Returns :
*/
A_UINT32 eCsrEncryptionType_to_rsn_cipherset (eCsrEncryptionType encr) {
switch (encr) {
case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
case eCSR_ENCRYPT_TYPE_WEP40:
case eCSR_ENCRYPT_TYPE_WEP104:
return (WMI_CIPHER_WEP);
case eCSR_ENCRYPT_TYPE_TKIP:
return (WMI_CIPHER_TKIP);
case eCSR_ENCRYPT_TYPE_AES:
return (WMI_CIPHER_AES_CCM);
#ifdef FEATURE_WLAN_WAPI
case eCSR_ENCRYPT_TYPE_WPI:
return (WMI_CIPHER_WAPI);
#endif /* FEATURE_WLAN_WAPI */
case eCSR_ENCRYPT_TYPE_ANY:
return (WMI_CIPHER_ANY);
case eCSR_ENCRYPT_TYPE_NONE:
default:
return (WMI_CIPHER_NONE);
}
}
/* function : wma_roam_scan_fill_ap_profile
* Description : Fill ap_profile structure from configured parameters
* Args :
* Returns :
*/
v_VOID_t wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, tpAniSirGlobal pMac,
tSirRoamOffloadScanReq *roam_req, wmi_ap_profile *ap_profile_p)
{
vos_mem_zero(ap_profile_p, sizeof(wmi_ap_profile));
if (roam_req == NULL) {
ap_profile_p->ssid.ssid_len = 0;
ap_profile_p->ssid.ssid[0] = 0;
ap_profile_p->rsn_authmode = WMI_AUTH_NONE;
ap_profile_p->rsn_ucastcipherset = WMI_CIPHER_NONE;
ap_profile_p->rsn_mcastcipherset = WMI_CIPHER_NONE;
ap_profile_p->rsn_mcastmgmtcipherset = WMI_CIPHER_NONE;
ap_profile_p->rssi_threshold = WMA_ROAM_RSSI_DIFF_DEFAULT;
} else {
ap_profile_p->ssid.ssid_len = roam_req->ConnectedNetwork.ssId.length;
vos_mem_copy(ap_profile_p->ssid.ssid, roam_req->ConnectedNetwork.ssId.ssId,
ap_profile_p->ssid.ssid_len);
ap_profile_p->rsn_authmode =
eCsrAuthType_to_rsn_authmode(roam_req->ConnectedNetwork.authentication,
roam_req->ConnectedNetwork.encryption);
ap_profile_p->rsn_ucastcipherset =
eCsrEncryptionType_to_rsn_cipherset(roam_req->ConnectedNetwork.encryption);
ap_profile_p->rsn_mcastcipherset =
eCsrEncryptionType_to_rsn_cipherset(roam_req->ConnectedNetwork.mcencryption);
ap_profile_p->rsn_mcastmgmtcipherset = ap_profile_p->rsn_mcastcipherset;
ap_profile_p->rssi_threshold = roam_req->RoamRssiDiff;
#ifdef WLAN_FEATURE_11W
if (roam_req->ConnectedNetwork.MFPEnabled)
ap_profile_p->flags |= WMI_AP_PROFILE_FLAG_PMF;
#endif
}
}
/* function : wma_roam_scan_scan_params
* Description : Fill scan_params structure from configured parameters
* Args : roam_req pointer = NULL if this routine is called before connect
* : It will be non-NULL if called after assoc.
* Returns :
*/
v_VOID_t wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle,
tpAniSirGlobal pMac,
tSirRoamOffloadScanReq *roam_req,
wmi_start_scan_cmd_fixed_param *scan_params)
{
tANI_U8 channels_per_burst = 0;
tANI_U32 val = 0;
if (NULL == pMac) {
WMA_LOGE("%s: pMac is NULL", __func__);
return;
}
vos_mem_zero(scan_params, sizeof(wmi_start_scan_cmd_fixed_param));
scan_params->scan_ctrl_flags = WMI_SCAN_ADD_CCK_RATES |
WMI_SCAN_ADD_OFDM_RATES |
WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ;
if (roam_req != NULL) {
/* Parameters updated after association is complete */
WMA_LOGI("%s: Input parameters: NeighborScanChannelMinTime"
" = %d, NeighborScanChannelMaxTime = %d",
__func__,
roam_req->NeighborScanChannelMinTime,
roam_req->NeighborScanChannelMaxTime);
WMA_LOGI("%s: Input parameters: NeighborScanTimerPeriod ="
" %d, HomeAwayTime = %d, nProbes = %d",
__func__,
roam_req->NeighborScanTimerPeriod,
roam_req->HomeAwayTime,
roam_req->nProbes);
/*
* roam_req->NeighborScanChannelMaxTime = SCAN_CHANNEL_TIME
* roam_req->HomeAwayTime = SCAN_HOME_AWAY_TIME
* roam_req->NeighborScanTimerPeriod = SCAN_HOME_TIME
*
* scan_params->dwell_time_active = time station stays on channel
* and sends probes;
* scan_params->dwell_time_passive = time station stays on channel
* and listens probes;
* scan_params->burst_duration = time station goes off channel
* to scan;
*/
if (wlan_cfgGetInt(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, &val) != eSIR_SUCCESS)
{
/*
* Could not get max channel value from CFG. Log error.
*/
WMA_LOGE("could not retrieve passive max channel value");
/* use a default value of 110ms */
val = WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT;
}
scan_params->dwell_time_passive = val;
/*
* Here is the formula,
* T(HomeAway) = N * T(dwell) + (N+1) * T(cs)
* where N is number of channels scanned in single burst
*/
scan_params->dwell_time_active = roam_req->NeighborScanChannelMaxTime;
if (roam_req->HomeAwayTime < 2*WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME) {
/* clearly we can't follow home away time.
* Make it a split scan.
*/
scan_params->burst_duration = 0;
} else {
channels_per_burst =
(roam_req->HomeAwayTime - WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME)
/ ( scan_params->dwell_time_active + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME);
if (channels_per_burst < 1) {
// dwell time and home away time conflicts
// we will override dwell time
scan_params->dwell_time_active =
roam_req->HomeAwayTime - 2*WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME;
scan_params->burst_duration = scan_params->dwell_time_active;
} else {
scan_params->burst_duration =
channels_per_burst * scan_params->dwell_time_active;
}
}
if (roam_req->allowDFSChannelRoam == SIR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL &&
roam_req->HomeAwayTime > 0 &&
roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) {
/* Roaming on DFS channels is supported and it is not app channel list.
* It is ok to override homeAwayTime to accomodate DFS dwell time in burst
* duration.
*/
scan_params->burst_duration = MAX(scan_params->burst_duration,
scan_params->dwell_time_passive);
}
scan_params->min_rest_time = roam_req->NeighborScanTimerPeriod;
scan_params->max_rest_time = roam_req->NeighborScanTimerPeriod;
scan_params->repeat_probe_time = (roam_req->nProbes > 0) ?
VOS_MAX(scan_params->dwell_time_active / roam_req->nProbes, 1) : 0;
scan_params->probe_spacing_time = 0;
scan_params->probe_delay = 0;
scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; /* 30 seconds for full scan cycle */
scan_params->idle_time = scan_params->min_rest_time;
scan_params->n_probes = roam_req->nProbes;
if (roam_req->allowDFSChannelRoam == SIR_ROAMING_DFS_CHANNEL_DISABLED) {
scan_params->scan_ctrl_flags |= WMI_SCAN_BYPASS_DFS_CHN;
} else {
/* Roaming scan on DFS channel is allowed.
* No need to change any flags for default allowDFSChannelRoam = 1.
* Special case where static channel list is given by application
* that contains DFS channels. Assume that the application
* has knowledge of matching APs being active and that
* probe request transmission is permitted on those channel.
* Force active scans on those channels.
*/
if (roam_req->allowDFSChannelRoam ==
SIR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE &&
roam_req->ChannelCacheType == CHANNEL_LIST_STATIC &&
roam_req->ConnectedNetwork.ChannelCount > 0) {
scan_params->scan_ctrl_flags |=
WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS;
}
}
} else {
/* roam_req = NULL during initial or pre-assoc invocation */
scan_params->dwell_time_active = WMA_ROAM_DWELL_TIME_ACTIVE_DEFAULT;
scan_params->dwell_time_passive = WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT;
scan_params->min_rest_time = WMA_ROAM_MIN_REST_TIME_DEFAULT;
scan_params->max_rest_time = WMA_ROAM_MAX_REST_TIME_DEFAULT;
scan_params->repeat_probe_time = 0;
scan_params->probe_spacing_time = 0;
scan_params->probe_delay = 0;
scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION;
scan_params->idle_time = scan_params->min_rest_time;
scan_params->burst_duration = 0;
scan_params->n_probes = 0;
}
WMA_LOGI("%s: Rome roam scan parameters:"
" dwell_time_active = %d, dwell_time_passive = %d",
__func__,
scan_params->dwell_time_active,
scan_params->dwell_time_passive);
WMA_LOGI("%s: min_rest_time = %d, max_rest_time = %d,"
" repeat_probe_time = %d n_probes = %d",
__func__,
scan_params->min_rest_time,
scan_params->max_rest_time,
scan_params->repeat_probe_time,
scan_params->n_probes);
WMA_LOGI("%s: max_scan_time = %d, idle_time = %d,"
" burst_duration = %d, scan_ctrl_flags = 0x%x",
__func__,
scan_params->max_scan_time,
scan_params->idle_time,
scan_params->burst_duration,
scan_params->scan_ctrl_flags);
}
/* function : wma_roam_scan_offload_ap_profile
* Description : Send WMI_ROAM_AP_PROFILE TLV to firmware
* Args : AP profile parameters are passed in as the structure used in TLV
* Returns :
*/
VOS_STATUS wma_roam_scan_offload_ap_profile(tp_wma_handle wma_handle,
wmi_ap_profile *ap_profile_p,
u_int32_t vdev_id)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf = NULL;
int status = 0;
int len;
u_int8_t *buf_ptr;
wmi_roam_ap_profile_fixed_param *roam_ap_profile_fp;
len = sizeof(wmi_roam_ap_profile_fixed_param) +
sizeof(wmi_ap_profile);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
roam_ap_profile_fp = (wmi_roam_ap_profile_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&roam_ap_profile_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_roam_ap_profile_fixed_param));
/* fill in threshold values */
roam_ap_profile_fp->vdev_id = vdev_id;
roam_ap_profile_fp->id = 0;
buf_ptr += sizeof(wmi_roam_ap_profile_fixed_param);
vos_mem_copy(buf_ptr, ap_profile_p, sizeof(wmi_ap_profile));
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_STRUC_wmi_ap_profile,
WMITLV_GET_STRUCT_TLVLEN(
wmi_ap_profile));
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_AP_PROFILE);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_AP_PROFILE returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI("WMA --> WMI_ROAM_AP_PROFILE and other parameters");
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return vos_status;
}
VOS_STATUS wma_roam_scan_filter(tp_wma_handle wma_handle,
tSirRoamOffloadScanReq *roam_req)
{
wmi_buf_t buf = NULL;
int status = 0, i;
uint32_t len, num_bssid_black_list = 0, num_ssid_white_list = 0,
num_bssid_preferred_list = 0;
uint32_t op_bitmap = 0;
uint8_t *buf_ptr;
wmi_roam_filter_fixed_param *roam_filter;
uint8_t *bssid_src_ptr = NULL;
wmi_mac_addr *bssid_dst_ptr = NULL;
wmi_ssid *ssid_ptr = NULL;
uint32_t *bssid_preferred_factor_ptr = NULL;
struct roam_ext_params *roam_params;
roam_params = &roam_req->roam_params;
len = sizeof(wmi_roam_filter_fixed_param);
len += WMI_TLV_HDR_SIZE;
if (roam_req->Command != ROAM_SCAN_OFFLOAD_STOP) {
switch (roam_req->reason) {
case REASON_ROAM_SET_BLACKLIST_BSSID:
op_bitmap |= 0x1;
num_bssid_black_list = roam_params->num_bssid_avoid_list;
len += num_bssid_black_list * sizeof(wmi_mac_addr);
len += WMI_TLV_HDR_SIZE;
break;
case REASON_ROAM_SET_SSID_ALLOWED:
op_bitmap |= 0x2;
num_ssid_white_list = roam_params->num_ssid_allowed_list;
len += num_ssid_white_list * sizeof(wmi_ssid);
len += WMI_TLV_HDR_SIZE;
break;
case REASON_ROAM_SET_FAVORED_BSSID:
op_bitmap |= 0x4;
num_bssid_preferred_list = roam_params->num_bssid_favored;
len += num_bssid_preferred_list * sizeof(wmi_mac_addr);
len += WMI_TLV_HDR_SIZE;
len += num_bssid_preferred_list * sizeof(A_UINT32);
break;
default:
WMA_LOGD("%s : Roam Filter need not be sent", __func__);
return VOS_STATUS_SUCCESS;
break;
}
} else {
/* In case of STOP command, reset all the variables
* except for blacklist BSSID which should be retained
* across connections.*/
op_bitmap = 0x2 | 0x4;
num_ssid_white_list = roam_params->num_ssid_allowed_list;
len += num_ssid_white_list * sizeof(wmi_ssid);
num_bssid_preferred_list = roam_params->num_bssid_favored;
len += num_bssid_preferred_list * sizeof(wmi_mac_addr);
len += num_bssid_preferred_list * sizeof(A_UINT32);
len += (2 * WMI_TLV_HDR_SIZE);
}
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
roam_filter = (wmi_roam_filter_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&roam_filter->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_roam_filter_fixed_param));
/* fill in fixed values */
roam_filter->vdev_id = roam_req->sessionId;
roam_filter->flags = 0;
roam_filter->op_bitmap = op_bitmap;
roam_filter->num_bssid_black_list = num_bssid_black_list;
roam_filter->num_ssid_white_list = num_ssid_white_list;
roam_filter->num_bssid_preferred_list = num_bssid_preferred_list;
buf_ptr += sizeof(wmi_roam_filter_fixed_param);
WMITLV_SET_HDR((buf_ptr),
WMITLV_TAG_ARRAY_FIXED_STRUC,
(num_bssid_black_list * sizeof(wmi_mac_addr)));
bssid_src_ptr = (uint8_t *)&roam_params->bssid_avoid_list;
bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE);
for(i=0; i<num_bssid_black_list; i++) {
WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr, bssid_dst_ptr);
bssid_src_ptr += ATH_MAC_LEN;
bssid_dst_ptr++;
}
buf_ptr += WMI_TLV_HDR_SIZE + (num_bssid_black_list * sizeof(wmi_mac_addr));
WMITLV_SET_HDR((buf_ptr),
WMITLV_TAG_ARRAY_FIXED_STRUC,
(num_ssid_white_list * sizeof(wmi_ssid)));
ssid_ptr = (wmi_ssid *)(buf_ptr + WMI_TLV_HDR_SIZE);
for(i=0; i<num_ssid_white_list; i++) {
memcpy(&ssid_ptr->ssid, &roam_params->ssid_allowed_list[i].ssId,
roam_params->ssid_allowed_list[i].length);
ssid_ptr->ssid_len = roam_params->ssid_allowed_list[i].length;
WMA_LOGD("%s: Passing SSID of length=%d", __func__,ssid_ptr->ssid_len);
VOS_TRACE_HEX_DUMP(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_DEBUG,
(uint8_t *)ssid_ptr->ssid,
ssid_ptr->ssid_len);
ssid_ptr++;
}
buf_ptr += WMI_TLV_HDR_SIZE + (num_ssid_white_list * sizeof(wmi_ssid));
WMITLV_SET_HDR((buf_ptr),
WMITLV_TAG_ARRAY_FIXED_STRUC,
(num_bssid_preferred_list * sizeof(wmi_mac_addr)));
bssid_src_ptr = (uint8_t *)&roam_params->bssid_favored;
bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE);
for(i=0; i<num_bssid_preferred_list; i++) {
WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr,
(wmi_mac_addr *)bssid_dst_ptr);
bssid_src_ptr += ATH_MAC_LEN;
bssid_dst_ptr++;
}
buf_ptr += WMI_TLV_HDR_SIZE +
(num_bssid_preferred_list * sizeof(wmi_mac_addr));
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(num_bssid_preferred_list * sizeof(uint32_t)));
bssid_preferred_factor_ptr = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE);
for (i=0; i<num_bssid_preferred_list; i++) {
*bssid_preferred_factor_ptr = roam_params->bssid_favored_factor[i];
bssid_preferred_factor_ptr++;
}
buf_ptr += WMI_TLV_HDR_SIZE + (num_bssid_preferred_list * sizeof(uint32_t));
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_FILTER_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_FILTER_CMDID returned Error %d",
status);
goto error;
}
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
VOS_STATUS wma_roam_scan_offload_command(tp_wma_handle wma_handle,
u_int32_t command,
u_int32_t vdev_id)
{
VOS_STATUS vos_status;
wmi_roam_scan_cmd_fixed_param *cmd_fp;
wmi_buf_t buf = NULL;
int status = 0;
int len;
u_int8_t *buf_ptr;
len = sizeof(wmi_roam_scan_cmd_fixed_param);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd_fp = (wmi_roam_scan_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_roam_scan_cmd_fixed_param));
cmd_fp->vdev_id = vdev_id;
cmd_fp->command_arg = command;
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_ROAM_SCAN_CMD);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_CMD returned Error %d",
status);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_CMD", __func__);
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return vos_status;
}
/* function : wma_process_roam_scan_req
* Description : Main routine to handle ROAM commands coming from CSR module.
* Args :
* Returns :
*/
VOS_STATUS wma_process_roam_scan_req(tp_wma_handle wma_handle,
tSirRoamOffloadScanReq *roam_req)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_start_scan_cmd_fixed_param scan_params;
wmi_ap_profile ap_profile;
tpAniSirGlobal pMac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
u_int32_t mode = 0;
struct wma_txrx_node *intr = NULL;
WMA_LOGI("%s: command 0x%x, reason %d", __func__, roam_req->Command,
roam_req->reason);
if (NULL == pMac)
{
WMA_LOGE("%s: pMac is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
if (!wma_handle->roam_offload_enabled) {
/* roam scan offload is not enabled in firmware.
* Cannot initialize it in the middle of connection.
*/
vos_mem_free(roam_req);
return VOS_STATUS_E_PERM;
}
switch (roam_req->Command) {
case ROAM_SCAN_OFFLOAD_START:
intr = &wma_handle->interfaces[roam_req->sessionId];
intr->delay_before_vdev_stop = roam_req->delay_before_vdev_stop;
/*
* Scan/Roam threshold parameters are translated from fields of tSirRoamOffloadScanReq
* to WMITLV values sent to Rome firmware.
* some of these parameters are configurable in qcom_cfg.ini file.
*/
/* First parameter is positive rssi value to trigger rssi based scan.
* Opportunistic scan is started at 30 dB higher that trigger rssi.
*/
wma_handle->suitable_ap_hb_failure = FALSE;
vos_status = wma_roam_scan_offload_rssi_thresh(wma_handle,
roam_req);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
vos_status = wma_roam_scan_bmiss_cnt(wma_handle,
roam_req->RoamBmissFirstBcnt, roam_req->RoamBmissFinalBcnt,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
/* Opportunistic scan runs on a timer, value set by EmptyRefreshScanPeriod.
* Age out the entries after 3 such cycles.
*/
if (roam_req->EmptyRefreshScanPeriod > 0) {
vos_status = wma_roam_scan_offload_scan_period(wma_handle,
roam_req->EmptyRefreshScanPeriod,
roam_req->EmptyRefreshScanPeriod * 3,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
mode = WMI_ROAM_SCAN_MODE_PERIODIC;
/* Don't use rssi triggered roam scans if external app
* is in control of channel list.
*/
if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) {
mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE;
}
} else {
mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE;
}
/* Start new rssi triggered scan only if it changes by RoamRssiDiff value.
* Beacon weight of 14 means average rssi is taken over 14 previous samples +
* 2 times the current beacon's rssi.
*/
vos_status = wma_roam_scan_offload_rssi_change(wma_handle,
roam_req->sessionId,
roam_req->RoamRescanRssiDiff,
roam_req->RoamBeaconRssiWeight,
roam_req->hi_rssi_scan_delay);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
wma_roam_scan_fill_ap_profile(wma_handle, pMac, roam_req, &ap_profile);
vos_status = wma_roam_scan_offload_ap_profile(wma_handle,
&ap_profile,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
vos_status = wma_roam_scan_offload_chan_list(wma_handle,
roam_req->ConnectedNetwork.ChannelCount,
&roam_req->ConnectedNetwork.ChannelCache[0],
roam_req->ChannelCacheType,
roam_req->sessionId);
if ((vos_status != VOS_STATUS_SUCCESS) &&
(vos_status != VOS_STATUS_E_EMPTY)) {
break;
}
wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, &scan_params);
vos_status = wma_roam_scan_offload_mode(wma_handle,
&scan_params,
roam_req,
mode,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
vos_status = wma_roam_scan_filter(wma_handle, roam_req);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Sending start for roam scan filter failed");
break;
}
break;
case ROAM_SCAN_OFFLOAD_STOP:
wma_handle->suitable_ap_hb_failure = FALSE;
if (wma_handle->roam_offload_enabled) {
wma_roam_scan_fill_scan_params(wma_handle, pMac,
NULL, &scan_params);
vos_status = wma_roam_scan_offload_mode(wma_handle,
&scan_params,
NULL,
WMI_ROAM_SCAN_MODE_NONE,
roam_req->sessionId);
}
/*
* If the STOP command is due to a disconnect, then
* send the filter command to clear all the filter
* entries. If it is roaming scenario, then do not
* send the cleared entries.
*/
if (!roam_req->middle_of_roaming) {
vos_status = wma_roam_scan_filter(wma_handle, roam_req);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Sending clear for roam scan filter failed");
break;
}
}
if (roam_req->reason == REASON_OS_REQUESTED_ROAMING_NOW) {
vos_msg_t vosMsg;
tSirRoamOffloadScanRsp *scan_offload_rsp;
scan_offload_rsp = vos_mem_malloc(sizeof(*scan_offload_rsp));
if (!scan_offload_rsp) {
WMA_LOGE("%s: Alloc failed for scan_offload_rsp", __func__);
vos_mem_free(roam_req);
return VOS_STATUS_E_NOMEM;
}
vosMsg.type = eWNI_SME_ROAM_SCAN_OFFLOAD_RSP;
scan_offload_rsp->sessionId = roam_req->sessionId;
scan_offload_rsp->reason = roam_req->reason;
vosMsg.bodyptr = scan_offload_rsp;
/*
* Since REASSOC request is processed in Roam_Scan_Offload_Rsp
* post a dummy rsp msg back to SME with proper reason code.
*/
if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME,
(vos_msg_t*)&vosMsg))
{
vos_mem_free(scan_offload_rsp);
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
"%s: Failed to post Scan Offload Rsp to UMAC",
__func__);
}
}
break;
case ROAM_SCAN_OFFLOAD_ABORT_SCAN:
/* If roam scan is running, stop that cycle.
* It will continue automatically on next trigger.
*/
vos_status = wma_roam_scan_offload_command(wma_handle,
WMI_ROAM_SCAN_STOP_CMD,
roam_req->sessionId);
break;
case ROAM_SCAN_OFFLOAD_RESTART:
/* Rome offload engine does not stop after any scan.
* If this command is sent because all preauth attempts failed
* and WMI_ROAM_REASON_SUITABLE_AP event was received earlier,
* now it is time to call it heartbeat failure.
*/
if ((roam_req->reason == REASON_PREAUTH_FAILED_FOR_ALL)
&& wma_handle->suitable_ap_hb_failure) {
WMA_LOGE("%s: Sending heartbeat failure after preauth failures",
__func__);
wma_beacon_miss_handler(wma_handle, roam_req->sessionId,
wma_handle->suitable_ap_hb_failure_rssi);
wma_handle->suitable_ap_hb_failure = FALSE;
}
break;
case ROAM_SCAN_OFFLOAD_UPDATE_CFG:
wma_handle->suitable_ap_hb_failure = FALSE;
wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, &scan_params);
vos_status = wma_roam_scan_offload_mode(wma_handle,
&scan_params,
roam_req,
WMI_ROAM_SCAN_MODE_NONE,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
if (roam_req->RoamScanOffloadEnabled == FALSE) {
break;
}
vos_status = wma_roam_scan_bmiss_cnt(wma_handle,
roam_req->RoamBmissFirstBcnt, roam_req->RoamBmissFinalBcnt,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
vos_status = wma_roam_scan_filter(wma_handle, roam_req);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Sending update for roam scan filter failed");
break;
}
/*
* Runtime (after association) changes to rssi thresholds and other parameters.
*/
vos_status = wma_roam_scan_offload_chan_list(wma_handle,
roam_req->ConnectedNetwork.ChannelCount,
&roam_req->ConnectedNetwork.ChannelCache[0],
roam_req->ChannelCacheType,
roam_req->sessionId);
/*
* Even though the channel list is empty, we can
* still go ahead and start Roaming.
*/
if ((vos_status != VOS_STATUS_SUCCESS) &&
(vos_status != VOS_STATUS_E_EMPTY)) {
break;
}
vos_status = wma_roam_scan_offload_rssi_thresh(wma_handle,
roam_req);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
if (roam_req->EmptyRefreshScanPeriod > 0) {
vos_status = wma_roam_scan_offload_scan_period(wma_handle,
roam_req->EmptyRefreshScanPeriod,
roam_req->EmptyRefreshScanPeriod * 3,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
mode = WMI_ROAM_SCAN_MODE_PERIODIC;
/* Don't use rssi triggered roam scans if external app
* is in control of channel list.
*/
if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) {
mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE;
}
} else {
mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE;
}
vos_status = wma_roam_scan_offload_rssi_change(wma_handle,
roam_req->sessionId,
roam_req->RoamRescanRssiDiff,
roam_req->RoamBeaconRssiWeight,
roam_req->hi_rssi_scan_delay);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
wma_roam_scan_fill_ap_profile(wma_handle, pMac, roam_req, &ap_profile);
vos_status = wma_roam_scan_offload_ap_profile(wma_handle,
&ap_profile,
roam_req->sessionId);
if (vos_status != VOS_STATUS_SUCCESS) {
break;
}
wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, &scan_params);
vos_status = wma_roam_scan_offload_mode(
wma_handle,
&scan_params,
roam_req,
mode,
roam_req->sessionId);
break;
default:
break;
}
vos_mem_free(roam_req);
return vos_status;
}
#ifdef FEATURE_WLAN_LPHB
/* function : wma_lphb_conf_hbenable
* Description : handles the enable command of LPHB configuration requests
* Args : wma_handle - WMA handle
* lphb_conf_req - configuration info
* by_user - whether this call is from user or cached resent
* Returns :
*/
VOS_STATUS wma_lphb_conf_hbenable(tp_wma_handle wma_handle,
tSirLPHBReq *lphb_conf_req,
v_BOOL_t by_user)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int status = 0;
tSirLPHBEnableStruct *ts_lphb_enable;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_hb_set_enable_cmd_fixed_param *hb_enable_fp;
int len = sizeof(wmi_hb_set_enable_cmd_fixed_param);
int i;
if (lphb_conf_req == NULL)
{
WMA_LOGE("%s : LPHB configuration is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
ts_lphb_enable = &(lphb_conf_req->params.lphbEnableReq);
WMA_LOGI("%s: WMA --> WMI_HB_SET_ENABLE enable=%d, item=%d, session=%d",
__func__,
ts_lphb_enable->enable,
ts_lphb_enable->item,
ts_lphb_enable->session);
if ((ts_lphb_enable->item != 1) && (ts_lphb_enable->item != 2)) {
WMA_LOGE("%s : LPHB configuration wrong item %d",
__func__,
ts_lphb_enable->item);
return VOS_STATUS_E_FAILURE;
}
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
hb_enable_fp = (wmi_hb_set_enable_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_enable_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_hb_set_enable_cmd_fixed_param));
/* fill in values */
hb_enable_fp->vdev_id = ts_lphb_enable->session;
hb_enable_fp->enable= ts_lphb_enable->enable;
hb_enable_fp->item = ts_lphb_enable->item;
hb_enable_fp->session = ts_lphb_enable->session;
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_HB_SET_ENABLE_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_ENABLE returned Error %d",
status);
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
if (by_user) {
/* target already configured, now cache command status */
if (ts_lphb_enable->enable) {
i = ts_lphb_enable->item-1;
wma_handle->wow.lphb_cache[i].cmd
= LPHB_SET_EN_PARAMS_INDID;
wma_handle->wow.lphb_cache[i].params.lphbEnableReq.enable
= ts_lphb_enable->enable;
wma_handle->wow.lphb_cache[i].params.lphbEnableReq.item
= ts_lphb_enable->item;
wma_handle->wow.lphb_cache[i].params.lphbEnableReq.session
= ts_lphb_enable->session;
WMA_LOGI("%s: cached LPHB status in WMA context for item %d",
__func__, i);
} else {
vos_mem_zero((void *)&wma_handle->wow.lphb_cache,
sizeof(wma_handle->wow.lphb_cache));
WMA_LOGI("%s: cleared all cached LPHB status in WMA context",
__func__);
}
}
return VOS_STATUS_SUCCESS;
error:
return vos_status;
}
/* function : wma_lphb_conf_tcp_params
* Description : handles the tcp params command of LPHB configuration requests
* Args :
* Returns :
*/
VOS_STATUS wma_lphb_conf_tcp_params(tp_wma_handle wma_handle,
tSirLPHBReq *lphb_conf_req)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int status = 0;
tSirLPHBTcpParamStruct *ts_lphb_tcp_param;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_hb_set_tcp_params_cmd_fixed_param *hb_tcp_params_fp;
int len = sizeof(wmi_hb_set_tcp_params_cmd_fixed_param);
if (lphb_conf_req == NULL)
{
WMA_LOGE("%s : LPHB configuration is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
ts_lphb_tcp_param = &(lphb_conf_req->params.lphbTcpParamReq);
WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PARAMS srv_ip=%08x, dev_ip=%08x, src_port=%d, "
"dst_port=%d, timeout=%d, session=%d, gateway_mac=%02x:%02x:%02x:%02x:%02x:%02x, "
"timePeriodSec=%d, tcpSn=%d",
__func__,
ts_lphb_tcp_param->srv_ip, ts_lphb_tcp_param->dev_ip,
ts_lphb_tcp_param->src_port, ts_lphb_tcp_param->dst_port,
ts_lphb_tcp_param->timeout, ts_lphb_tcp_param->session,
ts_lphb_tcp_param->gateway_mac[0],
ts_lphb_tcp_param->gateway_mac[1],
ts_lphb_tcp_param->gateway_mac[2],
ts_lphb_tcp_param->gateway_mac[3],
ts_lphb_tcp_param->gateway_mac[4],
ts_lphb_tcp_param->gateway_mac[5],
ts_lphb_tcp_param->timePeriodSec, ts_lphb_tcp_param->tcpSn);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
hb_tcp_params_fp = (wmi_hb_set_tcp_params_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_tcp_params_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_hb_set_tcp_params_cmd_fixed_param));
/* fill in values */
hb_tcp_params_fp->vdev_id = ts_lphb_tcp_param->session;
hb_tcp_params_fp->srv_ip = ts_lphb_tcp_param->srv_ip;
hb_tcp_params_fp->dev_ip = ts_lphb_tcp_param->dev_ip;
hb_tcp_params_fp->seq = ts_lphb_tcp_param->tcpSn;
hb_tcp_params_fp->src_port = ts_lphb_tcp_param->src_port;
hb_tcp_params_fp->dst_port = ts_lphb_tcp_param->dst_port;
hb_tcp_params_fp->interval = ts_lphb_tcp_param->timePeriodSec;
hb_tcp_params_fp->timeout = ts_lphb_tcp_param->timeout;
hb_tcp_params_fp->session = ts_lphb_tcp_param->session;
WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_tcp_param->gateway_mac, &hb_tcp_params_fp->gateway_mac);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_HB_SET_TCP_PARAMS_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PARAMS returned Error %d",
status);
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
return VOS_STATUS_SUCCESS;
error:
return vos_status;
}
/* function : wma_lphb_conf_tcp_pkt_filter
* Description : handles the tcp packet filter command of LPHB configuration requests
* Args :
* Returns :
*/
VOS_STATUS wma_lphb_conf_tcp_pkt_filter(tp_wma_handle wma_handle,
tSirLPHBReq *lphb_conf_req)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int status = 0;
tSirLPHBTcpFilterStruct *ts_lphb_tcp_filter;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *hb_tcp_filter_fp;
int len = sizeof(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param);
if (lphb_conf_req == NULL)
{
WMA_LOGE("%s : LPHB configuration is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
ts_lphb_tcp_filter = &(lphb_conf_req->params.lphbTcpFilterReq);
WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PKT_FILTER length=%d, offset=%d, session=%d, "
"filter=%2x:%2x:%2x:%2x:%2x:%2x ...",
__func__,
ts_lphb_tcp_filter->length,
ts_lphb_tcp_filter->offset,
ts_lphb_tcp_filter->session,
ts_lphb_tcp_filter->filter[0],
ts_lphb_tcp_filter->filter[1],
ts_lphb_tcp_filter->filter[2],
ts_lphb_tcp_filter->filter[3],
ts_lphb_tcp_filter->filter[4],
ts_lphb_tcp_filter->filter[5]);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
hb_tcp_filter_fp = (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_tcp_filter_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_hb_set_tcp_pkt_filter_cmd_fixed_param));
/* fill in values */
hb_tcp_filter_fp->vdev_id = ts_lphb_tcp_filter->session;
hb_tcp_filter_fp->length = ts_lphb_tcp_filter->length;
hb_tcp_filter_fp->offset = ts_lphb_tcp_filter->offset;
hb_tcp_filter_fp->session = ts_lphb_tcp_filter->session;
memcpy((void *) &hb_tcp_filter_fp->filter, (void *) &ts_lphb_tcp_filter->filter,
WMI_WLAN_HB_MAX_FILTER_SIZE);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_HB_SET_TCP_PKT_FILTER_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PKT_FILTER returned Error %d",
status);
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
return VOS_STATUS_SUCCESS;
error:
return vos_status;
}
/* function : wma_lphb_conf_udp_params
* Description : handles the udp params command of LPHB configuration requests
* Args :
* Returns :
*/
VOS_STATUS wma_lphb_conf_udp_params(tp_wma_handle wma_handle,
tSirLPHBReq *lphb_conf_req)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int status = 0;
tSirLPHBUdpParamStruct *ts_lphb_udp_param;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_hb_set_udp_params_cmd_fixed_param *hb_udp_params_fp;
int len = sizeof(wmi_hb_set_udp_params_cmd_fixed_param);
if (lphb_conf_req == NULL)
{
WMA_LOGE("%s : LPHB configuration is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
ts_lphb_udp_param = &(lphb_conf_req->params.lphbUdpParamReq);
WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PARAMS srv_ip=%d, dev_ip=%d, src_port=%d, "
"dst_port=%d, interval=%d, timeout=%d, session=%d, "
"gateway_mac=%2x:%2x:%2x:%2x:%2x:%2x",
__func__,
ts_lphb_udp_param->srv_ip, ts_lphb_udp_param->dev_ip,
ts_lphb_udp_param->src_port, ts_lphb_udp_param->dst_port,
ts_lphb_udp_param->interval, ts_lphb_udp_param->timeout, ts_lphb_udp_param->session,
ts_lphb_udp_param->gateway_mac[0],
ts_lphb_udp_param->gateway_mac[1],
ts_lphb_udp_param->gateway_mac[2],
ts_lphb_udp_param->gateway_mac[3],
ts_lphb_udp_param->gateway_mac[4],
ts_lphb_udp_param->gateway_mac[5]);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
hb_udp_params_fp = (wmi_hb_set_udp_params_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_udp_params_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_hb_set_udp_params_cmd_fixed_param));
/* fill in values */
hb_udp_params_fp->vdev_id = ts_lphb_udp_param->session;
hb_udp_params_fp->srv_ip = ts_lphb_udp_param->srv_ip;
hb_udp_params_fp->dev_ip = ts_lphb_udp_param->dev_ip;
hb_udp_params_fp->src_port = ts_lphb_udp_param->src_port;
hb_udp_params_fp->dst_port = ts_lphb_udp_param->dst_port;
hb_udp_params_fp->interval = ts_lphb_udp_param->interval;
hb_udp_params_fp->timeout = ts_lphb_udp_param->timeout;
hb_udp_params_fp->session = ts_lphb_udp_param->session;
WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_udp_param->gateway_mac, &hb_udp_params_fp->gateway_mac);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_HB_SET_UDP_PARAMS_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PARAMS returned Error %d",
status);
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
return VOS_STATUS_SUCCESS;
error:
return vos_status;
}
/* function : wma_lphb_conf_udp_pkt_filter
* Description : handles the udp packet filter command of LPHB configuration requests
* Args :
* Returns :
*/
VOS_STATUS wma_lphb_conf_udp_pkt_filter(tp_wma_handle wma_handle,
tSirLPHBReq *lphb_conf_req)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int status = 0;
tSirLPHBUdpFilterStruct *ts_lphb_udp_filter;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_hb_set_udp_pkt_filter_cmd_fixed_param *hb_udp_filter_fp;
int len = sizeof(wmi_hb_set_udp_pkt_filter_cmd_fixed_param);
if (lphb_conf_req == NULL)
{
WMA_LOGE("%s : LPHB configuration is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
ts_lphb_udp_filter = &(lphb_conf_req->params.lphbUdpFilterReq);
WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PKT_FILTER length=%d, offset=%d, session=%d, "
"filter=%2x:%2x:%2x:%2x:%2x:%2x ...",
__func__,
ts_lphb_udp_filter->length,
ts_lphb_udp_filter->offset,
ts_lphb_udp_filter->session,
ts_lphb_udp_filter->filter[0],
ts_lphb_udp_filter->filter[1],
ts_lphb_udp_filter->filter[2],
ts_lphb_udp_filter->filter[3],
ts_lphb_udp_filter->filter[4],
ts_lphb_udp_filter->filter[5]);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
hb_udp_filter_fp = (wmi_hb_set_udp_pkt_filter_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&hb_udp_filter_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_hb_set_udp_pkt_filter_cmd_fixed_param));
/* fill in values */
hb_udp_filter_fp->vdev_id = ts_lphb_udp_filter->session;
hb_udp_filter_fp->length = ts_lphb_udp_filter->length;
hb_udp_filter_fp->offset = ts_lphb_udp_filter->offset;
hb_udp_filter_fp->session = ts_lphb_udp_filter->session;
memcpy((void *) &hb_udp_filter_fp->filter, (void *) &ts_lphb_udp_filter->filter,
WMI_WLAN_HB_MAX_FILTER_SIZE);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_HB_SET_UDP_PKT_FILTER_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PKT_FILTER returned Error %d",
status);
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
goto error;
}
return VOS_STATUS_SUCCESS;
error:
return vos_status;
}
/* function : wma_process_lphb_conf_req
* Description : handles LPHB configuration requests
* Args :
* Returns :
*/
VOS_STATUS wma_process_lphb_conf_req(tp_wma_handle wma_handle,
tSirLPHBReq *lphb_conf_req)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
if (lphb_conf_req == NULL)
{
WMA_LOGE("%s : LPHB configuration is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGI("%s : LPHB configuration cmd id is %d", __func__,
lphb_conf_req->cmd);
switch (lphb_conf_req->cmd) {
case LPHB_SET_EN_PARAMS_INDID:
vos_status = wma_lphb_conf_hbenable(wma_handle,
lphb_conf_req, TRUE);
break;
case LPHB_SET_TCP_PARAMS_INDID:
vos_status = wma_lphb_conf_tcp_params(wma_handle,
lphb_conf_req);
break;
case LPHB_SET_TCP_PKT_FILTER_INDID:
vos_status = wma_lphb_conf_tcp_pkt_filter(wma_handle,
lphb_conf_req);
break;
case LPHB_SET_UDP_PARAMS_INDID:
vos_status = wma_lphb_conf_udp_params(wma_handle,
lphb_conf_req);
break;
case LPHB_SET_UDP_PKT_FILTER_INDID:
vos_status = wma_lphb_conf_udp_pkt_filter(wma_handle,
lphb_conf_req);
break;
case LPHB_SET_NETWORK_INFO_INDID:
default:
break;
}
vos_mem_free(lphb_conf_req);
return vos_status;
}
#endif
VOS_STATUS wma_process_dhcp_ind(tp_wma_handle wma_handle,
tAniDHCPInd *ta_dhcp_ind)
{
uint8_t vdev_id;
int status = 0;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_peer_set_param_cmd_fixed_param *peer_set_param_fp;
int len = sizeof(wmi_peer_set_param_cmd_fixed_param);
if (!ta_dhcp_ind)
{
WMA_LOGE("%s : DHCP indication is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
if (!wma_find_vdev_by_addr(wma_handle, ta_dhcp_ind->adapterMacAddr,
&vdev_id))
{
WMA_LOGE("%s: Failed to find vdev id for DHCP indication",
__func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGI("%s: WMA --> WMI_PEER_SET_PARAM triggered by DHCP, "
"msgType=%s,"
"device_mode=%d, macAddr=" MAC_ADDRESS_STR,
__func__,
ta_dhcp_ind->msgType==WDA_DHCP_START_IND?
"WDA_DHCP_START_IND":"WDA_DHCP_STOP_IND",
ta_dhcp_ind->device_mode,
MAC_ADDR_ARRAY(ta_dhcp_ind->peerMacAddr));
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
peer_set_param_fp = (wmi_peer_set_param_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&peer_set_param_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_peer_set_param_cmd_fixed_param));
/* fill in values */
peer_set_param_fp->vdev_id = vdev_id;
peer_set_param_fp->param_id = WMI_PEER_CRIT_PROTO_HINT_ENABLED;
if (WDA_DHCP_START_IND == ta_dhcp_ind->msgType)
peer_set_param_fp->param_value = 1;
else
peer_set_param_fp->param_value = 0;
WMI_CHAR_ARRAY_TO_MAC_ADDR(ta_dhcp_ind->peerMacAddr,
&peer_set_param_fp->peer_macaddr);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_PEER_SET_PARAM_CMDID);
if (status != EOK) {
WMA_LOGE("%s: wmi_unified_cmd_send WMI_PEER_SET_PARAM_CMD"
" returned Error %d",
__func__, status);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_chan_to_mode() - calculate phy mode corresponding to channel
* @chan: channel
* @chan_offset: secondary channel offset
* @vht_capable: If vht capable
* @dot11_mode: dot11 mode
*
* calculate phy mode corresponding to channel, dot11 mode, vht capability
* and secondary channel offset.
*
* Return: WLAN_PHY_MODE
*/
WLAN_PHY_MODE wma_chan_to_mode(uint8_t chan, ePhyChanBondState chan_offset,
uint8_t vht_capable, uint8_t dot11_mode)
{
WLAN_PHY_MODE phymode = MODE_UNKNOWN;
/* 2.4 GHz band */
if ((chan >= WMA_11G_CHANNEL_BEGIN) && (chan <= WMA_11G_CHANNEL_END)) {
switch (chan_offset) {
case PHY_SINGLE_CHANNEL_CENTERED:
/* In case of no channel bonding, use dot11_mode
* to set phy mode
*/
switch (dot11_mode) {
case WNI_CFG_DOT11_MODE_11A:
phymode = MODE_11A;
break;
case WNI_CFG_DOT11_MODE_11B:
phymode = MODE_11B;
break;
case WNI_CFG_DOT11_MODE_11G:
phymode = MODE_11G;
break;
case WNI_CFG_DOT11_MODE_11G_ONLY:
phymode = MODE_11GONLY;
break;
default:
/* Configure MODE_11NG_HT20 for
* self vdev(for vht too)
*/
phymode = MODE_11NG_HT20;
break;
}
break;
case PHY_DOUBLE_CHANNEL_LOW_PRIMARY:
case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY:
phymode = vht_capable ? MODE_11AC_VHT40_2G :MODE_11NG_HT40;
break;
default:
break;
}
}
/* 5 GHz band */
if ((chan >= WMA_11A_CHANNEL_BEGIN) && (chan <= WMA_11A_CHANNEL_END)) {
switch (chan_offset) {
case PHY_SINGLE_CHANNEL_CENTERED:
if (dot11_mode == WNI_CFG_DOT11_MODE_11A)
phymode = MODE_11A;
else
phymode = vht_capable ? MODE_11AC_VHT20 :
MODE_11NA_HT20;
break;
case PHY_DOUBLE_CHANNEL_LOW_PRIMARY:
case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY:
phymode = vht_capable ? MODE_11AC_VHT40 :MODE_11NA_HT40;
break;
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW:
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH:
phymode = MODE_11AC_VHT80;
break;
default:
break;
}
}
/* 5.9 GHz Band */
if ((chan >= WMA_11P_CHANNEL_BEGIN) && (chan <= WMA_11P_CHANNEL_END)) {
/* Only Legacy Modulation Schemes are supported */
phymode = MODE_11A;
}
WMA_LOGD("%s: phymode %d channel %d offset %d vht_capable %d "
"dot11_mode %d", __func__, phymode, chan,
chan_offset, vht_capable, dot11_mode);
return phymode;
}
tANI_U8 wma_getCenterChannel(tANI_U8 chan, tANI_U8 chan_offset)
{
tANI_U8 band_center_chan = 0;
if ((chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED) ||
(chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW))
band_center_chan = chan + 2;
else if (chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW)
band_center_chan = chan + 6;
else if ((chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH) ||
(chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED))
band_center_chan = chan - 2;
else if (chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH)
band_center_chan = chan - 6;
return band_center_chan;
}
/**
* wma_switch_channel() - WMA api to switch channel dynamically
* @wma: Pointer of WMA context
* @req: Pointer vdev_start having channel switch info.
*
* Return: 0 for success, otherwise appropriate error code
*/
VOS_STATUS wma_switch_channel(tp_wma_handle wma, struct wma_vdev_start_req *req)
{
wmi_buf_t buf;
wmi_channel *cmd;
int32_t len, ret;
WLAN_PHY_MODE chanmode;
struct wma_txrx_node *intr = wma->interfaces;
tpAniSirGlobal pmac;
uint8_t *buf_ptr;
pmac = vos_get_context(VOS_MODULE_ID_PE, wma->vos_context);
if (pmac == NULL) {
WMA_LOGE("%s: vdev start failed as pmac is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_channel *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_channel,
WMITLV_GET_STRUCT_TLVLEN(wmi_channel));
/* Fill channel info */
cmd->mhz = vos_chan_to_freq(req->chan);
chanmode = wma_chan_to_mode(req->chan, req->chan_offset,
req->vht_capable, req->dot11_mode);
intr[req->vdev_id].chanmode = chanmode; /* save channel mode */
intr[req->vdev_id].ht_capable = req->ht_capable;
intr[req->vdev_id].vht_capable = req->vht_capable;
intr[req->vdev_id].config.gtx_info.gtxRTMask[0] =
CFG_TGT_DEFAULT_GTX_HT_MASK;
intr[req->vdev_id].config.gtx_info.gtxRTMask[1] =
CFG_TGT_DEFAULT_GTX_VHT_MASK;
if (wlan_cfgGetInt(pmac, WNI_CFG_TGT_GTX_USR_CFG,
&intr[req->vdev_id].config.gtx_info.gtxUsrcfg)
!= eSIR_SUCCESS) {
WMA_LOGE("Failed to read target gtx user config");
intr[req->vdev_id].config.gtx_info.gtxUsrcfg =
WNI_CFG_TGT_GTX_USR_CFG_STADEF;
}
intr[req->vdev_id].config.gtx_info.gtxPERThreshold =
CFG_TGT_DEFAULT_GTX_PER_THRESHOLD;
intr[req->vdev_id].config.gtx_info.gtxPERMargin =
CFG_TGT_DEFAULT_GTX_PER_MARGIN;
intr[req->vdev_id].config.gtx_info.gtxTPCstep =
CFG_TGT_DEFAULT_GTX_TPC_STEP;
intr[req->vdev_id].config.gtx_info.gtxTPCMin =
CFG_TGT_DEFAULT_GTX_TPC_MIN;
intr[req->vdev_id].config.gtx_info.gtxBWMask =
CFG_TGT_DEFAULT_GTX_BW_MASK;
intr[req->vdev_id].mhz = cmd->mhz;
intr[req->vdev_id].channelwidth = req->channelwidth;
WMI_SET_CHANNEL_MODE(cmd, chanmode);
cmd->band_center_freq1 = cmd->mhz;
if (chanmode == MODE_11AC_VHT80)
cmd->band_center_freq1 = vos_chan_to_freq(wma_getCenterChannel
(req->chan, req->chan_offset));
if ((chanmode == MODE_11NA_HT40) || (chanmode == MODE_11NG_HT40) ||
(chanmode == MODE_11AC_VHT40) || (chanmode == MODE_11AC_VHT40_2G)) {
if (req->chan_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
cmd->band_center_freq1 += 10;
else
cmd->band_center_freq1 -= 10;
}
cmd->band_center_freq2 = 0;
/* Set half or quarter rate WMI flags */
if (req->is_half_rate)
WMI_SET_CHANNEL_FLAG(cmd, WMI_CHAN_FLAG_HALF_RATE);
else if (req->is_quarter_rate)
WMI_SET_CHANNEL_FLAG(cmd, WMI_CHAN_FLAG_QUARTER_RATE);
WMA_LOGE("switch chan width: quarterrate_flag: %d, halfrate_flag: %d",
req->is_quarter_rate, req->is_half_rate);
/* Find out min, max and regulatory power levels */
WMI_SET_CHANNEL_REG_POWER(cmd, req->max_txpow);
WMI_SET_CHANNEL_MAX_TX_POWER(cmd, req->max_txpow);
WMA_LOGD("%s: freq %d channel %d chanmode %d center_chan %d center_freq2 %d reg_info_1: 0x%x reg_info_2: 0x%x, req->max_txpow: 0x%x",
__func__, cmd->mhz, req->chan, chanmode,
cmd->band_center_freq1, cmd->band_center_freq2,
cmd->reg_info_1, cmd->reg_info_2, req->max_txpow);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PDEV_SET_CHANNEL_CMDID);
if (ret < 0) {
WMA_LOGP("%s: Failed to send vdev start command", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
uint32_t wma_get_bcn_rate_code(uint16_t rate)
{
/* rate in multiples of 100 Kbps */
switch (rate) {
case WMA_BEACON_TX_RATE_1_M:
return WMA_BEACON_TX_RATE_HW_CODE_1_M;
case WMA_BEACON_TX_RATE_2_M:
return WMA_BEACON_TX_RATE_HW_CODE_2_M;
case WMA_BEACON_TX_RATE_5_5_M:
return WMA_BEACON_TX_RATE_HW_CODE_5_5_M;
case WMA_BEACON_TX_RATE_11_M:
return WMA_BEACON_TX_RATE_HW_CODE_11M;
case WMA_BEACON_TX_RATE_6_M:
return WMA_BEACON_TX_RATE_HW_CODE_6_M;
case WMA_BEACON_TX_RATE_9_M:
return WMA_BEACON_TX_RATE_HW_CODE_9_M;
case WMA_BEACON_TX_RATE_12_M:
return WMA_BEACON_TX_RATE_HW_CODE_12_M;
case WMA_BEACON_TX_RATE_18_M:
return WMA_BEACON_TX_RATE_HW_CODE_18_M;
case WMA_BEACON_TX_RATE_24_M:
return WMA_BEACON_TX_RATE_HW_CODE_24_M;
case WMA_BEACON_TX_RATE_36_M:
return WMA_BEACON_TX_RATE_HW_CODE_36_M;
case WMA_BEACON_TX_RATE_48_M:
return WMA_BEACON_TX_RATE_HW_CODE_48_M;
case WMA_BEACON_TX_RATE_54_M:
return WMA_BEACON_TX_RATE_HW_CODE_54_M;
default:
return WMA_BEACON_TX_RATE_HW_CODE_1_M;
}
}
VOS_STATUS wma_vdev_start(tp_wma_handle wma,
struct wma_vdev_start_req *req, v_BOOL_t isRestart)
{
wmi_vdev_start_request_cmd_fixed_param *cmd;
wmi_buf_t buf;
wmi_channel *chan;
int32_t len, ret;
WLAN_PHY_MODE chanmode;
u_int8_t *buf_ptr;
struct wma_txrx_node *intr = wma->interfaces;
tpAniSirGlobal pmac = NULL;
struct ath_dfs *dfs;
ol_txrx_pdev_handle pdev = NULL;
pmac = (tpAniSirGlobal)
vos_get_context(VOS_MODULE_ID_PE, wma->vos_context);
if (pmac == NULL) {
WMA_LOGE("%s: vdev start failed as pmac is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (pdev == NULL) {
WMA_LOGE("%s: vdev start failed as pdev is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
dfs = (struct ath_dfs *)wma->dfs_ic->ic_dfs;
WMA_LOGD("%s: Enter isRestart=%d vdev=%d", __func__, isRestart,req->vdev_id);
len = sizeof(*cmd) + sizeof(wmi_channel) +
WMI_TLV_HDR_SIZE;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_vdev_start_request_cmd_fixed_param *) buf_ptr;
chan = (wmi_channel *) (buf_ptr + sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_start_request_cmd_fixed_param));
WMITLV_SET_HDR(&chan->tlv_header,
WMITLV_TAG_STRUC_wmi_channel,
WMITLV_GET_STRUCT_TLVLEN(wmi_channel));
cmd->vdev_id = req->vdev_id;
/* Fill channel info */
chan->mhz = vos_chan_to_freq(req->chan);
chanmode = wma_chan_to_mode(req->chan, req->chan_offset,
req->vht_capable, req->dot11_mode);
intr[cmd->vdev_id].chanmode = chanmode; /* save channel mode */
intr[cmd->vdev_id].ht_capable = req->ht_capable;
intr[cmd->vdev_id].vht_capable = req->vht_capable;
intr[cmd->vdev_id].config.gtx_info.gtxRTMask[0] = CFG_TGT_DEFAULT_GTX_HT_MASK;
intr[cmd->vdev_id].config.gtx_info.gtxRTMask[1] = CFG_TGT_DEFAULT_GTX_VHT_MASK;
if (wlan_cfgGetInt(pmac, WNI_CFG_TGT_GTX_USR_CFG,
&intr[cmd->vdev_id].config.gtx_info.gtxUsrcfg)
!= eSIR_SUCCESS) {
WMA_LOGE("Failed to read target gtx user config");
intr[cmd->vdev_id].config.gtx_info.gtxUsrcfg =
WNI_CFG_TGT_GTX_USR_CFG_STADEF;
}
intr[cmd->vdev_id].config.gtx_info.gtxPERThreshold = CFG_TGT_DEFAULT_GTX_PER_THRESHOLD;
intr[cmd->vdev_id].config.gtx_info.gtxPERMargin = CFG_TGT_DEFAULT_GTX_PER_MARGIN;
intr[cmd->vdev_id].config.gtx_info.gtxTPCstep = CFG_TGT_DEFAULT_GTX_TPC_STEP;
intr[cmd->vdev_id].config.gtx_info.gtxTPCMin = CFG_TGT_DEFAULT_GTX_TPC_MIN;
intr[cmd->vdev_id].config.gtx_info.gtxBWMask = CFG_TGT_DEFAULT_GTX_BW_MASK;
intr[cmd->vdev_id].mhz = chan->mhz;
intr[req->vdev_id].channelwidth = req->channelwidth;
WMI_SET_CHANNEL_MODE(chan, chanmode);
chan->band_center_freq1 = chan->mhz;
if (chanmode == MODE_11AC_VHT80)
chan->band_center_freq1 = vos_chan_to_freq(wma_getCenterChannel
(req->chan, req->chan_offset));
if ((chanmode == MODE_11NA_HT40) || (chanmode == MODE_11NG_HT40) ||
(chanmode == MODE_11AC_VHT40) || (chanmode == MODE_11AC_VHT40_2G)) {
if (req->chan_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
chan->band_center_freq1 += 10;
else
chan->band_center_freq1 -= 10;
}
chan->band_center_freq2 = 0;
/* Set half or quarter rate WMI flags */
if (req->is_half_rate) {
WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE);
} else if (req->is_quarter_rate) {
WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE);
}
WMA_LOGE("BSS chan width: quarterrate_flag: %d, halfrate_flag: %d",
req->is_quarter_rate, req->is_half_rate);
/*
* If the channel has DFS set, flip on radar reporting.
*
* It may be that this should only be done for IBSS/hostap operation
* as this flag may be interpreted (at some point in the future)
* by the firmware as "oh, and please do radar DETECTION."
*
* If that is ever the case we would insert the decision whether to
* enable the firmware flag here.
*/
/*
* If the Channel is DFS,
* set the WMI_CHAN_FLAG_DFS flag
*/
if ((VOS_MONITOR_MODE != vos_get_conparam()) && req->is_dfs) {
WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_DFS);
cmd->disable_hw_ack = VOS_TRUE;
req->dfs_pri_multiplier = wma->dfs_pri_multiplier;
/*
* Configure the current operating channel
* to DFS module only if the device operating
* mode is AP.
* Enable/Disable Phyerr filtering offload
* depending on dfs_phyerr_filter_offload
* flag status as set in ini for SAP mode.
* Currently, only AP supports DFS master
* mode operation on DFS channels, P2P-GO
* does not support operation on DFS Channels.
*/
if (wma_is_vdev_in_ap_mode(wma, cmd->vdev_id) == true) {
/*
* If DFS regulatory domain is invalid,
* then, DFS radar filters intialization
* will fail. So, do not configure the
* channel in to DFS modlue, do not
* indicate if phyerror filtering offload
* is enabled or not to the firmware, simply
* fail the VDEV start on the DFS channel
* early on, to protect the DFS module from
* processing phyerrors without being intialized.
*/
if (DFS_UNINIT_DOMAIN == wma->dfs_ic->current_dfs_regdomain) {
WMA_LOGE("%s[%d]:DFS Configured with Invalid regdomain"
" Failed to send VDEV START command",
__func__, __LINE__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
adf_os_spin_lock_bh(&wma->dfs_ic->chan_lock);
if (isRestart)
wma->dfs_ic->disable_phy_err_processing = true;
/* provide the current channel to DFS */
wma->dfs_ic->ic_curchan =
wma_dfs_configure_channel(wma->dfs_ic,chan,chanmode,req);
adf_os_spin_unlock_bh(&wma->dfs_ic->chan_lock);
wma_unified_dfs_phyerr_filter_offload_enable(wma);
dfs->disable_dfs_ch_switch =
pmac->sap.SapDfsInfo.disable_dfs_ch_switch;
dfs->dfs_enable_radar_war =
pmac->sap.SapDfsInfo.sap_enable_radar_war;
}
}
cmd->beacon_interval = req->beacon_intval;
cmd->dtim_period = req->dtim_period;
cmd->flags &= ~WMI_UNIFIED_VDEV_START_BCN_TX_RATE_PRESENT;
if (req->beacon_tx_rate) {
WMA_LOGI("%s: beacon_tx_rate present. beacon tx rate [%hu * 100 Kbps]",
__func__, req->beacon_tx_rate);
cmd->flags |= WMI_UNIFIED_VDEV_START_BCN_TX_RATE_PRESENT;
/* beacon_tx_rate is in multiples of 100 Kbps. Convert the
* data rate to hw rate code */
cmd->bcn_tx_rate = wma_get_bcn_rate_code(req->beacon_tx_rate);
WMA_LOGI("bcn rate code %02x", cmd->bcn_tx_rate);
}
/* FIXME: Find out min, max and regulatory power levels */
WMI_SET_CHANNEL_REG_POWER(chan, req->max_txpow);
WMI_SET_CHANNEL_MAX_TX_POWER(chan, req->max_txpow);
/* TODO: Handle regulatory class, max antenna */
if (!isRestart) {
cmd->beacon_interval = req->beacon_intval;
cmd->dtim_period = req->dtim_period;
/* Copy the SSID */
if (req->ssid.length) {
if (req->ssid.length < sizeof(cmd->ssid.ssid))
cmd->ssid.ssid_len = req->ssid.length;
else
cmd->ssid.ssid_len = sizeof(cmd->ssid.ssid);
vos_mem_copy(cmd->ssid.ssid, req->ssid.ssId,
cmd->ssid.ssid_len);
}
if (req->hidden_ssid)
cmd->flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID;
if (req->pmf_enabled)
cmd->flags |= WMI_UNIFIED_VDEV_START_PMF_ENABLED;
}
cmd->num_noa_descriptors = 0;
buf_ptr = (u_int8_t *)(((uintptr_t) cmd) + sizeof(*cmd) +
sizeof(wmi_channel));
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
cmd->num_noa_descriptors *
sizeof(wmi_p2p_noa_descriptor));
WMA_LOGD("%s: vdev_id %d freq %d channel %d chanmode %d is_dfs %d "
"beacon interval %d dtim %d center_chan %d center_freq2 %d "
"reg_info_1: 0x%x reg_info_2: 0x%x, req->max_txpow: 0x%x",
__func__, req->vdev_id, chan->mhz, req->chan, chanmode, req->is_dfs,
req->beacon_intval, cmd->dtim_period, chan->band_center_freq1,
chan->band_center_freq2, chan->reg_info_1, chan->reg_info_2,
req->max_txpow);
/* Store vdev params in SAP mode which can be used in vdev restart */
if (intr[req->vdev_id].type == WMI_VDEV_TYPE_AP &&
intr[req->vdev_id].sub_type == 0) {
intr[req->vdev_id].vdev_restart_params.vdev_id = req->vdev_id;
intr[req->vdev_id].vdev_restart_params.ssid.ssid_len = cmd->ssid.ssid_len;
vos_mem_copy(intr[req->vdev_id].vdev_restart_params.ssid.ssid, cmd->ssid.ssid,
cmd->ssid.ssid_len);
intr[req->vdev_id].vdev_restart_params.flags = cmd->flags;
intr[req->vdev_id].vdev_restart_params.requestor_id = cmd->requestor_id;
intr[req->vdev_id].vdev_restart_params.disable_hw_ack = cmd->disable_hw_ack;
intr[req->vdev_id].vdev_restart_params.chan.mhz = chan->mhz;
intr[req->vdev_id].vdev_restart_params.chan.band_center_freq1 = chan->band_center_freq1;
intr[req->vdev_id].vdev_restart_params.chan.band_center_freq2 = chan->band_center_freq1;
intr[req->vdev_id].vdev_restart_params.chan.info = chan->info;
intr[req->vdev_id].vdev_restart_params.chan.reg_info_1 = chan->reg_info_1;
intr[req->vdev_id].vdev_restart_params.chan.reg_info_2 = chan->reg_info_2;
}
if (isRestart) {
/*
* Marking the VDEV UP STATUS to FALSE
* since, VDEV RESTART will do a VDEV DOWN
* in the firmware.
*/
intr[cmd->vdev_id].vdev_up = FALSE;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_RESTART_REQUEST_CMDID);
} else {
/*
*Need to put other vdevs to pause to avoid current connection
*credit starvation.
*/
if (wma_is_mcc_starting(wma, chan->mhz)) {
WMA_LOGD("%s, vdev_id: %d, pasue other VDEVs when MCC on",
__func__, cmd->vdev_id);
wdi_in_pdev_pause_other_vdev(pdev,
OL_TXQ_PAUSE_REASON_MCC_VDEV_START,
req->vdev_id);
wma->pause_other_vdev_on_mcc_start = true;
}
WMA_LOGD("%s, vdev_id: %d, unpausing tx_ll_queue at VDEV_START",
__func__, cmd->vdev_id);
wdi_in_vdev_unpause(wma->interfaces[cmd->vdev_id].handle,
0xffffffff);
wma->interfaces[cmd->vdev_id].pause_bitmap = 0;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_START_REQUEST_CMDID);
}
if (ret < 0) {
WMA_LOGP("%s: Failed to send vdev start command", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
void wma_vdev_resp_timer(void *data)
{
tp_wma_handle wma;
struct wma_target_req *tgt_req = (struct wma_target_req *)data;
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
ol_txrx_peer_handle peer;
ol_txrx_pdev_handle pdev;
u_int8_t peer_id;
struct wma_target_req *msg;
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
tpAniSirGlobal mac_ctx = NULL;
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
wma = (tp_wma_handle) vos_get_context(VOS_MODULE_ID_WDA, vos_context);
if (NULL == wma) {
WMA_LOGE("%s: Failed to get wma", __func__);
return;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
vos_timer_stop(&tgt_req->event_timeout);
goto free_tgt_req;
}
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
mac_ctx = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == mac_ctx) {
WMA_LOGE("%s: Failed to get mac_ctx", __func__);
vos_timer_stop(&tgt_req->event_timeout);
goto free_tgt_req;
}
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
WMA_LOGA("%s: request %d is timed out for vdev_id - %d", __func__,
tgt_req->msg_type, tgt_req->vdev_id);
msg = wma_find_vdev_req(wma, tgt_req->vdev_id, tgt_req->type);
if (!msg) {
WMA_LOGE("%s: Failed to lookup request message - %d",
__func__, tgt_req->msg_type);
return;
}
if (tgt_req->msg_type == WDA_CHNL_SWITCH_REQ) {
tpSwitchChannelParams params =
(tpSwitchChannelParams)tgt_req->user_data;
params->status = VOS_STATUS_E_TIMEOUT;
WMA_LOGA("%s: WDA_SWITCH_CHANNEL_REQ timedout", __func__);
wma_send_msg(wma, WDA_SWITCH_CHANNEL_RSP, (void *)params, 0);
wma->roam_preauth_chan_context = NULL;
adf_os_spin_lock_bh(&wma->roam_preauth_lock);
wma->roam_preauth_scan_id = -1;
adf_os_spin_unlock_bh(&wma->roam_preauth_lock);
if (wma->interfaces[tgt_req->vdev_id].is_channel_switch)
wma->interfaces[tgt_req->vdev_id].is_channel_switch =
VOS_FALSE;
} else if (tgt_req->msg_type == WDA_DELETE_BSS_REQ) {
tpDeleteBssParams params =
(tpDeleteBssParams)tgt_req->user_data;
struct beacon_info *bcn;
struct wma_txrx_node *iface;
if (tgt_req->vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %d", __func__,
tgt_req->vdev_id);
vos_mem_free(params);
vos_timer_stop(&tgt_req->event_timeout);
goto free_tgt_req;
}
iface = &wma->interfaces[tgt_req->vdev_id];
if (iface->handle == NULL) {
WMA_LOGE("%s vdev id %d is already deleted",
__func__, tgt_req->vdev_id);
vos_mem_free(params);
vos_timer_stop(&tgt_req->event_timeout);
goto free_tgt_req;
}
#ifdef QCA_IBSS_SUPPORT
if (wma_is_vdev_in_ibss_mode(wma, tgt_req->vdev_id))
wma_delete_all_ibss_peers(wma, tgt_req->vdev_id);
else
#endif
{
if (wma_is_vdev_in_ap_mode(wma, tgt_req->vdev_id))
{
wma_delete_all_ap_remote_peers(wma, tgt_req->vdev_id);
}
peer = ol_txrx_find_peer_by_addr(pdev, params->bssid,
&peer_id);
wma_remove_peer(wma, params->bssid, tgt_req->vdev_id,
peer, VOS_FALSE);
}
if (wmi_unified_vdev_down_send(wma->wmi_handle, tgt_req->vdev_id) < 0) {
WMA_LOGE("Failed to send vdev down cmd: vdev %d",
tgt_req->vdev_id);
} else {
wma->interfaces[tgt_req->vdev_id].vdev_up = FALSE;
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
if (mac_ctx->sap.sap_channel_avoidance)
wma_find_mcc_ap(wma, tgt_req->vdev_id, false);
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
}
ol_txrx_vdev_flush(iface->handle);
WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for WDA_DELETE_BSS_REQ timeout",
__func__, tgt_req->vdev_id);
wdi_in_vdev_unpause(iface->handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST);
adf_os_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED);
WMA_LOGD("%s: (type %d subtype %d) BSS is stopped",
__func__, iface->type, iface->sub_type);
bcn = wma->interfaces[tgt_req->vdev_id].beacon;
if (bcn) {
WMA_LOGD("%s: Freeing beacon struct %pK, "
"template memory %pK", __func__,
bcn, bcn->buf);
if (bcn->dma_mapped)
adf_nbuf_unmap_single(pdev->osdev, bcn->buf,
ADF_OS_DMA_TO_DEVICE);
adf_nbuf_free(bcn->buf);
vos_mem_free(bcn);
wma->interfaces[tgt_req->vdev_id].beacon = NULL;
}
params->status = VOS_STATUS_E_TIMEOUT;
WMA_LOGA("%s: WDA_DELETE_BSS_REQ timedout", __func__);
wma_send_msg(wma, WDA_DELETE_BSS_RSP, (void *)params, 0);
if (iface->del_staself_req) {
WMA_LOGA("scheduling defered deletion(vdev id %x)",
tgt_req->vdev_id);
wma_vdev_detach(wma, iface->del_staself_req, 1);
}
} else if (tgt_req->msg_type == WDA_DEL_STA_SELF_REQ) {
struct wma_txrx_node *iface =
(struct wma_txrx_node *)tgt_req->user_data;
tpDelStaSelfParams params =
(tpDelStaSelfParams)iface->del_staself_req;
params->status = VOS_STATUS_E_TIMEOUT;
WMA_LOGA("%s: WDA_DEL_STA_SELF_REQ timedout", __func__);
wma_send_msg(wma, WDA_DEL_STA_SELF_RSP,
(void *)iface->del_staself_req, 0);
if(iface->addBssStaContext)
adf_os_mem_free(iface->addBssStaContext);
#if defined WLAN_FEATURE_VOWIFI_11R
if (iface->staKeyParams)
adf_os_mem_free(iface->staKeyParams);
#endif
vos_mem_zero(iface, sizeof(*iface));
} else if (tgt_req->msg_type == WDA_ADD_BSS_REQ) {
tpAddBssParams params = (tpAddBssParams)tgt_req->user_data;
tDeleteBssParams *del_bss_params =
vos_mem_malloc(sizeof(tDeleteBssParams));
if (NULL == del_bss_params) {
WMA_LOGE("Failed to allocate memory for del_bss_params");
peer = ol_txrx_find_peer_by_addr(pdev, params->bssId,
&peer_id);
goto error0;
}
del_bss_params->status = params->status =
eHAL_STATUS_FW_MSG_TIMEDOUT;
del_bss_params->sessionId = params->sessionId;
del_bss_params->bssIdx = params->bssIdx;
vos_mem_copy(del_bss_params->bssid, params->bssId,
sizeof(tSirMacAddr));
WMA_LOGA("%s: WDA_ADD_BSS_REQ timedout", __func__);
peer = ol_txrx_find_peer_by_addr(pdev, params->bssId, &peer_id);
if (!peer) {
WMA_LOGP("%s: Failed to find peer %pM", __func__, params->bssId);
}
msg = wma_fill_vdev_req(wma, tgt_req->vdev_id, WDA_DELETE_BSS_REQ,
WMA_TARGET_REQ_TYPE_VDEV_STOP,
del_bss_params,
WMA_VDEV_STOP_REQUEST_TIMEOUT);
if (!msg) {
WMA_LOGP("%s: Failed to fill vdev request for vdev_id %d",
__func__, tgt_req->vdev_id);
vos_mem_free(del_bss_params);
goto error0;
}
WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (WDA_ADD_BSS_REQ timedout)",
__func__, tgt_req->vdev_id);
wdi_in_vdev_pause(wma->interfaces[tgt_req->vdev_id].handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
wma->interfaces[tgt_req->vdev_id].pause_bitmap |=
(1 << PAUSE_TYPE_HOST);
if (wma->pause_other_vdev_on_mcc_start) {
WMA_LOGD("%s: unpause other vdevs since paused when MCC start", __func__);
wma->pause_other_vdev_on_mcc_start = false;
wdi_in_pdev_unpause_other_vdev(pdev,
OL_TXQ_PAUSE_REASON_MCC_VDEV_START,
tgt_req->vdev_id);
}
if (wmi_unified_vdev_stop_send(wma->wmi_handle, tgt_req->vdev_id)) {
WMA_LOGP("%s: %d Failed to send vdev stop", __func__, __LINE__);
vos_mem_free(del_bss_params);
wma_remove_vdev_req(wma, tgt_req->vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_STOP);
goto error0;
}
WMA_LOGI("%s: bssid %pM vdev_id %d", __func__, params->bssId,
tgt_req->vdev_id);
error0:
if (peer)
wma_remove_peer(wma, params->bssId,
tgt_req->vdev_id, peer,
VOS_FALSE);
wma_send_msg(wma, WDA_ADD_BSS_RSP, (void *)params, 0);
} else if (tgt_req->msg_type == WDA_OCB_SET_CONFIG_CMD) {
struct wma_txrx_node *iface;
WMA_LOGE(FL("Failed to send OCB set config cmd"));
iface = &wma->interfaces[tgt_req->vdev_id];
iface->vdev_up = FALSE;
wma_ocb_set_config_resp(wma, VOS_STATUS_E_TIMEOUT);
} else if (tgt_req->msg_type == WDA_HIDDEN_SSID_VDEV_RESTART) {
WMA_LOGE("Hidden ssid vdev restart Timed Out; vdev_id: %d, type = %d",
tgt_req->vdev_id, tgt_req->type);
}
free_tgt_req:
vos_timer_destroy(&tgt_req->event_timeout);
adf_os_mem_free(tgt_req);
}
static void
wma_update_beacon_interval(tp_wma_handle wma, u_int8_t vdev_id,
u_int16_t beacon_interval);
/**
* wma_vdev_reset_beacon_interval_timer() - reset beacon interval back
* to its original value after the channel switch.
*
* @data: data
*
* Return: void
*/
void wma_vdev_reset_beacon_interval_timer(void *data)
{
tp_wma_handle wma;
struct wma_beacon_interval_reset_req *req =
(struct wma_beacon_interval_reset_req *)data;
void *vos_context =
vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
uint16_t beacon_interval = req->interval;
uint8_t vdev_id = req->vdev_id;
wma = (tp_wma_handle)vos_get_context(VOS_MODULE_ID_WDA, vos_context);
if (NULL == wma) {
WMA_LOGE("%s: Failed to get wma", __func__);
goto end;
}
/* Change the beacon interval back to its original value */
WMA_LOGE("%s: Change beacon interval back to %d",
__func__, beacon_interval);
wma_update_beacon_interval(wma, vdev_id, beacon_interval);
end:
vos_timer_stop(&req->event_timeout);
vos_timer_destroy(&req->event_timeout);
adf_os_mem_free(req);
}
/**
* wma_fill_beacon_interval_reset_req() - req to reset beacon interval
*
* @wma: wma handle
* @vdev_id: vdev id
* @beacon_interval: beacon interval
* @timeout: timeout val
*
* Return: status
*/
int wma_fill_beacon_interval_reset_req(tp_wma_handle wma, uint8_t vdev_id,
uint16_t beacon_interval, uint32_t timeout)
{
struct wma_beacon_interval_reset_req *req;
req = adf_os_mem_alloc(NULL, sizeof(*req));
if (!req) {
WMA_LOGE("%s: Failed to allocate memory"
"for beacon_interval_reset_req vdev %d",
__func__, vdev_id);
return -ENOMEM;
}
WMA_LOGD("%s: vdev_id %d ", __func__, vdev_id);
req->vdev_id = vdev_id;
req->interval = beacon_interval;
vos_timer_init(&req->event_timeout, VOS_TIMER_TYPE_SW,
wma_vdev_reset_beacon_interval_timer, req);
vos_timer_start(&req->event_timeout, timeout);
return 0;
}
struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, u_int8_t vdev_id,
u_int32_t msg_type, u_int8_t type,
void *params, u_int32_t timeout)
{
struct wma_target_req *req;
req = adf_os_mem_alloc(NULL, sizeof(*req));
if (!req) {
WMA_LOGP("%s: Failed to allocate memory for msg %d vdev %d",
__func__, msg_type, vdev_id);
return NULL;
}
WMA_LOGD("%s: vdev_id %d msg %d", __func__, vdev_id, msg_type);
req->vdev_id = vdev_id;
req->msg_type = msg_type;
req->type = type;
req->user_data = params;
vos_timer_init(&req->event_timeout, VOS_TIMER_TYPE_SW,
wma_vdev_resp_timer, req);
vos_timer_start(&req->event_timeout, timeout);
adf_os_spin_lock_bh(&wma->vdev_respq_lock);
list_add_tail(&req->node, &wma->vdev_resp_queue);
adf_os_spin_unlock_bh(&wma->vdev_respq_lock);
return req;
}
void wma_remove_vdev_req(tp_wma_handle wma, u_int8_t vdev_id,
u_int8_t type)
{
struct wma_target_req *req_msg;
req_msg = wma_find_vdev_req(wma, vdev_id, type);
if (!req_msg)
return;
vos_timer_stop(&req_msg->event_timeout);
vos_timer_destroy(&req_msg->event_timeout);
adf_os_mem_free(req_msg);
}
/* function : wma_roam_preauth_chan_set
* Description: Send a single channel passive scan request
* to handle set_channel operation for preauth
* Args:
* Returns :
*/
VOS_STATUS wma_roam_preauth_chan_set(tp_wma_handle wma_handle,
tpSwitchChannelParams params, u_int8_t vdev_id)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
tSirScanOffloadReq scan_req;
u_int8_t bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
WMA_LOGI("%s: channel %d", __func__, params->channelNumber);
/* Check for prior operation in progress */
if (wma_handle->roam_preauth_chan_context != NULL) {
vos_status = VOS_STATUS_E_FAILURE;
WMA_LOGE("%s: Rejected request. Previous operation in progress", __func__);
goto send_resp;
}
wma_handle->roam_preauth_chan_context = params;
/* Prepare a dummy scan request and get the
* wmi_start_scan_cmd_fixed_param structure filled properly
*/
vos_mem_zero(&scan_req, sizeof(scan_req));
vos_copy_macaddr((v_MACADDR_t *) &scan_req.bssId, (v_MACADDR_t *)bssid);
vos_copy_macaddr((v_MACADDR_t *)&scan_req.selfMacAddr, (v_MACADDR_t *)&params->selfStaMacAddr);
scan_req.channelList.numChannels = 1;
scan_req.channelList.channelNumber[0] = params->channelNumber;
scan_req.numSsid = 0;
scan_req.minChannelTime = WMA_ROAM_PREAUTH_SCAN_TIME;
scan_req.maxChannelTime = WMA_ROAM_PREAUTH_SCAN_TIME;
scan_req.scanType = eSIR_PASSIVE_SCAN;
scan_req.p2pScanType = P2P_SCAN_TYPE_LISTEN;
scan_req.sessionId = vdev_id;
wma_handle->roam_preauth_chanfreq = vos_chan_to_freq(params->channelNumber);
/* set the state in advance before calling wma_start_scan and be ready
* to handle scan events from firmware. Otherwise print statments
* in wma_start_can create a race condition.
*/
wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_REQUESTED;
vos_status = wma_start_scan(wma_handle, &scan_req, WDA_CHNL_SWITCH_REQ);
if (vos_status == VOS_STATUS_SUCCESS)
return vos_status;
wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_NONE;
/* Failed operation. Safely clear context */
wma_handle->roam_preauth_chan_context = NULL;
send_resp:
WMA_LOGI("%s: sending WDA_SWITCH_CHANNEL_RSP, status = 0x%x",
__func__, vos_status);
params->chainMask = wma_handle->pdevconfig.txchainmask;
params->smpsMode = SMPS_MODE_DISABLED;
params->status = vos_status;
wma_send_msg(wma_handle, WDA_SWITCH_CHANNEL_RSP, (void *)params, 0);
return vos_status;
}
VOS_STATUS wma_roam_preauth_chan_cancel(tp_wma_handle wma_handle,
tpSwitchChannelParams params, u_int8_t vdev_id)
{
tAbortScanParams abort_scan_req;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
WMA_LOGI("%s: channel %d", __func__, params->channelNumber);
/* Check for prior operation in progress */
if (wma_handle->roam_preauth_chan_context != NULL) {
vos_status = VOS_STATUS_E_FAILURE;
WMA_LOGE("%s: Rejected request. Previous operation in progress", __func__);
goto send_resp;
}
wma_handle->roam_preauth_chan_context = params;
abort_scan_req.SessionId = vdev_id;
wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_CANCEL_REQUESTED;
vos_status = wma_stop_scan(wma_handle, &abort_scan_req);
if (vos_status == VOS_STATUS_SUCCESS)
return vos_status;
/* Failed operation. Safely clear context */
wma_handle->roam_preauth_chan