blob: ef97c56142b9840adaed7c6bf7bd4053a552d09c [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) +
WMI_TLV_HDR_SIZE +
(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);
if (src_hotlist->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) {
WMA_LOGE("%s Invalid SSID len %d, truncating",
__func__, src_hotlist->ssid.ssid_len);
src_hotlist->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH;
}
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);
if (src_hotlist->ssid.ssid_len >
SIR_MAC_MAX_SSID_LENGTH) {
WMA_LOGD("%s Invalid SSID len %d, truncating",
__func__, src_hotlist->ssid.ssid_len);
src_hotlist->ssid.ssid_len =
SIR_MAC_MAX_SSID_LENGTH;
}
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);
return -EINVAL;
}
if (event->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) {
WMA_LOGD("%s: Invalid ssid len %d, truncating",
__func__, event->ssid.ssid_len);
event->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH;
}
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);
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 ((fixed_param->power_level_offset >
rs_results->total_num_tx_power_levels) ||
(fixed_param->num_tx_power_levels >
rs_results->total_num_tx_power_levels -
fixed_param->power_level_offset)) {
WMA_LOGE("%s: Invalid offset %d total_num %d num %d",
__func__, fixed_param->power_level_offset,
rs_results->total_num_tx_power_levels,
fixed_param->num_tx_power_levels);
return -EINVAL;
}
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)) ||
nan_rsp_event_hdr->data_len > param_buf->num_data) {
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)) ||
stats_ext_info->data_len > param_buf->num_data) {
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_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;
}
static void wma_roam_preauth_scan_event_handler(tp_wma_handle wma_handle,
u_int8_t vdev_id, wmi_scan_event_fixed_param *wmi_event)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
tSwitchChannelParams *params;
WMA_LOGI("%s: preauth_scan_state %d, event 0x%x, reason 0x%x",
__func__, wma_handle->roam_preauth_scan_state,
wmi_event->event, wmi_event->reason);
switch(wma_handle->roam_preauth_scan_state) {
case WMA_ROAM_PREAUTH_CHAN_REQUESTED:
if (wmi_event->event & WMI_SCAN_EVENT_FOREIGN_CHANNEL) {
/* complete set_chan request */
wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_ON_CHAN;
vos_status = VOS_STATUS_SUCCESS;
} else if (wmi_event->event & WMI_SCAN_FINISH_EVENTS){
/* Failed to get preauth channel or finished (unlikely) */
wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_NONE;
vos_status = VOS_STATUS_E_FAILURE;
} else
return;
break;
case WMA_ROAM_PREAUTH_CHAN_CANCEL_REQUESTED:
/* Completed or cancelled, complete set_chan cancel request */
wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_NONE;
break;
case WMA_ROAM_PREAUTH_ON_CHAN:
if ((wmi_event->event & WMI_SCAN_EVENT_BSS_CHANNEL) ||
(wmi_event->event & WMI_SCAN_FINISH_EVENTS))
wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_COMPLETED;
/* There is no WDA request to complete. Next set channel request will
* look at this state and complete it.
*/
break;
default:
WMA_LOGE("%s: unhandled event 0x%x, reason 0x%x",
__func__, wmi_event->event, wmi_event->reason);
return;
}
if((params = (tpSwitchChannelParams) wma_handle->roam_preauth_chan_context)) {
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);
wma_handle->roam_preauth_chan_context = NULL;
}
}
void wma_roam_preauth_ind(tp_wma_handle wma_handle, u_int8_t *buf) {
wmi_scan_event_fixed_param *wmi_event = NULL;
u_int8_t vdev_id;
wmi_event = (wmi_scan_event_fixed_param *)buf;
if (wmi_event == NULL) {
WMA_LOGE("%s: Invalid param wmi_event is null", __func__);
return;
}
vdev_id = wmi_event->vdev_id;
if (vdev_id >= wma_handle->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %d wmi_event %pK", __func__,
vdev_id, wmi_event);
return;
}
wma_roam_preauth_scan_event_handler(wma_handle, vdev_id, wmi_event);
return;
}
/*
* wma_set_channel
* If this request is called when station is connected, it should use
*/
static void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params)
{
struct wma_vdev_start_req req;
struct wma_target_req *msg;
VOS_STATUS status = VOS_STATUS_SUCCESS;
u_int8_t vdev_id, peer_id;
ol_txrx_peer_handle peer;
ol_txrx_pdev_handle pdev;
struct wma_txrx_node *intr = wma->interfaces;
uint16_t beacon_interval_ori;
WMA_LOGD("%s: Enter", __func__);
if (!wma_find_vdev_by_addr(wma, params->selfStaMacAddr, &vdev_id)) {
WMA_LOGP("%s: Failed to find vdev id for %pM",
__func__, params->selfStaMacAddr);
status = VOS_STATUS_E_FAILURE;
goto send_resp;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
status = VOS_STATUS_E_FAILURE;
goto send_resp;
}
peer = ol_txrx_find_peer_by_addr(pdev, intr[vdev_id].bssid, &peer_id);
/*
* Roam offload feature is currently supported
* only in STA mode. Other modes still require
* to issue a Vdev Start/Vdev Restart for
* channel change.
*/
if (((wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA) &&
(wma->interfaces[vdev_id].sub_type == 0)) &&
!wma->interfaces[vdev_id].is_channel_switch) {
if (peer && (peer->state == ol_txrx_peer_state_conn ||
peer->state == ol_txrx_peer_state_auth)) {
/* Trying to change channel while connected
* should not invoke VDEV_START.
* Instead, use start scan command in passive
* mode to park station on that channel
*/
WMA_LOGI("%s: calling set_scan, state 0x%x",
__func__, wma->roam_preauth_scan_state);
if (wma->roam_preauth_scan_state ==
WMA_ROAM_PREAUTH_CHAN_NONE) {
/* Is channel change required?
*/
if(wma_is_mcc_starting(wma,
vos_chan_to_freq(params->channelNumber)))
{
status = wma_roam_preauth_chan_set(wma,
params, vdev_id);
/* response will be asynchronous */
return;
}
} else if (wma->roam_preauth_scan_state ==
WMA_ROAM_PREAUTH_CHAN_REQUESTED ||
wma->roam_preauth_scan_state == WMA_ROAM_PREAUTH_ON_CHAN) {
status = wma_roam_preauth_chan_cancel(wma, params, vdev_id);
/* response will be asynchronous */
return;
} else if (wma->roam_preauth_scan_state ==
WMA_ROAM_PREAUTH_CHAN_COMPLETED) {
/* Already back on home channel. Complete the request */
wma->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_NONE;
status = VOS_STATUS_SUCCESS;
}
goto send_resp;
}
}
vos_mem_zero(&req, sizeof(req));
req.vdev_id = vdev_id;
msg = wma_fill_vdev_req(wma, req.vdev_id, WDA_CHNL_SWITCH_REQ,
WMA_TARGET_REQ_TYPE_VDEV_START, params,
WMA_VDEV_START_REQUEST_TIMEOUT);
if (!msg) {
WMA_LOGP("%s: Failed to fill channel switch request for vdev %d",
__func__, req.vdev_id);
status = VOS_STATUS_E_NOMEM;
goto send_resp;
}
req.chan = params->channelNumber;
req.channelwidth = params->channelwidth;
if (params->channelwidth == CH_WIDTH_10MHZ)
req.is_half_rate = 1;
else if (params->channelwidth == CH_WIDTH_5MHZ)
req.is_quarter_rate = 1;
req.chan_offset = params->secondaryChannelOffset;
req.vht_capable = params->vhtCapable;
req.dot11_mode = params->dot11_mode;
#ifdef WLAN_FEATURE_VOWIFI
req.max_txpow = params->maxTxPower;
#else
req.max_txpow = params->localPowerConstraint;
#endif
req.beacon_intval = 100;
req.dtim_period = 1;
req.is_dfs = params->isDfsChannel;
/* In case of AP mode, once radar is detected, we need to
* issuse VDEV RESTART, so we making is_channel_switch as
* TRUE
*/
if ((wma_is_vdev_in_ap_mode(wma, req.vdev_id) == true) ||
params->restart_on_chan_switch == VOS_TRUE)
wma->interfaces[req.vdev_id].is_channel_switch = VOS_TRUE;
if ((wma_is_vdev_in_ap_mode(wma, req.vdev_id) == true)) {
if (params->reduced_beacon_interval) {
/* Reduce the beacon interval just before the channel switch.
* This would help in reducing the downtime on the STA side
* (which is waiting for beacons from the AP to resume back
* transmission). Switch back the beacon_interval to its
* original value after the channel switch based on the
* timeout. This would ensure there are atleast some beacons
* sent with increased frequency.
*/
WMA_LOGD("%s: Changing beacon interval to %d",
__func__, params->reduced_beacon_interval);
/* Add a timer to reset the beacon interval back*/
beacon_interval_ori = req.beacon_intval;
req.beacon_intval = params->reduced_beacon_interval;
if (wma_fill_beacon_interval_reset_req(wma,
req.vdev_id,
beacon_interval_ori,
RESET_BEACON_INTERVAL_TIMEOUT)) {
WMA_LOGD("%s: Failed to fill beacon"
" interval reset req", __func__);
}
}
}
if ((VOS_MONITOR_MODE == vos_get_conparam()) && wma_is_vdev_up(0)) {
status = wma_switch_channel(wma, &req);
if (status != VOS_STATUS_SUCCESS)
WMA_LOGE("%s: wma_switch_channel failed %d\n", __func__,
status);
return;
} else {
status = wma_vdev_start(wma, &req,
wma->interfaces[req.vdev_id].is_channel_switch);
if (status != VOS_STATUS_SUCCESS) {
wma_remove_vdev_req(wma, req.vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_START);
WMA_LOGP("%s: vdev start failed status = %d", __func__,
status);
goto send_resp;
}
return;
}
send_resp:
WMA_LOGD("%s: channel %d offset %d txpower %d status %d", __func__,
params->channelNumber, params->secondaryChannelOffset,
#ifdef WLAN_FEATURE_VOWIFI
params->maxTxPower,
#else
params->localPowerConstraint,
#endif
status);
params->status = status;
WMA_LOGI("%s: sending WDA_SWITCH_CHANNEL_RSP, status = 0x%x",
__func__, status);
wma_send_msg(wma, WDA_SWITCH_CHANNEL_RSP, (void *)params, 0);
}
static WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, u_int8_t sta_type,
u_int8_t is_ht, u_int8_t is_cw40, u_int8_t is_vht, u_int8_t is_cw_vht)
{
WLAN_PHY_MODE phymode = MODE_UNKNOWN;
switch (nw_type) {
case eSIR_11B_NW_TYPE:
if (is_vht) {
if (is_cw_vht)
phymode = MODE_11AC_VHT80;
else
phymode = (is_cw40) ?
MODE_11AC_VHT40 :
MODE_11AC_VHT20;
}
else if (is_ht) {
phymode = (is_cw40) ?
MODE_11NG_HT40 : MODE_11NG_HT20;
} else
phymode = MODE_11B;
break;
case eSIR_11G_NW_TYPE:
if (is_vht) {
if (is_cw_vht)
phymode = MODE_11AC_VHT80;
else
phymode = (is_cw40) ?
MODE_11AC_VHT40 :
MODE_11AC_VHT20;
}
else if (is_ht) {
phymode = (is_cw40) ?
MODE_11NG_HT40 :
MODE_11NG_HT20;
} else
phymode = MODE_11G;
break;
case eSIR_11A_NW_TYPE:
if (is_vht) {
if (is_cw_vht)
phymode = MODE_11AC_VHT80;
else
phymode = (is_cw40) ?
MODE_11AC_VHT40 :
MODE_11AC_VHT20;
}
else if (is_ht) {
phymode = (is_cw40) ?
MODE_11NA_HT40 :
MODE_11NA_HT20;
} else
phymode = MODE_11A;
break;
default:
WMA_LOGP("%s: Invalid nw type %d", __func__, nw_type);
break;
}
WMA_LOGD("%s: nw_type %d is_ht %d is_cw40 %d is_vht %d is_cw_vht %d phymode %d",
__func__, nw_type, is_ht, is_cw40, is_vht, is_cw_vht, phymode);
return phymode;
}
static int32_t wmi_unified_send_txbf(tp_wma_handle wma,
tpAddStaParams params)
{
wmi_vdev_txbf_en txbf_en = {0};
/*
* This is set when Other partner is Bformer
* and we are capable bformee(enabled both in ini and fw)
*/
txbf_en.sutxbfee = params->vhtTxBFCapable;
txbf_en.mutxbfee = params->vhtTxMUBformeeCapable;
/* When MU TxBfee is set, SU TxBfee must be set by default */
if (txbf_en.mutxbfee)
txbf_en.sutxbfee = txbf_en.mutxbfee;
WMA_LOGD("txbf_en.sutxbfee %d txbf_en.mutxbfee %d",
txbf_en.sutxbfee, txbf_en.mutxbfee);
return(wmi_unified_vdev_set_param_send(wma->wmi_handle,
params->smesessionId, WMI_VDEV_PARAM_TXBF,
*((A_UINT8 *)&txbf_en)));
}
static void wma_update_txrx_chainmask(int num_rf_chains, int *cmd_value)
{
if (*cmd_value > WMA_MAX_RF_CHAINS(num_rf_chains)) {
WMA_LOGE("%s: Chainmask value exceeds the maximum"
" supported range setting it to"
" maximum value. Requested value %d"
" Updated value %d", __func__, *cmd_value,
WMA_MAX_RF_CHAINS(num_rf_chains));
*cmd_value = WMA_MAX_RF_CHAINS(num_rf_chains);
} else if (*cmd_value < WMA_MIN_RF_CHAINS) {
WMA_LOGE("%s: Chainmask value is less than the minimum"
" supported range setting it to"
" minimum value. Requested value %d"
" Updated value %d", __func__, *cmd_value,
WMA_MIN_RF_CHAINS);
*cmd_value = WMA_MIN_RF_CHAINS;
}
}
#define CFG_CTRL_MASK 0xFF00
#define CFG_DATA_MASK 0x00FF
/**
* wma_mask_tx_ht_rate() - mask tx ht rate based on config
* @wma: wma handle
* @mcs_set mcs set buffer
*
* Return: None
*/
static void wma_mask_tx_ht_rate(tp_wma_handle wma, uint8_t *mcs_set)
{
uint32_t mcs_limit, i, j;
uint8_t *rate_pos = mcs_set;
/*
* Get MCS limit from ini configure, and map it to rate parameters
* This will limit HT rate upper bound. CFG_CTRL_MASK is used to
* check whether ini config is enabled and CFG_DATA_MASK to get the
* MCS value.
*/
if (wlan_cfgGetInt(wma->mac_context, WNI_CFG_MAX_HT_MCS_TX_DATA,
&mcs_limit) != eSIR_SUCCESS) {
mcs_limit = WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF;
}
if (mcs_limit & CFG_CTRL_MASK) {
WMA_LOGD("%s: set mcs_limit %x", __func__, mcs_limit);
mcs_limit &= CFG_DATA_MASK;
for (i = 0, j = 0; i < MAX_SUPPORTED_RATES;) {
if (j < mcs_limit / 8) {
rate_pos[j] = 0xff;
j++;
i += 8;
} else if (j < mcs_limit / 8 + 1) {
if (i <= mcs_limit)
rate_pos[i / 8] |= 1 << (i % 8);
else
rate_pos[i / 8] &= ~(1 << (i % 8));
i++;
if (i >= (j + 1) * 8)
j++;
} else {
rate_pos[j++] = 0;
i += 8;
}
}
}
}
static int32_t wmi_unified_send_peer_assoc(tp_wma_handle wma,
tSirNwType nw_type,
tpAddStaParams params)
{
ol_txrx_pdev_handle pdev;
wmi_peer_assoc_complete_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int32_t ret, max_rates, i;
u_int8_t rx_stbc, tx_stbc;
u_int8_t *rate_pos, *buf_ptr;
wmi_rate_set peer_legacy_rates, peer_ht_rates;
wmi_vht_rate_set *mcs;
u_int32_t num_peer_legacy_rates;
u_int32_t num_peer_ht_rates;
u_int32_t num_peer_11b_rates=0;
u_int32_t num_peer_11a_rates=0;
u_int32_t phymode;
u_int32_t peer_nss=1;
u_int32_t disable_abg_rate;
struct wma_txrx_node *intr = NULL;
if (NULL == params) {
WMA_LOGE("%s: params is NULL", __func__);
return -EINVAL;
}
intr = &wma->interfaces[params->smesessionId];
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
return -EINVAL;
}
wma_mask_tx_ht_rate(wma, params->supportedRates.supportedMCSSet);
vos_mem_zero(&peer_legacy_rates, sizeof(wmi_rate_set));
vos_mem_zero(&peer_ht_rates, sizeof(wmi_rate_set));
phymode = wma_peer_phymode(nw_type, params->staType,
params->htCapable,
params->txChannelWidthSet,
params->vhtCapable,
params->vhtTxChannelWidthSet);
if (wlan_cfgGetInt(wma->mac_context,
WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA,
&disable_abg_rate) != eSIR_SUCCESS)
disable_abg_rate = WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF;
if (!disable_abg_rate) {
/* Legacy Rateset */
rate_pos = (u_int8_t *) peer_legacy_rates.rates;
for (i = 0; i < SIR_NUM_11B_RATES; i++) {
if (!params->supportedRates.llbRates[i])
continue;
rate_pos[peer_legacy_rates.num_rates++] =
params->supportedRates.llbRates[i];
num_peer_11b_rates++;
}
for (i = 0; i < SIR_NUM_11A_RATES; i++) {
if (!params->supportedRates.llaRates[i])
continue;
rate_pos[peer_legacy_rates.num_rates++] =
params->supportedRates.llaRates[i];
num_peer_11a_rates++;
}
}
if ((phymode == MODE_11A && num_peer_11a_rates == 0) ||
(phymode == MODE_11B && num_peer_11b_rates == 0)) {
WMA_LOGW("%s: Invalid phy rates. phymode 0x%x,"
"11b_rates %d, 11a_rates %d",
__func__, phymode,
num_peer_11b_rates,
num_peer_11a_rates);
return -EINVAL;
}
/* Set the Legacy Rates to Word Aligned */
num_peer_legacy_rates = roundup(peer_legacy_rates.num_rates,
sizeof(u_int32_t));
/* HT Rateset */
max_rates = sizeof(peer_ht_rates.rates) /
sizeof(peer_ht_rates.rates[0]);
rate_pos = (u_int8_t *) peer_ht_rates.rates;
for (i = 0; i < MAX_SUPPORTED_RATES; i++) {
if (params->supportedRates.supportedMCSSet[i / 8] &
(1 << (i % 8))) {
rate_pos[peer_ht_rates.num_rates++] = i;
if (i >= 8) {
/* MCS8 or higher rate is present, must be 2x2 */
peer_nss = 2;
}
}
if (peer_ht_rates.num_rates == max_rates)
break;
}
if (params->htCapable && !peer_ht_rates.num_rates) {
u_int8_t temp_ni_rates[8] = {0x0, 0x1, 0x2, 0x3,
0x4, 0x5, 0x6, 0x7};
/*
* Workaround for EV 116382: The peer is marked HT but with
* supported rx mcs set is set to 0. 11n spec mandates MCS0-7
* for a HT STA. So forcing the supported rx mcs rate to
* MCS 0-7. This workaround will be removed once we get
* clarification from WFA regarding this STA behavior.
*/
/* TODO: Do we really need this? */
WMA_LOGW("Peer is marked as HT capable but supported mcs rate is 0");
peer_ht_rates.num_rates = sizeof(temp_ni_rates);
vos_mem_copy((u_int8_t *) peer_ht_rates.rates, temp_ni_rates,
peer_ht_rates.num_rates);
}
/* Set the Peer HT Rates to Word Aligned */
num_peer_ht_rates = roundup(peer_ht_rates.num_rates,
sizeof(u_int32_t));
len = sizeof(*cmd) +
WMI_TLV_HDR_SIZE + /* Place holder for peer legacy rate array */
(num_peer_legacy_rates * sizeof(u_int8_t)) + /* peer legacy rate array size */
WMI_TLV_HDR_SIZE + /* Place holder for peer Ht rate array */
(num_peer_ht_rates * sizeof(u_int8_t)) + /* peer HT rate array size */
sizeof(wmi_vht_rate_set);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_peer_assoc_complete_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_peer_assoc_complete_cmd_fixed_param));
/* in ap/ibss mode and for tdls peer, use mac address of the peer in
* the other end as the new peer address; in sta mode, use bss id to
* be the new peer address
*/
if ((wma_is_vdev_in_ap_mode(wma, params->smesessionId))
#ifdef QCA_IBSS_SUPPORT
|| (wma_is_vdev_in_ibss_mode(wma, params->smesessionId))
#endif
#ifdef FEATURE_WLAN_TDLS
|| (STA_ENTRY_TDLS_PEER == params->staType)
#endif
)
WMI_CHAR_ARRAY_TO_MAC_ADDR(params->staMac, &cmd->peer_macaddr);
else
WMI_CHAR_ARRAY_TO_MAC_ADDR(params->bssId, &cmd->peer_macaddr);
cmd->vdev_id = params->smesessionId;
cmd->peer_new_assoc = 1;
cmd->peer_associd = params->assocId;
/*
* The target only needs a subset of the flags maintained in the host.
* Just populate those flags and send it down
*/
cmd->peer_flags = 0;
if (params->wmmEnabled)
cmd->peer_flags |= WMI_PEER_QOS;
if (params->uAPSD) {
cmd->peer_flags |= WMI_PEER_APSD;
WMA_LOGD("Set WMI_PEER_APSD: uapsd Mask %d", params->uAPSD);
}
if (params->htCapable) {
cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_QOS);
cmd->peer_rate_caps |= WMI_RC_HT_FLAG;
if (params->txChannelWidthSet) {
cmd->peer_flags |= WMI_PEER_40MHZ;
cmd->peer_rate_caps |= WMI_RC_CW40_FLAG;
if (params->fShortGI40Mhz)
cmd->peer_rate_caps |= WMI_RC_SGI_FLAG;
} else if (params->fShortGI20Mhz) {
cmd->peer_rate_caps |= WMI_RC_SGI_FLAG;
}
}
#ifdef WLAN_FEATURE_11AC
if (params->vhtCapable) {
cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_VHT | WMI_PEER_QOS);
cmd->peer_rate_caps |= WMI_RC_HT_FLAG;
}
if (params->vhtTxChannelWidthSet)
cmd->peer_flags |= WMI_PEER_80MHZ;
cmd->peer_vht_caps = params->vht_caps;
#endif
if (params->p2pCapableSta)
cmd->peer_flags |= WMI_PEER_IS_P2P_CAPABLE;
if (params->rmfEnabled)
cmd->peer_flags |= WMI_PEER_PMF;
rx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_RXSTBC) >>
IEEE80211_HTCAP_C_RXSTBC_S;
if (rx_stbc) {
cmd->peer_flags |= WMI_PEER_STBC;
cmd->peer_rate_caps |= (rx_stbc << WMI_RC_RX_STBC_FLAG_S);
}
tx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_TXSTBC) >>
IEEE80211_HTCAP_C_TXSTBC_S;
if (tx_stbc) {
cmd->peer_flags |= WMI_PEER_STBC;
cmd->peer_rate_caps |= (tx_stbc << WMI_RC_TX_STBC_FLAG_S);
}
if (params->htLdpcCapable || params->vhtLdpcCapable)
cmd->peer_flags |= WMI_PEER_LDPC;
switch (params->mimoPS) {
case eSIR_HT_MIMO_PS_STATIC:
cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS;
break;
case eSIR_HT_MIMO_PS_DYNAMIC:
cmd->peer_flags |= WMI_PEER_DYN_MIMOPS;
break;
case eSIR_HT_MIMO_PS_NO_LIMIT:
cmd->peer_flags |= WMI_PEER_SPATIAL_MUX;
break;
default:
break;
}
#ifdef FEATURE_WLAN_TDLS
if (STA_ENTRY_TDLS_PEER == params->staType)
cmd->peer_flags |= WMI_PEER_AUTH;
#endif
if (params->wpa_rsn
#ifdef FEATURE_WLAN_WAPI
|| params->encryptType == eSIR_ED_WPI
#endif
)
cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
if (params->wpa_rsn >> 1)
cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
if (STA_ENTRY_TDLS_PEER == params->staType)
ol_txrx_peer_state_update(pdev, params->staMac, ol_txrx_peer_state_auth);
else
ol_txrx_peer_state_update(pdev, params->bssId, ol_txrx_peer_state_auth);
#else
ol_txrx_peer_state_update(pdev, params->bssId, ol_txrx_peer_state_auth);
#endif
#ifdef FEATURE_WLAN_WAPI
if (params->encryptType == eSIR_ED_WPI) {
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
params->smesessionId,
WMI_VDEV_PARAM_DROP_UNENCRY,
FALSE);
if (ret) {
WMA_LOGE("Set WMI_VDEV_PARAM_DROP_UNENCRY Param status:%d\n", ret);
wmi_buf_free(buf);
return ret;
}
}
#endif
cmd->peer_caps = params->capab_info;
cmd->peer_listen_intval = params->listenInterval;
cmd->peer_ht_caps = params->ht_caps;
cmd->peer_max_mpdu = (1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
params->maxAmpduSize)) - 1;
cmd->peer_mpdu_density = wma_parse_mpdudensity(params->maxAmpduDensity);
if (params->supportedRates.supportedMCSSet[1] &&
params->supportedRates.supportedMCSSet[2])
cmd->peer_rate_caps |= WMI_RC_TS_FLAG;
else if (params->supportedRates.supportedMCSSet[1])
cmd->peer_rate_caps |= WMI_RC_DS_FLAG;
/* Update peer legacy rate information */
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
num_peer_legacy_rates);
buf_ptr += WMI_TLV_HDR_SIZE;
cmd->num_peer_legacy_rates = peer_legacy_rates.num_rates;
vos_mem_copy(buf_ptr, peer_legacy_rates.rates,
peer_legacy_rates.num_rates);
/* Update peer HT rate information */
buf_ptr += num_peer_legacy_rates;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
num_peer_ht_rates);
buf_ptr += WMI_TLV_HDR_SIZE;
cmd->num_peer_ht_rates = peer_ht_rates.num_rates;
vos_mem_copy(buf_ptr, peer_ht_rates.rates,
peer_ht_rates.num_rates);
/* VHT Rates */
buf_ptr += num_peer_ht_rates;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_STRUC_wmi_vht_rate_set,
WMITLV_GET_STRUCT_TLVLEN(wmi_vht_rate_set));
cmd->peer_nss = peer_nss;
WMA_LOGD("peer_nss %d peer_ht_rates.num_rates %d ", cmd->peer_nss,
peer_ht_rates.num_rates);
mcs = (wmi_vht_rate_set *)buf_ptr;
if ( params->vhtCapable) {
#define VHT2x2MCSMASK 0xc
mcs->rx_max_rate = params->supportedRates.vhtRxHighestDataRate;
mcs->rx_mcs_set = params->supportedRates.vhtRxMCSMap;
mcs->tx_max_rate = params->supportedRates.vhtTxHighestDataRate;
mcs->tx_mcs_set = params->supportedRates.vhtTxMCSMap;
if(params->vhtSupportedRxNss) {
cmd->peer_nss = params->vhtSupportedRxNss;
} else {
cmd->peer_nss = ((mcs->rx_mcs_set & VHT2x2MCSMASK)
== VHT2x2MCSMASK) ? 1 : 2;
}
}
/*
* Limit nss to max number of rf chain supported by target
* Otherwise Fw will crash
*/
wma_update_txrx_chainmask(wma->num_rf_chains, &cmd->peer_nss);
intr->nss = cmd->peer_nss;
cmd->peer_phymode = phymode;
WMA_LOGD("%s: vdev_id %d associd %d peer_flags %x rate_caps %x "
"peer_caps %x listen_intval %d ht_caps %x max_mpdu %d "
"nss %d phymode %d peer_mpdu_density %d encr_type %d "
"cmd->peer_vht_caps %x", __func__,
cmd->vdev_id, cmd->peer_associd, cmd->peer_flags,
cmd->peer_rate_caps, cmd->peer_caps,
cmd->peer_listen_intval, cmd->peer_ht_caps,
cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode,
cmd->peer_mpdu_density, params->encryptType,
cmd->peer_vht_caps);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PEER_ASSOC_CMDID);
if (ret != EOK) {
WMA_LOGP("%s: Failed to send peer assoc command ret = %d",
__func__, ret);
wmi_buf_free(buf);
}
return ret;
}
static int
wmi_unified_modem_power_state(wmi_unified_t wmi_handle, u_int32_t param_value)
{
int ret;
wmi_modem_power_state_cmd_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_modem_power_state_cmd_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_modem_power_state_cmd_param));
cmd->modem_power_state = param_value;
WMA_LOGD("%s: Setting cmd->modem_power_state = %u", __func__, param_value);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_MODEM_POWER_STATE_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send notify cmd ret = %d", ret);
wmi_buf_free(buf);
}
return ret;
}
VOS_STATUS wma_get_link_speed(WMA_HANDLE handle,
tSirLinkSpeedInfo *pLinkSpeed)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_peer_get_estimated_linkspeed_cmd_fixed_param* cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue get link speed cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_ESTIMATE_LINKSPEED)) {
WMA_LOGE("%s: Linkspeed feature bit not enabled"
" Sending value 0 as link speed.",
__func__);
wma_send_link_speed(0);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(wmi_peer_get_estimated_linkspeed_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 = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_peer_get_estimated_linkspeed_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_peer_get_estimated_linkspeed_cmd_fixed_param));
/* Copy the peer macaddress to the wma buffer */
WMI_CHAR_ARRAY_TO_MAC_ADDR(pLinkSpeed->peer_macaddr, &cmd->peer_macaddr);
WMA_LOGD("%s: pLinkSpeed->peerMacAddr: %pM, "
"peer_macaddr.mac_addr31to0: 0x%x, peer_macaddr.mac_addr47to32: 0x%x",
__func__, pLinkSpeed->peer_macaddr,
cmd->peer_macaddr.mac_addr31to0,
cmd->peer_macaddr.mac_addr47to32);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID)) {
WMA_LOGE("%s: failed to send link speed command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_get_peer_info() - get station's information
* @handle: wma interface
* @prssi_req: get peer info request information
*
* This function will send WMI_REQUEST_STATS_CMDID
* to wmi
*
* Return: 0 on success, otherwise error value
*/
static VOS_STATUS wma_get_peer_info(WMA_HANDLE handle,
struct sir_peer_info_req *peer_info_req)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
wmi_request_stats_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;
}
len = sizeof(wmi_request_stats_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_stats_cmd_fixed_param *)buf_ptr;
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_PEER_STAT;
cmd->vdev_id = peer_info_req->sessionid;
wma_handle->get_sta_peer_info = TRUE;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_REQUEST_STATS_CMDID)) {
WMA_LOGE("Failed to send host stats request to fw");
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
vos_mem_copy(&(wma_handle->peer_macaddr),
&(peer_info_req->peer_macaddr),
VOS_MAC_ADDR_SIZE);
return VOS_STATUS_SUCCESS;
}
static int
wmi_unified_pdev_set_param(wmi_unified_t wmi_handle, WMI_PDEV_PARAM param_id,
u_int32_t param_value)
{
int ret;
wmi_pdev_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_pdev_set_param_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_param_cmd_fixed_param));
cmd->pdev_id = 0;
cmd->param_id = param_id;
cmd->param_value = param_value;
WMA_LOGD("Setting pdev param = %x, value = %u",
param_id, param_value);
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_PDEV_SET_PARAM_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send set param command ret = %d", ret);
wmi_buf_free(buf);
}
return ret;
}
static int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle,
uint8_t vdev_id, u_int32_t value)
{
struct ol_txrx_stats_req req;
ol_txrx_vdev_handle vdev;
vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
if (!vdev) {
WMA_LOGE("%s:Invalid vdev handle", __func__);
return -EINVAL;
}
vos_mem_zero(&req, sizeof(req));
req.stats_type_reset_mask = value;
ol_txrx_fw_stats_get(vdev, &req, false);
return 0;
}
static int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle,
uint8_t vdev_id, u_int32_t value)
{
struct ol_txrx_stats_req req;
ol_txrx_vdev_handle vdev;
vdev = wma_find_vdev_by_id(wma_handle, vdev_id);
if (!vdev) {
WMA_LOGE("%s:Invalid vdev handle", __func__);
return -EINVAL;
}
vos_mem_zero(&req, sizeof(req));
req.print.verbose = 1;
switch (value) {
case WMA_FW_PHY_STATS:
case WMA_FW_RX_REORDER_STATS:
case WMA_FW_RX_RC_STATS:
case WMA_FW_TX_PPDU_STATS:
req.stats_type_upload_mask = 1 << (value - 1);
break;
case WMA_FW_TX_CONCISE_STATS:
/*
* Stats request 5 is the same as stats request 4,
* but with only a concise printout.
*/
req.print.concise = 1;
req.stats_type_upload_mask = 1 << (WMA_FW_TX_PPDU_STATS - 1);
break;
case WMA_FW_TX_RC_STATS:
req.stats_type_upload_mask = 1 << (WMA_FW_TX_CONCISE_STATS - 1);
break;
case WMA_FW_RX_REM_RING_BUF:
/*
* This part of the code is a bit confusing.
* For the statistics command iwpriv wlan0 txrx_fw_stats <n>,
* for all n <= 4, there is 1:1 mapping of WMA defined value (n)
* with f/w required stats_type_upload_mask.
* For n <= 4, stats_type_upload_mask = 1 << (n - 1)
* With the introduction of WMA_FW_TX_CONCISE_STATS,
* there is a need for special handling, where for n = 5,
* stats_type_upload_mask = 1 << (n - 2).
* However per current code, there is no way to set the value of
* stats_type_upload_mask for n > 5.
* In the mean-time for dumping Remote Ring Buffer information,
* f/w expects stats_type_upload_mask = 1 << 12.
* However going by CLI command arguments, n should be 7.
* There seems to be no apparent correlation between 7 & 12.
* To fix this properly, one needs to fix the WMA defines
* appropriately and always let n have a 1:1
* correspondence with the bitmask expected by f/w.
* Do not want to disturb the existing code now,
* but extending this code, so that CLI argument "n" has
* 1:1 correspondence with f/w bitmask.
* With this approach, for remote ring information,
* the statistics command should be:
* iwpriv wlan0 txrx_fw_stats 12
*/
/* FIXME : Fix all the values in the appropriate way. */
req.stats_type_upload_mask = 1 << WMA_FW_RX_REM_RING_BUF;
break;
case WMA_FW_RX_TXBF_MUSU_NDPA:
req.stats_type_upload_mask = 1 << WMA_FW_RX_TXBF_MUSU_NDPA;
break;
default:
WMA_LOGE("Invalid txrx_fw_stats requested id:%d",
value);
return -EINVAL;
}
ol_txrx_fw_stats_get(vdev, &req, true);
return 0;
}
static int32_t wma_set_priv_cfg(tp_wma_handle wma_handle,
wda_cli_set_cmd_t *privcmd)
{
int32_t ret = 0;
switch (privcmd->param_id) {
case WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID:
ret = wma_set_txrx_fw_stats_level(wma_handle,
privcmd->param_vdev_id,
privcmd->param_value);
break;
case WMA_VDEV_TXRX_FWSTATS_RESET_CMDID:
ret = wma_txrx_fw_stats_reset(wma_handle,
privcmd->param_vdev_id,
privcmd->param_value);
break;
case WMI_STA_SMPS_FORCE_MODE_CMDID:
ret = wma_set_mimops(wma_handle, privcmd->param_vdev_id,
privcmd->param_value);
break;
case WMI_STA_SMPS_PARAM_CMDID:
wma_set_smps_params(wma_handle, privcmd->param_vdev_id,
privcmd->param_value);
break;
case WMA_VDEV_MCC_SET_TIME_LATENCY:
{
/* Extract first MCC adapter/vdev channel number and latency */
tANI_U8 mcc_channel = privcmd->param_value & 0x000000FF;
tANI_U8 mcc_channel_latency =
(privcmd->param_value & 0x0000FF00) >> 8;
int ret = -1;
WMA_LOGD("%s: Parsed input: Channel #1:%d, latency:%dms",
__func__, mcc_channel, mcc_channel_latency);
ret = wma_set_mcc_channel_time_latency
(
wma_handle,
mcc_channel,
mcc_channel_latency
);
}
break;
case WMA_VDEV_MCC_SET_TIME_QUOTA:
{
/** Extract the MCC 2 adapters/vdevs channel numbers and time
* quota value for the first adapter only (which is specified
* in iwpriv command.
*/
tANI_U8 adapter_2_chan_number =
privcmd->param_value & 0x000000FF;
tANI_U8 adapter_1_chan_number =
(privcmd->param_value & 0x0000FF00) >> 8;
tANI_U8 adapter_1_quota =
(privcmd->param_value & 0x00FF0000) >> 16;
int ret = -1;
WMA_LOGD("%s: Parsed input: Channel #1:%d, Channel #2:%d,"
"quota 1:%dms", __func__, adapter_1_chan_number,
adapter_2_chan_number, adapter_1_quota);
ret = wma_set_mcc_channel_time_quota
(
wma_handle,
adapter_1_chan_number,
adapter_1_quota,
adapter_2_chan_number
);
}
break;
case WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE:
{
wma_handle->wma_ibss_power_save_params.atimWindowLength =
privcmd->param_value;
WMA_LOGD("%s: IBSS power save ATIM Window = %d", __func__,
wma_handle->wma_ibss_power_save_params.atimWindowLength);
}
break;
case WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED:
{
wma_handle->wma_ibss_power_save_params.isPowerSaveAllowed =
privcmd->param_value;
WMA_LOGD("%s: IBSS is Power Save Allowed = %d", __func__,
wma_handle->wma_ibss_power_save_params.isPowerSaveAllowed);
}
break;
case WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED:
{
wma_handle->wma_ibss_power_save_params.isPowerCollapseAllowed =
privcmd->param_value;
WMA_LOGD("%s: IBSS is Power Collapse Allowed = %d", __func__,
wma_handle->wma_ibss_power_save_params.isPowerCollapseAllowed);
}
break;
case WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX:
{
wma_handle->wma_ibss_power_save_params.isAwakeonTxRxEnabled =
privcmd->param_value;
WMA_LOGD("%s: IBSS Power Save Awake on Tx/Rx Enabled = %d", __func__,
wma_handle->wma_ibss_power_save_params.isAwakeonTxRxEnabled);
}
break;
case WMA_VDEV_IBSS_SET_INACTIVITY_TIME:
{
wma_handle->wma_ibss_power_save_params.inactivityCount =
privcmd->param_value;
WMA_LOGD("%s: IBSS Power Save Data Inactivity Count = %d", __func__,
wma_handle->wma_ibss_power_save_params.inactivityCount);
}
break;
case WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME:
{
wma_handle->wma_ibss_power_save_params.txSPEndInactivityTime =
privcmd->param_value;
WMA_LOGD("%s: IBSS Power Save Transmit EOSP inactivity time out = %d",
__func__,
wma_handle->wma_ibss_power_save_params.txSPEndInactivityTime);
}
break;
case WMA_VDEV_DFS_CONTROL_CMDID:
{
struct ieee80211com *dfs_ic = wma_handle->dfs_ic;
struct ath_dfs *dfs;
if (!dfs_ic) {
ret = -ENOENT;
} else {
if (dfs_ic->ic_curchan) {
WMA_LOGD("%s: Debug cmd: %s received on ch: %d",
__func__,
"WMA_VDEV_DFS_CONTROL_CMDID",
dfs_ic->ic_curchan->ic_ieee);
if (dfs_ic->ic_curchan->ic_flagext &
IEEE80211_CHAN_DFS) {
dfs = (struct ath_dfs *)dfs_ic->ic_dfs;
dfs->dfs_bangradar = 1;
dfs->ath_radar_tasksched = 1;
OS_SET_TIMER(&dfs->ath_dfs_task_timer,
0);
} else {
ret = -ENOENT;
}
} else {
ret = -ENOENT;
}
}
if ( ret == -ENOENT) {
WMA_LOGE("%s: Operating channel is not DFS capable, "
"ignoring %s",
__func__,
"WMA_VDEV_DFS_CONTROL_CMDID");
} else if (ret) {
WMA_LOGE("%s: Sending command %s failed with %d\n",
__func__,
"WMA_VDEV_DFS_CONTROL_CMDID",
ret);
}
}
break;
case WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS:
{
wma_handle->wma_ibss_power_save_params.ibssPsWarmupTime =
privcmd->param_value;
WMA_LOGD("%s: IBSS Power Save Warm Up Time in Seconds = %d",
__func__,
wma_handle->wma_ibss_power_save_params.ibssPsWarmupTime);
}
break;
case WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW:
{
wma_handle->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable =
privcmd->param_value;
WMA_LOGD("%s: IBSS Power Save single RX Chain Enable In ATIM = %d",
__func__,
wma_handle->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable);
}
break;
#ifdef IPA_UC_OFFLOAD
case WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID:
{
ol_txrx_pdev_handle pdev;
if (vos_is_load_unload_in_progress(VOS_MODULE_ID_WDA, NULL)) {
WMA_LOGE("%s: Driver load/unload in progress", __func__);
return -EINVAL;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX,
wma_handle->vos_context);
if (!pdev) {
WMA_LOGE("pdev NULL for uc stat");
return -EINVAL;
}
ol_txrx_ipa_uc_get_stat(pdev);
}
break;
#endif /* IPA_UC_OFFLOAD */
default:
WMA_LOGE("Invalid wma config command id:%d",
privcmd->param_id);
ret = -EINVAL;
}
return ret;
}
static int wmi_crash_inject(wmi_unified_t wmi_handle, u_int32_t type,
u_int32_t delay_time_ms)
{
int ret = 0;
WMI_FORCE_FW_HANG_CMD_fixed_param *cmd;
u_int16_t len = sizeof(*cmd);
wmi_buf_t buf;
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed!", __func__);
return -ENOMEM;
}
cmd = (WMI_FORCE_FW_HANG_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(WMI_FORCE_FW_HANG_CMD_fixed_param));
cmd->type = type;
cmd->delay_time_ms = delay_time_ms;
ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_FORCE_FW_HANG_CMDID);
if (ret < 0) {
WMA_LOGE("%s: Failed to send set param command, ret = %d",
__func__, ret);
wmi_buf_free(buf);
}
return ret;
}
/**
* wma_crash_inject() - sends command to FW to simulate crash
* @wma_handle: pointer of WMA context
* @type: subtype of the command
* @delay_time_ms: time in milliseconds for FW to delay the crash
*
* This function will send a command to FW in order to simulate different
* kinds of FW crashes.
*
* Return: 0 for success or reasons for failure
*/
int wma_crash_inject(tp_wma_handle wma_handle, uint32_t type,
uint32_t delay_time_ms)
{
return wmi_crash_inject(wma_handle->wmi_handle, type, delay_time_ms);
}
static int32_t wmi_unified_set_sta_ps_param(wmi_unified_t wmi_handle,
u_int32_t vdev_id, u_int32_t param, u_int32_t value)
{
wmi_sta_powersave_param_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
tp_wma_handle wma;
struct wma_txrx_node *iface;
wma = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
if (NULL == wma) {
WMA_LOGE("%s: wma is NULL", __func__);
return -EIO;
}
iface = &wma->interfaces[vdev_id];
WMA_LOGD("Set Sta Ps param vdevId %d Param %d val %d",
vdev_id, param, value);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: Set Sta Ps param Mem Alloc Failed", __func__);
return -ENOMEM;
}
cmd = (wmi_sta_powersave_param_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_sta_powersave_param_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->param = param;
cmd->value = value;
if (wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_STA_POWERSAVE_PARAM_CMDID)) {
WMA_LOGE("Set Sta Ps param Failed vdevId %d Param %d val %d",
vdev_id, param, value);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
#ifdef FEATURE_GREEN_AP
static int32_t wmi_unified_pdev_green_ap_ps_enable_cmd(wmi_unified_t wmi_handle,
u_int32_t value)
{
wmi_pdev_green_ap_ps_enable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
WMA_LOGD("Set Green AP PS val %d", value);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: Green AP PS Mem Alloc Failed", __func__);
return -ENOMEM;
}
cmd = (wmi_pdev_green_ap_ps_enable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_green_ap_ps_enable_cmd_fixed_param));
cmd->pdev_id = 0;
cmd->enable = value;
if (wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID)) {
WMA_LOGE("Set Green AP PS param Failed val %d", value);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
/**
* wma_egap_info_status_event() - egap info status event
* @handle: pointer to wma handler
* @event: pointer to event
* @len: len of the event
*
* Return: 0 for success, otherwise appropriate error code
*/
static int wma_egap_info_status_event(void *handle, u_int8_t *event,
uint32_t len)
{
WMI_TX_PAUSE_EVENTID_param_tlvs *param_buf;
wmi_ap_ps_egap_info_event_fixed_param *egap_info_event;
wmi_ap_ps_egap_info_chainmask_list *chainmask_event;
u_int8_t *buf_ptr;
param_buf = (WMI_TX_PAUSE_EVENTID_param_tlvs *)event;
if (!param_buf) {
WMA_LOGE("Invalid EGAP Info status event buffer");
return -EINVAL;
}
egap_info_event = (wmi_ap_ps_egap_info_event_fixed_param *)
param_buf->fixed_param;
buf_ptr = (uint8_t *)egap_info_event;
buf_ptr += sizeof(wmi_ap_ps_egap_info_event_fixed_param);
chainmask_event = (wmi_ap_ps_egap_info_chainmask_list *)buf_ptr;
WMA_LOGI("mac_id: %d, status: %d, tx_mask: %x, rx_mask: %d",
chainmask_event->mac_id,
egap_info_event->status,
chainmask_event->tx_chainmask,
chainmask_event->rx_chainmask);
return 0;
}
/**
* wma_send_egap_conf_params() - send wmi cmd of egap configuration params
* @wma_handle: wma handler
* @egap_params: pointer to egap_params
*
* Return: 0 for success, otherwise appropriate error code
*/
VOS_STATUS wma_send_egap_conf_params(WMA_HANDLE handle,
struct egap_conf_params *egap_params)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_ap_ps_egap_param_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send ap_ps_egap cmd");
return -ENOMEM;
}
cmd = (wmi_ap_ps_egap_param_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_ap_ps_egap_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_ap_ps_egap_param_cmd_fixed_param));
cmd->enable = egap_params->enable;
cmd->inactivity_time = egap_params->inactivity_time;
cmd->wait_time = egap_params->wait_time;
cmd->flags = egap_params->flags;
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_AP_PS_EGAP_PARAM_CMDID);
if (err) {
WMA_LOGE("Failed to send ap_ps_egap cmd");
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
/**
* wma_setup_egap_support() - setup the EGAP support flag
* @tgt_cfg: pointer to hdd target configuration
* @egap_support: EGAP support flag
*
* Return: None
*/
void wma_setup_egap_support(struct hdd_tgt_cfg *tgt_cfg, WMA_HANDLE handle)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
if (tgt_cfg && wma_handle)
tgt_cfg->egap_support = wma_handle->egap_support;
}
/**
* wma_register_egap_event_handle() - register the EGAP event handle
* @wma_handle: wma handler
*
* Return: None
*/
void wma_register_egap_event_handle(WMA_HANDLE handle)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
int status;
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_EGAP)) {
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_AP_PS_EGAP_INFO_EVENTID,
wma_egap_info_status_event);
if (status) {
WMA_LOGE("Failed to register Enhance Green AP event");
wma_handle->egap_support = false;
} else {
WMA_LOGI("Set the Enhance Green AP event handler");
wma_handle->egap_support = true;
}
} else
wma_handle->egap_support = false;
}
#endif /* FEATURE_GREEN_AP */
static int
wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, u_int32_t if_id,
gtx_config_t *gtx_info)
{
wmi_vdev_set_gtx_params_cmd_fixed_param *cmd;
wmi_buf_t buf;
int len = sizeof(wmi_vdev_set_gtx_params_cmd_fixed_param);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __FUNCTION__);
return -1;
}
cmd = (wmi_vdev_set_gtx_params_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_set_gtx_params_cmd_fixed_param));
cmd->vdev_id = if_id;
cmd->gtxRTMask[0] = gtx_info->gtxRTMask[0];
cmd->gtxRTMask[1] = gtx_info->gtxRTMask[1];
cmd->userGtxMask = gtx_info->gtxUsrcfg;
cmd->gtxPERThreshold = gtx_info->gtxPERThreshold;
cmd->gtxPERMargin = gtx_info->gtxPERMargin;
cmd->gtxTPCstep = gtx_info->gtxTPCstep;
cmd->gtxTPCMin = gtx_info->gtxTPCMin;
cmd->gtxBWMask = gtx_info->gtxBWMask;
WMA_LOGD("Setting vdev%d GTX values:htmcs 0x%x, vhtmcs 0x%x, usermask 0x%x, gtxPERThreshold %d, gtxPERMargin %d, gtxTPCstep %d, gtxTPCMin %d, gtxBWMask 0x%x.",
if_id, cmd->gtxRTMask[0], cmd->gtxRTMask[1],
cmd->userGtxMask, cmd->gtxPERThreshold, cmd->gtxPERMargin,
cmd->gtxTPCstep, cmd->gtxTPCMin, cmd->gtxBWMask);
return wmi_unified_cmd_send(wmi_handle, buf, len, WMI_VDEV_SET_GTX_PARAMS_CMDID);
}
/**
* wma_send_echo_request() - send echo request to firmware
* @wma: wma context
*
* Return: none
*/
static void wma_send_echo_request(tp_wma_handle wma)
{
wmi_echo_cmd_fixed_param *cmd;
wmi_buf_t buf;
int len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __FUNCTION__);
return;
}
cmd = (wmi_echo_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_echo_cmd_fixed_param));
cmd->value = true;
WMA_LOGD("Sent Echo request to firmware!");
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_ECHO_CMDID)) {
WMA_LOGE("Failed to send Echo cmd to firmware");
wmi_buf_free(buf);
}
}
/**
* wma_set_modulated_dtim() - function to configure modulated dtim
* @wma: wma handle
* @privcmd: structure containing parameters
*
* This function configures the modulated dtim in firmware
*
* Return: none
*/
static void wma_set_modulated_dtim(tp_wma_handle wma,
wda_cli_set_cmd_t *privcmd)
{
uint8_t vdev_id = privcmd->param_vdev_id;
struct wma_txrx_node *iface =
&wma->interfaces[vdev_id];
bool prev_dtim_enabled;
uint32_t listen_interval;
int ret;
iface->alt_modulated_dtim = privcmd->param_value;
prev_dtim_enabled = iface->alt_modulated_dtim_enabled;
if (1 != privcmd->param_value)
iface->alt_modulated_dtim_enabled = true;
else
iface->alt_modulated_dtim_enabled = false;
if ((true == iface->alt_modulated_dtim_enabled) ||
(true == prev_dtim_enabled)) {
listen_interval = iface->alt_modulated_dtim
* iface->dtimPeriod;
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
privcmd->param_vdev_id,
WMI_VDEV_PARAM_LISTEN_INTERVAL,
listen_interval);
if (ret)
/* Even if it fails, continue */
WMA_LOGW("Failed to set listen interval %d",
listen_interval);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
privcmd->param_vdev_id,
WMI_VDEV_PARAM_DTIM_POLICY ,
NORMAL_DTIM);
if (ret)
WMA_LOGE("Failed to Set to Normal DTIM policy");
}
}
static int32_t wma_send_pdev_monitor_mode_cmd(
tp_wma_handle wma,
wda_cli_set_cmd_t *privcmd)
{
wmi_pdev_set_rx_filter_promiscuous_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
WMA_LOGD("Set pdev monitor mode value %d", privcmd->param_value);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: pdev monitor mode Mem Alloc Failed", __func__);
return -ENOMEM;
}
cmd = (wmi_pdev_set_rx_filter_promiscuous_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_rx_filter_promiscuous_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_rx_filter_promiscuous_cmd_fixed_param));
cmd->pdev_id = 0; /* default 0, pdev id */
cmd->rx_filter_promiscuous_enable = privcmd->param_value;
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PDEV_SET_RX_FILTER_PROMISCUOUS_CMDID)) {
WMA_LOGE("set pdev monitor mode failed, val %d",
privcmd->param_value);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
static void wma_process_cli_set_cmd(tp_wma_handle wma,
wda_cli_set_cmd_t *privcmd)
{
int ret = 0, vid = privcmd->param_vdev_id, pps_val = 0;
struct wma_txrx_node *intr = wma->interfaces;
tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
struct qpower_params *qparams = &intr[vid].config.qpower_params;
if (NULL == pMac) {
WMA_LOGE("%s: Failed to get pMac", __func__);
return;
}
if (privcmd->param_id >= WMI_CMDID_MAX) {
/*
* This configuration setting is not done using any wmi
* command, call appropriate handler.
*/
if (wma_set_priv_cfg(wma, privcmd))
WMA_LOGE("Failed to set wma priv congiuration");
return;
}
switch (privcmd->param_vp_dev) {
case VDEV_CMD:
if (!wma->interfaces[privcmd->param_vdev_id].is_vdev_valid) {
WMA_LOGE("%s Vdev id is not valid", __func__);
return ;
}
WMA_LOGD("vdev id %d pid %d pval %d", privcmd->param_vdev_id,
privcmd->param_id, privcmd->param_value);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
privcmd->param_vdev_id,
privcmd->param_id,
privcmd->param_value);
if (ret) {
WMA_LOGE("wmi_unified_vdev_set_param_send"
" failed ret %d", ret);
return;
}
break;
case PDEV_CMD:
WMA_LOGD("pdev pid %d pval %d", privcmd->param_id,
privcmd->param_value);
if ((privcmd->param_id == WMI_PDEV_PARAM_RX_CHAIN_MASK) ||
(privcmd->param_id == WMI_PDEV_PARAM_TX_CHAIN_MASK) ||
(privcmd->param_id == WMI_PDEV_PARAM_RX_CHAIN_MASK_2G) ||
(privcmd->param_id == WMI_PDEV_PARAM_TX_CHAIN_MASK_2G) ||
(privcmd->param_id == WMI_PDEV_PARAM_RX_CHAIN_MASK_5G) ||
(privcmd->param_id == WMI_PDEV_PARAM_TX_CHAIN_MASK_5G))
wma_update_txrx_chainmask(wma->num_rf_chains,
&privcmd->param_value);
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
privcmd->param_id,
privcmd->param_value);
if (ret) {
WMA_LOGE("wmi_unified_vdev_set_param_send"
" failed ret %d", ret);
return;
}
break;
case GEN_CMD:
{
ol_txrx_vdev_handle vdev = NULL;
struct wma_txrx_node *intr = wma->interfaces;
vdev = wma_find_vdev_by_id(wma, privcmd->param_vdev_id);
if (!vdev) {
WMA_LOGE("%s:Invalid vdev handle", __func__);
return;
}
WMA_LOGD("gen pid %d pval %d", privcmd->param_id,
privcmd->param_value);
switch (privcmd->param_id) {
case GEN_VDEV_PARAM_AMPDU:
ret = ol_txrx_aggr_cfg(vdev, privcmd->param_value, 0);
if (ret)
WMA_LOGE("ol_txrx_aggr_cfg set ampdu"
" failed ret %d", ret);
else
intr[privcmd->param_vdev_id].config.ampdu = privcmd->param_value;
break;
case GEN_VDEV_PARAM_AMSDU:
ret = ol_txrx_aggr_cfg(vdev, 0, privcmd->param_value);
if (ret)
WMA_LOGE("ol_txrx_aggr_cfg set amsdu"
" failed ret %d", ret);
else
intr[privcmd->param_vdev_id].config.amsdu = privcmd->param_value;
break;
case GEN_PARAM_DUMP_AGC_START:
HTCDump(wma->htc_handle, AGC_DUMP, true);
break;
case GEN_PARAM_DUMP_AGC:
HTCDump(wma->htc_handle, AGC_DUMP, false);
break;
case GEN_PARAM_DUMP_CHANINFO_START:
HTCDump(wma->htc_handle, CHAN_DUMP, true);
break;
case GEN_PARAM_DUMP_CHANINFO:
HTCDump(wma->htc_handle, CHAN_DUMP, false);
break;
case GEN_PARAM_DUMP_WATCHDOG:
HTCDump(wma->htc_handle, WD_DUMP, false);
break;
case GEN_PARAM_CRASH_INJECT:
ret = wmi_crash_inject(wma->wmi_handle,
privcmd->param_value, privcmd->param_sec_value);
break;
case GEN_PARAM_CAPTURE_TSF:
ret = wma_capture_tsf(wma, privcmd->param_value);
break;
case GEN_PARAM_RESET_TSF_GPIO:
ret = wma_reset_tsf_gpio(wma, privcmd->param_value);
break;
#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
case GEN_PARAM_DUMP_PCIE_ACCESS_LOG:
HTCDump(wma->htc_handle, PCIE_DUMP, false);
break;
#endif
case GEN_PARAM_MODULATED_DTIM:
wma_set_modulated_dtim(wma, privcmd);
break;
case GEN_PDEV_MONITOR_MODE:
wma_send_pdev_monitor_mode_cmd(wma, privcmd);
break;
default:
WMA_LOGE("Invalid param id 0x%x", privcmd->param_id);
break;
}
break;
}
case DBG_CMD:
WMA_LOGD("dbg pid %d pval %d", privcmd->param_id,
privcmd->param_value);
switch (privcmd->param_id) {
case WMI_DBGLOG_LOG_LEVEL:
ret = dbglog_set_log_lvl(wma->wmi_handle, privcmd->param_value);
if (ret)
WMA_LOGE("dbglog_set_log_lvl"
" failed ret %d", ret);
break;
case WMI_DBGLOG_VAP_ENABLE:
ret = dbglog_vap_log_enable(wma->wmi_handle, privcmd->param_value, TRUE);
if (ret)
WMA_LOGE("dbglog_vap_log_enable"
" failed ret %d", ret);
break;
case WMI_DBGLOG_VAP_DISABLE:
ret = dbglog_vap_log_enable(wma->wmi_handle, privcmd->param_value, FALSE);
if (ret)
WMA_LOGE("dbglog_vap_log_enable"
" failed ret %d", ret);
break;
case WMI_DBGLOG_MODULE_ENABLE:
ret = dbglog_module_log_enable(wma->wmi_handle, privcmd->param_value, TRUE);
if (ret)
WMA_LOGE("dbglog_module_log_enable"
" failed ret %d", ret);
break;
case WMI_DBGLOG_MODULE_DISABLE:
ret = dbglog_module_log_enable(wma->wmi_handle, privcmd->param_value, FALSE);
if (ret)
WMA_LOGE("dbglog_module_log_enable"
" failed ret %d", ret);
break;
case WMI_DBGLOG_MOD_LOG_LEVEL:
ret = dbglog_set_mod_log_lvl(wma->wmi_handle, privcmd->param_value);
if (ret)
WMA_LOGE("dbglog_module_log_enable"
" failed ret %d", ret);
break;
case WMI_DBGLOG_TYPE:
ret = dbglog_parser_type_init(wma->wmi_handle, privcmd->param_value);
if (ret)
WMA_LOGE("dbglog_parser_type_init"
" failed ret %d", ret);
break;
case WMI_DBGLOG_REPORT_ENABLE:
ret = dbglog_report_enable(wma->wmi_handle, privcmd->param_value);
if (ret)
WMA_LOGE("dbglog_report_enable"
" failed ret %d", ret);
break;
#ifdef FEATURE_GREEN_AP
case WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID:
/* Set the Green AP */
ret = wmi_unified_pdev_green_ap_ps_enable_cmd(wma->wmi_handle,
privcmd->param_value);
if (ret) {
WMA_LOGE("Set GreenAP Failed val %d", privcmd->param_value);
}
break;
#endif /* FEATURE_GREEN_AP */
default:
WMA_LOGE("Invalid param id 0x%x", privcmd->param_id);
break;
}
break;
case PPS_CMD:
WMA_LOGD("dbg pid %d pval %d", privcmd->param_id,
privcmd->param_value);
switch (privcmd->param_id) {
case WMI_VDEV_PPS_PAID_MATCH:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_PAID_MATCH & 0xffff);
intr[vid].config.pps_params.paid_match_enable = privcmd->param_value;
break;
case WMI_VDEV_PPS_GID_MATCH:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_GID_MATCH & 0xffff);
intr[vid].config.pps_params.gid_match_enable = privcmd->param_value;
break;
case WMI_VDEV_PPS_EARLY_TIM_CLEAR:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff);
intr[vid].config.pps_params.tim_clear = privcmd->param_value;
break;
case WMI_VDEV_PPS_EARLY_DTIM_CLEAR:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff);
intr[vid].config.pps_params.dtim_clear = privcmd->param_value;
break;
case WMI_VDEV_PPS_EOF_PAD_DELIM:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff);
intr[vid].config.pps_params.eof_delim = privcmd->param_value;
break;
case WMI_VDEV_PPS_MACADDR_MISMATCH:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff);
intr[vid].config.pps_params.mac_match = privcmd->param_value;
break;
case WMI_VDEV_PPS_DELIM_CRC_FAIL:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff);
intr[vid].config.pps_params.delim_fail = privcmd->param_value;
break;
case WMI_VDEV_PPS_GID_NSTS_ZERO:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff);
intr[vid].config.pps_params.nsts_zero = privcmd->param_value;
break;
case WMI_VDEV_PPS_RSSI_CHECK:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_RSSI_CHECK & 0xffff);
intr[vid].config.pps_params.rssi_chk = privcmd->param_value;
break;
case WMI_VDEV_PPS_5G_EBT:
pps_val = ((privcmd->param_value << 31) & 0xffff0000) |
(PKT_PWR_SAVE_5G_EBT & 0xffff);
intr[vid].config.pps_params.ebt_5g = privcmd->param_value;
break;
default:
WMA_LOGE("Invalid param id 0x%x", privcmd->param_id);
break;
}
break;
case QPOWER_CMD:
WMA_LOGD("QPOWER CLI CMD pid %d pval %d", privcmd->param_id,
privcmd->param_value);
switch (privcmd->param_id) {
case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT:
WMA_LOGD("QPOWER CLI CMD:Ps Poll Cnt val %d",
privcmd->param_value);
/* Set the QPower Ps Poll Count */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
vid,
WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT,
privcmd->param_value);
if (ret) {
WMA_LOGE("Set Q-PsPollCnt Failed vdevId %d val %d",
vid, privcmd->param_value);
} else {
qparams->max_ps_poll_cnt =
privcmd->param_value;
}
break;
case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE:
WMA_LOGD("QPOWER CLI CMD:Max Tx Before wake val %d",
privcmd->param_value);
/* Set the QPower Max Tx Before Wake */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
vid,
WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE,
privcmd->param_value);
if (ret) {
WMA_LOGE("Set Q-MaxTxBefWake Failed vId %d val %d",
vid, privcmd->param_value);
} else {
qparams->max_tx_before_wake =
privcmd->param_value;
}
break;
case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL:
WMA_LOGD("QPOWER CLI CMD:Ps Poll Wake Inv val %d",
privcmd->param_value);
/* Set the QPower Spec Ps Poll Wake Inv */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
vid,
WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL,
privcmd->param_value);
if (ret) {
WMA_LOGE("Set Q-PsPoll WakeIntv Failed vId %d val %d",
vid, privcmd->param_value);
} else {
qparams->spec_ps_poll_wake_interval =
privcmd->param_value;
}
break;
case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL:
WMA_LOGD("QPOWER CLI CMD:Spec NoData Ps Poll val %d",
privcmd->param_value);
/* Set the QPower Spec NoData PsPoll */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
vid,
WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL,
privcmd->param_value);
if (ret) {
WMA_LOGE("Set Q-SpecNoDataPsPoll Failed vId %d val %d",
vid, privcmd->param_value);
} else {
qparams->max_spec_nodata_ps_poll =
privcmd->param_value;
}
break;
default:
WMA_LOGE("Invalid param id 0x%x", privcmd->param_id);
break;
}
break;
case GTX_CMD:
WMA_LOGD("vdev id %d pid %d pval %d", privcmd->param_vdev_id,
privcmd->param_id, privcmd->param_value);
switch (privcmd->param_id) {
case WMI_VDEV_PARAM_GTX_HT_MCS:
intr[vid].config.gtx_info.gtxRTMask[0] = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
break;
case WMI_VDEV_PARAM_GTX_VHT_MCS:
intr[vid].config.gtx_info.gtxRTMask[1] = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
break;
case WMI_VDEV_PARAM_GTX_USR_CFG:
intr[vid].config.gtx_info.gtxUsrcfg = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
break;
case WMI_VDEV_PARAM_GTX_THRE:
intr[vid].config.gtx_info.gtxPERThreshold = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
break;
case WMI_VDEV_PARAM_GTX_MARGIN:
intr[vid].config.gtx_info.gtxPERMargin = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
break;
case WMI_VDEV_PARAM_GTX_STEP:
intr[vid].config.gtx_info.gtxTPCstep = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
break;
case WMI_VDEV_PARAM_GTX_MINTPC:
intr[vid].config.gtx_info.gtxTPCMin = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
break;
case WMI_VDEV_PARAM_GTX_BW_MASK:
intr[vid].config.gtx_info.gtxBWMask = privcmd->param_value;
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle,
privcmd->param_vdev_id,
&intr[vid].config.gtx_info);
if (ret) {
WMA_LOGE("wmi_unified_vdev_set_param_send"
" failed ret %d", ret);
return;
}
break;
default:
break;
}
break;
default:
WMA_LOGE("Invalid vpdev command id");
}
if (1 == privcmd->param_vp_dev) {
switch (privcmd->param_id) {
case WMI_VDEV_PARAM_NSS:
intr[vid].config.nss = privcmd->param_value;
break;
case WMI_VDEV_PARAM_LDPC:
intr[vid].config.ldpc = privcmd->param_value;
break;
case WMI_VDEV_PARAM_TX_STBC:
intr[vid].config.tx_stbc = privcmd->param_value;
break;
case WMI_VDEV_PARAM_RX_STBC:
intr[vid].config.rx_stbc = privcmd->param_value;
break;
case WMI_VDEV_PARAM_SGI:
intr[vid].config.shortgi = privcmd->param_value;
break;
case WMI_VDEV_PARAM_ENABLE_RTSCTS:
intr[vid].config.rtscts_en = privcmd->param_value;
break;
case WMI_VDEV_PARAM_CHWIDTH:
intr[vid].config.chwidth = privcmd->param_value;
break;
case WMI_VDEV_PARAM_FIXED_RATE:
intr[vid].config.tx_rate = privcmd->param_value;
break;
case WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE:
intr[vid].config.erx_adjust = privcmd->param_value;
break;
case WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM:
intr[vid].config.erx_bmiss_num = privcmd->param_value;
break;
case WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE:
intr[vid].config.erx_bmiss_cycle = privcmd->param_value;
break;
case WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP:
intr[vid].config.erx_slop_step = privcmd->param_value;
break;
case WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP:
intr[vid].config.erx_init_slop = privcmd->param_value;
break;
case WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE:
intr[vid].config.erx_adj_pause = privcmd->param_value;
break;
case WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE:
intr[vid].config.erx_dri_sample = privcmd->param_value;
break;
default:
WMA_LOGE("Invalid wda_cli_set vdev command/Not"
" yet implemented 0x%x", privcmd->param_id);
break;
}
} else if (2 == privcmd->param_vp_dev) {
switch (privcmd->param_id) {
case WMI_PDEV_PARAM_ANI_ENABLE:
wma->pdevconfig.ani_enable = privcmd->param_value;
break;
case WMI_PDEV_PARAM_ANI_POLL_PERIOD:
wma->pdevconfig.ani_poll_len = privcmd->param_value;
break;
case WMI_PDEV_PARAM_ANI_LISTEN_PERIOD:
wma->pdevconfig.ani_listen_len = privcmd->param_value;
break;
case WMI_PDEV_PARAM_ANI_OFDM_LEVEL:
wma->pdevconfig.ani_ofdm_level = privcmd->param_value;
break;
case WMI_PDEV_PARAM_ANI_CCK_LEVEL:
wma->pdevconfig.ani_cck_level = privcmd->param_value;
break;
case WMI_PDEV_PARAM_DYNAMIC_BW:
wma->pdevconfig.cwmenable = privcmd->param_value;
break;
case WMI_PDEV_PARAM_CTS_CBW:
wma->pdevconfig.cts_cbw = privcmd->param_value;
break;
case WMI_PDEV_PARAM_TX_CHAIN_MASK:
wma->pdevconfig.txchainmask = privcmd->param_value;
break;
case WMI_PDEV_PARAM_RX_CHAIN_MASK:
wma->pdevconfig.rxchainmask = privcmd->param_value;
break;
case WMI_PDEV_PARAM_TX_CHAIN_MASK_2G:
wma->pdevconfig.chainmask_2g_tx = privcmd->param_value;
break;
case WMI_PDEV_PARAM_RX_CHAIN_MASK_2G:
wma->pdevconfig.chainmask_2g_rx = privcmd->param_value;
break;
case WMI_PDEV_PARAM_TX_CHAIN_MASK_5G:
wma->pdevconfig.chainmask_5g_tx = privcmd->param_value;
break;
case WMI_PDEV_PARAM_RX_CHAIN_MASK_5G:
wma->pdevconfig.chainmask_5g_rx = privcmd->param_value;
break;
case WMI_PDEV_PARAM_BURST_ENABLE:
wma->pdevconfig.burst_enable = privcmd->param_value;
if ((wma->pdevconfig.burst_enable == 1) &&
(wma->pdevconfig.burst_dur == 0))
wma->pdevconfig.burst_dur = WMA_DEFAULT_SIFS_BURST_DURATION;
else if (wma->pdevconfig.burst_enable == 0)
wma->pdevconfig.burst_dur = 0;
break;
case WMI_PDEV_PARAM_BURST_DUR:
wma->pdevconfig.burst_dur = privcmd->param_value;
break;
case WMI_PDEV_PARAM_TXPOWER_LIMIT2G:
wma->pdevconfig.txpow2g = privcmd->param_value;
if ((pMac->roam.configParam.bandCapability ==
eCSR_BAND_ALL) ||
(pMac->roam.configParam.bandCapability ==
eCSR_BAND_24)) {
if (cfgSetInt(pMac,
WNI_CFG_CURRENT_TX_POWER_LEVEL,
privcmd->param_value) != eSIR_SUCCESS) {
WMA_LOGE("could not set"
" WNI_CFG_CURRENT_TX_POWER_LEVEL");
}
}
else
WMA_LOGE("Current band is not 2G");
break;
case WMI_PDEV_PARAM_TXPOWER_LIMIT5G:
wma->pdevconfig.txpow5g = privcmd->param_value;
if ((pMac->roam.configParam.bandCapability ==
eCSR_BAND_ALL) ||
(pMac->roam.configParam.bandCapability ==
eCSR_BAND_5G)) {
if (cfgSetInt(pMac,
WNI_CFG_CURRENT_TX_POWER_LEVEL,
privcmd->param_value) != eSIR_SUCCESS) {
WMA_LOGE("could not set"
" WNI_CFG_CURRENT_TX_POWER_LEVEL");
}
}
else
WMA_LOGE("Current band is not 5G");
break;
case WMI_PDEV_PARAM_ENA_ANT_DIV:
case WMI_PDEV_PARAM_FORCE_CHAIN_ANT:
case WMI_PDEV_PARAM_ANT_DIV_SELFTEST:
case WMI_PDEV_PARAM_ANT_DIV_SELFTEST_INTVL:
case WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE:
case WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE:
break;
default:
WMA_LOGE("Invalid wda_cli_set pdev command/Not"
" yet implemented 0x%x", privcmd->param_id);
break;
}
} else if (5 == privcmd->param_vp_dev) {
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, privcmd->param_vdev_id,
WMI_VDEV_PARAM_PACKET_POWERSAVE,
pps_val);
if (ret)
WMA_LOGE("Failed to send wmi packet power save cmd");
else
WMA_LOGD("Sent packet power save cmd %d value %x to target",
privcmd->param_id, pps_val);
}
}
int wma_cli_get_command(void *wmapvosContext, int vdev_id,
int param_id, int vpdev)
{
int ret = 0;
tp_wma_handle wma;
struct wma_txrx_node *intr = NULL;
wma = (tp_wma_handle) vos_get_context(VOS_MODULE_ID_WDA,
wmapvosContext);
if (NULL == wma)
{
WMA_LOGE("%s: Invalid wma handle", __func__);
return -EINVAL;
}
intr = wma->interfaces;
if (VDEV_CMD == vpdev) {
switch (param_id) {
case WMI_VDEV_PARAM_NSS:
ret = intr[vdev_id].config.nss;
break;
#ifdef QCA_SUPPORT_GTX
case WMI_VDEV_PARAM_GTX_HT_MCS:
ret = intr[vdev_id].config.gtx_info.gtxRTMask[0];
break;
case WMI_VDEV_PARAM_GTX_VHT_MCS:
ret = intr[vdev_id].config.gtx_info.gtxRTMask[1];
break;
case WMI_VDEV_PARAM_GTX_USR_CFG:
ret = intr[vdev_id].config.gtx_info.gtxUsrcfg;
break;
case WMI_VDEV_PARAM_GTX_THRE:
ret = intr[vdev_id].config.gtx_info.gtxPERThreshold;
break;
case WMI_VDEV_PARAM_GTX_MARGIN:
ret = intr[vdev_id].config.gtx_info.gtxPERMargin;
break;
case WMI_VDEV_PARAM_GTX_STEP:
ret = intr[vdev_id].config.gtx_info.gtxTPCstep;
break;
case WMI_VDEV_PARAM_GTX_MINTPC:
ret = intr[vdev_id].config.gtx_info.gtxTPCMin;
break;
case WMI_VDEV_PARAM_GTX_BW_MASK:
ret = intr[vdev_id].config.gtx_info.gtxBWMask;
break;
#endif
case WMI_VDEV_PARAM_LDPC:
ret = intr[vdev_id].config.ldpc;
break;
case WMI_VDEV_PARAM_TX_STBC:
ret = intr[vdev_id].config.tx_stbc;
break;
case WMI_VDEV_PARAM_RX_STBC:
ret = intr[vdev_id].config.rx_stbc;
break;
case WMI_VDEV_PARAM_SGI:
ret = intr[vdev_id].config.shortgi;
break;
case WMI_VDEV_PARAM_ENABLE_RTSCTS:
ret = intr[vdev_id].config.rtscts_en;
break;
case WMI_VDEV_PARAM_CHWIDTH:
ret = intr[vdev_id].config.chwidth;
break;
case WMI_VDEV_PARAM_FIXED_RATE:
ret = intr[vdev_id].config.tx_rate;
break;
default:
WMA_LOGE("Invalid cli_get vdev command/Not"
" yet implemented 0x%x", param_id);
return -EINVAL;
}
} else if (PDEV_CMD == vpdev) {
switch (param_id) {
case WMI_PDEV_PARAM_ANI_ENABLE:
ret = wma->pdevconfig.ani_enable;
break;
case WMI_PDEV_PARAM_ANI_POLL_PERIOD:
ret = wma->pdevconfig.ani_poll_len;
break;
case WMI_PDEV_PARAM_ANI_LISTEN_PERIOD:
ret = wma->pdevconfig.ani_listen_len;
break;
case WMI_PDEV_PARAM_ANI_OFDM_LEVEL:
ret = wma->pdevconfig.ani_ofdm_level;
break;
case WMI_PDEV_PARAM_ANI_CCK_LEVEL:
ret = wma->pdevconfig.ani_cck_level;
break;
case WMI_PDEV_PARAM_DYNAMIC_BW:
ret = wma->pdevconfig.cwmenable;
break;
case WMI_PDEV_PARAM_CTS_CBW:
ret = wma->pdevconfig.cts_cbw;
break;
case WMI_PDEV_PARAM_TX_CHAIN_MASK:
ret = wma->pdevconfig.txchainmask;
break;
case WMI_PDEV_PARAM_RX_CHAIN_MASK:
ret = wma->pdevconfig.rxchainmask;
break;
case WMI_PDEV_PARAM_TXPOWER_LIMIT2G:
ret = wma->pdevconfig.txpow2g;
break;
case WMI_PDEV_PARAM_TXPOWER_LIMIT5G:
ret = wma->pdevconfig.txpow5g;
break;
case WMI_PDEV_PARAM_BURST_ENABLE:
ret = wma->pdevconfig.burst_enable;
break;
case WMI_PDEV_PARAM_BURST_DUR:
ret = wma->pdevconfig.burst_dur;
break;
default:
WMA_LOGE("Invalid cli_get pdev command/Not"
" yet implemented 0x%x", param_id);
return -EINVAL;
}
} else if (GEN_CMD == vpdev) {
switch (param_id) {
case GEN_VDEV_PARAM_AMPDU:
ret = intr[vdev_id].config.ampdu;
break;
case GEN_VDEV_PARAM_AMSDU:
ret = intr[vdev_id].config.amsdu;
break;
default:
WMA_LOGE("Invalid generic vdev command/Not"
" yet implemented 0x%x", param_id);
return -EINVAL;
}
} else if (PPS_CMD == vpdev) {
switch (param_id) {
case WMI_VDEV_PPS_PAID_MATCH:
ret = intr[vdev_id].config.pps_params.paid_match_enable;
break;
case WMI_VDEV_PPS_GID_MATCH:
ret = intr[vdev_id].config.pps_params.gid_match_enable;
break;
case WMI_VDEV_PPS_EARLY_TIM_CLEAR:
ret = intr[vdev_id].config.pps_params.tim_clear;
break;
case WMI_VDEV_PPS_EARLY_DTIM_CLEAR:
ret = intr[vdev_id].config.pps_params.dtim_clear;
break;
case WMI_VDEV_PPS_EOF_PAD_DELIM:
ret = intr[vdev_id].config.pps_params.eof_delim;
break;
case WMI_VDEV_PPS_MACADDR_MISMATCH:
ret = intr[vdev_id].config.pps_params.mac_match;
break;
case WMI_VDEV_PPS_DELIM_CRC_FAIL:
ret = intr[vdev_id].config.pps_params.delim_fail;
break;
case WMI_VDEV_PPS_GID_NSTS_ZERO:
ret = intr[vdev_id].config.pps_params.nsts_zero;
break;
case WMI_VDEV_PPS_RSSI_CHECK:
ret = intr[vdev_id].config.pps_params.rssi_chk;
break;
default:
WMA_LOGE("Invalid pps vdev command/Not"
" yet implemented 0x%x", param_id);
return -EINVAL;
}
} else if (QPOWER_CMD == vpdev) {
switch (param_id) {
case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT:
ret = intr[vdev_id].config.qpower_params.max_ps_poll_cnt;
break;
case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE:
ret = intr[vdev_id].config.qpower_params.max_tx_before_wake;
break;
case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL:
ret =
intr[vdev_id].config.qpower_params.spec_ps_poll_wake_interval;
break;
case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL:
ret = intr[vdev_id].config.qpower_params.max_spec_nodata_ps_poll;
break;
default:
WMA_LOGE("Invalid generic vdev command/Not"
" yet implemented 0x%x", param_id);
return -EINVAL;
}
} else if (GTX_CMD == vpdev) {
switch (param_id) {
case WMI_VDEV_PARAM_GTX_HT_MCS:
ret = intr[vdev_id].config.gtx_info.gtxRTMask[0];
break;
case WMI_VDEV_PARAM_GTX_VHT_MCS:
ret = intr[vdev_id].config.gtx_info.gtxRTMask[1];
break;
case WMI_VDEV_PARAM_GTX_USR_CFG:
ret = intr[vdev_id].config.gtx_info.gtxUsrcfg;
break;
case WMI_VDEV_PARAM_GTX_THRE:
ret = intr[vdev_id].config.gtx_info.gtxPERThreshold;
break;
case WMI_VDEV_PARAM_GTX_MARGIN:
ret = intr[vdev_id].config.gtx_info.gtxPERMargin;
break;
case WMI_VDEV_PARAM_GTX_STEP:
ret = intr[vdev_id].config.gtx_info.gtxTPCstep;
break;
case WMI_VDEV_PARAM_GTX_MINTPC:
ret = intr[vdev_id].config.gtx_info.gtxTPCMin;
break;
case WMI_VDEV_PARAM_GTX_BW_MASK:
ret = intr[vdev_id].config.gtx_info.gtxBWMask;
break;
default:
WMA_LOGE("Invalid generic vdev command/Not"
" yet implemented 0x%x", param_id);
return -EINVAL;
}
}
return ret;
}
/**
* wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW
*
* @wma: Pointer to wma handle
* @ie_params: Pointer to IE data.
* @nss: Nss values to prepare the HT IE.
*
* Sends the WMI req to set the HT IE to FW.
*
* Return: None
*/
void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma,
struct set_ie_param *ie_params)
{
int ret;
wmi_pdev_set_ht_ie_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int16_t len;
u_int16_t ie_len_pad;
u_int8_t *buf_ptr;
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
ie_len_pad = roundup(ie_params->ie_len, sizeof(u_int32_t));
len += ie_len_pad;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return;
}
cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_ht_ie_cmd_fixed_param));
cmd->reserved0 = 0;
cmd->ie_len = ie_params->ie_len;
cmd->tx_streams = ie_params->nss;
cmd->rx_streams = ie_params->nss;
WMA_LOGD("Setting pdev HT ie with Nss = %u",
ie_params->nss);
buf_ptr = (u_int8_t *)cmd + sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
if (ie_params->ie_len) {
vos_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
(u_int8_t *)ie_params->ie_ptr,
ie_params->ie_len);
}
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PDEV_SET_HT_CAP_IE_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send set param command ret = %d", ret);
wmi_buf_free(buf);
}
}
/**
* wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW
*
* @wma: Pointer to wma handle
* @ie_params: Pointer to IE data.
* @nss: Nss values to prepare the VHT IE.
*
* Sends the WMI req to set the VHT IE to FW.
*
* Return: None
*/
void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma,
struct set_ie_param *ie_params)
{
int ret;
wmi_pdev_set_vht_ie_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int16_t len;
u_int16_t ie_len_pad;
u_int8_t *buf_ptr;
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE;
ie_len_pad = roundup(ie_params->ie_len, sizeof(u_int32_t));
len += ie_len_pad;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return;
}
cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_vht_ie_cmd_fixed_param));
cmd->reserved0 = 0;
cmd->ie_len = ie_params->ie_len;
cmd->tx_streams = ie_params->nss;
cmd->rx_streams = ie_params->nss;
WMA_LOGD("Setting pdev VHT ie with Nss = %u",
ie_params->nss);
buf_ptr = (u_int8_t *)cmd + sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad);
if (ie_params->ie_len) {
vos_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
(u_int8_t *)ie_params->ie_ptr,
ie_params->ie_len);
}
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PDEV_SET_VHT_CAP_IE_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send set param command ret = %d", ret);
wmi_buf_free(buf);
}
}
/**
* wma_process_set_pdev_ie_req() - process the pdev set IE req
*
* @wma: Pointer to wma handle
* @ie_params: Pointer to IE data.
*
* Sends the WMI req to set the IE to FW.
*
* Return: None
*/
void wma_process_set_pdev_ie_req(tp_wma_handle wma,
struct set_ie_param *ie_params)
{
if (ie_params->ie_type == DOT11_HT_IE)
wma_process_set_pdev_ht_ie_req(wma, ie_params);
if (ie_params->ie_type == DOT11_VHT_IE)
wma_process_set_pdev_vht_ie_req(wma, ie_params);
vos_mem_free(ie_params->ie_ptr);
}
static void
wma_update_protection_mode(tp_wma_handle wma, u_int8_t vdev_id,
u_int8_t llbcoexist)
{
int ret;
enum ieee80211_protmode prot_mode;
prot_mode = llbcoexist ? IEEE80211_PROT_CTSONLY : IEEE80211_PROT_NONE;
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_PROTECTION_MODE,
prot_mode);
if (ret)
WMA_LOGE("Failed to send wmi protection mode cmd");
else
WMA_LOGD("Updated protection mode %d to target", prot_mode);
}
static void
wma_update_beacon_interval(tp_wma_handle wma, u_int8_t vdev_id,
u_int16_t beaconInterval)
{
int ret;
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_BEACON_INTERVAL,
beaconInterval);
if (ret)
WMA_LOGE("Failed to update beacon interval");
else
WMA_LOGI("Updated beacon interval %d for vdev %d", beaconInterval, vdev_id);
}
/*
* Function : wma_process_update_beacon_params
* Description : update the beacon parameters to target
* Args : wma handle, beacon parameters
* Returns : None
*/
static void
wma_process_update_beacon_params(tp_wma_handle wma,
tUpdateBeaconParams *bcn_params)
{
if (!bcn_params) {
WMA_LOGE("bcn_params NULL");
return;
}
if (bcn_params->smeSessionId >= wma->max_bssid) {
WMA_LOGE("Invalid vdev id %d", bcn_params->smeSessionId);
return;
}
if (bcn_params->paramChangeBitmap & PARAM_BCN_INTERVAL_CHANGED) {
wma_update_beacon_interval(wma, bcn_params->smeSessionId,
bcn_params->beaconInterval);
}
if (bcn_params->paramChangeBitmap & PARAM_llBCOEXIST_CHANGED)
wma_update_protection_mode(wma, bcn_params->smeSessionId,
bcn_params->llbCoexist);
}
/*
* Function : wma_update_cfg_params
* Description : update the cfg parameters to target
* Args : wma handle, cfg parameter
* Returns : None
*/
static void
wma_update_cfg_params(tp_wma_handle wma, tSirMsgQ *cfgParam)
{
u_int8_t vdev_id;
u_int32_t param_id;
tANI_U32 cfg_val;
int ret;
/* get mac to acess CFG data base */
struct sAniSirGlobal *pmac;
switch(cfgParam->bodyval) {
case WNI_CFG_RTS_THRESHOLD:
param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
break;
case WNI_CFG_FRAGMENTATION_THRESHOLD:
param_id = WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD;
break;
default:
WMA_LOGD("Unhandled cfg parameter %d", cfgParam->bodyval);
return;
}
pmac = (struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == pmac) {
WMA_LOGE("%s: Failed to get pmac", __func__);
return;
}
if (wlan_cfgGetInt(pmac, (tANI_U16) cfgParam->bodyval,
&cfg_val) != eSIR_SUCCESS)
{
WMA_LOGE("Failed to get value for CFG PARAMS %d. returning without updating",
cfgParam->bodyval);
return;
}
for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) {
if (wma->interfaces[vdev_id].handle != 0) {
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
vdev_id, param_id, cfg_val);
if (ret)
WMA_LOGE("Update cfg params failed for vdevId %d", vdev_id);
}
}
}
/* BSS set params functions */
static void
wma_vdev_set_bss_params(tp_wma_handle wma, int vdev_id,
tSirMacBeaconInterval beaconInterval, tANI_U8 dtimPeriod,
tANI_U8 shortSlotTimeSupported, tANI_U8 llbCoexist,
tPowerdBm maxTxPower)
{
int ret;
uint32_t slot_time;
struct wma_txrx_node *intr = wma->interfaces;
/* Beacon Interval setting */
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_BEACON_INTERVAL,
beaconInterval);
if (ret)
WMA_LOGE("failed to set WMI_VDEV_PARAM_BEACON_INTERVAL");
ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, vdev_id,
&intr[vdev_id].config.gtx_info);
if (ret)
WMA_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD");
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_DTIM_PERIOD,
dtimPeriod);
if (ret)
WMA_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD");
if (!maxTxPower)
{
WMA_LOGW("Setting Tx power limit to 0");
}
WMA_LOGI("%s: Set maxTx pwr [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d",
__func__, maxTxPower);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_TX_PWRLIMIT,
maxTxPower);
if (ret)
WMA_LOGE("failed to set WMI_VDEV_PARAM_TX_PWRLIMIT");
else
intr[vdev_id].max_tx_power = maxTxPower;
/* Slot time */
if (shortSlotTimeSupported)
slot_time = WMI_VDEV_SLOT_TIME_SHORT;
else
slot_time = WMI_VDEV_SLOT_TIME_LONG;
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_SLOT_TIME,
slot_time);
if (ret)
WMA_LOGE("failed to set WMI_VDEV_PARAM_SLOT_TIME");
/* Initialize protection mode in case of coexistence */
wma_update_protection_mode(wma, vdev_id, llbCoexist);
}
static void wma_add_bss_ap_mode(tp_wma_handle wma, tpAddBssParams add_bss)
{
ol_txrx_pdev_handle pdev;
ol_txrx_vdev_handle vdev;
struct wma_vdev_start_req req;
ol_txrx_peer_handle peer;
struct wma_target_req *msg;
u_int8_t vdev_id, peer_id;
VOS_STATUS status;
tPowerdBm maxTxPower;
#ifdef WLAN_FEATURE_11W
int ret = 0;
#endif /* WLAN_FEATURE_11W */
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
goto send_fail_resp;
}
vdev = wma_find_vdev_by_addr(wma, add_bss->bssId, &vdev_id);
if (!vdev) {
WMA_LOGE("%s: Failed to get vdev handle", __func__);
goto send_fail_resp;
}
wma->interfaces[vdev_id].wps_state = add_bss->wps_state;
wma_set_bss_rate_flags(&wma->interfaces[vdev_id], add_bss);
status = wma_create_peer(wma, pdev, vdev, add_bss->bssId,
WMI_PEER_TYPE_DEFAULT, vdev_id,
VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to create peer", __func__);
goto send_fail_resp;
}
peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, &peer_id);
if (!peer) {
WMA_LOGE("%s Failed to find peer %pM", __func__,
add_bss->bssId);
goto send_fail_resp;
}
msg = wma_fill_vdev_req(wma, vdev_id, WDA_ADD_BSS_REQ,
WMA_TARGET_REQ_TYPE_VDEV_START, add_bss,
WMA_VDEV_START_REQUEST_TIMEOUT);
if (!msg) {
WMA_LOGP("%s Failed to allocate vdev request vdev_id %d",
__func__, vdev_id);
goto peer_cleanup;
}
add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer);
vos_mem_zero(&req, sizeof(req));
req.vdev_id = vdev_id;
req.chan = add_bss->currentOperChannel;
req.channelwidth = add_bss->channelwidth;
if (add_bss->channelwidth == CH_WIDTH_5MHZ)
req.is_quarter_rate = 1;
else if (add_bss->channelwidth == CH_WIDTH_10MHZ)
req.is_half_rate = 1;
req.chan_offset = add_bss->currentExtChannel;
req.vht_capable = add_bss->vhtCapable;
#if defined WLAN_FEATURE_VOWIFI
req.max_txpow = add_bss->maxTxPower;
maxTxPower = add_bss->maxTxPower;
#else
req.max_txpow = 0;
maxTxPower = 0;
#endif
#ifdef WLAN_FEATURE_11W
if (add_bss->rmfEnabled) {
/*
* when 802.11w PMF is enabled for hw encr/decr
* use hw MFP Qos bits 0x10
*/
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_PMF_QOS, TRUE);
if(ret) {
WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)",
__func__, ret);
} else {
WMA_LOGI("%s: QOS MFP/PMF set to %d",
__func__, TRUE);
}
}
#endif /* WLAN_FEATURE_11W */
req.beacon_intval = add_bss->beaconInterval;
req.dtim_period = add_bss->dtimPeriod;
req.beacon_tx_rate = add_bss->beacon_tx_rate;
req.hidden_ssid = add_bss->bHiddenSSIDEn;
req.is_dfs = add_bss->bSpectrumMgtEnabled;
req.oper_mode = BSS_OPERATIONAL_MODE_AP;
req.ssid.length = add_bss->ssId.length;
if (req.ssid.length > 0)
vos_mem_copy(req.ssid.ssId, add_bss->ssId.ssId,
add_bss->ssId.length);
status = wma_vdev_start(wma, &req, VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
wma_remove_vdev_req(wma, vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_START);
goto peer_cleanup;
}
wma_vdev_set_bss_params(wma, vdev_id,
add_bss->beaconInterval, add_bss->dtimPeriod,
add_bss->shortSlotTimeSupported, add_bss->llbCoexist,
maxTxPower);
return;
peer_cleanup:
wma_remove_peer(wma, add_bss->bssId, vdev_id, peer,
VOS_FALSE);
send_fail_resp:
add_bss->status = VOS_STATUS_E_FAILURE;
wma_send_msg(wma, WDA_ADD_BSS_RSP, (void *)add_bss, 0);
}
#ifdef QCA_IBSS_SUPPORT
static VOS_STATUS
wma_set_ibss_pwrsave_params(tp_wma_handle wma, u_int8_t vdev_id)
{
int ret;
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH,
wma->wma_ibss_power_save_params.atimWindowLength);
if (ret < 0) {
WMA_LOGE("Failed to set WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH ret = %d",
ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED,
wma->wma_ibss_power_save_params.isPowerSaveAllowed);
if (ret < 0) {
WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED ret=%d",
ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED,
wma->wma_ibss_power_save_params.isPowerCollapseAllowed);
if (ret < 0) {
WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED ret=%d",
ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED,
wma->wma_ibss_power_save_params.isAwakeonTxRxEnabled);
if (ret < 0) {
WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED ret=%d",
ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_INACTIVITY_CNT,
wma->wma_ibss_power_save_params.inactivityCount);
if (ret < 0) {
WMA_LOGE("Failed, set WMI_VDEV_PARAM_INACTIVITY_CNT ret=%d",
ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS,
wma->wma_ibss_power_save_params.txSPEndInactivityTime);
if (ret < 0) {
WMA_LOGE("Failed, set WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS ret=%d",
ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS,
wma->wma_ibss_power_save_params.ibssPsWarmupTime);
if (ret < 0) {
WMA_LOGE("Failed, set WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS ret=%d",
ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE,
wma->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable);
if (ret < 0) {
WMA_LOGE("Failed to set IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE ret=%d",
ret);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
static void wma_add_bss_ibss_mode(tp_wma_handle wma, tpAddBssParams add_bss)
{
ol_txrx_pdev_handle pdev;
ol_txrx_vdev_handle vdev;
struct wma_vdev_start_req req;
ol_txrx_peer_handle peer = NULL;
struct wma_target_req *msg;
u_int8_t vdev_id, peer_id;
VOS_STATUS status;
tSetBssKeyParams key_info;
u_int8_t nss_2g, nss_5g;
WMA_LOGD("%s: add_bss->sessionId = %d", __func__, add_bss->sessionId);
vdev_id = add_bss->sessionId;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
goto send_fail_resp;
}
nss_2g = wma->interfaces[vdev_id].nss_2g;
nss_5g = wma->interfaces[vdev_id].nss_5g;
wma_set_bss_rate_flags(&wma->interfaces[vdev_id], add_bss);
wma->interfaces[vdev_id].tx_aggregation_size =
add_bss->tx_aggregation_size;
wma->interfaces[vdev_id].rx_aggregation_size =
add_bss->rx_aggregation_size;
vdev = wma_find_vdev_by_id(wma, vdev_id);
if (!vdev) {
WMA_LOGE("%s: vdev not found for vdev id %d.",
__func__, vdev_id);
goto send_fail_resp;
}
/* create ibss bss peer */
status = wma_create_peer(wma, pdev, vdev, add_bss->selfMacAddr,
WMI_PEER_TYPE_DEFAULT, vdev_id,
VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to create peer", __func__);
goto send_fail_resp;
}
WMA_LOGA("IBSS BSS peer created with mac %pM", add_bss->selfMacAddr);
peer = ol_txrx_find_peer_by_addr(pdev, add_bss->selfMacAddr, &peer_id);
if (!peer) {
WMA_LOGE("%s Failed to find peer %pM", __func__,
add_bss->selfMacAddr);
goto send_fail_resp;
}
/* clear leftover ibss keys on bss peer */
WMA_LOGD("%s: ibss bss key clearing", __func__);
vos_mem_set(&key_info, sizeof(key_info), 0);
key_info.smesessionId = vdev_id;
key_info.numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS;
vos_mem_copy(&wma->ibsskey_info, &key_info, sizeof(tSetBssKeyParams));
/* start ibss vdev */
add_bss->operMode = BSS_OPERATIONAL_MODE_IBSS;
msg = wma_fill_vdev_req(wma, vdev_id, WDA_ADD_BSS_REQ,
WMA_TARGET_REQ_TYPE_VDEV_START, add_bss,
WMA_VDEV_START_REQUEST_TIMEOUT);
if (!msg) {
WMA_LOGP("%s Failed to allocate vdev request vdev_id %d",
__func__, vdev_id);
goto peer_cleanup;
}
WMA_LOGD("%s: vdev start request for IBSS enqueued", __func__);
add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer);
/*
* If IBSS Power Save is supported by firmware
* set the IBSS power save params to firmware.
*/
if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_IBSS_PWRSAVE)) {
status = wma_set_ibss_pwrsave_params(wma, vdev_id);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to Set IBSS Power Save Params to firmware",
__func__);
goto peer_cleanup;
}
}
vos_mem_zero(&req, sizeof(req));
req.vdev_id = vdev_id;
req.chan = add_bss->currentOperChannel;
req.chan_offset = add_bss->currentExtChannel;
req.vht_capable = add_bss->vhtCapable;
#if defined WLAN_FEATURE_VOWIF
req.max_txpow = add_bss->maxTxPower;
#else
req.max_txpow = 0;
#endif
req.beacon_intval = add_bss->beaconInterval;
req.dtim_period = add_bss->dtimPeriod;
req.hidden_ssid = add_bss->bHiddenSSIDEn;
req.is_dfs = add_bss->bSpectrumMgtEnabled;
req.oper_mode = BSS_OPERATIONAL_MODE_IBSS;
req.ssid.length = add_bss->ssId.length;
if (req.ssid.length > 0)
vos_mem_copy(req.ssid.ssId, add_bss->ssId.ssId,
add_bss->ssId.length);
WMA_LOGD("%s: chan %d chan_offset %d", __func__, req.chan, req.chan_offset);
WMA_LOGD("%s: ssid = %s", __func__, req.ssid.ssId);
status = wma_vdev_start(wma, &req, VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
wma_remove_vdev_req(wma, vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_START);
goto peer_cleanup;
}
WMA_LOGD("%s: vdev start request for IBSS sent to target", __func__);
/* Initialize protection mode to no protection */
if (wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_PROTECTION_MODE,
IEEE80211_PROT_NONE)) {
WMA_LOGE("Failed to initialize protection mode");
}
return;
peer_cleanup:
if (peer) {
wma_remove_peer(wma, add_bss->bssId, vdev_id, peer,
VOS_FALSE);
}
send_fail_resp:
add_bss->status = VOS_STATUS_E_FAILURE;
wma_send_msg(wma, WDA_ADD_BSS_RSP, (void *)add_bss, 0);
}
#endif
void wma_set_bss_rate_flags(struct wma_txrx_node *iface,
tpAddBssParams add_bss)
{
iface->rate_flags = 0;
#ifdef WLAN_FEATURE_11AC
if (add_bss->vhtCapable) {
if (add_bss->vhtTxChannelWidthSet)
iface->rate_flags |= eHAL_TX_RATE_VHT80;
else if (add_bss->txChannelWidthSet)
iface->rate_flags |= eHAL_TX_RATE_VHT40;
else
iface->rate_flags |= eHAL_TX_RATE_VHT20;
}
/* avoid to conflict with htCapable flag */
else
#endif
if (add_bss->htCapable) {
if (add_bss->txChannelWidthSet)
iface->rate_flags |= eHAL_TX_RATE_HT40;
else
iface->rate_flags |= eHAL_TX_RATE_HT20;
}
if (add_bss->staContext.fShortGI20Mhz ||
add_bss->staContext.fShortGI40Mhz)
iface->rate_flags |= eHAL_TX_RATE_SGI;
if (!add_bss->htCapable && !add_bss->vhtCapable)
iface->rate_flags = eHAL_TX_RATE_LEGACY;
}
static void wma_add_bss_sta_mode(tp_wma_handle wma, tpAddBssParams add_bss)
{
ol_txrx_pdev_handle pdev;
struct wma_vdev_start_req req;
struct wma_target_req *msg;
u_int8_t vdev_id, peer_id;
ol_txrx_peer_handle peer;
VOS_STATUS status;
struct wma_txrx_node *iface;
int ret = 0;
int pps_val = 0;
v_BOOL_t roam_synch_in_progress = VOS_FALSE;
tpAniSirGlobal pMac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == pMac) {
WMA_LOGE("%s: Unable to get PE context", __func__);
goto send_fail_resp;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s Failed to get pdev", __func__);
goto send_fail_resp;
}
vdev_id = add_bss->staContext.smesessionId;
iface = &wma->interfaces[vdev_id];
wma_set_bss_rate_flags(iface, add_bss);
if (add_bss->operMode) {
// Save parameters later needed by WDA_ADD_STA_REQ
if (iface->addBssStaContext) {
adf_os_mem_free(iface->addBssStaContext);
}
iface->addBssStaContext = adf_os_mem_alloc(NULL, sizeof(tAddStaParams));
if (!iface->addBssStaContext) {
WMA_LOGE("%s Failed to allocat memory", __func__);
goto send_fail_resp;
}
adf_os_mem_copy(iface->addBssStaContext, &add_bss->staContext,
sizeof(tAddStaParams));
#if defined WLAN_FEATURE_VOWIFI_11R
if (iface->staKeyParams) {
adf_os_mem_free(iface->staKeyParams);
iface->staKeyParams = NULL;
}
if (add_bss->extSetStaKeyParamValid) {
iface->staKeyParams = adf_os_mem_alloc(NULL, sizeof(tSetStaKeyParams));
if (!iface->staKeyParams) {
WMA_LOGE("%s Failed to allocat memory", __func__);
goto send_fail_resp;
}
adf_os_mem_copy(iface->staKeyParams, &add_bss->extSetStaKeyParam,
sizeof(tSetStaKeyParams));
}
#endif
// Save parameters later needed by WDA_ADD_STA_REQ
iface->rmfEnabled = add_bss->rmfEnabled;
iface->beaconInterval = add_bss->beaconInterval;
iface->dtimPeriod = add_bss->dtimPeriod;
iface->llbCoexist = add_bss->llbCoexist;
iface->shortSlotTimeSupported = add_bss->shortSlotTimeSupported;
iface->nwType = add_bss->nwType;
if(add_bss->nonRoamReassoc) {
peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, &peer_id);
if(peer) {
add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer);
goto send_bss_resp;
}
}
if (add_bss->reassocReq) {
#ifdef QCA_SUPPORT_TXRX_VDEV_PAUSE_LL
ol_txrx_vdev_handle vdev;
#endif
// Called in preassoc state. BSSID peer is already added by set_linkstate
peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, &peer_id);
if (!peer) {
WMA_LOGE("%s Failed to find peer %pM", __func__,
add_bss->bssId);
goto send_fail_resp;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if(iface->roam_synch_in_progress) {
add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer);
goto send_bss_resp;
}
#endif
msg = wma_fill_vdev_req(wma, vdev_id, WDA_ADD_BSS_REQ,
WMA_TARGET_REQ_TYPE_VDEV_START,
add_bss,
WMA_VDEV_START_REQUEST_TIMEOUT);
if (!msg) {
WMA_LOGP("%s Failed to allocate vdev request vdev_id %d",
__func__, vdev_id);
goto peer_cleanup;
}
add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer);
vos_mem_zero(&req, sizeof(req));
req.vdev_id = vdev_id;
req.chan = add_bss->currentOperChannel;
req.chan_offset = add_bss->currentExtChannel;
req.channelwidth = add_bss->channelwidth;
if (add_bss->channelwidth == CH_WIDTH_5MHZ)
req.is_quarter_rate = 1;
else if (add_bss->channelwidth == CH_WIDTH_10MHZ)
req.is_half_rate = 1;
#if defined WLAN_FEATURE_VOWIFI
req.max_txpow = add_bss->maxTxPower;
#else
req.max_txpow = 0;
#endif
req.beacon_intval = add_bss->beaconInterval;
req.dtim_period = add_bss->dtimPeriod;
req.hidden_ssid = add_bss->bHiddenSSIDEn;
req.is_dfs = add_bss->bSpectrumMgtEnabled;
req.ssid.length = add_bss->ssId.length;
req.oper_mode = BSS_OPERATIONAL_MODE_STA;
if (req.ssid.length > 0)
vos_mem_copy(req.ssid.ssId, add_bss->ssId.ssId,
add_bss->ssId.length);
status = wma_vdev_start(wma, &req, VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
wma_remove_vdev_req(wma, vdev_id,
WMA_TARGET_REQ_TYPE_VDEV_START);
goto peer_cleanup;
}
#ifdef QCA_SUPPORT_TXRX_VDEV_PAUSE_LL
vdev = wma_find_vdev_by_id(wma, vdev_id);
if (!vdev) {
WMA_LOGE("%s Invalid txrx vdev", __func__);
goto peer_cleanup;
}
wdi_in_vdev_pause(vdev,
OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED);
#endif
// ADD_BSS_RESP will be deferred to completion of VDEV_START
return;
}
if (!add_bss->updateBss) {
goto send_bss_resp;
}
/* Update peer state */
if (add_bss->staContext.encryptType == eSIR_ED_NONE) {
WMA_LOGD("%s: Update peer(%pM) state into auth",
__func__, add_bss->bssId);
ol_txrx_peer_state_update(pdev, add_bss->bssId,
ol_txrx_peer_state_auth);
} else {
#ifdef QCA_SUPPORT_TXRX_VDEV_PAUSE_LL
ol_txrx_vdev_handle vdev;
#endif
WMA_LOGD("%s: Update peer(%pM) state into conn",
__func__, add_bss->bssId);
ol_txrx_peer_state_update(pdev, add_bss->bssId,
ol_txrx_peer_state_conn);
#ifdef QCA_SUPPORT_TXRX_VDEV_PAUSE_LL
peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, &peer_id);
if (!peer) {
WMA_LOGE("%s:%d Failed to find peer %pM", __func__,
__LINE__, add_bss->bssId);
goto send_fail_resp;
}
vdev = wma_find_vdev_by_id(wma, vdev_id);
if (!vdev) {
WMA_LOGE("%s Invalid txrx vdev", __func__);
goto peer_cleanup;
}
wdi_in_vdev_pause(vdev,
OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED);
#endif
}
wmi_unified_send_txbf(wma, &add_bss->staContext);
pps_val = ((pMac->enable5gEBT << 31) & 0xffff0000) | (PKT_PWR_SAVE_5G_EBT & 0xffff);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_PACKET_POWERSAVE,
pps_val);
if (ret)
WMA_LOGE("Failed to send wmi packet power save cmd");
else
WMA_LOGD("Sent PKT_PWR_SAVE_5G_EBT cmd to target, val = %x, ret = %d",
pps_val, ret);
wmi_unified_send_peer_assoc(wma, add_bss->nwType,
&add_bss->staContext);
#ifdef WLAN_FEATURE_11W
if (add_bss->rmfEnabled) {
/* when 802.11w PMF is enabled for hw encr/decr
use hw MFP Qos bits 0x10 */
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_PMF_QOS, TRUE);
if(ret) {
WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)",
__func__, ret);
} else {
WMA_LOGI("%s: QOS MFP/PMF set to %d",
__func__, TRUE);
}
}
#endif /* WLAN_FEATURE_11W */
wma_vdev_set_bss_params(wma, add_bss->staContext.smesessionId,
add_bss->beaconInterval, add_bss->dtimPeriod,
add_bss->shortSlotTimeSupported, add_bss->llbCoexist,
add_bss->maxTxPower);
/*
* Store the bssid in interface table, bssid will
* be used during group key setting sta mode.
*/
vos_mem_copy(iface->bssid, add_bss->bssId, ETH_ALEN);
}
send_bss_resp:
ol_txrx_find_peer_by_addr(pdev, add_bss->bssId,
&add_bss->staContext.staIdx);
add_bss->status =
(add_bss->staContext.staIdx == HAL_STA_INVALID_IDX) ?
VOS_STATUS_E_FAILURE : VOS_STATUS_SUCCESS;
add_bss->bssIdx = add_bss->staContext.smesessionId;
vos_mem_copy(add_bss->staContext.staMac, add_bss->bssId,
sizeof(add_bss->staContext.staMac));
WMA_LOGD("%s: opermode %d update_bss %d nw_type %d bssid %pM"
" staIdx %d status %d", __func__, add_bss->operMode,
add_bss->updateBss, add_bss->nwType, add_bss->bssId,
add_bss->staContext.staIdx, add_bss->status);
wma_send_msg(wma, WDA_ADD_BSS_RSP, (void *)add_bss, 0);
return;
peer_cleanup:
wma_remove_peer(wma, add_bss->bssId, vdev_id, peer,
roam_synch_in_progress);
send_fail_resp:
add_bss->status = VOS_STATUS_E_FAILURE;
wma_send_msg(wma, WDA_ADD_BSS_RSP, (void *)add_bss, 0);
}
static void wma_add_bss(tp_wma_handle wma, tpAddBssParams params)
{
WMA_LOGD("%s: add_bss_param.halPersona = %d",
__func__, params->halPersona);
switch(params->halPersona) {
/*If current bring up SAP or P2P channel matches the previous
*radar found channel then reset the last_radar_found_chan
*variable to avoid race conditions.
*/
case VOS_STA_SAP_MODE:
case VOS_P2P_GO_MODE:
if (params->currentOperChannel ==
wma->dfs_ic->last_radar_found_chan)
wma->dfs_ic->last_radar_found_chan = 0;
wma_add_bss_ap_mode(wma, params);
break;
#ifdef QCA_IBSS_SUPPORT
case VOS_IBSS_MODE:
wma_add_bss_ibss_mode(wma, params);
break;
#endif
case VOS_NDI_MODE:
wma_add_bss_ndi_mode(wma, params);
break;
default:
wma_add_bss_sta_mode(wma, params);
break;
}
}
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])
{
wmi_vdev_up_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
WMA_LOGD("%s: VDEV_UP", __func__);
WMA_LOGD("%s: vdev_id %d aid %d bssid %pM", __func__,
vdev_id, aid, bssid);
buf = wmi_buf_alloc(wmi, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_vdev_up_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_up_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->vdev_assoc_id = aid;
WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid, &cmd->vdev_bssid);
if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_UP_CMDID)) {
WMA_LOGP("%s: Failed to send vdev up command", __func__);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
static int32_t wmi_unified_set_ap_ps_param(void *wma_ctx, u_int32_t vdev_id,
u_int8_t *peer_addr, u_int32_t param, u_int32_t value)
{
tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx;
wmi_ap_ps_peer_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set_ap_ps_param cmd");
return -ENOMEM;
}
cmd = (wmi_ap_ps_peer_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_ap_ps_peer_cmd_fixed_param));
cmd->vdev_id = vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
cmd->param = param;
cmd->value = value;
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_AP_PS_PEER_PARAM_CMDID);
if (err) {
WMA_LOGE("Failed to send set_ap_ps_param cmd");
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
static int32_t wma_set_ap_peer_uapsd(tp_wma_handle wma, u_int32_t vdev_id,
u_int8_t *peer_addr, u_int8_t uapsd_value, u_int8_t max_sp)
{
u_int32_t uapsd = 0;
u_int32_t max_sp_len = 0;
int32_t ret = 0;
if (uapsd_value & UAPSD_VO_ENABLED) {
uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
}
if (uapsd_value & UAPSD_VI_ENABLED) {
uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC2_TRIGGER_EN;
}
if (uapsd_value & UAPSD_BK_ENABLED) {
uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC1_TRIGGER_EN;
}
if (uapsd_value & UAPSD_BE_ENABLED) {
uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
}
switch (max_sp) {
case UAPSD_MAX_SP_LEN_2:
max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_2;
break;
case UAPSD_MAX_SP_LEN_4:
max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_4;
break;
case UAPSD_MAX_SP_LEN_6:
max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_6;
break;
default:
max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED;
break;
}
WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_UAPSD 0x%x for %pM",
uapsd, peer_addr);
ret = wmi_unified_set_ap_ps_param(wma, vdev_id,
peer_addr,
WMI_AP_PS_PEER_PARAM_UAPSD,
uapsd);
if (ret) {
WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_UAPSD for %pM",
peer_addr);
return ret;
}
WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_MAX_SP 0x%x for %pM",
max_sp_len, peer_addr);
ret = wmi_unified_set_ap_ps_param(wma, vdev_id,
peer_addr,
WMI_AP_PS_PEER_PARAM_MAX_SP,
max_sp_len);
if (ret) {
WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_MAX_SP for %pM",
peer_addr);
return ret;
}
return 0;
}
static void wma_add_sta_req_ap_mode(tp_wma_handle wma, tpAddStaParams add_sta)
{
enum ol_txrx_peer_state state = ol_txrx_peer_state_conn;
ol_txrx_pdev_handle pdev;
ol_txrx_vdev_handle vdev;
ol_txrx_peer_handle peer;
u_int8_t peer_id;
VOS_STATUS status;
int32_t ret;
struct wma_txrx_node *iface = NULL;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to find pdev", __func__);
add_sta->status = VOS_STATUS_E_FAILURE;
goto send_rsp;
}
/* UMAC sends WDA_ADD_STA_REQ msg twice to WMA when the station
* associates. First WDA_ADD_STA_REQ will have staType as
* STA_ENTRY_PEER and second posting will have STA_ENTRY_SELF.
* Peer creation is done in first WDA_ADD_STA_REQ and second
* WDA_ADD_STA_REQ which has STA_ENTRY_SELF is ignored and
* send fake response with success to UMAC. Otherwise UMAC
* will get blocked.
*/
if (add_sta->staType != STA_ENTRY_PEER) {
add_sta->status = VOS_STATUS_SUCCESS;
goto send_rsp;
}
vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId);
if (!vdev) {
WMA_LOGE("%s: Failed to find vdev", __func__);
add_sta->status = VOS_STATUS_E_FAILURE;
goto send_rsp;
}
iface = &wma->interfaces[vdev->vdev_id];
peer = ol_txrx_find_peer_by_addr_and_vdev(pdev,
vdev,
add_sta->staMac,
&peer_id);
if (peer) {
wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId,
peer, VOS_FALSE);
WMA_LOGE("%s: Peer already exists, Deleted peer with peer_addr %pM",
__func__, add_sta->staMac);
}
/* The code above only checks the peer existence on its own vdev.
* Need to check whether the peer exists on other vDevs because firmware
* can't create the peer if the peer with same MAC address already
* exists on the pDev. As this peer belongs to other vDevs, just return
* here.
*/
peer = ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id);
if (peer) {
WMA_LOGE("%s: My vdev:%d, but Peer exists on other vdev with "
"peer_addr %pM and peer_id %d",
__func__, vdev->vdev_id, add_sta->staMac, peer_id);
add_sta->status = VOS_STATUS_E_FAILURE;
goto send_rsp;
}
status = wma_create_peer(wma, pdev, vdev, add_sta->staMac,
WMI_PEER_TYPE_DEFAULT, add_sta->smesessionId,
VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to create peer for %pM",
__func__, add_sta->staMac);
add_sta->status = status;
goto send_rsp;
}
peer = ol_txrx_find_peer_by_addr_and_vdev(pdev,
vdev,
add_sta->staMac,
&peer_id);
if (!peer) {
WMA_LOGE("%s: Failed to find peer handle using peer mac %pM",
__func__, add_sta->staMac);
add_sta->status = VOS_STATUS_E_FAILURE;
wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId,
peer, VOS_FALSE);
goto send_rsp;
}
wmi_unified_send_txbf(wma, add_sta);
ret = wmi_unified_send_peer_assoc(wma, add_sta->nwType, add_sta);
if (ret) {
add_sta->status = VOS_STATUS_E_FAILURE;
wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId,
peer, VOS_FALSE);
goto send_rsp;
}
#ifdef QCA_IBSS_SUPPORT
/*
* In IBSS mode send the peer
* Atim Window length if IBSS
* power save is enabled by the
* firmware.
*/
if ( wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId) &&
WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_IBSS_PWRSAVE) ) {
/*
* If ATIM Window is present in the peer
* beacon then send it to firmware else
* configure Zero ATIM Window length to
* firmware.
*/
if(add_sta->atimIePresent) {
wma_set_peer_param(wma, add_sta->staMac,
WMI_PEER_IBSS_ATIM_WINDOW_LENGTH,
add_sta->peerAtimWindowLength,
add_sta->smesessionId);
}
else {
wma_set_peer_param(wma, add_sta->staMac,
WMI_PEER_IBSS_ATIM_WINDOW_LENGTH,
0,
add_sta->smesessionId);
}
}
#endif
#ifdef WLAN_FEATURE_11W
if (add_sta->rmfEnabled) {
/*
* We have to store the state of PMF connection
* per STA for SAP case
* We will isolate the ifaces based on vdevid
*/
iface->rmfEnabled = add_sta->rmfEnabled;
/*
* when 802.11w PMF is enabled for hw encr/decr
* use hw MFP Qos bits 0x10
*/
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_PMF_QOS, TRUE);
if(ret) {
WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)",
__func__, ret);
}
else {
WMA_LOGI("%s: QOS MFP/PMF set to %d",
__func__, TRUE);
}
}
#endif /* WLAN_FEATURE_11W */
if (add_sta->uAPSD) {
ret = wma_set_ap_peer_uapsd(wma, add_sta->smesessionId,
add_sta->staMac,
add_sta->uAPSD,
add_sta->maxSPLen);
if (ret) {
WMA_LOGE("Failed to set peer uapsd param for %pM",
add_sta->staMac);
add_sta->status = VOS_STATUS_E_FAILURE;
wma_remove_peer(wma, add_sta->staMac,
add_sta->smesessionId, peer,
VOS_FALSE);
goto send_rsp;
}
}
WMA_LOGD("%s: Moving peer %pM to state %d",
__func__, add_sta->staMac, state);
ol_txrx_peer_state_update(pdev, add_sta->staMac, state);
add_sta->staIdx = ol_txrx_local_peer_id(peer);
add_sta->nss = iface->nss;
add_sta->status = VOS_STATUS_SUCCESS;
send_rsp:
WMA_LOGD("%s: Sending add sta rsp to umac (mac:%pM, status:%d)",
__func__, add_sta->staMac, add_sta->status);
wma_send_msg(wma, WDA_ADD_STA_RSP, (void *)add_sta, 0);
}
static int wmi_unified_nat_keepalive_enable(tp_wma_handle wma,
u_int8_t vdev_id)
{
WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
WMA_LOGD("%s: vdev_id %d", __func__, vdev_id);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->action = IPSEC_NATKEEPALIVE_FILTER_ENABLE;
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID)) {
WMA_LOGP("%s: Failed to send NAT keepalive enable command",
__func__);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
static int wmi_unified_csa_offload_enable(tp_wma_handle wma,
u_int8_t vdev_id)
{
wmi_csa_offload_enable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
WMA_LOGD("%s: vdev_id %d", __func__, vdev_id);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_csa_offload_enable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_csa_offload_enable_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->csa_offload_enable = WMI_CSA_OFFLOAD_ENABLE;
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_CSA_OFFLOAD_ENABLE_CMDID)) {
WMA_LOGP("%s: Failed to send CSA offload enable command",
__func__);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
#ifdef QCA_IBSS_SUPPORT
static u_int16_t wma_calc_ibss_heart_beat_timer(int16_t peer_num)
{
/* heart beat timer value look-up table */
/* entry index : (the number of currently connected peers) - 1
entry value : the heart time threshold value in seconds for
detecting ibss peer departure */
static const u_int16_t heart_beat_timer[HDD_MAX_NUM_IBSS_STA] = {
4, 4, 4, 4, 4, 4, 4, 4,
8, 8, 8, 8, 8, 8, 8, 8,
12, 12, 12, 12, 12, 12, 12, 12,
16, 16, 16, 16, 16, 16, 16, 16};
if (peer_num < 1 || peer_num > HDD_MAX_NUM_IBSS_STA)
return 0;
return heart_beat_timer[peer_num - 1];
}
static void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma,
u_int8_t vdev_id,
int8_t peer_num_delta)
{
ol_txrx_vdev_handle vdev;
int16_t new_peer_num;
u_int16_t new_timer_value_sec;
u_int32_t new_timer_value_ms;
if (peer_num_delta != 1 && peer_num_delta != -1) {
WMA_LOGE("Invalid peer_num_delta value %d", peer_num_delta);
return;
}
vdev = wma_find_vdev_by_id(wma, vdev_id);
if (!vdev) {
WMA_LOGE("vdev not found : vdev_id %d", vdev_id);
return;
}
new_peer_num = vdev->ibss_peer_num + peer_num_delta;
if (new_peer_num > HDD_MAX_NUM_IBSS_STA || new_peer_num < 0) {
WMA_LOGE("new peer num %d out of valid boundary", new_peer_num);
return;
}
/* adjust peer numbers */
vdev->ibss_peer_num = new_peer_num;
/* reset timer value if all peers departed */
if (new_peer_num == 0) {
vdev->ibss_peer_heart_beat_timer = 0;
return;
}
/* calculate new timer value */
new_timer_value_sec = wma_calc_ibss_heart_beat_timer(new_peer_num);
if (new_timer_value_sec == 0) {
WMA_LOGE("timer value %d is invalid for peer number %d",
new_timer_value_sec, new_peer_num);
return;
}
if (new_timer_value_sec == vdev->ibss_peer_heart_beat_timer) {
WMA_LOGD("timer value %d stays same, no need to notify target",
new_timer_value_sec);
return;
}
/* send new timer value to target */
vdev->ibss_peer_heart_beat_timer = new_timer_value_sec;
new_timer_value_ms = ((u_int32_t)new_timer_value_sec) * 1000;
if (wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS,
new_timer_value_ms)) {
WMA_LOGE("Failed to set IBSS link monitoring timer value");
return;
}
WMA_LOGD("Set IBSS link monitor timer: peer_num = %d timer_value = %d",
new_peer_num, new_timer_value_ms);
}
#endif /* QCA_IBSS_SUPPORT */
#ifdef FEATURE_WLAN_TDLS
static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta)
{
ol_txrx_pdev_handle pdev;
ol_txrx_vdev_handle vdev;
ol_txrx_peer_handle peer;
u_int8_t peer_id;
VOS_STATUS status;
int32_t ret;
tTdlsPeerStateParams *peerStateParams;
WMA_LOGD("%s: staType: %d, staIdx: %d, updateSta: %d, "
"bssId: %pM, staMac: %pM",
__func__, add_sta->staType, add_sta->staIdx,
add_sta->updateSta, add_sta->bssId, add_sta->staMac);
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to find pdev", __func__);
add_sta->status = VOS_STATUS_E_FAILURE;
goto send_rsp;
}
vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId);
if (!vdev) {
WMA_LOGE("%s: Failed to find vdev", __func__);
add_sta->status = VOS_STATUS_E_FAILURE;
goto send_rsp;
}
if (0 == add_sta->updateSta) {
/* its a add sta request **/
#if defined(CONFIG_HL_SUPPORT)
if (vdev->last_real_peer &&
(adf_os_mem_cmp((u8 *)add_sta->bssId,
vdev->last_real_peer->mac_addr.raw,
IEEE80211_ADDR_LEN) == 0)) {
adf_os_mem_copy(vdev->hl_tdls_ap_mac_addr.raw,
vdev->last_real_peer->mac_addr.raw,
OL_TXRX_MAC_ADDR_LEN);
}
#endif
WMA_LOGD("%s: addSta, calling wma_create_peer for %pM, vdev_id %hu",
__func__, add_sta->staMac, add_sta->smesessionId);
status = wma_create_peer(wma, pdev, vdev, add_sta->staMac,
WMI_PEER_TYPE_TDLS, add_sta->smesessionId,
VOS_FALSE);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to create peer for %pM",
__func__, add_sta->staMac);
add_sta->status = status;
goto send_rsp;
}
peer = ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id);
if (!peer) {
WMA_LOGE("%s: addSta, failed to find peer handle for mac %pM",
__func__, add_sta->staMac);
add_sta->status = VOS_STATUS_E_FAILURE;
wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, peer,
VOS_FALSE);
#if defined(CONFIG_HL_SUPPORT)
if (vdev->last_real_peer == NULL) {
peer = NULL;
peer = ol_txrx_find_peer_by_addr(pdev, vdev->hl_tdls_ap_mac_addr.raw, &peer_id);
if (peer && (peer->peer_ids[0] != HTT_INVALID_PEER_ID))
vdev->last_real_peer = peer;
}
#endif
goto send_rsp;
}
add_sta->staIdx = ol_txrx_local_peer_id(peer);
WMA_LOGD("%s: addSta, after calling ol_txrx_local_peer_id, "
"staIdx: %d, staMac: %pM",
__func__, add_sta->staIdx, add_sta->staMac);
peerStateParams = vos_mem_malloc(sizeof(tTdlsPeerStateParams));
if (!peerStateParams) {
WMA_LOGE("%s: Failed to allocate memory for peerStateParams for %pM",
__func__, add_sta->staMac);
add_sta->status = VOS_STATUS_E_FAILURE;
goto send_rsp;
}
vos_mem_zero(peerStateParams, sizeof(*peerStateParams));
peerStateParams->peerState = WMI_TDLS_PEER_STATE_PEERING;
peerStateParams->vdevId = vdev->vdev_id;
vos_mem_copy(&peerStateParams->peerMacAddr,
&add_sta->staMac,
sizeof(tSirMacAddr));
wma_update_tdls_peer_state(wma, peerStateParams);
} else {
/* its a change sta request **/
peer = ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id);
if (!peer) {
WMA_LOGE("%s: changeSta,failed to find peer handle for mac %pM",
__func__, add_sta->staMac);
add_sta->status = VOS_STATUS_E_FAILURE;
wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, peer,
VOS_FALSE);
#if defined(CONFIG_HL_SUPPORT)
if (vdev->last_real_peer == NULL) {
peer = NULL;
peer = ol_txrx_find_peer_by_addr(pdev, vdev->hl_tdls_ap_mac_addr.raw, &peer_id);
if (peer && (peer->peer_ids[0] != HTT_INVALID_PEER_ID))
vdev->last_real_peer = peer;
}
#endif
goto send_rsp;
}
WMA_LOGD("%s: changeSta, calling wmi_unified_send_peer_assoc",
__func__);
ret = wmi_unified_send_peer_assoc(wma, add_sta->nwType, add_sta);
if (ret) {
add_sta->status = VOS_STATUS_E_FAILURE;
wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, peer,
VOS_FALSE);
#if defined(CONFIG_HL_SUPPORT)
if (vdev->last_real_peer == NULL) {
peer = NULL;
peer = ol_txrx_find_peer_by_addr(pdev, vdev->hl_tdls_ap_mac_addr.raw, &peer_id);
if (peer && (peer->peer_ids[0] != HTT_INVALID_PEER_ID))
vdev->last_real_peer = peer;
}
#endif
goto send_rsp;
}
}
send_rsp:
WMA_LOGD("%s: Sending add sta rsp to umac (mac:%pM, status:%d), "
"staType: %d, staIdx: %d, updateSta: %d",
__func__, add_sta->staMac, add_sta->status,
add_sta->staType, add_sta->staIdx, add_sta->updateSta);
wma_send_msg(wma, WDA_ADD_STA_RSP, (void *)add_sta, 0);
}
#endif
static void wma_add_sta_req_sta_mode(tp_wma_handle wma, tpAddStaParams params)
{
ol_txrx_pdev_handle pdev;
VOS_STATUS status = VOS_STATUS_SUCCESS;
ol_txrx_peer_handle peer;
struct wma_txrx_node *iface = NULL;
tPowerdBm maxTxPower;
int ret = 0;
int smps_param;
#ifdef FEATURE_WLAN_TDLS
if (STA_ENTRY_TDLS_PEER == params->staType)
{
wma_add_tdls_sta(wma, params);
return;
}
#endif
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Unable to get pdev", __func__);
goto out;
}
iface = &wma->interfaces[params->smesessionId];
if (params->staType != STA_ENTRY_SELF) {
WMA_LOGP("%s: unsupported station type %d",
__func__, params->staType);
goto out;
}
peer = ol_txrx_find_peer_by_addr(pdev, params->bssId, &params->staIdx);
if(params->nonRoamReassoc) {
ol_txrx_peer_state_update(pdev, params->bssId,
ol_txrx_peer_state_auth);
adf_os_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED);
iface->aid = params->assocId;
goto out;
}
if (wma->interfaces[params->smesessionId].vdev_up == true) {
WMA_LOGE("%s: vdev id %d is already UP for %pM", __func__,
params->smesessionId, params->bssId);
status = VOS_STATUS_E_FAILURE;
goto out;
}
if (peer != NULL && peer->state == ol_txrx_peer_state_disc) {
/*
* This is the case for reassociation.
* peer state update and peer_assoc is required since it
* was not done by WDA_ADD_BSS_REQ.
*/
/* Update peer state */
if (params->encryptType == eSIR_ED_NONE) {
WMA_LOGD("%s: Update peer(%pM) state into auth",
__func__, params->bssId);
ol_txrx_peer_state_update(pdev, params->bssId,
ol_txrx_peer_state_auth);
} else {
WMA_LOGD("%s: Update peer(%pM) state into conn",
__func__, params->bssId);
ol_txrx_peer_state_update(pdev, params->bssId,
ol_txrx_peer_state_conn);
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if(iface->roam_synch_in_progress)
{
// iface->nss = params->nss;
/*In LFR2.0, the following operations are performed as
* part of wmi_unified_send_peer_assoc. As we are
* skipping this operation, we are just executing the
* following which are useful for LFR3.0.*/
ol_txrx_peer_state_update(pdev, params->bssId,
ol_txrx_peer_state_auth);
adf_os_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED);
iface->aid = params->assocId;
goto out;
}
#endif
wmi_unified_send_txbf(wma, params);
ret = wmi_unified_send_peer_assoc(wma,
iface->nwType,
(tAddStaParams *)iface->addBssStaContext);
if (ret) {
status = VOS_STATUS_E_FAILURE;
wma_remove_peer(wma, params->bssId,
params->smesessionId, peer, VOS_FALSE);
goto out;
}
#ifdef WLAN_FEATURE_11W
if (params->rmfEnabled) {
/* when 802.11w PMF is enabled for hw encr/decr
use hw MFP Qos bits 0x10 */
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_PMF_QOS, TRUE);
if(ret) {
WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)",
__func__, ret);
} else {
WMA_LOGI("%s: QOS MFP/PMF set to %d",
__func__, TRUE);
}
}
#endif /* WLAN_FEATURE_11W */
#if defined WLAN_FEATURE_VOWIFI_11R
/*
* Set the PTK in 11r mode because we already have it.
*/
if (iface->staKeyParams) {
wma_set_stakey(wma, (tpSetStaKeyParams) iface->staKeyParams);
}
#endif
}
#if defined WLAN_FEATURE_VOWIFI
maxTxPower = params->maxTxPower;
#else
maxTxPower = 0;
#endif
wma_vdev_set_bss_params(wma, params->smesessionId, iface->beaconInterval,
iface->dtimPeriod, iface->shortSlotTimeSupported,
iface->llbCoexist, maxTxPower);
params->csaOffloadEnable = 0;
if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_CSA_OFFLOAD)) {
params->csaOffloadEnable = 1;
if (wmi_unified_csa_offload_enable(wma, params->smesessionId) < 0) {
WMA_LOGE("Unable to enable CSA offload for vdev_id:%d",
params->smesessionId);
}
}
if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE)) {
if (wmi_unified_nat_keepalive_enable(wma, params->smesessionId) < 0) {
WMA_LOGE("Unable to enable NAT keepalive for vdev_id:%d",
params->smesessionId);
}
}
if (wmi_unified_vdev_up_send(wma->wmi_handle, params->smesessionId,
params->assocId, params->bssId) < 0) {
WMA_LOGP("%s: Failed to send vdev up cmd: vdev %d bssid %pM",
__func__, params->smesessionId, params->bssId);
status = VOS_STATUS_E_FAILURE;
}
else {
wma->interfaces[params->smesessionId].vdev_up = TRUE;
}
adf_os_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED);
WMA_LOGD("%s: STA mode (type %d subtype %d) BSS is started",
__func__, iface->type, iface->sub_type);
/* Sta is now associated, configure various params */
/* Send SMPS force command to FW to send the required
* action frame. The SM power save is also included
* in the assoc request if ht smps is enabled either
* from INI or as a result of dynamic antenna switch
*/
if (params->enableHtSmps) {
smps_param = wma_smps_mode_to_force_mode_param(
params->htSmpsconfig);
if (smps_param >= 0) {
WMA_LOGD("%s: Set MIMO power save smps mode %d",
__func__, params->htSmpsconfig);
wma_set_mimops(wma, params->smesessionId,
smps_param);
}
}
#ifdef WLAN_FEATURE_11AC
/* Partial AID match power save, enable when SU bformee*/
if (params->enableVhtpAid && params->vhtTxBFCapable)
wma_set_ppsconfig(params->smesessionId,
WMA_VHT_PPS_PAID_MATCH, 1);
#endif
/* Enable AMPDU power save, if htCapable/vhtCapable */
if (params->enableAmpduPs &&
(params->htCapable || params->vhtCapable))
wma_set_ppsconfig(params->smesessionId,
WMA_VHT_PPS_DELIM_CRC_FAIL, 1);
iface->aid = params->assocId;
params->nss = iface->nss;
out:
params->status = status;
/* change logging before release */
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if(iface && iface->roam_synch_in_progress)
WMA_LOGD("%s:statype %d vdevid %d aid %d bssid %pM staIdx %d status %d",
__func__, params->staType, params->smesessionId,
params->assocId, params->bssId, params->staIdx, status);
else
WMA_LOGE("%s:statype %d vdevid %d aid %d bssid %pM staIdx %d status %d",
__func__, params->staType, params->smesessionId,
params->assocId, params->bssId, params->staIdx, status);
#endif
wma_send_msg(wma, WDA_ADD_STA_RSP, (void *)params, 0);
}
#ifdef FEATURE_WLAN_D0WOW
static void wma_add_pm_vote(tp_wma_handle wma)
{
if (++wma->ap_client_cnt == 1) {
vos_runtime_pm_prevent_suspend(wma->runtime_context.ap);
vos_pm_control(DISABLE_PCIE_POWER_COLLAPSE);
}
}
static void wma_del_pm_vote(tp_wma_handle wma)
{
if (--wma->ap_client_cnt == 0) {
vos_runtime_pm_allow_suspend(wma->runtime_context.ap);
vos_pm_control(ENABLE_PCIE_POWER_COLLAPSE);
}
}
#else
static void wma_prevent_suspend_check(tp_wma_handle wma)
{
wma->ap_client_cnt++;
if (wma->ap_client_cnt ==
wma->wlan_resource_config.num_offload_peers) {
vos_runtime_pm_prevent_suspend(wma->runtime_context.ap);
vos_wake_lock_acquire(&wma->wow_wake_lock,
WIFI_POWER_EVENT_WAKELOCK_ADD_STA);
WMA_LOGW("%s: %d clients connected, prevent suspend",
__func__, wma->ap_client_cnt);
}
}
static void wma_allow_suspend_check(tp_wma_handle wma)
{
wma->ap_client_cnt--;
if (wma->ap_client_cnt ==
wma->wlan_resource_config.num_offload_peers - 1) {
vos_wake_lock_release(&wma->wow_wake_lock,
WIFI_POWER_EVENT_WAKELOCK_DEL_STA);
vos_runtime_pm_allow_suspend(wma->runtime_context.ap);
WMA_LOGW("%s: %d clients connected, allow suspend",
__func__, wma->ap_client_cnt);
}
}
#endif /* FEATURE_WLAN_D0WOW */
int wma_get_client_count(WMA_HANDLE handle)
{
tp_wma_handle wma = (tp_wma_handle)handle;
return wma->ap_client_cnt;
}
static void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta)
{
tANI_U8 oper_mode = BSS_OPERATIONAL_MODE_STA;
WMA_LOGD("%s: add_sta->sessionId = %d.", __func__, add_sta->smesessionId);
WMA_LOGD("%s: add_sta->bssId = %x:%x:%x:%x:%x:%x", __func__,
add_sta->bssId[0], add_sta->bssId[1], add_sta->bssId[2],
add_sta->bssId[3], add_sta->bssId[4], add_sta->bssId[5]);
if (wma_is_vdev_in_ap_mode(wma, add_sta->smesessionId)) {
#ifdef FEATURE_WLAN_D0WOW
wma_add_pm_vote(wma);
#else
wma_prevent_suspend_check(wma);
#endif
oper_mode = BSS_OPERATIONAL_MODE_AP;
}
#ifdef QCA_IBSS_SUPPORT
else if (wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId)) {
oper_mode = BSS_OPERATIONAL_MODE_IBSS;
#ifdef FEATURE_WLAN_D0WOW
wma_add_pm_vote(wma);
#endif
}
#endif
if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, add_sta->smesessionId))
oper_mode = BSS_OPERATIONAL_MODE_NDI;
switch (oper_mode) {
case BSS_OPERATIONAL_MODE_STA:
wma_add_sta_req_sta_mode(wma, add_sta);
break;
#ifdef QCA_IBSS_SUPPORT
case BSS_OPERATIONAL_MODE_IBSS: /* IBSS should share the same code as AP mode */
#endif
case BSS_OPERATIONAL_MODE_AP:
wma_add_sta_req_ap_mode(wma, add_sta);
break;
case BSS_OPERATIONAL_MODE_NDI:
wma_add_sta_ndi_mode(wma, add_sta);
break;
}
#ifdef QCA_IBSS_SUPPORT
/* adjust heart beat thresold timer value for detecting ibss peer departure */
if (oper_mode == BSS_OPERATIONAL_MODE_IBSS)
wma_adjust_ibss_heart_beat_timer(wma, add_sta->smesessionId, 1);
#endif
}
/*
* This function reads WEP keys from cfg and fills
* up key_info.
*/
static void wma_read_cfg_wepkey(tp_wma_handle wma_handle,
tSirKeys *key_info, v_U32_t *def_key_idx,
u_int8_t *num_keys)
{
tSirRetStatus status;
v_U32_t val = SIR_MAC_KEY_LENGTH;
u_int8_t i, j;
WMA_LOGD("Reading WEP keys from cfg");
/* NOTE:def_key_idx is initialized to 0 by the caller */
status = wlan_cfgGetInt(wma_handle->mac_context,
WNI_CFG_WEP_DEFAULT_KEYID, def_key_idx);
if (status != eSIR_SUCCESS)
WMA_LOGE("Unable to read default id, defaulting to 0");
for (i = 0, j = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) {
status = wlan_cfgGetStr(wma_handle->mac_context,
(u_int16_t) WNI_CFG_WEP_DEFAULT_KEY_1 + i,
key_info[j].key, &val);
if (status != eSIR_SUCCESS) {
WMA_LOGE("WEP key is not configured at :%d", i);
} else {
key_info[j].keyId = i;
key_info[j].keyLength = (u_int16_t) val;
j++;
}
}
*num_keys = j;
}
/*
* This function setsup wmi buffer from information
* passed in key_params.
*/
static wmi_buf_t wma_setup_install_key_cmd(tp_wma_handle wma_handle,
struct wma_set_key_params *key_params,
u_int32_t *len, u_int8_t mode)
{
wmi_vdev_install_key_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int8_t *buf_ptr;
u_int8_t *key_data;
#ifdef WLAN_FEATURE_11W
struct wma_txrx_node *iface = NULL;
#endif /* WLAN_FEATURE_11W */
if ((key_params->key_type == eSIR_ED_NONE &&
key_params->key_len) || (key_params->key_type != eSIR_ED_NONE &&
!key_params->key_len)) {
WMA_LOGE("%s:Invalid set key request", __func__);
return NULL;
}
*len = sizeof(*cmd) + roundup(key_params->key_len, sizeof(u_int32_t)) +
WMI_TLV_HDR_SIZE;
buf = wmi_buf_alloc(wma_handle->wmi_handle, *len);
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set key cmd");
return NULL;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_vdev_install_key_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_install_key_cmd_fixed_param));
cmd->vdev_id = key_params->vdev_id;
cmd->key_ix = key_params->key_idx;
WMI_CHAR_ARRAY_TO_MAC_ADDR(key_params->peer_mac,
&cmd->peer_macaddr);
vos_mem_copy(&cmd->key_rsc_counter,
&key_params->key_rsc[0], sizeof(uint64_t));
if (key_params->unicast)
cmd->key_flags |= PAIRWISE_USAGE;
else
cmd->key_flags |= GROUP_USAGE;
switch (key_params->key_type) {
case eSIR_ED_NONE:
cmd->key_cipher = WMI_CIPHER_NONE;
break;
case eSIR_ED_WEP40:
case eSIR_ED_WEP104:
cmd->key_cipher = WMI_CIPHER_WEP;
if (key_params->unicast &&
cmd->key_ix == key_params->def_key_idx) {
WMA_LOGD("STA Mode: cmd->key_flags |= TX_USAGE");
cmd->key_flags |= TX_USAGE;
} else if ((mode == wlan_op_mode_ap) &&
(cmd->key_ix == key_params->def_key_idx)) {
WMA_LOGD("AP Mode: cmd->key_flags |= TX_USAGE");
cmd->key_flags |= TX_USAGE;
}
break;
case eSIR_ED_TKIP:
cmd->key_txmic_len = WMA_TXMIC_LEN;
cmd->key_rxmic_len = WMA_RXMIC_LEN;
cmd->key_cipher = WMI_CIPHER_TKIP;
break;
#ifdef FEATURE_WLAN_WAPI
#define WPI_IV_LEN 16
case eSIR_ED_WPI:
{
/*initialize receive and transmit IV with default values*/
/* **Note: tx_iv must be sent in reverse** */
unsigned char tx_iv[16] = {0x36,0x5c,0x36,0x5c,0x36,0x5c,0x36,
0x5c,0x36,0x5c,0x36,0x5c,0x36,0x5c,
0x36,0x5c};
unsigned char rx_iv[16] = {0x5c,0x36,0x5c,0x36,0x5c,0x36,0x5c,
0x36,0x5c,0x36,0x5c,0x36,0x5c,0x36,
0x5c,0x37};
if (mode == wlan_op_mode_ap) {
/*Authenticator initializes the value of PN as
*0x5C365C365C365C365C365C365C365C36 for MCastkey Update
*/
if (key_params->unicast)
tx_iv[0] = 0x37;
rx_iv[WPI_IV_LEN - 1] = 0x36;
} else {
if (!key_params->unicast)
rx_iv[WPI_IV_LEN - 1] = 0x36;
}
cmd->key_txmic_len = WMA_TXMIC_LEN;
cmd->key_rxmic_len = WMA_RXMIC_LEN;
vos_mem_copy(&cmd->wpi_key_rsc_counter, &rx_iv, WPI_IV_LEN);
vos_mem_copy(&cmd->wpi_key_tsc_counter, &tx_iv, WPI_IV_LEN);
cmd->key_cipher = WMI_CIPHER_WAPI;
break;
}
#endif
case eSIR_ED_CCMP:
cmd->key_cipher = WMI_CIPHER_AES_CCM;
break;
#ifdef WLAN_FEATURE_11W
case eSIR_ED_AES_128_CMAC:
cmd->key_cipher = WMI_CIPHER_AES_CMAC;
break;
#endif /* WLAN_FEATURE_11W */
default:
/* TODO: MFP ? */
WMA_LOGE("%s:Invalid encryption type:%d", __func__, key_params->key_type);
wmi_buf_free(buf);
return NULL;
}
buf_ptr += sizeof(wmi_vdev_install_key_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
roundup(key_params->key_len, sizeof(u_int32_t)));
key_data = (A_UINT8*)(buf_ptr + WMI_TLV_HDR_SIZE);
#ifdef BIG_ENDIAN_HOST
{
/* for big endian host, copy engine byte_swap is enabled
* But the key data content is in network byte order
* Need to byte swap the key data content - so when copy engine
* does byte_swap - target gets key_data content in the correct
* order.
*/
int8_t i;
u_int32_t *destp, *srcp;
destp = (u_int32_t *) key_data;
srcp = (u_int32_t *) key_params->key_data;
for(i = 0;
i < roundup(key_params->key_len, sizeof(u_int32_t)) / 4;
i++) {
*destp = le32_to_cpu(*srcp);
destp++;
srcp++;
}
}
#else
vos_mem_copy((void *) key_data,
(const void *) key_params->key_data,
key_params->key_len);
#endif
cmd->key_len = key_params->key_len;
#ifdef WLAN_FEATURE_11W
if (key_params->key_type == eSIR_ED_AES_128_CMAC)
{
iface = &wma_handle->interfaces[key_params->vdev_id];
if (iface) {
iface->key.key_length = key_params->key_len;
vos_mem_copy (iface->key.key,
(const void *) key_params->key_data,
iface->key.key_length);
if ((cmd->key_ix == WMA_IGTK_KEY_INDEX_4) ||
(cmd->key_ix == WMA_IGTK_KEY_INDEX_5))
vos_mem_zero (iface->key.key_id[cmd->key_ix - WMA_IGTK_KEY_INDEX_4].ipn,
CMAC_IPN_LEN);
}
}
#endif /* WLAN_FEATURE_11W */
WMA_LOGD("Key setup : vdev_id %d key_idx %d key_type %d key_len %d"
" unicast %d peer_mac %pM def_key_idx %d", key_params->vdev_id,
key_params->key_idx, key_params->key_type, key_params->key_len,
key_params->unicast, key_params->peer_mac,
key_params->def_key_idx);
WMA_LOGD("keyrsc param key_seq_counter_h:0x%x key_seq_counter_l: 0x%x",
cmd->key_rsc_counter.key_seq_counter_h,
cmd->key_rsc_counter.key_seq_counter_l);
return buf;
}
static void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info)
{
struct wma_set_key_params key_params;
wmi_buf_t buf;
int32_t status;
u_int32_t len = 0, i;
v_U32_t def_key_idx = 0;
ol_txrx_vdev_handle txrx_vdev;
WMA_LOGD("BSS key setup");
txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId);
if (!txrx_vdev) {
WMA_LOGE("%s:Invalid vdev handle", __func__);
key_info->status = eHAL_STATUS_FAILURE;
goto out;
}
/*
** For IBSS, WMI expects the BSS key to be set per peer key
** So cache the BSS key in the wma_handle and re-use it when the STA key is been setup for a peer
*/
if (wlan_op_mode_ibss == txrx_vdev->opmode) {
key_info->status = eHAL_STATUS_SUCCESS;
if (wma_handle->ibss_started > 0)
goto out;
WMA_LOGD("Caching IBSS Key");
vos_mem_copy(&wma_handle->ibsskey_info, key_info, sizeof(tSetBssKeyParams));
}
adf_os_mem_set(&key_params, 0, sizeof(key_params));
key_params.vdev_id = key_info->smesessionId;
key_params.key_type = key_info->encType;
key_params.singl_tid_rc = key_info->singleTidRc;
key_params.unicast = FALSE;
if (txrx_vdev->opmode == wlan_op_mode_sta) {
vos_mem_copy(key_params.peer_mac,
wma_handle->interfaces[key_info->smesessionId].bssid,
ETH_ALEN);
} else {
/* vdev mac address will be passed for all other modes */
vos_mem_copy(key_params.peer_mac, txrx_vdev->mac_addr.raw,
ETH_ALEN);
WMA_LOGA("BSS Key setup with vdev_mac %pM\n",
txrx_vdev->mac_addr.raw);
}
if (key_info->numKeys == 0 &&
(key_info->encType == eSIR_ED_WEP40 ||
key_info->encType == eSIR_ED_WEP104)) {
wma_read_cfg_wepkey(wma_handle, key_info->key,
&def_key_idx, &key_info->numKeys);
} else if ((key_info->encType == eSIR_ED_WEP40) ||
(key_info->encType == eSIR_ED_WEP104)) {
struct wma_txrx_node *intf =
&wma_handle->interfaces[key_info->smesessionId];
key_params.def_key_idx = intf->wep_default_key_idx;
}
for (i = 0; i < key_info->numKeys; i++) {
if (key_params.key_type != eSIR_ED_NONE &&
!key_info->key[i].keyLength)
continue;
if (key_info->encType == eSIR_ED_WPI) {
key_params.key_idx = key_info->key[i].keyId;
key_params.def_key_idx = key_info->key[i].keyId;
} else
key_params.key_idx = key_info->key[i].keyId;
key_params.key_len = key_info->key[i].keyLength;
vos_mem_copy(key_params.key_rsc,
key_info->key[i].keyRsc,
SIR_MAC_MAX_KEY_RSC_LEN);
if (key_info->encType == eSIR_ED_TKIP) {
vos_mem_copy(key_params.key_data,
key_info->key[i].key, 16);
vos_mem_copy(&key_params.key_data[16],
&key_info->key[i].key[24], 8);
vos_mem_copy(&key_params.key_data[24],
&key_info->key[i].key[16], 8);
} else
vos_mem_copy((v_VOID_t *) key_params.key_data,
(const v_VOID_t *) key_info->key[i].key,
key_info->key[i].keyLength);
WMA_LOGD("%s: bss key[%d] length %d", __func__, i,
key_info->key[i].keyLength);
buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len,
txrx_vdev->opmode);
if (!buf) {
WMA_LOGE("%s:Failed to setup install key buf", __func__);
key_info->status = eHAL_STATUS_FAILED_ALLOC;
goto out;
}
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_VDEV_INSTALL_KEY_CMDID);
if (status) {
wmi_buf_free(buf);
WMA_LOGE("%s:Failed to send install key command", __func__);
key_info->status = eHAL_STATUS_FAILURE;
goto out;
}
}
wma_handle->ibss_started++;
/* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */
key_info->status = eHAL_STATUS_SUCCESS;
out:
wma_send_msg(wma_handle, WDA_SET_BSSKEY_RSP, (void *)key_info, 0);
}
static void wma_set_ibsskey_helper(tp_wma_handle wma_handle, tpSetBssKeyParams key_info, u_int8_t* peerMacAddr)
{
struct wma_set_key_params key_params;
wmi_buf_t buf;
int32_t status;
u_int32_t len = 0, i;
v_U32_t def_key_idx = 0;
ol_txrx_vdev_handle txrx_vdev;
WMA_LOGD("BSS key setup for peer");
ASSERT( NULL != peerMacAddr);
txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId);
if (!txrx_vdev) {
WMA_LOGE("%s:Invalid vdev handle", __func__);
key_info->status = eHAL_STATUS_FAILURE;
return;
}
adf_os_mem_set(&key_params, 0, sizeof(key_params));
key_params.vdev_id = key_info->smesessionId;
key_params.key_type = key_info->encType;
key_params.singl_tid_rc = key_info->singleTidRc;
key_params.unicast = FALSE;
ASSERT(wlan_op_mode_ibss == txrx_vdev->opmode);
vos_mem_copy(key_params.peer_mac, peerMacAddr, ETH_ALEN);
if (key_info->numKeys == 0 &&
(key_info->encType == eSIR_ED_WEP40 ||
key_info->encType == eSIR_ED_WEP104)) {
wma_read_cfg_wepkey(wma_handle, key_info->key,
&def_key_idx, &key_info->numKeys);
}
for (i = 0; i < key_info->numKeys; i++) {
if (key_params.key_type != eSIR_ED_NONE &&
!key_info->key[i].keyLength)
continue;
key_params.key_idx = key_info->key[i].keyId;
key_params.key_len = key_info->key[i].keyLength;
if (key_info->encType == eSIR_ED_TKIP) {
vos_mem_copy(key_params.key_data,
key_info->key[i].key, 16);
vos_mem_copy(&key_params.key_data[16],
&key_info->key[i].key[24], 8);
vos_mem_copy(&key_params.key_data[24],
&key_info->key[i].key[16], 8);
} else
vos_mem_copy((v_VOID_t *) key_params.key_data,
(const v_VOID_t *) key_info->key[i].key,
key_info->key[i].keyLength);
WMA_LOGD("%s: peer bcast key[%d] length %d", __func__, i,
key_info->key[i].keyLength);
buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len,
txrx_vdev->opmode);
if (!buf) {
WMA_LOGE("%s:Failed to setup install key buf", __func__);
return;
}
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_VDEV_INSTALL_KEY_CMDID);
if (status) {
wmi_buf_free(buf);
WMA_LOGE("%s:Failed to send install key command", __func__);
}
}
}
static void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info)
{
wmi_buf_t buf;
int32_t status, i;
u_int32_t len = 0;
ol_txrx_pdev_handle txrx_pdev;
ol_txrx_vdev_handle txrx_vdev;
struct ol_txrx_peer_t *peer;
u_int8_t num_keys = 0, peer_id;
struct wma_set_key_params key_params;
v_U32_t def_key_idx = 0;
WMA_LOGD("STA key setup");
/* Get the txRx Pdev handle */
txrx_pdev = vos_get_context(VOS_MODULE_ID_TXRX,
wma_handle->vos_context);
if (!txrx_pdev) {
WMA_LOGE("%s:Invalid txrx pdev handle", __func__);
key_info->status = eHAL_STATUS_FAILURE;
goto out;
}
peer = ol_txrx_find_peer_by_addr(txrx_pdev, key_info->peerMacAddr,
&peer_id);
if (!peer) {
WMA_LOGE("%s:Invalid peer for key setting", __func__);
key_info->status = eHAL_STATUS_FAILURE;
goto out;
}
txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId);
if(!txrx_vdev) {
WMA_LOGE("%s:TxRx Vdev Handle is NULL", __func__);
key_info->status = eHAL_STATUS_FAILURE;
goto out;
}
if (key_info->defWEPIdx == WMA_INVALID_KEY_IDX &&
(key_info->encType == eSIR_ED_WEP40 ||
key_info->encType == eSIR_ED_WEP104) &&
txrx_vdev->opmode != wlan_op_mode_ap) {
wma_read_cfg_wepkey(wma_handle, key_info->key,
&def_key_idx, &num_keys);
key_info->defWEPIdx = def_key_idx;
} else {
num_keys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS;
if (key_info->encType != eSIR_ED_NONE) {
for (i = 0; i < num_keys; i++) {
if (key_info->key[i].keyDirection ==
eSIR_TX_DEFAULT) {
key_info->defWEPIdx = i;
break;
}
}
}
}
adf_os_mem_set(&key_params, 0, sizeof(key_params));
key_params.vdev_id = key_info->smesessionId;
key_params.key_type = key_info->encType;
key_params.singl_tid_rc = key_info->singleTidRc;
key_params.unicast = TRUE;
key_params.def_key_idx = key_info->defWEPIdx;
vos_mem_copy((v_VOID_t *) key_params.peer_mac,
(const v_VOID_t *) key_info->peerMacAddr, ETH_ALEN);
for (i = 0; i < num_keys; i++) {
if (key_params.key_type != eSIR_ED_NONE &&
!key_info->key[i].keyLength)
continue;
if (key_info->encType == eSIR_ED_TKIP) {
vos_mem_copy(key_params.key_data,
key_info->key[i].key, 16);
vos_mem_copy(&key_params.key_data[16],
&key_info->key[i].key[24], 8);
vos_mem_copy(&key_params.key_data[24],
&key_info->key[i].key[16], 8);
} else
vos_mem_copy(key_params.key_data, key_info->key[i].key,
key_info->key[i].keyLength);
if (key_info->encType == eSIR_ED_WPI) {
key_params.key_idx = key_info->key[i].keyId;
key_params.def_key_idx = key_info->key[i].keyId;
} else
key_params.key_idx = i;
key_params.key_len = key_info->key[i].keyLength;
buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len,
txrx_vdev->opmode);
if (!buf) {
WMA_LOGE("%s:Failed to setup install key buf", __func__);
key_info->status = eHAL_STATUS_FAILED_ALLOC;
goto out;
}
WMA_LOGD("%s: peer unicast key[%d] %d ", __func__, i,
key_info->key[i].keyLength);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_VDEV_INSTALL_KEY_CMDID);
if (status) {
wmi_buf_free(buf);
WMA_LOGE("%s:Failed to send install key command", __func__);
key_info->status = eHAL_STATUS_FAILURE;
goto out;
}
}
/* In IBSS mode, set the BSS KEY for this peer
** BSS key is supposed to be cache into wma_handle
*/
if (wlan_op_mode_ibss == txrx_vdev->opmode){
wma_set_ibsskey_helper(wma_handle, &wma_handle->ibsskey_info, key_info->peerMacAddr);
}
/* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */
key_info->status = eHAL_STATUS_SUCCESS;
out:
if (key_info->sendRsp)
wma_send_msg(wma_handle, WDA_SET_STAKEY_RSP, (void *) key_info, 0);
}
static void wma_delete_sta_req_ap_mode(tp_wma_handle wma,
tpDeleteStaParams del_sta)
{
ol_txrx_pdev_handle pdev;
struct ol_txrx_peer_t *peer;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
del_sta->status = VOS_STATUS_E_FAILURE;
goto send_del_rsp;
}
peer = ol_txrx_peer_find_by_local_id(pdev, del_sta->staIdx);
if (!peer) {
WMA_LOGE("%s: Failed to get peer handle using peer id %d",
__func__, del_sta->staIdx);
del_sta->status = VOS_STATUS_E_FAILURE;
goto send_del_rsp;
}
wma_remove_peer(wma, peer->mac_addr.raw, del_sta->smesessionId, peer,
VOS_FALSE);
del_sta->status = VOS_STATUS_SUCCESS;
send_del_rsp:
if (del_sta->respReqd) {
WMA_LOGD("%s: Sending del rsp to umac (status: %d)",
__func__, del_sta->status);
wma_send_msg(wma, WDA_DELETE_STA_RSP, (void *)del_sta, 0);
}
}
#ifdef FEATURE_WLAN_TDLS
static void wma_del_tdls_sta(tp_wma_handle wma,
tpDeleteStaParams del_sta)
{
ol_txrx_pdev_handle pdev;
ol_txrx_vdev_handle vdev;
struct ol_txrx_peer_t *peer;
tTdlsPeerStateParams *peerStateParams;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to find pdev", __func__);
del_sta->status = VOS_STATUS_E_FAILURE;
goto send_del_rsp;
}
vdev = wma_find_vdev_by_id(wma, del_sta->smesessionId);
if (!vdev) {
WMA_LOGE("%s: Failed to find vdev", __func__);
del_sta->status = VOS_STATUS_E_FAILURE;
goto send_del_rsp;
}
peer = ol_txrx_peer_find_by_local_id(pdev, del_sta->staIdx);
if (!peer) {
WMA_LOGE("%s: Failed to get peer handle using peer id %d",
__func__, del_sta->staIdx);
del_sta->status = VOS_STATUS_E_FAILURE;
goto send_del_rsp;
}
peerStateParams = vos_mem_malloc(sizeof(tTdlsPeerStateParams));
if (!peerStateParams) {
WMA_LOGE("%s: Failed to allocate memory for peerStateParams for: %pM",
__func__, del_sta->staMac);
del_sta->status = VOS_STATUS_E_FAILURE;
goto send_del_rsp;
}
vos_mem_zero(peerStateParams, sizeof(*peerStateParams));
peerStateParams->peerState = WDA_TDLS_PEER_STATE_TEARDOWN;
peerStateParams->vdevId = vdev->vdev_id;
vos_mem_copy(&peerStateParams->peerMacAddr,
&del_sta->staMac,
sizeof(tSirMacAddr));
WMA_LOGD("%s: sending tdls_peer_state for peer mac: %pM, "
" peerState: %d",
__func__, peerStateParams->peerMacAddr,
peerStateParams->peerState);
wma_update_tdls_peer_state(wma, peerStateParams);
del_sta->status = VOS_STATUS_SUCCESS;
send_del_rsp:
if (del_sta->respReqd) {
WMA_LOGD("%s: Sending del rsp to umac (status: %d)",
__func__, del_sta->status);
wma_send_msg(wma, WDA_DELETE_STA_RSP, (void *)del_sta, 0);
}
}
#endif
static void wma_delete_sta_req_sta_mode(tp_wma_handle wma,
tpDeleteStaParams params)
{
VOS_STATUS status = VOS_STATUS_SUCCESS;
struct wma_txrx_node *iface;
iface = &wma->interfaces[params->smesessionId];
iface->uapsd_cached_val = 0;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
/* In case of LFR3.0 we need not send any
* WMI commands to FW before SYNCH_CONFIRM */
if(iface->roam_synch_in_progress)
goto send_del_sta_rsp;
#endif
#ifdef FEATURE_WLAN_TDLS
if (STA_ENTRY_TDLS_PEER == params->staType)
{
wma_del_tdls_sta(wma, params);
return;
}
#endif
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
send_del_sta_rsp:
#endif
params->status = status;
if (params->respReqd) {
WMA_LOGD("%s: vdev_id %d status %d", __func__,
params->smesessionId, status);
wma_send_msg(wma, WDA_DELETE_STA_RSP, (void *)params, 0);
}
}
static void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta)
{
tANI_U8 oper_mode = BSS_OPERATIONAL_MODE_STA;
u_int8_t smesession_id = del_sta->smesessionId;
bool rsp_requested = del_sta->respReqd;
if (wma_is_vdev_in_ap_mode(wma, smesession_id)) {
#ifdef FEATURE_WLAN_D0WOW
wma_del_pm_vote(wma);
#else
wma_allow_suspend_check(wma);
#endif
oper_mode = BSS_OPERATIONAL_MODE_AP;
}
#ifdef QCA_IBSS_SUPPORT
if (wma_is_vdev_in_ibss_mode(wma, smesession_id)) {
oper_mode = BSS_OPERATIONAL_MODE_IBSS;
#ifdef FEATURE_WLAN_D0WOW
wma_del_pm_vote(wma);
#endif
WMA_LOGD("%s: to delete sta for IBSS mode", __func__);
}
#endif
if (del_sta->staType == STA_ENTRY_NDI_PEER)
oper_mode = BSS_OPERATIONAL_MODE_NDI;
switch (oper_mode) {
case BSS_OPERATIONAL_MODE_STA:
wma_delete_sta_req_sta_mode(wma, del_sta);
break;
#ifdef QCA_IBSS_SUPPORT
case BSS_OPERATIONAL_MODE_IBSS: /* IBSS shares AP code */
#endif
case BSS_OPERATIONAL_MODE_AP:
wma_delete_sta_req_ap_mode(wma, del_sta);
break;
case BSS_OPERATIONAL_MODE_NDI:
wma_delete_sta_req_ndi_mode(wma, del_sta);
break;
}
#ifdef QCA_IBSS_SUPPORT
/* adjust heart beat thresold timer value for
* detecting ibss peer departure
*/
if (oper_mode == BSS_OPERATIONAL_MODE_IBSS)
wma_adjust_ibss_heart_beat_timer(wma, smesession_id, -1);
#endif
if (!rsp_requested) {
WMA_LOGD("%s: vdev_id %d status %d", __func__,
del_sta->smesessionId, del_sta->status);
vos_mem_free(del_sta);
}
}
static int32_t wmi_unified_vdev_stop_send(wmi_unified_t wmi, u_int8_t vdev_id)
{
wmi_vdev_stop_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_stop_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_stop_cmd_fixed_param));
cmd->vdev_id = vdev_id;
if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_STOP_CMDID)) {
WMA_LOGP("%s: Failed to send vdev stop command", __func__);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
static void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params)
{
ol_txrx_pdev_handle pdev;
ol_txrx_peer_handle peer = NULL;
struct wma_target_req *msg;
VOS_STATUS status = VOS_STATUS_SUCCESS;
u_int8_t peer_id;
u_int8_t max_wait_iterations = 0;
ol_txrx_vdev_handle txrx_vdev = NULL;
v_BOOL_t roam_synch_in_progress = VOS_FALSE;
u_int32_t timeout = WMA_VDEV_STOP_REQUEST_TIMEOUT;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s:Unable to get TXRX context", __func__);
goto out;
}
#ifdef QCA_IBSS_SUPPORT
if (wma_is_vdev_in_ibss_mode(wma, params->smesessionId))
/* in rome ibss case, self mac is used to create the bss peer */
peer = ol_txrx_find_peer_by_addr(pdev,
wma->interfaces[params->smesessionId].addr,
&peer_id);
else
#endif
if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces,
params->smesessionId))
/* In ndi case, self mac is used to create the self peer */
peer = ol_txrx_find_peer_by_addr(pdev,
wma->interfaces[params->smesessionId].addr,
&peer_id);
else
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);
status = VOS_STATUS_E_FAILURE;
goto out;
}
vos_mem_zero(wma->interfaces[params->smesessionId].bssid, ETH_ALEN);
txrx_vdev = wma_find_vdev_by_id(wma, params->smesessionId);
if (!txrx_vdev) {
WMA_LOGE("%s:Invalid vdev handle", __func__);
status = VOS_STATUS_E_FAILURE;
goto out;
}
/*Free the allocated stats response buffer for the the session*/
if (wma->interfaces[params->smesessionId].stats_rsp) {
vos_mem_free(wma->interfaces[params->smesessionId].stats_rsp);
wma->interfaces[params->smesessionId].stats_rsp = NULL;
}
if (wma->interfaces[params->smesessionId].psnr_req) {
vos_mem_free(wma->interfaces[params->smesessionId].psnr_req);
wma->interfaces[params->smesessionId].psnr_req = NULL;
}
if (wma->interfaces[params->smesessionId].action_frame_filter) {
struct action_frame_random_filter *action_frame_filter =
wma->interfaces[params->smesessionId].action_frame_filter;
wma->interfaces[params->smesessionId].action_frame_filter =
NULL;
vos_mem_free(action_frame_filter);
}
if (wlan_op_mode_ibss == txrx_vdev->opmode) {
wma->ibss_started = 0;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if(wma->interfaces[params->smesessionId].roam_synch_in_progress)
{
roam_synch_in_progress = VOS_TRUE;
goto detach_peer;
}
#endif
/* overwrite the timeout value to shorten the SSR latency in HL
* solution
*/
if (vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)) {
WMA_LOGP("%s: %d HL ssr in progress",
__func__, __LINE__);
timeout = WMA_DEL_BSS_TIMEOUT_IN_SSR;
}
msg = wma_fill_vdev_req(wma, params->smesessionId, WDA_DELETE_BSS_REQ,
WMA_TARGET_REQ_TYPE_VDEV_STOP, params,
timeout);
if (!msg) {
WMA_LOGP("%s: Failed to fill vdev request for vdev_id %d",
__func__, params->smesessionId);
status = VOS_STATUS_E_NOMEM;
goto detach_peer;
}
WMA_LOGW(FL("Outstanding msdu packets: %d"),
ol_txrx_get_tx_pending(pdev));
max_wait_iterations =
wma->interfaces[params->smesessionId].delay_before_vdev_stop /
WMA_TX_Q_RECHECK_TIMER_WAIT;
while ( ol_txrx_get_tx_pending(pdev) && max_wait_iterations )
{
WMA_LOGW(FL("Waiting for outstanding packet to drain."));
vos_wait_single_event(&wma->tx_queue_empty_event,
WMA_TX_Q_RECHECK_TIMER_WAIT);
max_wait_iterations--;
}
if (ol_txrx_get_tx_pending(pdev))
{
WMA_LOGW(FL("Outstanding msdu packets before VDEV_STOP : %d"),
ol_txrx_get_tx_pending(pdev));
}
WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)",
__func__, params->smesessionId);
wdi_in_vdev_pause(wma->interfaces[params->smesessionId].handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
wma->interfaces[params->smesessionId].pause_bitmap |=
(1 << PAUSE_TYPE_HOST);
if (wmi_unified_vdev_stop_send(wma->wmi_handle, params->smesessionId)) {
WMA_LOGP("%s: %d Failed to send vdev stop",
__func__, __LINE__);
wma_remove_vdev_req(wma, params->smesessionId,
WMA_TARGET_REQ_TYPE_VDEV_STOP);
status = VOS_STATUS_E_FAILURE;
goto detach_peer;
}
WMA_LOGD("%s: bssid %pM vdev_id %d",
__func__, params->bssid, params->smesessionId);
return;
detach_peer:
wma_remove_peer(wma, params->bssid, params->smesessionId, peer,
roam_synch_in_progress);
out:
params->status = status;
wma_send_msg(wma, WDA_DELETE_BSS_RSP, (void *)params, 0);
}
static void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params)
{
ol_txrx_pdev_handle pdev;
ol_txrx_vdev_handle vdev;
ol_txrx_peer_handle peer;
u_int8_t vdev_id, peer_id;
v_BOOL_t roam_synch_in_progress = VOS_FALSE;
VOS_STATUS status;
params->status = VOS_TRUE;
WMA_LOGD("%s: state %d selfmac %pM", __func__,
params->state, params->selfMacAddr);
if ((params->state != eSIR_LINK_PREASSOC_STATE) &&
(params->state != eSIR_LINK_DOWN_STATE)) {
WMA_LOGD("%s: unsupported link state %d",
__func__, params->state);
goto out;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Unable to get TXRX context", __func__);
goto out;
}
vdev = wma_find_vdev_by_addr(wma, params->selfMacAddr, &vdev_id);
if (!vdev) {
WMA_LOGP("%s: vdev not found for addr: %pM",
__func__, params->selfMacAddr);
goto out;
}
if (wma_is_vdev_in_ap_mode(wma, vdev_id)) {
WMA_LOGD("%s: Ignoring set link req in ap mode", __func__);
goto out;
}
if (params->state == eSIR_LINK_PREASSOC_STATE) {
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if(wma->interfaces[vdev_id].roam_synch_in_progress){
roam_synch_in_progress = VOS_TRUE;
}
#endif
status = wma_create_peer(wma, pdev, vdev, params->bssid,
WMI_PEER_TYPE_DEFAULT, vdev_id,
roam_synch_in_progress);
if (status != VOS_STATUS_SUCCESS)
params->status = VOS_FALSE;
}
else {
WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP",
__func__, vdev_id);
wdi_in_vdev_pause(wma->interfaces[vdev_id].handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
wma->interfaces[vdev_id].pause_bitmap |= (1 << PAUSE_TYPE_HOST);
if (wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id)) {
WMA_LOGP("%s: %d Failed to send vdev stop",
__func__, __LINE__);
}
peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, &peer_id);
if (peer) {
WMA_LOGP("%s: Deleting peer %pM vdev id %d",
__func__, params->bssid, vdev_id);
wma_remove_peer(wma, params->bssid, vdev_id, peer,
roam_synch_in_progress);
}
}
out:
wma_send_msg(wma, WDA_SET_LINK_STATE_RSP, (void *)params, 0);
}
/*
* Function to update per ac EDCA parameters
*/
static void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param,
wmi_wmm_vparams *wmm_param,
int ac)
{
#define WMA_WMM_EXPO_TO_VAL(val) ((1 << (val)) - 1)
wmm_param->cwmin = WMA_WMM_EXPO_TO_VAL(edca_param->cw.min);
wmm_param->cwmax = WMA_WMM_EXPO_TO_VAL(edca_param->cw.max);
wmm_param->aifs = edca_param->aci.aifsn;
wmm_param->txoplimit = edca_param->txoplimit;
wmm_param->acm = edca_param->aci.acm;
/* TODO: No ack is not present in EdcaParamRecord */
wmm_param->no_ack = vos_config_is_no_ack();
WMA_LOGI("WMM PARAMS AC[%d]: AIFS %d Min %d Max %d TXOP %d ACM %d NOACK %d",
ac,
wmm_param->aifs,
wmm_param->cwmin,
wmm_param->cwmax,
wmm_param->txoplimit,
wmm_param->acm,
wmm_param->no_ack);
}
/*
* Set TX power limit through vdev param
*/
static void wma_set_tx_power(WMA_HANDLE handle,
tMaxTxPowerParams *tx_pwr_params)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
u_int8_t vdev_id;
int ret = -1;
void *pdev;
if (tx_pwr_params->dev_mode == VOS_STA_SAP_MODE ||
tx_pwr_params->dev_mode == VOS_P2P_GO_MODE) {
pdev = wma_find_vdev_by_addr(wma_handle,
tx_pwr_params->bssId, &vdev_id);
} else {
pdev = wma_find_vdev_by_bssid(wma_handle,
tx_pwr_params->bssId, &vdev_id);
}
if (!pdev) {
WMA_LOGE("vdev handle is invalid for %pM", tx_pwr_params->bssId);
vos_mem_free(tx_pwr_params);
return;
}
if (!(wma_handle->interfaces[vdev_id].vdev_up)) {
WMA_LOGE("%s: vdev id %d is not up for %pM", __func__, vdev_id,
tx_pwr_params->bssId);
vos_mem_free(tx_pwr_params);
return;
}
if (tx_pwr_params->power == 0) {
/* set to default. Since the app does not care the tx power
* we keep the previous setting */
wma_handle->interfaces[vdev_id].tx_power = 0;
ret = 0;
goto end;
}
if (wma_handle->interfaces[vdev_id].max_tx_power != 0) {
/* make sure tx_power less than max_tx_power */
if (tx_pwr_params->power >
wma_handle->interfaces[vdev_id].max_tx_power) {
tx_pwr_params->power =
wma_handle->interfaces[vdev_id].max_tx_power;
}
}
if (wma_handle->interfaces[vdev_id].tx_power != tx_pwr_params->power) {
/* tx_power changed, Push the tx_power to FW */
WMA_LOGI("%s: Set TX pwr limit WMI_VDEV_PARAM_TX_PWRLIMIT %d",
__func__, tx_pwr_params->power);
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id,
WMI_VDEV_PARAM_TX_PWRLIMIT, tx_pwr_params->power);
if (ret == 0)
wma_handle->interfaces[vdev_id].tx_power = tx_pwr_params->power;
} else {
/* no tx_power change */
ret = 0;
}
end:
vos_mem_free(tx_pwr_params);
if (ret)
WMA_LOGE("Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT");
}
/*
* Set TX power limit through vdev param
*/
static void wma_set_max_tx_power(WMA_HANDLE handle,
tMaxTxPowerParams *tx_pwr_params)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
u_int8_t vdev_id;
int ret = -1;
void *pdev;
tPowerdBm prev_max_power;
pdev = wma_find_vdev_by_addr(wma_handle, tx_pwr_params->bssId, &vdev_id);
if (pdev == NULL) {
/* not in SAP array. Try the station/p2p array */
pdev = wma_find_vdev_by_bssid(wma_handle,
tx_pwr_params->bssId, &vdev_id);
}
if (!pdev) {
WMA_LOGE("vdev handle is invalid for %pM", tx_pwr_params->bssId);
vos_mem_free(tx_pwr_params);
return;
}
if (! (wma_handle->interfaces[vdev_id].vdev_up)) {
WMA_LOGE("%s: vdev id %d is not up",__func__, vdev_id);
vos_mem_free(tx_pwr_params);
return;
}
if (wma_handle->interfaces[vdev_id].max_tx_power == tx_pwr_params->power) {
ret = 0;
goto end;
}
prev_max_power = wma_handle->interfaces[vdev_id].max_tx_power;
wma_handle->interfaces[vdev_id].max_tx_power = tx_pwr_params->power;
if (wma_handle->interfaces[vdev_id].max_tx_power == 0) {
ret = 0;
goto end;
}
WMA_LOGI("Set MAX TX pwr limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d",
wma_handle->interfaces[vdev_id].max_tx_power);
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id,
WMI_VDEV_PARAM_TX_PWRLIMIT,
wma_handle->interfaces[vdev_id].max_tx_power);
if (ret == 0)
wma_handle->interfaces[vdev_id].tx_power =
wma_handle->interfaces[vdev_id].max_tx_power;
else
wma_handle->interfaces[vdev_id].max_tx_power = prev_max_power;
end:
vos_mem_free(tx_pwr_params);
if (ret)
WMA_LOGE("%s: Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT", __func__);
}
/*
* Function to update the EDCA parameters to the target
*/
static VOS_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle,
tEdcaParams *edca_params)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
u_int8_t *buf_ptr;
wmi_buf_t buf;
wmi_vdev_set_wmm_params_cmd_fixed_param *cmd;
wmi_wmm_vparams *wmm_param;
tSirMacEdcaParamRecord *edca_record;
int ac;
int len = sizeof(*cmd);
ol_txrx_pdev_handle pdev;
struct ol_tx_wmm_param_t ol_tx_wmm_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 = (wmi_vdev_set_wmm_params_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_set_wmm_params_cmd_fixed_param));
cmd->vdev_id = edca_params->bssIdx;
for (ac = 0; ac < WME_NUM_AC; ac++) {
wmm_param = (wmi_wmm_vparams *)(&cmd->wmm_params[ac]);
WMITLV_SET_HDR(&wmm_param->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_wmm_vparams));
switch (ac) {
case WME_AC_BE:
edca_record = &edca_params->acbe;
break;
case WME_AC_BK:
edca_record = &edca_params->acbk;
break;
case WME_AC_VI:
edca_record = &edca_params->acvi;
break;
case WME_AC_VO:
edca_record = &edca_params->acvo;
break;
default:
goto fail;
}
wma_update_edca_params_for_ac(edca_record, wmm_param, ac);
ol_tx_wmm_param.ac[ac].aifs = wmm_param->aifs;
ol_tx_wmm_param.ac[ac].cwmin = wmm_param->cwmin;
ol_tx_wmm_param.ac[ac].cwmax = wmm_param->cwmax;
}
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_VDEV_SET_WMM_PARAMS_CMDID))
goto fail;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma_handle->vos_context);
if (pdev) {
wdi_in_set_wmm_param(pdev, ol_tx_wmm_param);
}
return VOS_STATUS_SUCCESS;
fail:
wmi_buf_free(buf);
WMA_LOGE("%s: Failed to set WMM Paremeters", __func__);
return VOS_STATUS_E_FAILURE;
}
static int wmi_unified_probe_rsp_tmpl_send(tp_wma_handle wma,
u_int8_t vdev_id,
tpSendProbeRespParams probe_rsp_info)
{
wmi_prb_tmpl_cmd_fixed_param *cmd;
wmi_bcn_prb_info *bcn_prb_info;
wmi_buf_t wmi_buf;
u_int32_t tmpl_len, tmpl_len_aligned, wmi_buf_len;
u_int8_t *frm, *buf_ptr;
int ret;
u_int64_t adjusted_tsf_le;
struct ieee80211_frame *wh;
WMA_LOGD(FL("Send probe response template for vdev %d"), vdev_id);
frm = probe_rsp_info->pProbeRespTemplate;
tmpl_len = probe_rsp_info->probeRespTemplateLen;
tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32));
/*
* Make the TSF offset negative so probe response in the same
* staggered batch have the same TSF.
*/
adjusted_tsf_le = cpu_to_le64(0ULL -
wma->interfaces[vdev_id].tsfadjust);
/* Update the timstamp in the probe response buffer with adjusted TSF */
wh = (struct ieee80211_frame *)frm;
A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le));
wmi_buf_len = sizeof(wmi_prb_tmpl_cmd_fixed_param) +
sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE +
tmpl_len_aligned;
if (wmi_buf_len > BEACON_TX_BUFFER_SIZE) {
WMA_LOGE(FL("wmi_buf_len: %d > %d. Can't send wmi cmd"),
wmi_buf_len, BEACON_TX_BUFFER_SIZE);
return -EINVAL;
}
wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len);
if (!wmi_buf) {
WMA_LOGE(FL("wmi_buf_alloc failed"));
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_prb_tmpl_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_prb_tmpl_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->buf_len = tmpl_len;
buf_ptr += sizeof(wmi_prb_tmpl_cmd_fixed_param);
bcn_prb_info = (wmi_bcn_prb_info *)buf_ptr;
WMITLV_SET_HDR(&bcn_prb_info->tlv_header,
WMITLV_TAG_STRUC_wmi_bcn_prb_info,
WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info));
bcn_prb_info->caps = 0;
bcn_prb_info->erp = 0;
buf_ptr += sizeof(wmi_bcn_prb_info);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, frm, tmpl_len);
ret = wmi_unified_cmd_send(wma->wmi_handle,
wmi_buf, wmi_buf_len,
WMI_PRB_TMPL_CMDID);
if (ret) {
WMA_LOGE(FL("Failed to send PRB RSP tmpl: %d"), ret);
wmi_buf_free(wmi_buf);
}
return ret;
}
static int wmi_unified_bcn_tmpl_send(tp_wma_handle wma,
u_int8_t vdev_id,
tpSendbeaconParams bcn_info,
u_int8_t bytes_to_strip)
{
wmi_bcn_tmpl_cmd_fixed_param *cmd;
wmi_bcn_prb_info *bcn_prb_info;
wmi_buf_t wmi_buf;
u_int32_t tmpl_len, tmpl_len_aligned, wmi_buf_len;
u_int8_t *frm, *buf_ptr;
int ret;
u_int8_t *p2p_ie;
u_int16_t p2p_ie_len = 0;
u_int64_t adjusted_tsf_le;
struct ieee80211_frame *wh;
WMA_LOGD("Send beacon template for vdev %d", vdev_id);
if (bcn_info->p2pIeOffset) {
p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset;
p2p_ie_len = (u_int16_t) p2p_ie[1] + 2;
}
/*
* XXX: The first byte of beacon buffer contains beacon length
* only when UMAC in sending the beacon template. In othercases
* (ex: from tbtt update) beacon length is read from beacon
* information.
*/
if (bytes_to_strip)
tmpl_len = *(u_int32_t *)&bcn_info->beacon[0];
else
tmpl_len = bcn_info->beaconLength;
if (p2p_ie_len) {
tmpl_len -= (u_int32_t) p2p_ie_len;
}
frm = bcn_info->beacon + bytes_to_strip;
tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32));
/*
* Make the TSF offset negative so beacons in the same
* staggered batch have the same TSF.
*/
adjusted_tsf_le = cpu_to_le64(0ULL -
wma->interfaces[vdev_id].tsfadjust);
/* Update the timstamp in the beacon buffer with adjusted TSF */
wh = (struct ieee80211_frame *)frm;
A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le));
wmi_buf_len = sizeof(wmi_bcn_tmpl_cmd_fixed_param) +
sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE +
tmpl_len_aligned;
wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len);
if (!wmi_buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_bcn_tmpl_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->tim_ie_offset = bcn_info->timIeOffset - bytes_to_strip;
cmd->buf_len = tmpl_len;
buf_ptr += sizeof(wmi_bcn_tmpl_cmd_fixed_param);
bcn_prb_info = (wmi_bcn_prb_info *)buf_ptr;
WMITLV_SET_HDR(&bcn_prb_info->tlv_header,
WMITLV_TAG_STRUC_wmi_bcn_prb_info,
WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info));
bcn_prb_info->caps = 0;
bcn_prb_info->erp = 0;
buf_ptr += sizeof(wmi_bcn_prb_info);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, frm, tmpl_len);
ret = wmi_unified_cmd_send(wma->wmi_handle,
wmi_buf, wmi_buf_len,
WMI_BCN_TMPL_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send bcn tmpl: %d", __func__, ret);
wmi_buf_free(wmi_buf);
}
return ret;
}
VOS_STATUS wma_store_bcn_tmpl(tp_wma_handle wma, u_int8_t vdev_id,
tpSendbeaconParams bcn_info)
{
struct beacon_info *bcn;
u_int32_t len;
u_int8_t *bcn_payload;
struct beacon_tim_ie *tim_ie;
bcn = wma->interfaces[vdev_id].beacon;
if (!bcn || !bcn->buf) {
WMA_LOGE("%s: Memory is not allocated to hold bcn template",
__func__);
return VOS_STATUS_E_INVAL;
}
len = *(u32 *)&bcn_info->beacon[0];
if (len > WMA_BCN_BUF_MAX_SIZE) {
WMA_LOGE("%s: Received beacon len %d exceeding max limit %d",
__func__, len, WMA_BCN_BUF_MAX_SIZE);
return VOS_STATUS_E_INVAL;
}
WMA_LOGD("%s: Storing received beacon template buf to local buffer",
__func__);
adf_os_spin_lock_bh(&bcn->lock);
/*
* Copy received beacon template content in local buffer.
* this will be send to target on the reception of SWBA
* event from target.
*/
adf_nbuf_trim_tail(bcn->buf, adf_nbuf_len(bcn->buf));
memcpy(adf_nbuf_data(bcn->buf),
bcn_info->beacon + 4 /* Exclude beacon length field */,
len);
if (bcn_info->timIeOffset > 3)
{
bcn->tim_ie_offset = bcn_info->timIeOffset - 4;
}
else
{
bcn->tim_ie_offset = bcn_info->timIeOffset;
}
if (bcn_info->p2pIeOffset > 3)
{
bcn->p2p_ie_offset = bcn_info->p2pIeOffset - 4;
}
else
{
bcn->p2p_ie_offset = bcn_info->p2pIeOffset;
}
bcn_payload = adf_nbuf_data(bcn->buf);
if (bcn->tim_ie_offset)
{
tim_ie = (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]);
/*
* Intial Value of bcn->dtim_count will be 0.
* But if the beacon gets updated then current dtim
* count will be restored
*/
tim_ie->dtim_count = bcn->dtim_count;
tim_ie->tim_bitctl = 0;
}
adf_nbuf_put_tail(bcn->buf, len);
bcn->len = len;
adf_os_spin_unlock_bh(&bcn->lock);
return VOS_STATUS_SUCCESS;
}
static int wma_tbtt_update_ind(tp_wma_handle wma, u_int8_t *buf)
{
struct wma_txrx_node *intf;
struct beacon_info *bcn;
tSendbeaconParams bcn_info;
u_int32_t *adjusted_tsf = NULL;
u_int32_t if_id = 0, vdev_map;
u_int32_t num_tbttoffset_list;
wmi_tbtt_offset_event_fixed_param *tbtt_offset_event;
WMA_LOGI("%s: Enter", __func__);
if (!buf) {
WMA_LOGE("Invalid event buffer");
return -EINVAL;
}
if (!wma) {
WMA_LOGE("Invalid wma handle");
return -EINVAL;
}
intf = wma->interfaces;
tbtt_offset_event = (wmi_tbtt_offset_event_fixed_param *)buf;
vdev_map = tbtt_offset_event->vdev_map;
num_tbttoffset_list = *(u_int32_t *)(buf + sizeof(wmi_tbtt_offset_event_fixed_param));
adjusted_tsf = (u_int32_t *) ((u_int8_t *)buf +
sizeof(wmi_tbtt_offset_event_fixed_param) +
sizeof (u_int32_t));
if (!adjusted_tsf) {
WMA_LOGE("%s: Invalid adjusted_tsf", __func__);
return -EINVAL;
}
for ( ;(vdev_map); vdev_map >>= 1, if_id++) {
if (!(vdev_map & 0x1) || (!(intf[if_id].handle)))
continue;
bcn = intf[if_id].beacon;
if (!bcn) {
WMA_LOGE("%s: Invalid beacon", __func__);
return -EINVAL;
}
if (!bcn->buf) {
WMA_LOGE("%s: Invalid beacon buffer", __func__);
return -EINVAL;
}
/* Save the adjusted TSF */
intf[if_id].tsfadjust = adjusted_tsf[if_id];
adf_os_spin_lock_bh(&bcn->lock);
vos_mem_zero(&bcn_info, sizeof(bcn_info));
bcn_info.beacon = adf_nbuf_data(bcn->buf);
bcn_info.p2pIeOffset = bcn->p2p_ie_offset;
bcn_info.beaconLength = bcn->len;
bcn_info.timIeOffset = bcn->tim_ie_offset;
adf_os_spin_unlock_bh(&bcn->lock);
/* Update beacon template in firmware */
wmi_unified_bcn_tmpl_send(wma, if_id, &bcn_info, 0);
}
return 0;
}
static int wma_tbttoffset_update_event_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *param_buf;
wmi_tbtt_offset_event_fixed_param *tbtt_offset_event;
u_int8_t *buf, *tempBuf;
vos_msg_t vos_msg = {0};
param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *)event;
if(!param_buf) {
WMA_LOGE("Invalid tbtt update event buffer");
return -EINVAL;
}
tbtt_offset_event = param_buf->fixed_param;
if (param_buf->num_tbttoffset_list >
(UINT_MAX - sizeof(u_int32_t) -
sizeof(wmi_tbtt_offset_event_fixed_param))/
sizeof(u_int32_t)) {
WMA_LOGE("%s: Received offset list %d greater than maximum limit",
__func__, param_buf->num_tbttoffset_list);
return -EINVAL;
}
buf = vos_mem_malloc(sizeof(wmi_tbtt_offset_event_fixed_param) +
sizeof (u_int32_t) +
(param_buf->num_tbttoffset_list * sizeof (u_int32_t)));
if (!buf) {
WMA_LOGE("%s: Failed alloc memory for buf", __func__);
return -EINVAL;
}
tempBuf = buf;
vos_mem_zero(buf, (sizeof(wmi_tbtt_offset_event_fixed_param) +
sizeof (u_int32_t) +
(param_buf->num_tbttoffset_list * sizeof (u_int32_t))));
vos_mem_copy(buf, (u_int8_t *)tbtt_offset_event, sizeof (wmi_tbtt_offset_event_fixed_param));
buf += sizeof (wmi_tbtt_offset_event_fixed_param);
vos_mem_copy(buf, (u_int8_t *) &param_buf->num_tbttoffset_list, sizeof (u_int32_t));
buf += sizeof(u_int32_t);
vos_mem_copy(buf, (u_int8_t *)param_buf->tbttoffset_list, (param_buf->num_tbttoffset_list * sizeof(u_int32_t)));
vos_msg.type = WDA_TBTT_UPDATE_IND;
vos_msg.bodyptr = tempBuf;
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_TBTT_UPDATE_IND msg", __func__);
vos_mem_free(tempBuf);
return -1;
}
WMA_LOGD("WDA_TBTT_UPDATE_IND posted");
return 0;
}
static int wma_p2p_go_set_beacon_ie(t_wma_handle *wma_handle,
A_UINT32 vdev_id, u_int8_t *p2pIe)
{
int ret;
wmi_p2p_go_set_beacon_ie_fixed_param *cmd;
wmi_buf_t wmi_buf;
u_int32_t ie_len, ie_len_aligned, wmi_buf_len;
u_int8_t *buf_ptr;
ie_len = (u_int32_t) (p2pIe[1] + 2);
/* More than one P2P IE may be included in a single frame.
If multiple P2P IEs are present, the complete P2P attribute
data consists of the concatenation of the P2P Attribute
fields of the P2P IEs. The P2P Attributes field of each
P2P IE may be any length up to the maximum (251 octets).
In this case host sends one P2P IE to firmware so the length
should not exceed more than 251 bytes
*/
if (ie_len > 251) {
WMA_LOGE("%s : invalid p2p ie length %u", __func__, ie_len);
return -EINVAL;
}
ie_len_aligned = roundup(ie_len, sizeof(A_UINT32));
wmi_buf_len = sizeof(wmi_p2p_go_set_beacon_ie_fixed_param) + ie_len_aligned + WMI_TLV_HDR_SIZE;
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, wmi_buf_len);
if (!wmi_buf) {
WMA_LOGE("%s : wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_p2p_go_set_beacon_ie_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_p2p_go_set_beacon_ie_fixed_param));
cmd->vdev_id = vdev_id;
cmd->ie_buf_len = ie_len;
buf_ptr += sizeof(wmi_p2p_go_set_beacon_ie_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, p2pIe, ie_len);
WMA_LOGI("%s: Sending WMI_P2P_GO_SET_BEACON_IE", __func__);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle,
wmi_buf, wmi_buf_len,
WMI_P2P_GO_SET_BEACON_IE
);
if (ret) {
WMA_LOGE("Failed to send bcn tmpl: %d", ret);
wmi_buf_free(wmi_buf);
}
WMA_LOGI("%s: Successfully sent WMI_P2P_GO_SET_BEACON_IE", __func__);
return ret;
}
static void wma_send_probe_rsp_tmpl(tp_wma_handle wma,
tpSendProbeRespParams probe_rsp_info)
{
ol_txrx_vdev_handle vdev;
u_int8_t vdev_id;
tpAniProbeRspStruct probe_rsp;
if(!probe_rsp_info) {
WMA_LOGE(FL("probe_rsp_info is NULL"));
return;
}
probe_rsp = (tpAniProbeRspStruct)(probe_rsp_info->pProbeRespTemplate);
if(!probe_rsp) {
WMA_LOGE(FL("probe_rsp is NULL"));
return;
}
vdev = wma_find_vdev_by_addr(wma, probe_rsp->macHdr.sa, &vdev_id);
if (!vdev) {
WMA_LOGE(FL("failed to get vdev handle"));
return;
}
if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_BEACON_OFFLOAD)) {
WMA_LOGI("Beacon Offload Enabled Sending Unified command");
if (wmi_unified_probe_rsp_tmpl_send(wma, vdev_id,
probe_rsp_info) < 0){
WMA_LOGE(FL("wmi_unified_probe_rsp_tmpl_send Failed "));
return;
}
}
}
static void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info)
{
ol_txrx_vdev_handle vdev;
u_int8_t vdev_id;
VOS_STATUS status;
u_int8_t *p2p_ie;
tpAniBeaconStruct beacon;
beacon = (tpAniBeaconStruct)(bcn_info->beacon);
vdev = wma_find_vdev_by_addr(wma, beacon->macHdr.sa, &vdev_id);
if (!vdev) {
WMA_LOGE("%s : failed to get vdev handle", __func__);
return;
}
if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_BEACON_OFFLOAD)) {
WMA_LOGI("Beacon Offload Enabled Sending Unified command");
if (wmi_unified_bcn_tmpl_send(wma, vdev_id, bcn_info, 4) < 0){
WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ", __func__);
return;
}
if (bcn_info->p2pIeOffset) {
p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset;
WMA_LOGI(" %s: p2pIe is present - vdev_id %hu, p2p_ie = %pK, p2p ie len = %hu",
__func__, vdev_id, p2p_ie, p2p_ie[1]);
if (wma_p2p_go_set_beacon_ie(wma, vdev_id, p2p_ie) < 0) {
WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ", __func__);
return;
}
}
}
status = wma_store_bcn_tmpl(wma, vdev_id, bcn_info);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s : wma_store_bcn_tmpl Failed", __func__);
return;
}
if (!((adf_os_atomic_read(
&wma->interfaces[vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) ||
(wma->interfaces[vdev_id].is_channel_switch))) {
if (!wma->interfaces[vdev_id].vdev_up) {
if (wmi_unified_vdev_up_send(wma->wmi_handle, vdev_id, 0,
bcn_info->bssId) < 0) {
WMA_LOGE("%s : failed to send vdev up", __func__);
return;
}
wma->interfaces[vdev_id].vdev_up = TRUE;
wma_set_sap_keepalive(wma, vdev_id);
}
}
}
#if !defined(REMOVE_PKT_LOG)
static VOS_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle,
struct ath_pktlog_wmi_params *params)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_PKTLOG_EVENT PKTLOG_EVENT;
WMI_CMD_ID CMD_ID;
wmi_pdev_pktlog_enable_cmd_fixed_param *cmd;
wmi_pdev_pktlog_disable_cmd_fixed_param *disable_cmd;
int len = 0;
wmi_buf_t buf;
/*Check if packet log is enabled in cfg.ini*/
if (! vos_is_packet_log_enabled())
{
WMA_LOGE("%s:pkt log is not enabled in cfg.ini", __func__);
return VOS_STATUS_E_FAILURE;
}
PKTLOG_EVENT = params->pktlog_event;
CMD_ID = params->cmd_id;
switch (CMD_ID) {
case WMI_PDEV_PKTLOG_ENABLE_CMDID:
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd =
(wmi_pdev_pktlog_enable_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_pktlog_enable_cmd_fixed_param));
cmd->evlist = PKTLOG_EVENT;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PDEV_PKTLOG_ENABLE_CMDID)) {
WMA_LOGE("failed to send pktlog enable cmdid");
goto wmi_send_failed;
}
break;
case WMI_PDEV_PKTLOG_DISABLE_CMDID:
len = sizeof(*disable_cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
disable_cmd = (wmi_pdev_pktlog_disable_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&disable_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_pktlog_disable_cmd_fixed_param));
disable_cmd->pdev_id = 0;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PDEV_PKTLOG_DISABLE_CMDID)) {
WMA_LOGE("failed to send pktlog disable cmdid");
goto wmi_send_failed;
}
break;
default:
WMA_LOGD("%s: invalid PKTLOG command", __func__);
break;
}
return VOS_STATUS_SUCCESS;
wmi_send_failed:
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
#endif
static int32_t wmi_unified_set_sta_ps(wmi_unified_t wmi_handle,
u_int32_t vdev_id, u_int8_t val)
{
wmi_sta_powersave_mode_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
WMA_LOGD("Set Sta Mode Ps vdevId %d val %d", vdev_id, val);
buf = wmi_buf_alloc(wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: Set Sta Mode Ps Mem Alloc Failed", __func__);
return -ENOMEM;
}
cmd = (wmi_sta_powersave_mode_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_sta_powersave_mode_cmd_fixed_param));
cmd->vdev_id = vdev_id;
if(val)
cmd->sta_ps_mode = WMI_STA_PS_MODE_ENABLED;
else
cmd->sta_ps_mode = WMI_STA_PS_MODE_DISABLED;
if(wmi_unified_cmd_send(wmi_handle, buf, len,
WMI_STA_POWERSAVE_MODE_CMDID))
{
WMA_LOGE("Set Sta Mode Ps Failed vdevId %d val %d",
vdev_id, val);
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
static inline u_int32_t wma_get_uapsd_mask(tpUapsd_Params uapsd_params)
{
u_int32_t uapsd_val = 0;
if(uapsd_params->beDeliveryEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC0_DELIVERY_EN;
if(uapsd_params->beTriggerEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
if(uapsd_params->bkDeliveryEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC1_DELIVERY_EN;
if(uapsd_params->bkTriggerEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
if(uapsd_params->viDeliveryEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC2_DELIVERY_EN;
if(uapsd_params->viTriggerEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
if(uapsd_params->voDeliveryEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC3_DELIVERY_EN;
if(uapsd_params->voTriggerEnabled)
uapsd_val |= WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
return uapsd_val;
}
static int32_t wma_set_force_sleep(tp_wma_handle wma, u_int32_t vdev_id,
u_int8_t enable, enum powersave_qpower_mode qpower_config)
{
int32_t ret;
tANI_U32 cfg_data_val = 0;
/* get mac to acess CFG data base */
struct sAniSirGlobal *mac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
u_int32_t rx_wake_policy;
u_int32_t tx_wake_threshold;
u_int32_t pspoll_count;
u_int32_t inactivity_time;
u_int32_t psmode;
WMA_LOGD("Set Force Sleep vdevId %d val %d", vdev_id, enable);
if (NULL == mac) {
WMA_LOGE("%s: Unable to get PE context", __func__);
return -ENOMEM;
}
/* Set Tx/Rx Data InActivity Timeout */
if (wlan_cfgGetInt(mac, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT");
cfg_data_val = POWERSAVE_DEFAULT_INACTIVITY_TIME;
}
inactivity_time = (u_int32_t)cfg_data_val;
if (enable) {
/* override normal configuration and force station asleep */
rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER;
if (wlan_cfgGetInt(mac, WNI_CFG_MAX_PS_POLL,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get value for WNI_CFG_MAX_PS_POLL");
}
if (cfg_data_val)
pspoll_count = (u_int32_t)cfg_data_val;
else
pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE;
psmode = WMI_STA_PS_MODE_ENABLED;
} else {
/* Ps Poll Wake Policy */
if (wlan_cfgGetInt(mac, WNI_CFG_MAX_PS_POLL,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get value for WNI_CFG_MAX_PS_POLL");
}
if (cfg_data_val) {
/* Ps Poll is enabled */
rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
pspoll_count = (u_int32_t)cfg_data_val;
tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER;
} else {
rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
pspoll_count = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
}
psmode = WMI_STA_PS_MODE_ENABLED;
}
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_ENABLE_QPOWER, qpower_config);
if (ret) {
WMA_LOGE("%s(%d) QPower Failed vdevId %d",
qpower_config ? "Enable" : "Disable",
qpower_config, vdev_id);
return ret;
}
WMA_LOGD("QPower %s(%d) vdevId %d",
qpower_config ? "Enabled" : "Disabled",
qpower_config, vdev_id);
/* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD*/
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_RX_WAKE_POLICY,
rx_wake_policy);
if (ret) {
WMA_LOGE("Setting wake policy Failed vdevId %d", vdev_id);
return ret;
}
WMA_LOGD("Setting wake policy to %d vdevId %d",
rx_wake_policy, vdev_id);
/* Set the Tx Wake Threshold */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD,
tx_wake_threshold);
if (ret) {
WMA_LOGE("Setting TxWake Threshold vdevId %d", vdev_id);
return ret;
}
WMA_LOGD("Setting TxWake Threshold to %d vdevId %d",
tx_wake_threshold, vdev_id);
/* Set the Ps Poll Count */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_PSPOLL_COUNT,
pspoll_count);
if (ret) {
WMA_LOGE("Set Ps Poll Count Failed vdevId %d ps poll cnt %d",
vdev_id, pspoll_count);
return ret;
}
WMA_LOGD("Set Ps Poll Count vdevId %d ps poll cnt %d",
vdev_id, pspoll_count);
/* Set the Tx/Rx InActivity */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_INACTIVITY_TIME,
inactivity_time);
if (ret) {
WMA_LOGE("Setting Tx/Rx InActivity Failed vdevId %d InAct %d",
vdev_id, inactivity_time);
return ret;
}
WMA_LOGD("Set Tx/Rx InActivity vdevId %d InAct %d",
vdev_id, inactivity_time);
/* Enable Sta Mode Power save */
ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true);
if (ret) {
WMA_LOGE("Enable Sta Mode Ps Failed vdevId %d", vdev_id);
return ret;
}
/* Set Listen Interval */
if (wlan_cfgGetInt(mac, WNI_CFG_LISTEN_INTERVAL,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get value for WNI_CFG_LISTEN_INTERVAL");
cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_LISTEN_INTERVAL,
cfg_data_val);
if (ret) {
/* Even it fails continue Fw will take default LI */
WMA_LOGE("Failed to Set Listen Interval vdevId %d",
vdev_id);
}
WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
vdev_id, cfg_data_val);
return 0;
}
int32_t wma_set_qpower_force_sleep(tp_wma_handle wma, u_int32_t vdev_id,
u_int8_t enable)
{
int32_t ret;
tANI_U32 cfg_data_val = 0;
/* get mac to acess CFG data base */
struct sAniSirGlobal *mac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
u_int32_t pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE;
enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
WMA_LOGE("Set QPower Force(1)/Normal(0) Sleep vdevId %d val %d",
vdev_id, enable);
if (NULL == mac) {
WMA_LOGE("%s: Unable to get PE context", __func__);
return -ENOMEM;
}
/* Get Configured Ps Poll Count */
if (wlan_cfgGetInt(mac, WNI_CFG_MAX_PS_POLL,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get value for WNI_CFG_MAX_PS_POLL");
}
if (cfg_data_val) {
pspoll_count = (u_int32_t)cfg_data_val;
}
if (qpower_config) {
/* Enable QPower */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_ENABLE_QPOWER, qpower_config);
if (ret) {
WMA_LOGE("Enable QPower Failed vdevId %d", vdev_id);
return ret;
}
WMA_LOGD("QPower Enabled vdevId %d", vdev_id);
}
/* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD*/
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_RX_WAKE_POLICY,
WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD);
if (ret) {
WMA_LOGE("Setting wake policy to pspoll/uapsd Failed vdevId %d", vdev_id);
return ret;
}
WMA_LOGD("Wake policy set to to pspoll/uapsd vdevId %d",
vdev_id);
if (enable) {
/* Set the Tx Wake Threshold */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD,
WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER);
if (ret) {
WMA_LOGE("Setting TxWake Threshold vdevId %d", vdev_id);
return ret;
}
WMA_LOGD("TxWake Threshold set to TX_WAKE_THRESHOLD_NEVER %d", vdev_id);
}
/* Set the QPower Ps Poll Count */
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT,
pspoll_count);
if (ret) {
WMA_LOGE("Set QPower Ps Poll Count Failed vdevId %d ps poll cnt %d",
vdev_id, pspoll_count);
return ret;
}
WMA_LOGD("Set QPower Ps Poll Count vdevId %d ps poll cnt %d",
vdev_id, pspoll_count);
/* Enable Sta Mode Power save */
ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true);
if (ret) {
WMA_LOGE("Enable Sta Mode Ps Failed vdevId %d", vdev_id);
return ret;
}
/* Set Listen Interval */
if (wlan_cfgGetInt(mac, WNI_CFG_LISTEN_INTERVAL,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get value for WNI_CFG_LISTEN_INTERVAL");
cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_LISTEN_INTERVAL,
cfg_data_val);
if (ret) {
/* Even it fails continue Fw will take default LI */
WMA_LOGE("Failed to Set Listen Interval vdevId %d",
vdev_id);
}
WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
vdev_id, cfg_data_val);
return 0;
}
/**
* wma_get_qpower_config() - get qpower configuration
* @wma: WMA handle
*
* Power Save Offload configuration:
* 0 -> Power save offload is disabled
* 1 -> Legacy Power save enabled + Deep sleep Disabled
* 2 -> QPower enabled + Deep sleep Disabled
* 3 -> Legacy Power save enabled + Deep sleep Enabled
* 4 -> QPower enabled + Deep sleep Enabled
* 5 -> Duty cycling QPower enabled
*
* Return: enum powersave_qpower_mode with below values
* QPOWER_DISABLED if QPOWER is disabled
* QPOWER_ENABLED if QPOWER is enabled
* QPOWER_DUTY_CYCLING if DUTY CYCLING QPOWER is enabled
*/
static enum powersave_qpower_mode wma_get_qpower_config(tp_wma_handle wma)
{
switch (wma->powersave_mode) {
case PS_QPOWER_NODEEPSLEEP:
case PS_QPOWER_DEEPSLEEP:
WMA_LOGI("QPOWER is enabled in power save mode %d",
wma->powersave_mode);
return QPOWER_ENABLED;
case PS_DUTY_CYCLING_QPOWER:
WMA_LOGI("DUTY cycling QPOWER is enabled in power save mode %d",
wma->powersave_mode);
return QPOWER_DUTY_CYCLING;
default:
WMA_LOGI("QPOWER is disabled in power save mode %d",
wma->powersave_mode);
return QPOWER_DISABLED;
}
}
static void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req)
{
uint32_t vdev_id = ps_req->sessionid;
int32_t ret;
enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
wma->psSetting = ps_req->psSetting;
if (eSIR_ADDON_NOTHING == ps_req->psSetting) {
WMA_LOGD("Enable Sta Mode Ps vdevId %d", vdev_id);
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_UAPSD, 0);
if (ret) {
WMA_LOGE("Set Uapsd param 0 Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
ret = wma_set_force_sleep(wma, vdev_id, false,
qpower_config);
if (ret) {
WMA_LOGE("Enable Sta Ps Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
} else if (eSIR_ADDON_ENABLE_UAPSD == ps_req->psSetting) {
u_int32_t uapsd_val = 0;
uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams);
if(uapsd_val != iface->uapsd_cached_val) {
WMA_LOGD("Enable Uapsd vdevId %d Mask %d",
vdev_id, uapsd_val);
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
vdev_id, WMI_STA_PS_PARAM_UAPSD,
uapsd_val);
if (ret) {
WMA_LOGE("Enable Uapsd Failed vdevId %d",
vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
/* Cache the Uapsd Mask */
iface->uapsd_cached_val = uapsd_val;
} else {
WMA_LOGD("Already Uapsd Enabled vdevId %d Mask %d",
vdev_id, uapsd_val);
}
WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id);
ret = wma_set_force_sleep(wma, vdev_id, true,
qpower_config);
if (ret) {
WMA_LOGE("Enable Forced Sleep Failed vdevId %d",
vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
}
ps_req->status = VOS_STATUS_SUCCESS;
iface->dtimPeriod = ps_req->bcnDtimPeriod;
iface->in_bmps = true;
resp:
wma_send_msg(wma, WDA_ENTER_BMPS_RSP, ps_req, 0);
}
static void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req)
{
int32_t ret;
uint32_t vdev_id = ps_req->sessionid;
struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
if (!iface) {
WMA_LOGE("Invalid vdev id not attched to any iface %d",
vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
WMA_LOGD("Disable Sta Mode Ps vdevId %d", vdev_id);
/* Disable Sta Mode Power save */
ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false);
if(ret) {
WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
/* Disable UAPSD incase if additional Req came */
if (eSIR_ADDON_DISABLE_UAPSD == ps_req->psSetting) {
WMA_LOGD("Disable Uapsd vdevId %d", vdev_id);
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_UAPSD, 0);
if (ret) {
WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id);
/*
* Even this fails we can proceed as success
* since we disabled powersave
*/
}
}
ps_req->status = VOS_STATUS_SUCCESS;
iface->in_bmps = false;
resp:
wma_send_msg(wma, WDA_EXIT_BMPS_RSP, ps_req, 0);
}
static void wma_enable_uapsd_mode(tp_wma_handle wma,
tpEnableUapsdParams ps_req)
{
int32_t ret;
u_int32_t vdev_id = ps_req->sessionid;
u_int32_t uapsd_val = 0;
enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
/* Disable Sta Mode Power save */
ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false);
if (ret) {
WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams);
WMA_LOGD("Enable Uapsd vdevId %d Mask %d", vdev_id, uapsd_val);
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_UAPSD, uapsd_val);
if (ret) {
WMA_LOGE("Enable Uapsd Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id);
ret = wma_set_force_sleep(wma, vdev_id, true,
qpower_config);
if (ret) {
WMA_LOGE("Enable Forced Sleep Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
ps_req->status = VOS_STATUS_SUCCESS;
resp:
wma_send_msg(wma, WDA_ENTER_UAPSD_RSP, ps_req, 0);
}
static void wma_disable_uapsd_mode(tp_wma_handle wma,
tpDisableUapsdParams ps_req)
{
int32_t ret;
u_int32_t vdev_id = ps_req->sessionid;
enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
WMA_LOGD("Disable Uapsd vdevId %d", vdev_id);
/* Disable Sta Mode Power save */
ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false);
if (ret) {
WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_UAPSD, 0);
if (ret) {
WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
/* Re enable Sta Mode Powersave with proper configuration */
ret = wma_set_force_sleep(wma, vdev_id, false,
qpower_config);
if (ret) {
WMA_LOGE("Disable Forced Sleep Failed vdevId %d", vdev_id);
ps_req->status = VOS_STATUS_E_FAILURE;
goto resp;
}
ps_req->status = VOS_STATUS_SUCCESS;
resp:
wma_send_msg(wma, WDA_EXIT_UAPSD_RSP, ps_req, 0);
}
static void wma_set_keepalive_req(tp_wma_handle wma,
tSirKeepAliveReq *keepalive)
{
WMA_LOGD("KEEPALIVE:PacketType:%d", keepalive->packetType);
wma_set_sta_keep_alive(wma, keepalive->sessionId,
keepalive->packetType,
keepalive->timePeriod,
keepalive->hostIpv4Addr,
keepalive->destIpv4Addr,
keepalive->destMacAddr);
vos_mem_free(keepalive);
}
/*
* This function sets the trigger uapsd
* params such as service interval, delay
* interval and suspend interval which
* will be used by the firmware to send
* trigger frames periodically when there
* is no traffic on the transmit side.
*/
int32_t
wmi_unified_set_sta_uapsd_auto_trig_cmd(
wmi_unified_t wmi_handle,
u_int32_t vdevid,
u_int8_t peer_addr[IEEE80211_ADDR_LEN],
u_int8_t *autoTriggerparam,
u_int32_t num_ac)
{
wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd;
int32_t ret;
u_int32_t param_len = num_ac *
sizeof(wmi_sta_uapsd_auto_trig_param);
u_int32_t cmd_len = sizeof(*cmd) + param_len + WMI_TLV_HDR_SIZE;
u_int32_t i;
wmi_buf_t buf;
u_int8_t *buf_ptr;
buf = wmi_buf_alloc(wmi_handle, cmd_len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_sta_uapsd_auto_trig_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_sta_uapsd_auto_trig_cmd_fixed_param));
cmd->vdev_id = vdevid;
cmd->num_ac = num_ac;
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
/* TLV indicating array of structures to follow */
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, param_len);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, autoTriggerparam, param_len);
/*
* Update tag and length for uapsd auto trigger params (this will take
* care of updating tag and length if it is not pre-filled by caller).
*/
for (i = 0; i < num_ac; i++) {
WMITLV_SET_HDR((buf_ptr +
(i * sizeof(wmi_sta_uapsd_auto_trig_param))),
WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_sta_uapsd_auto_trig_param));
}
ret = wmi_unified_cmd_send(wmi_handle, buf, cmd_len,
WMI_STA_UAPSD_AUTO_TRIG_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send set uapsd param ret = %d", ret);
wmi_buf_free(buf);
}
return ret;
}
/*
* This function sets the trigger uapsd
* params such as service interval, delay
* interval and suspend interval which
* will be used by the firmware to send
* trigger frames periodically when there
* is no traffic on the transmit side.
*/
VOS_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, u_int32_t vdev_id,
tp_wma_trigger_uapsd_params trigger_uapsd_params)
{
int32_t ret;
wmi_sta_uapsd_auto_trig_param uapsd_trigger_param;
WMA_LOGD("Trigger uapsd params vdev id %d", vdev_id);
WMA_LOGD("WMM AC %d User Priority %d SvcIntv %d DelIntv %d SusIntv %d",
trigger_uapsd_params->wmm_ac,
trigger_uapsd_params->user_priority,
trigger_uapsd_params->service_interval,
trigger_uapsd_params->delay_interval,
trigger_uapsd_params->suspend_interval);
if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_STA_UAPSD_BASIC_AUTO_TRIG) ||
!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_STA_UAPSD_VAR_AUTO_TRIG)) {
WMA_LOGD("Trigger uapsd is not supported vdev id %d", vdev_id);
return VOS_STATUS_SUCCESS;
}
uapsd_trigger_param.wmm_ac =
trigger_uapsd_params->wmm_ac;
uapsd_trigger_param.user_priority =
trigger_uapsd_params->user_priority;
uapsd_trigger_param.service_interval =
trigger_uapsd_params->service_interval;
uapsd_trigger_param.suspend_interval =
trigger_uapsd_params->suspend_interval;
uapsd_trigger_param.delay_interval =
trigger_uapsd_params->delay_interval;
ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, vdev_id,
wma_handle->interfaces[vdev_id].bssid,
(u_int8_t*)(&uapsd_trigger_param),
1);
if (ret) {
WMA_LOGE("Fail to send uapsd param cmd for vdevid %d ret = %d",
ret, vdev_id);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle,
u_int32_t vdev_id,
enum uapsd_ac ac)
{
int32_t ret;
struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id];
wmi_sta_uapsd_auto_trig_param uapsd_trigger_param;
enum uapsd_up user_priority;
WMA_LOGD("Disable Uapsd per ac vdevId %d ac %d", vdev_id, ac);
switch (ac) {
case UAPSD_VO:
iface->uapsd_cached_val &=
~(WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC3_TRIGGER_EN);
user_priority = UAPSD_UP_VO;
break;
case UAPSD_VI:
iface->uapsd_cached_val &=
~(WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC2_TRIGGER_EN);
user_priority = UAPSD_UP_VI;
break;
case UAPSD_BK:
iface->uapsd_cached_val &=
~(WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC1_TRIGGER_EN);
user_priority = UAPSD_UP_BK;
break;
case UAPSD_BE:
iface->uapsd_cached_val &=
~(WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC0_TRIGGER_EN);
user_priority = UAPSD_UP_BE;
break;
default:
WMA_LOGE("Invalid AC vdevId %d ac %d", vdev_id, ac);
return VOS_STATUS_E_FAILURE;
}
/*
* Disable Auto Trigger Functionality before
* disabling uapsd for a particular AC
*/
uapsd_trigger_param.wmm_ac = ac;
uapsd_trigger_param.user_priority = user_priority;
uapsd_trigger_param.service_interval = 0;
uapsd_trigger_param.suspend_interval = 0;
uapsd_trigger_param.delay_interval = 0;
ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle,
vdev_id,
wma_handle->interfaces[vdev_id].bssid,
(u_int8_t*)(&uapsd_trigger_param),
1);
if (ret) {
WMA_LOGE("Fail to send auto trig cmd for vdevid %d ret = %d",
ret, vdev_id);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_set_sta_ps_param(wma_handle->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_UAPSD, iface->uapsd_cached_val);
if (ret) {
WMA_LOGE("Disable Uapsd per ac Failed vdevId %d ac %d", vdev_id, ac);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Disable Uapsd per ac vdevId %d val %d", vdev_id,
iface->uapsd_cached_val);
return VOS_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_SCAN_PNO
/* Request FW to start PNO operation */
static VOS_STATUS wma_pno_start(tp_wma_handle wma, tpSirPNOScanReq pno)
{
wmi_nlo_config_cmd_fixed_param *cmd;
nlo_configured_parameters *nlo_list;
u_int32_t *channel_list;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
u_int8_t i;
int ret;
wmi_vendor_oui *voui = NULL;
struct vendor_oui *pvoui = NULL;
connected_nlo_rssi_params *nlo_relative_rssi;
connected_nlo_bss_band_rssi_pref *nlo_band_rssi;
WMA_LOGD("PNO Start");
len = sizeof(*cmd) +
WMI_TLV_HDR_SIZE + /* TLV place holder for array of structures nlo_configured_parameters(nlo_list) */
WMI_TLV_HDR_SIZE + /* TLV place holder for array of uint32 channel_list */
WMI_TLV_HDR_SIZE + /* TLV of nlo_channel_prediction_cfg */
WMI_TLV_HDR_SIZE + /* array of wmi_vendor_oui */
WMI_TLV_HDR_SIZE; /* array of connected_nlo_bss_band_rssi_pref */
len += sizeof(u_int32_t) * MIN(pno->aNetworks[0].ucChannelCount,
WMI_NLO_MAX_CHAN);
len += sizeof(nlo_configured_parameters) *
MIN(pno->ucNetworksCount, WMI_NLO_MAX_SSIDS);
/* Add the fixed length of enlo_candidate_score_params */
len += sizeof(enlo_candidate_score_params);
len += sizeof(wmi_vendor_oui) * pno->num_vendor_oui;
len += sizeof(connected_nlo_rssi_params);
len += sizeof(connected_nlo_bss_band_rssi_pref);
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_nlo_config_cmd_fixed_param *) wmi_buf_data(buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_nlo_config_cmd_fixed_param));
cmd->vdev_id = pno->sessionId;
cmd->flags = WMI_NLO_CONFIG_START | WMI_NLO_CONFIG_SSID_HIDE_EN;
/* Current FW does not support min-max range for dwell time */
cmd->active_dwell_time = pno->active_max_time;
cmd->passive_dwell_time = pno->passive_max_time;
if (pno->do_passive_scan)
cmd->flags |= WMI_NLO_CONFIG_SCAN_PASSIVE;
/* Copy scan interval */
cmd->fast_scan_period = pno->fast_scan_period;
cmd->slow_scan_period = pno->slow_scan_period;
cmd->fast_scan_max_cycles = pno->fast_scan_max_cycles;
WMA_LOGD("fast_scan_period: %d msec slow_scan_period: %d msec",
cmd->fast_scan_period, cmd->slow_scan_period);
WMA_LOGD("fast_scan_max_cycles: %d", cmd->fast_scan_max_cycles);
if (pno->enable_pno_scan_randomization) {
cmd->flags |= WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ |
WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ;
WMI_CHAR_ARRAY_TO_MAC_ADDR(pno->mac_addr, &cmd->mac_addr);
WMI_CHAR_ARRAY_TO_MAC_ADDR(pno->mac_addr_mask, &cmd->mac_mask);
}
if (pno->ie_whitelist)
cmd->flags |= WMI_NLO_CONFIG_ENABLE_IE_WHITELIST_IN_PROBE_REQ;
if(pno->relative_rssi_set)
cmd->flags |= WMI_NLO_CONFIG_ENABLE_CNLO_RSSI_CONFIG;
WMA_LOGI("pno flags = %x", cmd->flags);
cmd->num_vendor_oui = pno->num_vendor_oui;
if (pno->ie_whitelist) {
for (i = 0; i < PROBE_REQ_BITMAP_LEN; i++)
cmd->ie_bitmap[i] = pno->probe_req_ie_bitmap[i];
}
buf_ptr += sizeof(wmi_nlo_config_cmd_fixed_param);
cmd->no_of_ssids = MIN(pno->ucNetworksCount, WMI_NLO_MAX_SSIDS);
WMA_LOGD("SSID count : %d", cmd->no_of_ssids);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
cmd->no_of_ssids * sizeof(nlo_configured_parameters));
buf_ptr += WMI_TLV_HDR_SIZE;
nlo_list = (nlo_configured_parameters *) buf_ptr;
for (i = 0; i < cmd->no_of_ssids; i++) {
WMITLV_SET_HDR(&nlo_list[i].tlv_header,
WMITLV_TAG_ARRAY_BYTE,
WMITLV_GET_STRUCT_TLVLEN(nlo_configured_parameters));
/* Copy ssid and it's length */
nlo_list[i].ssid.valid = TRUE;
nlo_list[i].ssid.ssid.ssid_len = pno->aNetworks[i].ssId.length;
vos_mem_copy(nlo_list[i].ssid.ssid.ssid,
pno->aNetworks[i].ssId.ssId,
nlo_list[i].ssid.ssid.ssid_len);
WMA_LOGD("index: %d ssid: %.*s len: %d", i,
nlo_list[i].ssid.ssid.ssid_len,
(char *) nlo_list[i].ssid.ssid.ssid,
nlo_list[i].ssid.ssid.ssid_len);
/* Copy rssi threshold */
if (pno->aNetworks[i].rssiThreshold &&
pno->aNetworks[i].rssiThreshold > WMA_RSSI_THOLD_DEFAULT) {
nlo_list[i].rssi_cond.valid = TRUE;
nlo_list[i].rssi_cond.rssi =
pno->aNetworks[i].rssiThreshold;
WMA_LOGD("RSSI threshold : %d dBm",
nlo_list[i].rssi_cond.rssi);
}
nlo_list[i].bcast_nw_type.valid = TRUE;
nlo_list[i].bcast_nw_type.bcast_nw_type =
pno->aNetworks[i].bcastNetwType;
WMA_LOGI("Broadcast NW type (%u)",
nlo_list[i].bcast_nw_type.bcast_nw_type);
}
buf_ptr += cmd->no_of_ssids * sizeof(nlo_configured_parameters);
/* Copy channel info */
cmd->num_of_channels = MIN(pno->aNetworks[0].ucChannelCount,
WMI_NLO_MAX_CHAN);
WMA_LOGD("Channel count: %d", cmd->num_of_channels);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(cmd->num_of_channels * sizeof(u_int32_t)));
buf_ptr += WMI_TLV_HDR_SIZE;
channel_list = (u_int32_t *) buf_ptr;
for (i = 0; i < cmd->num_of_channels; i++) {
channel_list[i] = pno->aNetworks[0].aChannels[i];
if (channel_list[i] < WMA_NLO_FREQ_THRESH)
channel_list[i] = vos_chan_to_freq(channel_list[i]);
WMA_LOGD("Ch[%d]: %d MHz", i, channel_list[i]);
}
buf_ptr += cmd->num_of_channels * sizeof(u_int32_t);
/*
* For pno start, this is not needed but to get the correct offset of
* wmi_vendor_oui, this is needed
*/
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE; /* zero no.of nlo_channel_prediction_cfg */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_STRUC_enlo_candidate_score_param,
WMITLV_GET_STRUCT_TLVLEN(enlo_candidate_score_params));
buf_ptr += sizeof(enlo_candidate_score_params);
/* ie white list */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
pno->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 *)((uint8_t *)pno + sizeof(*pno));
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);
}
/*
* Firmware calculation using connected PNO params:
* New AP's RSSI >= (Connected AP's RSSI + relative_rssi +/- rssi_pref)
* deduction of rssi_pref for chosen band_pref and
* addition of rssi_pref for remaining bands (other than chosen band).
*/
nlo_relative_rssi = (connected_nlo_rssi_params *) buf_ptr;
WMITLV_SET_HDR(&nlo_relative_rssi->tlv_header,
WMITLV_TAG_STRUC_wmi_connected_nlo_rssi_params,
WMITLV_GET_STRUCT_TLVLEN(connected_nlo_rssi_params));
nlo_relative_rssi->relative_rssi = pno->relative_rssi;
WMA_LOGD("relative_rssi %d", nlo_relative_rssi->relative_rssi);
buf_ptr += sizeof(*nlo_relative_rssi);
/*
* As of now Kernel and Host supports one band and rssi preference.
* Firmware supports array of band and rssi preferences
*/
cmd->num_cnlo_band_pref = 1;
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
cmd->num_cnlo_band_pref *
sizeof(connected_nlo_bss_band_rssi_pref));
buf_ptr += WMI_TLV_HDR_SIZE;
nlo_band_rssi = (connected_nlo_bss_band_rssi_pref *) buf_ptr;
for (i = 0; i < cmd->num_cnlo_band_pref; i++) {
WMITLV_SET_HDR(&nlo_band_rssi[i].tlv_header,
WMITLV_TAG_STRUC_wmi_connected_nlo_bss_band_rssi_pref,
WMITLV_GET_STRUCT_TLVLEN(
connected_nlo_bss_band_rssi_pref));
nlo_band_rssi[i].band = pno->band_rssi_pref.band;
nlo_band_rssi[i].rssi_pref = pno->band_rssi_pref.rssi;
WMA_LOGD("band_pref %d, rssi_pref %d",
nlo_band_rssi[i].band,
nlo_band_rssi[i].rssi_pref);
}
buf_ptr += cmd->num_cnlo_band_pref * sizeof(*nlo_band_rssi);
/* TODO: Discrete firmware doesn't have command/option to configure
* App IE which comes from wpa_supplicant as of part PNO start request.
*/
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send nlo wmi cmd", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
wma->interfaces[pno->sessionId].pno_in_progress = TRUE;
WMA_LOGD("PNO start request sent successfully for vdev %d",
pno->sessionId);
return VOS_STATUS_SUCCESS;
}
/* Request FW to stop ongoing PNO operation */
static VOS_STATUS wma_pno_stop(tp_wma_handle wma, u_int8_t vdev_id)
{
wmi_nlo_config_cmd_fixed_param *cmd;
int32_t len = sizeof(*cmd);
wmi_buf_t buf;
u_int8_t *buf_ptr;
int ret;
if (!wma->interfaces[vdev_id].pno_in_progress) {
WMA_LOGD("No active pno session found for vdev %d, skip pno stop request",
vdev_id);
return VOS_STATUS_SUCCESS;
}
WMA_LOGD("PNO Stop");
len += WMI_TLV_HDR_SIZE + /* TLV place holder for array of structures nlo_configured_parameters(nlo_list) */
WMI_TLV_HDR_SIZE; /* TLV place holder for array of uint32 channel_list */
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_nlo_config_cmd_fixed_param *) wmi_buf_data(buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_nlo_config_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->flags = WMI_NLO_CONFIG_STOP;
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send nlo wmi cmd", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
wma->interfaces[vdev_id].pno_in_progress = FALSE;
WMA_LOGD("PNO stop request sent successfully for vdev %d",
vdev_id);
return VOS_STATUS_SUCCESS;
}
static void wma_config_pno(tp_wma_handle wma, tpSirPNOScanReq pno)
{
VOS_STATUS ret;
if (pno->enable)
ret = wma_pno_start(wma, pno);
else
ret = wma_pno_stop(wma, pno->sessionId);
if (ret)
WMA_LOGE("%s: PNO %s failed %d", __func__,
pno->enable ? "start" : "stop", ret);
/* SME expects WMA to free tpSirPNOScanReq memory after
* processing PNO request. */
vos_mem_free(pno);
}
#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
static VOS_STATUS wma_plm_start(tp_wma_handle wma, const tpSirPlmReq plm)
{
wmi_vdev_plmreq_start_cmd_fixed_param *cmd;
u_int32_t *channel_list;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
u_int8_t count;
int ret;
if (NULL == plm || NULL == wma) {
WMA_LOGE("%s: input pointer is NULL ", __func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("PLM Start");
len = sizeof(*cmd) +
WMI_TLV_HDR_SIZE; /* TLV place holder for channel_list */
len += sizeof(u_int32_t) * plm->plmNumCh;
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_vdev_plmreq_start_cmd_fixed_param *) wmi_buf_data(buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_plmreq_start_cmd_fixed_param));
cmd->vdev_id = plm->sessionId;
cmd->meas_token = plm->meas_token;
cmd->dialog_token = plm->diag_token;
cmd->number_bursts = plm->numBursts;
cmd->burst_interval = WMA_SEC_TO_MSEC(plm->burstInt);
cmd->off_duration = plm->measDuration;
cmd->burst_cycle = plm->burstLen;
cmd->tx_power = plm->desiredTxPwr;
WMI_CHAR_ARRAY_TO_MAC_ADDR(plm->macAddr, &cmd->dest_mac);
cmd->num_chans = plm->plmNumCh;
buf_ptr += sizeof(wmi_vdev_plmreq_start_cmd_fixed_param);
WMA_LOGD("vdev : %d measu token : %d", cmd->vdev_id, cmd->meas_token);
WMA_LOGD("dialog_token: %d", cmd->dialog_token);
WMA_LOGD("number_bursts: %d", cmd->number_bursts);
WMA_LOGD("burst_interval: %d", cmd->burst_interval);
WMA_LOGD("off_duration: %d", cmd->off_duration);
WMA_LOGD("burst_cycle: %d", cmd->burst_cycle);
WMA_LOGD("tx_power: %d", cmd->tx_power);
WMA_LOGD("Number of channels : %d", cmd->num_chans);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(cmd->num_chans * sizeof(u_int32_t)));
buf_ptr += WMI_TLV_HDR_SIZE;
if (cmd->num_chans)
{
channel_list = (u_int32_t *) buf_ptr;
for (count = 0; count < cmd->num_chans; count++) {
channel_list[count] = plm->plmChList[count];
if (channel_list[count] < WMA_NLO_FREQ_THRESH)
channel_list[count] =
vos_chan_to_freq(channel_list[count]);
WMA_LOGD("Ch[%d]: %d MHz", count, channel_list[count]);
}
buf_ptr += cmd->num_chans * sizeof(u_int32_t);
}
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_PLMREQ_START_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send plm start wmi cmd", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
wma->interfaces[plm->sessionId].plm_in_progress = TRUE;
WMA_LOGD("Plm start request sent successfully for vdev %d",
plm->sessionId);
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_plm_stop(tp_wma_handle wma, const tpSirPlmReq plm)
{
wmi_vdev_plmreq_stop_cmd_fixed_param *cmd;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int ret;
if (NULL == plm || NULL == wma) {
WMA_LOGE("%s: input pointer is NULL ", __func__);
return VOS_STATUS_E_FAILURE;
}
if (FALSE == wma->interfaces[plm->sessionId].plm_in_progress) {
WMA_LOGE("No active plm req found, skip plm stop req" );
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("PLM Stop");
len = sizeof(*cmd);
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_vdev_plmreq_stop_cmd_fixed_param *) wmi_buf_data(buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_plmreq_stop_cmd_fixed_param));
cmd->vdev_id = plm->sessionId;
cmd->meas_token = plm->meas_token;
WMA_LOGD("vdev %d meas token %d", cmd->vdev_id, cmd->meas_token);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_PLMREQ_STOP_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send plm stop wmi cmd", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
wma->interfaces[plm->sessionId].plm_in_progress = FALSE;
WMA_LOGD("Plm stop request sent successfully for vdev %d",
plm->sessionId);
return VOS_STATUS_SUCCESS;
}
static void wma_config_plm(tp_wma_handle wma, tpSirPlmReq plm)
{
VOS_STATUS ret = 0;
if (NULL == plm || NULL == wma)
return;
if (plm->enable)
ret = wma_plm_start(wma, plm);
else
ret = wma_plm_stop(wma, plm);
if (ret)
WMA_LOGE("%s: PLM %s failed %d", __func__,
plm->enable ? "start" : "stop", ret);
/* SME expects WMA to free tpSirPlmReq memory after
* processing PLM request. */
vos_mem_free(plm);
plm = NULL;
}
#endif
/*
* After pushing cached scan results (that are stored in LIM) to SME,
* PE will post WDA_SME_SCAN_CACHE_UPDATED message indication to
* wma and intern this function handles that message. This function will
* check for PNO completion (by checking NLO match event) and post PNO
* completion back to SME if PNO operation is completed successfully.
*/
void wma_scan_cache_updated_ind(tp_wma_handle wma, u_int8_t sessionId)
{
tSirPrefNetworkFoundInd *nw_found_ind;
VOS_STATUS status;
vos_msg_t vos_msg;
u_int8_t len, i;
for (i = 0; i < wma->max_bssid; i++) {
if (wma->interfaces[i].nlo_match_evt_received)
break;
}
if (i == wma->max_bssid) {
WMA_LOGD("PNO match event is not received in any vdev, skip scan cache update indication");
return;
}
wma->interfaces[i].nlo_match_evt_received = FALSE;
WMA_LOGD("Posting PNO completion to umac");
len = sizeof(tSirPrefNetworkFoundInd);
nw_found_ind = (tSirPrefNetworkFoundInd *) vos_mem_malloc(len);
if (NULL == nw_found_ind) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return;
}
nw_found_ind->mesgType = eWNI_SME_PREF_NETWORK_FOUND_IND;
nw_found_ind->mesgLen = len;
nw_found_ind->sessionId = sessionId;
vos_msg.type = eWNI_SME_PREF_NETWORK_FOUND_IND;
vos_msg.bodyptr = (void *) nw_found_ind;
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 PNO completion match event to SME",
__func__);
vos_mem_free(nw_found_ind);
}
}
#endif
static void wma_send_status_to_suspend_ind(tp_wma_handle wma, boolean suspended,
bool runtime_pm)
{
tSirReadyToSuspendInd *ready_to_suspend;
VOS_STATUS status;
vos_msg_t vos_msg;
u_int8_t len;
if (runtime_pm) {
WMA_LOGD("Runtime PM: Posting ready to suspend indication");
vos_event_set(&wma->runtime_suspend);
return;
}
WMA_LOGD("Posting ready to suspend indication to umac");
len = sizeof(tSirReadyToSuspendInd);
ready_to_suspend = (tSirReadyToSuspendInd *) vos_mem_malloc(len);
if (NULL == ready_to_suspend) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return;
}
ready_to_suspend->mesgType = eWNI_SME_READY_TO_SUSPEND_IND;
ready_to_suspend->mesgLen = len;
ready_to_suspend->suspended = suspended;
vos_msg.type = eWNI_SME_READY_TO_SUSPEND_IND;
vos_msg.bodyptr = (void *) ready_to_suspend;
vos_msg.bodyval = 0;
status = vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to post ready to suspend");
vos_mem_free(ready_to_suspend);
}
}
/* Frees memory associated to given pattern ID in wow pattern cache. */
static inline void wma_free_wow_ptrn(tp_wma_handle wma, u_int8_t ptrn_id)
{
if (wma->wow.no_of_ptrn_cached <= 0 ||
!wma->wow.cache[ptrn_id])
return;
WMA_LOGD("Deleting wow pattern %d from cache which belongs to vdev id %d",
ptrn_id, wma->wow.cache[ptrn_id]->vdev_id);
vos_mem_free(wma->wow.cache[ptrn_id]->ptrn);
vos_mem_free(wma->wow.cache[ptrn_id]->mask);
vos_mem_free(wma->wow.cache[ptrn_id]);
wma->wow.cache[ptrn_id] = NULL;
wma->wow.no_of_ptrn_cached--;
}
/* Converts wow wakeup reason code to text format */
static const u8 *wma_wow_wake_reason_str(A_INT32 wake_reason, tp_wma_handle wma)
{
switch (wake_reason) {
case WOW_REASON_UNSPECIFIED:
if (!wmi_get_runtime_pm_inprogress(wma->wmi_handle))
return "UNSPECIFIED";
else
return "RUNTIME PM resume";
case WOW_REASON_NLOD:
return "NLOD";
case WOW_REASON_AP_ASSOC_LOST:
return "AP_ASSOC_LOST";
case WOW_REASON_LOW_RSSI:
return "LOW_RSSI";
case WOW_REASON_DEAUTH_RECVD:
return "DEAUTH_RECVD";
case WOW_REASON_DISASSOC_RECVD:
return "DISASSOC_RECVD";
case WOW_REASON_GTK_HS_ERR:
return "GTK_HS_ERR";
case WOW_REASON_EAP_REQ:
return "EAP_REQ";
case WOW_REASON_FOURWAY_HS_RECV:
return "FOURWAY_HS_RECV";
case WOW_REASON_TIMER_INTR_RECV:
return "TIMER_INTR_RECV";
case WOW_REASON_PATTERN_MATCH_FOUND:
return "PATTERN_MATCH_FOUND";
case WOW_REASON_RECV_MAGIC_PATTERN:
return "RECV_MAGIC_PATTERN";
case WOW_REASON_P2P_DISC:
return "P2P_DISC";
#ifdef FEATURE_WLAN_LPHB
case WOW_REASON_WLAN_HB:
return "WLAN_HB";
#endif /* FEATURE_WLAN_LPHB */
case WOW_REASON_CSA_EVENT:
return "CSA_EVENT";
case WOW_REASON_PROBE_REQ_WPS_IE_RECV:
return "PROBE_REQ_RECV";
case WOW_REASON_AUTH_REQ_RECV:
return "AUTH_REQ_RECV";
case WOW_REASON_ASSOC_REQ_RECV:
return "ASSOC_REQ_RECV";
case WOW_REASON_HTT_EVENT:
return "WOW_REASON_HTT_EVENT";
#ifdef FEATURE_WLAN_RA_FILTERING
case WOW_REASON_RA_MATCH:
return "WOW_REASON_RA_MATCH";
#endif
case WOW_REASON_BEACON_RECV:
return "WOW_REASON_IBSS_BEACON_RECV";
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
case WOW_REASON_HOST_AUTO_SHUTDOWN:
return "WOW_REASON_HOST_AUTO_SHUTDOWN";
#endif
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
case WOW_REASON_ROAM_HO:
return "WOW_REASON_ROAM_HO";
#endif
case WOW_REASON_CLIENT_KICKOUT_EVENT:
return "WOW_REASON_CLIENT_KICKOUT_EVENT";
#ifdef FEATURE_WLAN_EXTSCAN
case WOW_REASON_EXTSCAN:
return "WOW_REASON_EXTSCAN";
#endif
case WOW_REASON_RSSI_BREACH_EVENT:
return "WOW_REASON_RSSI_BREACH_EVENT";
case WOW_REASON_CHIP_POWER_FAILURE_DETECT:
return "WOW_REASON_CHIP_POWER_FAILURE_DETECT";
case WOW_REASON_NLO_SCAN_COMPLETE:
return "WOW_REASON_NLO_SCAN_COMPLETE";
case WOW_REASON_BPF_ALLOW:
return "WOW_REASON_BPF_ALLOW";
case WOW_REASON_NAN_EVENT:
return "WOW_REASON_NAN_EVENT";
case WOW_REASON_ASSOC_RES_RECV:
return "ASSOC_RES_RECV";
case WOW_REASON_REASSOC_REQ_RECV:
return "REASSOC_REQ_RECV";
case WOW_REASON_REASSOC_RES_RECV:
return "REASSOC_RES_RECV";
case WOW_REASON_ACTION_FRAME_RECV:
return "ACTION_FRAME_RECV";
case WOW_REASON_OEM_RESPONSE_EVENT:
return "WOW_REASON_OEM_RESPONSE_EVENT";
}
return "unknown";
}
static void wma_beacon_miss_handler(tp_wma_handle wma, u_int32_t vdev_id,
uint32_t rssi)
{
tSirSmeMissedBeaconInd *beacon_miss_ind;
beacon_miss_ind = (tSirSmeMissedBeaconInd *) vos_mem_malloc
(sizeof(tSirSmeMissedBeaconInd));
if (NULL == beacon_miss_ind) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return;
}
beacon_miss_ind->messageType = WDA_MISSED_BEACON_IND;
beacon_miss_ind->length = sizeof(tSirSmeMissedBeaconInd);
beacon_miss_ind->bssIdx = vdev_id;
wma_send_msg(wma, WDA_MISSED_BEACON_IND,
(void *)beacon_miss_ind, 0);
wma_lost_link_info_handler(wma, vdev_id, rssi +
WMA_TGT_NOISE_FLOOR_DBM);
}
#ifdef FEATURE_WLAN_LPHB
static int wma_lphb_handler(tp_wma_handle wma, u_int8_t *event)
{
wmi_hb_ind_event_fixed_param *hb_fp;
tSirLPHBInd *slphb_indication;
VOS_STATUS vos_status;
vos_msg_t sme_msg = {0} ;
hb_fp = (wmi_hb_ind_event_fixed_param *)event;
if (!hb_fp) {
WMA_LOGE("Invalid wmi_hb_ind_event_fixed_param buffer");
return -EINVAL;
}
WMA_LOGD("lphb indication received with vdev_id=%d, session=%d, reason=%d",
hb_fp->vdev_id, hb_fp->session, hb_fp->reason);
slphb_indication = (tSirLPHBInd *) vos_mem_malloc(sizeof(tSirLPHBInd));
if (!slphb_indication) {
WMA_LOGE("Invalid LPHB indication buffer");
return -EINVAL;
}
slphb_indication->sessionIdx = hb_fp->session;
slphb_indication->protocolType = hb_fp->reason;
slphb_indication->eventReason= hb_fp->reason;
sme_msg.type = eWNI_SME_LPHB_IND;
sme_msg.bodyptr = slphb_indication;
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_LPHB_IND msg to SME");
vos_mem_free(slphb_indication);
return -EINVAL;
}
return 0;
}
#endif /* FEATURE_WLAN_LPHB */
#ifdef FEATURE_WLAN_D0WOW
/*
* Handler to catch D0-WOW disable ACK event.
*/
static int wma_d0_wow_disable_ack_event(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_D0_WOW_DISABLE_ACK_EVENTID_param_tlvs *param_buf;
wmi_d0_wow_disable_ack_event_fixed_param *resp_data;
param_buf = (WMI_D0_WOW_DISABLE_ACK_EVENTID_param_tlvs *)event;
if (!param_buf) {
WMA_LOGE("Invalid D0-WOW disable ACK event buffer!");
return -EINVAL;
}
resp_data = param_buf->fixed_param;
vos_event_set(&wma->wma_resume_event);
WMA_LOGD("Received D0-WOW disable ACK");
return 0;
}
#endif
/* function : wma_get_temperature
* Descriptin : Function is used to send get pdev temperature req
* Args : wma_handle, request data which will be non-null
* Returns : SUCCESS or FAILURE
*/
VOS_STATUS wma_get_temperature(tp_wma_handle wma_handle)
{
wmi_pdev_get_temperature_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len = sizeof(wmi_pdev_get_temperature_cmd_fixed_param);
u_int8_t *buf_ptr;
if (!wma_handle) {
WMA_LOGE(FL("WMA is closed, can not issue cmd"));
return VOS_STATUS_E_INVAL;
}
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE(FL("wmi_buf_alloc failed"));
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t*)wmi_buf_data(wmi_buf);
cmd = (wmi_pdev_get_temperature_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_pdev_get_temperature_cmd_fixed_param));
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_PDEV_GET_TEMPERATURE_CMDID)) {
WMA_LOGE(FL("failed to send get temperature command"));
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/* function : wma_pdev_temperature_evt_handler
* Description : Handler for WMI_PDEV_TEMPERATURE_EVENTID event from firmware
* : This event reports the chip temperature
* Returns :
*/
static int wma_pdev_temperature_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
vos_msg_t sme_msg = {0};
WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *param_buf;
wmi_pdev_temperature_event_fixed_param *wmi_event;
param_buf = (WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *) event;
if (!param_buf)
{
WMA_LOGE("Invalid pdev_temperature event buffer");
return -EINVAL;
}
wmi_event = param_buf->fixed_param;
WMA_LOGI(FL("temperature: %d"), wmi_event->value);
sme_msg.type = eWNI_SME_MSG_GET_TEMPERATURE_IND;
sme_msg.bodyptr = NULL;
sme_msg.bodyval = wmi_event->value;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status) )
{
WMA_LOGE(FL("Fail to post get temperature ind msg"));
}
return 0;
}
/**
* wma_log_supported_evt_handler() - Enable/Disable FW diag/log events
* @handle: WMA handle
* @event: Event received from FW
* @len: Length of the event
*
* Enables the low frequency events and disables the high frequency
* events. Bit 17 indicates if the event if low/high frequency.
* 1 - high frequency, 0 - low frequency
*
* Return: 0 on successfully enabling/disabling the events
*/
static int wma_log_supported_evt_handler(void *handle,
u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
uint32_t num_of_diag_events_logs;
wmi_diag_event_log_config_fixed_param *cmd;
wmi_buf_t buf;
uint8_t *buf_ptr;
uint32_t *cmd_args, *evt_args;
uint32_t buf_len, i;
WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID_param_tlvs *param_buf;
wmi_diag_event_log_supported_event_fixed_params *wmi_event;
WMA_LOGI("Received WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID");
param_buf = (WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("Invalid log supported event buffer");
return -EINVAL;
}
wmi_event = param_buf->fixed_param;
num_of_diag_events_logs = wmi_event->num_of_diag_events_logs;
if (num_of_diag_events_logs >
param_buf->num_diag_events_logs_list) {
WMA_LOGE("message number of events %d is more than tlv hdr content %d",
num_of_diag_events_logs,
param_buf->num_diag_events_logs_list);
return -EINVAL;
}
evt_args = param_buf->diag_events_logs_list;
if (!evt_args) {
WMA_LOGE("%s: Event list is empty, num_of_diag_events_logs=%d",
__func__, num_of_diag_events_logs);
return -EINVAL;
}
WMA_LOGD("%s: num_of_diag_events_logs=%d",
__func__, num_of_diag_events_logs);
if (num_of_diag_events_logs >
(WMA_SVC_MSG_MAX_SIZE / sizeof(uint32_t))) {
WMA_LOGE("%s: excess num of logs:%d", __func__,
num_of_diag_events_logs);
VOS_ASSERT(0);
return -EINVAL;
}
/* Free any previous allocation */
if (wma->events_logs_list)
vos_mem_free(wma->events_logs_list);
/* Store the event list for run time enable/disable */
wma->events_logs_list = vos_mem_malloc(num_of_diag_events_logs *
sizeof(uint32_t));
if (!wma->events_logs_list) {
WMA_LOGE("%s: event log list memory allocation failed",
__func__);
return -ENOMEM;
}
wma->num_of_diag_events_logs = num_of_diag_events_logs;
/* Prepare the send buffer */
buf_len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
(num_of_diag_events_logs * sizeof(uint32_t));
buf = wmi_buf_alloc(wma->wmi_handle, buf_len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
vos_mem_free(wma->events_logs_list);
wma->events_logs_list = NULL;
return -ENOMEM;
}
cmd = (wmi_diag_event_log_config_fixed_param *) wmi_buf_data(buf);
buf_ptr = (uint8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_diag_event_log_config_fixed_param));
cmd->num_of_diag_events_logs = num_of_diag_events_logs;
buf_ptr += sizeof(wmi_diag_event_log_config_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(num_of_diag_events_logs * sizeof(uint32_t)));
cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE);
/* Populate the events */
for (i = 0; i < num_of_diag_events_logs; i++) {
/* Low freq (0) - Enable (1) the event
* High freq (1) - Disable (0) the event
*/
WMI_DIAG_ID_ENABLED_DISABLED_SET(cmd_args[i],
!(WMI_DIAG_FREQUENCY_GET(evt_args[i])));
/* Set the event ID */
WMI_DIAG_ID_SET(cmd_args[i],
WMI_DIAG_ID_GET(evt_args[i]));
/* Set the type */
WMI_DIAG_TYPE_SET(cmd_args[i],
WMI_DIAG_TYPE_GET(evt_args[i]));
/* Storing the event/log list in WMA */
wma->events_logs_list[i] = evt_args[i];
}
if (wmi_unified_cmd_send(wma->wmi_handle, buf, buf_len,
WMI_DIAG_EVENT_LOG_CONFIG_CMDID)) {
WMA_LOGE("%s: WMI_DIAG_EVENT_LOG_CONFIG_CMDID failed",
__func__);
wmi_buf_free(buf);
/* Not clearing events_logs_list, though wmi cmd failed.
* Host can still have this list
*/
return -EINVAL;
}
return 0;
}
/**
* wma_flush_complete_evt_handler() - FW log flush complete event handler
* @handle: WMI handle
* @event: Event recevied from FW
* @len: Length of the event
*
*/
static int wma_flush_complete_evt_handler(void *handle,
u_int8_t *event,
u_int32_t len)
{
VOS_STATUS status;
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *param_buf;
wmi_debug_mesg_flush_complete_fixed_param *wmi_event;
uint32_t reason_code;
param_buf = (WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("Invalid log flush complete event buffer");
return VOS_STATUS_E_FAILURE;
}
wmi_event = param_buf->fixed_param;
reason_code = wmi_event->reserved0;
/*
* reason_code = 0; Flush event in response to flush command
* reason_code = other value; Asynchronous flush event for fatal events
*/
if (!reason_code && (vos_is_log_report_in_progress() == false)) {
WMA_LOGE("Received WMI flush event without sending CMD");
return -EINVAL;
} else if (!reason_code && vos_is_log_report_in_progress() == true) {
/* Flush event in response to flush command */
WMA_LOGI("Received WMI flush event in response to flush CMD");
status = vos_timer_stop(&wma->log_completion_timer);
if (status != VOS_STATUS_SUCCESS)
WMA_LOGE("Failed to stop the log completion timeout");
vos_logging_set_fw_flush_complete();
} else if (reason_code && vos_is_log_report_in_progress() == false) {
/* Asynchronous flush event for fatal events */
WMA_LOGE("Received asynchronous WMI flush event: reason=%d",
reason_code);
status = vos_set_log_completion(WLAN_LOG_TYPE_FATAL,
WLAN_LOG_INDICATOR_FIRMWARE,
reason_code);
if (VOS_STATUS_SUCCESS != status) {
WMA_LOGE("%s: Failed to set log trigger params",
__func__);
return VOS_STATUS_E_FAILURE;
}
vos_logging_set_fw_flush_complete();
return status;
} else {
/* Asynchronous flush event for fatal event,
* but, report in progress already
*/
WMA_LOGI("%s: Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d",
__func__, WLAN_LOG_TYPE_FATAL,
WLAN_LOG_INDICATOR_FIRMWARE, reason_code);
return VOS_STATUS_E_FAILURE;
}
return 0;
}
#ifdef FEATURE_WLAN_EXTSCAN
/**
* wma_extscan_get_eventid_from_tlvtag() - map tlv tag to corresponding event id
* @tag: WMI TLV tag
*
* Return:
* 0 if TLV tag is invalid
* else return corresponding WMI event id
*/
static int wma_extscan_get_eventid_from_tlvtag(uint32_t tag)
{
uint32_t event_id;
switch (tag) {
case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param:
event_id = WMI_EXTSCAN_START_STOP_EVENTID;
break;
case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param:
event_id = WMI_EXTSCAN_OPERATION_EVENTID;
break;
case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param:
event_id = WMI_EXTSCAN_TABLE_USAGE_EVENTID;
break;
case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param:
event_id = WMI_EXTSCAN_CACHED_RESULTS_EVENTID;
break;
case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param:
event_id = WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID;
break;
case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param:
event_id = WMI_EXTSCAN_HOTLIST_MATCH_EVENTID;
break;
case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param:
event_id = WMI_EXTSCAN_CAPABILITIES_EVENTID;
break;
default:
event_id = 0;
WMA_LOGE("%s: Unknown tag: %d", __func__, tag);
break;
}
WMA_LOGI("%s: For tag %d WMI event 0x%x", __func__, tag, event_id);
return event_id;
}
/**
* wma_extscan_wow_event_callback() - extscan wow event callback
* @handle: WMA handle
* @event: event buffer
* @len: length of @event buffer
*
* In wow case, the wow event is followed by the payload of the event
* which generated the wow event.
* payload is 4 bytes of length followed by event buffer. the first 4 bytes
* of event buffer is common tlv header, which is a combination
* of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to
* identify the event which triggered wow event.
*
* @Return: none
*/
static void wma_extscan_wow_event_callback(void *handle, void *event,
uint32_t len)
{
uint32_t id;
int tlv_ok_status = 0;
void *wmi_cmd_struct_ptr = NULL;
uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event));
id = wma_extscan_get_eventid_from_tlvtag(tag);
if (!id) {
WMA_LOGE("%s: Invalid Tag: %d", __func__, tag);
return;
}
tlv_ok_status = wmitlv_check_and_pad_event_tlvs(
handle, event, len, id,
&wmi_cmd_struct_ptr);
if (tlv_ok_status != 0) {
WMA_LOGE("%s: Invalid Tag: %d could not check and pad tlvs",
__func__, tag);
return;
}
switch (tag) {
case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param:
wma_extscan_start_stop_event_handler(handle,
wmi_cmd_struct_ptr, len);
break;
case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param:
wma_extscan_operations_event_handler(handle,
wmi_cmd_struct_ptr, len);
break;
case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param:
wma_extscan_table_usage_event_handler(handle,
wmi_cmd_struct_ptr, len);
break;
case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param:
wma_extscan_cached_results_event_handler(handle,
wmi_cmd_struct_ptr, len);
break;
case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param:
wma_extscan_change_results_event_handler(handle,
wmi_cmd_struct_ptr, len);
break;
case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param:
wma_extscan_hotlist_match_event_handler(handle,
wmi_cmd_struct_ptr, len);
break;
case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param:
wma_extscan_capabilities_event_handler(handle,
wmi_cmd_struct_ptr, len);
break;
default:
WMA_LOGE("%s: Unknown tag: %d", __func__, tag);
break;
}
wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr);
return;
}
#endif
/**
* wma_wow_wake_up_stats_display() - display wow wake up stats
* @wma: Pointer to wma handle
*
* Return: none
*/
static void wma_wow_wake_up_stats_display(tp_wma_handle wma)
{
WMA_LOGA("uc %d bc %d v4_mc %d v6_mc %d ra %d ns %d na %d pno_match %d pno_complete %d gscan %d low_rssi %d rssi_breach %d icmp %d icmpv6 %d oem %d chip pwr save fail : %d",
wma->wow_ucast_wake_up_count,
wma->wow_bcast_wake_up_count,
wma->wow_ipv4_mcast_wake_up_count,
wma->wow_ipv6_mcast_wake_up_count,
wma->wow_ipv6_mcast_ra_stats,
wma->wow_ipv6_mcast_ns_stats,
wma->wow_ipv6_mcast_na_stats,
wma->wow_pno_match_wake_up_count,
wma->wow_pno_complete_wake_up_count,
wma->wow_gscan_wake_up_count,
wma->wow_low_rssi_wake_up_count,
wma->wow_rssi_breach_wake_up_count,
wma->wow_icmpv4_count,
wma->wow_icmpv6_count,
wma->wow_oem_response_wake_up_count,
wma->wow_pwr_save_fail_detected_wake_up_count);
return;
}
/**
* wma_wow_ipv6_mcast_stats() - ipv6 mcast wake up stats
* @wma: Pointer to wma handle
* @data: Pointer to pattern match data
*
* Return: none
*/
static void wma_wow_ipv6_mcast_stats(tp_wma_handle wma, uint8_t *data)
{
static const uint8_t ipv6_ether_type[] = {0x86, 0xDD};
if (!memcmp(ipv6_ether_type, (data + WMA_ETHER_TYPE_OFFSET),
sizeof(ipv6_ether_type))) {
if (WMA_ICMP_V6_HEADER_TYPE ==
*(data + WMA_ICMP_V6_HEADER_OFFSET)) {
wma->wow_icmpv6_count++;
if (WMA_ICMP_V6_RA_TYPE ==
*(data + WMA_ICMP_V6_TYPE_OFFSET))
wma->wow_ipv6_mcast_ra_stats++;
else if (WMA_ICMP_V6_NS_TYPE ==
*(data + WMA_ICMP_V6_TYPE_OFFSET))
wma->wow_ipv6_mcast_ns_stats++;
else if (WMA_ICMP_V6_NA_TYPE ==
*(data + WMA_ICMP_V6_TYPE_OFFSET))
wma->wow_ipv6_mcast_na_stats++;
else
WMA_LOGA("ICMP V6 type : 0x%x",
*(data + WMA_ICMP_V6_TYPE_OFFSET));
} else {
WMA_LOGA("ICMP_V6 header 0x%x",
*(data + WMA_ICMP_V6_HEADER_OFFSET));
}
} else {
WMA_LOGA("Ethertype x%x:0x%x",
*(data + WMA_ETHER_TYPE_OFFSET),
*(data + WMA_ETHER_TYPE_OFFSET + 1));
}
return;
}
/**
* wma_wow_wake_up_stats() - maintain wow pattern match wake up stats
* @wma: Pointer to wma handle
* @data: Pointer to pattern match data
* @len: Pattern match data length
* @event: Wake up event
*
* Return: none
*/
static void wma_wow_wake_up_stats(tp_wma_handle wma, uint8_t *data,
int32_t len, WOW_WAKE_REASON_TYPE event)
{
/* Do not increment debug stats if resume is for runtime pm */
if (wmi_get_runtime_pm_inprogress(wma->wmi_handle))
return;
switch(event) {
case WOW_REASON_PATTERN_MATCH_FOUND:
if (WMA_BCAST_MAC_ADDR == *data) {
wma->wow_bcast_wake_up_count++;
if (len >= WMA_IPV4_PROTO_GET_MIN_LEN &&
adf_nbuf_data_is_icmp_pkt(data))
wma->wow_icmpv4_count++;
else if ((len > WMA_ICMP_V6_TYPE_OFFSET) &&
adf_nbuf_data_is_icmpv6_pkt(data))
wma->wow_icmpv6_count++;
} else if (WMA_MCAST_IPV4_MAC_ADDR == *data) {
wma->wow_ipv4_mcast_wake_up_count++;
if (len >= WMA_IPV4_PROTO_GET_MIN_LEN &&
WMA_ICMP_PROTOCOL == *(data + WMA_IPV4_PROTOCOL))
wma->wow_icmpv4_count++;
} else if (WMA_MCAST_IPV6_MAC_ADDR == *data) {
wma->wow_ipv6_mcast_wake_up_count++;
if (len > WMA_ICMP_V6_TYPE_OFFSET)
wma_wow_ipv6_mcast_stats(wma, data);
else
WMA_LOGA("ICMP_V6 data len %d", len);
} else {
wma->wow_ucast_wake_up_count++;
if (adf_nbuf_data_is_ipv4_mcast_pkt(data))
wma->wow_ipv4_mcast_wake_up_count++;
else if (adf_nbuf_data_is_ipv6_mcast_pkt(data))
wma->wow_ipv6_mcast_wake_up_count++;
if (len >= WMA_IPV4_PROTO_GET_MIN_LEN &&
adf_nbuf_data_is_icmp_pkt(data))
wma->wow_icmpv4_count++;
else if (len > WMA_ICMP_V6_TYPE_OFFSET &&
adf_nbuf_data_is_icmpv6_pkt(data))
wma->wow_icmpv6_count++;
}
break;
case WOW_REASON_RA_MATCH:
wma->wow_icmpv6_count++;
wma->wow_ipv6_mcast_ra_stats++;
wma->wow_ipv6_mcast_wake_up_count++;
break;
case WOW_REASON_NLOD:
wma->wow_pno_match_wake_up_count++;
break;
case WOW_REASON_NLO_SCAN_COMPLETE:
wma->wow_pno_complete_wake_up_count++;
break;
case WOW_REASON_LOW_RSSI:
wma->wow_low_rssi_wake_up_count++;
break;
case WOW_REASON_EXTSCAN:
wma->wow_gscan_wake_up_count++;
break;
case WOW_REASON_RSSI_BREACH_EVENT:
wma->wow_rssi_breach_wake_up_count++;
break;
case WOW_REASON_OEM_RESPONSE_EVENT:
wma->wow_oem_response_wake_up_count++;
break;
case WOW_REASON_CHIP_POWER_FAILURE_DETECT:
wma->wow_pwr_save_fail_detected_wake_up_count++;
break;
default:
WMA_LOGE("Unknown wake up reason");
break;
}
wma_wow_wake_up_stats_display(wma);
return;
}
/**
* wma_wow_ap_lost_helper() - helper function to handle WOW_REASON_AP_ASSOC_LOST
* reason code and retrieve RSSI from the event.
* @wma: Pointer to wma handle
* @param: WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs buffer pointer
*
* Return: none
*/
static void wma_wow_ap_lost_helper(tp_wma_handle wma, void *param)
{
WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *param_buf;
WOW_EVENT_INFO_fixed_param *wake_info;
WMI_ROAM_EVENTID_param_tlvs event_param;
wmi_roam_event_fixed_param *roam_event;
u_int32_t wow_buf_pkt_len = 0;
param_buf = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *) param;
wake_info = param_buf->fixed_param;
WMA_LOGA("%s: Beacon miss indication on vdev %d",
__func__, wake_info->vdev_id);
if (NULL == param_buf->wow_packet_buffer) {
WMA_LOGE("%s: invalid wow packet buffer", __func__);
goto exit_handler;
}
vos_mem_copy((u_int8_t *) &wow_buf_pkt_len,
param_buf->wow_packet_buffer, 4);
WMA_LOGD("wow_packet_buffer dump");
vos_trace_hex_dump(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_DEBUG,
param_buf->wow_packet_buffer, wow_buf_pkt_len);
if (wow_buf_pkt_len >= sizeof(event_param)) {
roam_event = (wmi_roam_event_fixed_param *)
(param_buf->wow_packet_buffer + 4);
wma_beacon_miss_handler(wma, wake_info->vdev_id,
roam_event->rssi);
return;
}
exit_handler:
/* in the case that no RSSI is available from the event */
WMA_LOGE("%s: rssi is not available from wow_packet_buffer", __func__);
wma_beacon_miss_handler(wma, wake_info->vdev_id, 0);
}
/**
* wma_pkt_proto_subtype_to_string() - to convert proto subtype
* of data packet to string.
* @proto_subtype: proto subtype for data packet
*
* This function returns the string for the proto subtype of
* data packet.
*
* Return: string for proto subtype for data packet
*/
const char *
wma_pkt_proto_subtype_to_string(enum adf_proto_subtype proto_subtype)
{
switch (proto_subtype) {
case ADF_PROTO_EAPOL_M1:
return "EAPOL M1";
case ADF_PROTO_EAPOL_M2:
return "EAPOL M2";
case ADF_PROTO_EAPOL_M3:
return "EAPOL M3";
case ADF_PROTO_EAPOL_M4:
return "EAPOL M4";
case ADF_PROTO_DHCP_DISCOVER:
return "DHCP DISCOVER";
case ADF_PROTO_DHCP_REQUEST:
return "DHCP REQUEST";
case ADF_PROTO_DHCP_OFFER:
return "DHCP OFFER";
case ADF_PROTO_DHCP_ACK:
return "DHCP ACK";
case ADF_PROTO_DHCP_NACK:
return "DHCP NACK";
case ADF_PROTO_DHCP_RELEASE:
return "DHCP RELEASE";
case ADF_PROTO_DHCP_INFORM:
return "DHCP INFORM";
case ADF_PROTO_DHCP_DECLINE:
return "DHCP DECLINE";
case ADF_PROTO_ARP_REQ:
return "ARP REQUEST";
case ADF_PROTO_ARP_RES:
return "ARP RESPONSE";
case ADF_PROTO_ICMP_REQ:
return "ICMP REQUEST";
case ADF_PROTO_ICMP_RES:
return "ICMP RESPONSE";
case ADF_PROTO_ICMPV6_REQ:
return "ICMPV6 REQUEST";
case ADF_PROTO_ICMPV6_RES:
return "ICMPV6 RESPONSE";
case ADF_PROTO_ICMPV6_RS:
return "ICMPV6 RS";
case ADF_PROTO_ICMPV6_RA:
return "ICMPV6 RA";
case ADF_PROTO_ICMPV6_NS:
return "ICMPV6 NS";
case ADF_PROTO_ICMPV6_NA:
return "ICMPV6 NA";
case ADF_PROTO_IPV4_UDP:
return "IPV4 UDP Packet";
case ADF_PROTO_IPV4_TCP:
return "IPV4 TCP Packet";
case ADF_PROTO_IPV6_UDP:
return "IPV6 UDP Packet";
case ADF_PROTO_IPV6_TCP:
return "IPV6 TCP Packet";
default:
return "Invalid Packet";
}
}
/**
* wma_wow_get_pkt_proto_subtype() - get the proto subtype
* of the packet.
* @data: Pointer to data buffer
* @len: length of the data buffer
*
* This function gives the proto subtype of the packet.
*
* Return: proto subtype of the packet.
*/
static enum adf_proto_subtype
wma_wow_get_pkt_proto_subtype(uint8_t *data,
uint32_t len)
{
uint16_t ether_type = (uint16_t)(*(uint16_t *)(data +
ADF_NBUF_TRAC_ETH_TYPE_OFFSET));
WMA_LOGD("Ether Type: 0x%04x",
adf_os_cpu_to_be16(ether_type));
if (ADF_NBUF_TRAC_EAPOL_ETH_TYPE ==
adf_os_cpu_to_be16(ether_type)) {
if (len >= WMA_EAPOL_SUBTYPE_GET_MIN_LEN)
return adf_nbuf_data_get_eapol_subtype(data);
WMA_LOGD("EAPOL Packet");
return ADF_PROTO_INVALID;
} else if (ADF_NBUF_TRAC_ARP_ETH_TYPE ==
adf_os_cpu_to_be16(ether_type)) {
if (len >= WMA_ARP_SUBTYPE_GET_MIN_LEN)
return adf_nbuf_data_get_arp_subtype(data);
WMA_LOGD("ARP Packet");
return ADF_PROTO_INVALID;
} else if (ADF_NBUF_TRAC_IPV4_ETH_TYPE ==
adf_os_cpu_to_be16(ether_type)) {
if (len >= WMA_IPV4_PROTO_GET_MIN_LEN) {
uint8_t proto_type;
proto_type = adf_nbuf_data_get_ipv4_proto(data);
WMA_LOGD("IPV4_proto_type: %u", proto_type);
if (proto_type == ADF_NBUF_TRAC_ICMP_TYPE) {
if (len >= WMA_ICMP_SUBTYPE_GET_MIN_LEN)
return adf_nbuf_data_get_icmp_subtype(
data);
WMA_LOGD("ICMP Packet");
return ADF_PROTO_INVALID;
} else if (proto_type == ADF_NBUF_TRAC_UDP_TYPE) {
if (len >= WMA_IS_DHCP_GET_MIN_LEN) {
if (adf_nbuf_data_is_dhcp_pkt(data)) {
if (len >=
WMA_DHCP_SUBTYPE_GET_MIN_LEN)
return adf_nbuf_data_get_dhcp_subtype(data);
WMA_LOGD("DHCP Packet");
return ADF_PROTO_INVALID;
}
}
return ADF_PROTO_IPV4_UDP;
} else if (proto_type == ADF_NBUF_TRAC_TCP_TYPE) {
return ADF_PROTO_IPV4_TCP;
}
}
WMA_LOGD("IPV4 Packet");
return ADF_PROTO_INVALID;
} else if (ADF_NBUF_TRAC_IPV6_ETH_TYPE ==
adf_os_cpu_to_be16(ether_type)) {
if (len >= WMA_IPV6_PROTO_GET_MIN_LEN) {
uint8_t proto_type;
proto_type = adf_nbuf_data_get_ipv6_proto(data);
WMA_LOGD("IPV6_proto_type: %u", proto_type);
if (proto_type == ADF_NBUF_TRAC_ICMPV6_TYPE) {
if (len >= WMA_ICMPV6_SUBTYPE_GET_MIN_LEN)
return adf_nbuf_data_get_icmpv6_subtype(
data);
WMA_LOGD("ICMPV6 Packet");
return ADF_PROTO_INVALID;
} else if (proto_type == ADF_NBUF_TRAC_UDP_TYPE) {
return ADF_PROTO_IPV6_UDP;
} else if (proto_type == ADF_NBUF_TRAC_TCP_TYPE) {
return ADF_PROTO_IPV6_TCP;
}
}
WMA_LOGD("IPV6 Packet");
return ADF_PROTO_INVALID;
}
return ADF_PROTO_INVALID;
}
/**
* wma_wow_parse_data_pkt_buffer() - API to parse data buffer for data
* packet that resulted in WOW wakeup.
* @data: Pointer to data buffer
* @buf_len: data buffer length
*
* This function parses the data buffer received (first few bytes of
* skb->data) to get informaton like src mac addr, dst mac addr, packet
* len, seq_num, etc.
*
* Return: void
*/
static void wma_wow_parse_data_pkt_buffer(uint8_t *data,
uint32_t buf_len)
{
enum adf_proto_subtype proto_subtype;
uint16_t pkt_len, key_len, seq_num;
uint16_t src_port, dst_port;
uint32_t transaction_id, tcp_seq_num;
WMA_LOGD("wow_buf_pkt_len: %u", buf_len);
if (buf_len >= ADF_NBUF_TRAC_IPV4_OFFSET)
WMA_LOGD("Src_mac: " MAC_ADDRESS_STR " Dst_mac: " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(data + ADF_NBUF_SRC_MAC_OFFSET),
MAC_ADDR_ARRAY(data));
else
goto end;
proto_subtype = wma_wow_get_pkt_proto_subtype(data, buf_len);
switch (proto_subtype) {
case ADF_PROTO_EAPOL_M1:
case ADF_PROTO_EAPOL_M2:
case ADF_PROTO_EAPOL_M3:
case ADF_PROTO_EAPOL_M4:
WMA_LOGD("WOW Wakeup: %s rcvd",
wma_pkt_proto_subtype_to_string(proto_subtype));
if (buf_len >= WMA_EAPOL_INFO_GET_MIN_LEN) {
pkt_len = (uint16_t)(*(uint16_t *)(data +
EAPOL_PKT_LEN_OFFSET));
key_len = (uint16_t)(*(uint16_t *)(data +
EAPOL_KEY_LEN_OFFSET));
WMA_LOGD("Pkt_len: %u, Key_len: %u",
adf_os_cpu_to_be16(pkt_len),
adf_os_cpu_to_be16(key_len));
}
break;
case ADF_PROTO_DHCP_DISCOVER:
case ADF_PROTO_DHCP_REQUEST:
case ADF_PROTO_DHCP_OFFER:
case ADF_PROTO_DHCP_ACK:
case ADF_PROTO_DHCP_NACK:
case ADF_PROTO_DHCP_RELEASE:
case ADF_PROTO_DHCP_INFORM:
case ADF_PROTO_DHCP_DECLINE:
WMA_LOGD("WOW Wakeup: %s rcvd",
wma_pkt_proto_subtype_to_string(proto_subtype));
if (buf_len >= WMA_DHCP_INFO_GET_MIN_LEN) {
pkt_len = (uint16_t)(*(uint16_t *)(data +
DHCP_PKT_LEN_OFFSET));
transaction_id = (uint32_t)(*(uint32_t *)(data +
DHCP_TRANSACTION_ID_OFFSET));
WMA_LOGD("Pkt_len: %u, Transaction_id: %u",
adf_os_cpu_to_be16(pkt_len),
adf_os_cpu_to_be32(transaction_id));
}
break;
case ADF_PROTO_ARP_REQ:
case ADF_PROTO_ARP_RES:
WMA_LOGD("WOW Wakeup: %s rcvd",
wma_pkt_proto_subtype_to_string(proto_subtype));
break;
case ADF_PROTO_ICMP_REQ:
case ADF_PROTO_ICMP_RES:
WMA_LOGD("WOW Wakeup: %s rcvd",
wma_pkt_proto_subtype_to_string(proto_subtype));
if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) {
pkt_len = (uint16_t)(*(uint16_t *)(data +
IPV4_PKT_LEN_OFFSET));
seq_num = (uint16_t)(*(uint16_t *)(data +
ICMP_SEQ_NUM_OFFSET));
WMA_LOGD("Pkt_len: %u, Seq_num: %u",
adf_os_cpu_to_be16(pkt_len),
adf_os_cpu_to_be16(seq_num));
}
break;
case ADF_PROTO_ICMPV6_REQ:
case ADF_PROTO_ICMPV6_RES:
case ADF_PROTO_ICMPV6_RS:
case ADF_PROTO_ICMPV6_RA:
case ADF_PROTO_ICMPV6_NS:
case ADF_PROTO_ICMPV6_NA:
WMA_LOGD("WOW Wakeup: %s rcvd",
wma_pkt_proto_subtype_to_string(proto_subtype));
if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) {
pkt_len = (uint16_t)(*(uint16_t *)(data +
IPV6_PKT_LEN_OFFSET));
seq_num = (uint16_t)(*(uint16_t *)(data +
ICMPV6_SEQ_NUM_OFFSET));
WMA_LOGD("Pkt_len: %u, Seq_num: %u",
adf_os_cpu_to_be16(pkt_len),
adf_os_cpu_to_be16(seq_num));
}
break;
case ADF_PROTO_IPV4_UDP:
case ADF_PROTO_IPV4_TCP:
WMA_LOGD("WOW Wakeup: %s rcvd",
wma_pkt_proto_subtype_to_string(proto_subtype));
if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) {
pkt_len = (uint16_t)(*(uint16_t *)(data +
IPV4_PKT_LEN_OFFSET));
src_port = (uint16_t)(*(uint16_t *)(data +
IPV4_SRC_PORT_OFFSET));
dst_port = (uint16_t)(*(uint16_t *)(data +
IPV4_DST_PORT_OFFSET));
WMA_LOGD("Pkt_len: %u",
adf_os_cpu_to_be16(pkt_len));
WMA_LOGD("src_port: %u, dst_port: %u",
adf_os_cpu_to_be16(src_port),
adf_os_cpu_to_be16(dst_port));
if (proto_subtype == ADF_PROTO_IPV4_TCP) {
tcp_seq_num = (uint32_t)(*(uint32_t *)(data +
IPV4_TCP_SEQ_NUM_OFFSET));
WMA_LOGD("TCP_seq_num: %u",
adf_os_cpu_to_be32(tcp_seq_num));
}
}
break;
case ADF_PROTO_IPV6_UDP:
case ADF_PROTO_IPV6_TCP:
WMA_LOGD("WOW Wakeup: %s rcvd",
wma_pkt_proto_subtype_to_string(proto_subtype));
if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) {
pkt_len = (uint16_t)(*(uint16_t *)(data +
IPV6_PKT_LEN_OFFSET));
src_port = (uint16_t)(*(uint16_t *)(data +
IPV6_SRC_PORT_OFFSET));
dst_port = (uint16_t)(*(uint16_t *)(data +
IPV6_DST_PORT_OFFSET));
WMA_LOGD("Pkt_len: %u",
adf_os_cpu_to_be16(pkt_len));
WMA_LOGD("src_port: %u, dst_port: %u",
adf_os_cpu_to_be16(src_port),
adf_os_cpu_to_be16(dst_port));
if (proto_subtype == ADF_PROTO_IPV6_TCP) {
tcp_seq_num = (uint32_t)(*(uint32_t *)(data +
IPV6_TCP_SEQ_NUM_OFFSET));
WMA_LOGD("TCP_seq_num: %u",
adf_os_cpu_to_be32(tcp_seq_num));
}
}
break;
default:
end:
WMA_LOGD("wow_buf_pkt_len: %u", buf_len);
WMA_LOGD("Unknown Packet or Insufficient packet buffer");
break;
}
}
/**
* wma_wow_dump_mgmt_buffer() - API to parse data buffer for mgmt.
* packet that resulted in WOW wakeup.
* @wow_packet_buffer: Pointer to data buffer
* @buf_len: length of data buffer
*
* This function parses the data buffer received (802.11 header)
* to get informaton like src mac addr, dst mac addr, seq_num,
* frag_num, etc.
*
* Return: void
*/
static void wma_wow_dump_mgmt_buffer(uint8_t *wow_packet_buffer,
uint32_t buf_len)
{
struct ieee80211_frame_addr4 *wh;
WMA_LOGD("wow_buf_pkt_len: %u", buf_len);
wh = (struct ieee80211_frame_addr4 *)
(wow_packet_buffer + 4);
if (buf_len >= sizeof(struct ieee80211_frame)) {
uint8_t to_from_ds, frag_num;
uint32_t seq_num;
WMA_LOGE("RA: " MAC_ADDRESS_STR " TA: " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(wh->i_addr1),
MAC_ADDR_ARRAY(wh->i_addr2));
WMA_LOGE("TO_DS: %u, FROM_DS: %u",
wh->i_fc[1] & IEEE80211_FC1_DIR_TODS,
wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS);
to_from_ds = wh->i_fc[1] & IEEE80211_FC1_DIR_DSTODS;
switch (to_from_ds) {
case IEEE80211_NO_DS:
WMA_LOGE("BSSID: " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(wh->i_addr3));
break;
case IEEE80211_TO_DS:
WMA_LOGE("DA: " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(wh->i_addr3));
break;
case IEEE80211_FROM_DS:
WMA_LOGE("SA: " MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(wh->i_addr3));
break;
case IEEE80211_DS_TO_DS:
if (buf_len >= sizeof(struct ieee80211_frame_addr4))
WMA_LOGE("DA: " MAC_ADDRESS_STR " SA: "
MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(wh->i_addr3),
MAC_ADDR_ARRAY(wh->i_addr4));
break;
}
seq_num = (((*(uint16_t *)wh->i_seq) &
IEEE80211_SEQ_SEQ_MASK) >>
IEEE80211_SEQ_SEQ_SHIFT);
frag_num = (((*(uint16_t *)wh->i_seq) &
IEEE80211_SEQ_FRAG_MASK) >>
IEEE80211_SEQ_FRAG_SHIFT);
WMA_LOGE("SEQ_NUM: %u, FRAG_NUM: %u",
seq_num, frag_num);
} else {
WMA_LOGE("Insufficient buffer length for mgmt. packet");
}
}
/**
* wma_wow_get_wakelock_duration() - return the wakelock duration
* for some mgmt packets received.
* @wake_reason: wow wakeup reason
*
* This function returns the wakelock duration for some mgmt packets
* received while in wow suspend.
*
* Return: wakelock duration
*/
static uint32_t wma_wow_get_wakelock_duration(int wake_reason)
{
uint32_t wake_lock_duration = 0;
switch (wake_reason) {
case WOW_REASON_AUTH_REQ_RECV:
wake_lock_duration = WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT;
break;
case WOW_REASON_ASSOC_REQ_RECV:
wake_lock_duration = WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION;
break;
case WOW_REASON_DEAUTH_RECVD:
wake_lock_duration = WMA_DEAUTH_RECV_WAKE_LOCK_DURATION;
break;
case WOW_REASON_DISASSOC_RECVD:
wake_lock_duration = WMA_DISASSOC_RECV_WAKE_LOCK_DURATION;
break;
case WOW_REASON_AP_ASSOC_LOST:
wake_lock_duration = WMA_BMISS_EVENT_WAKE_LOCK_DURATION;
break;
case WOW_REASON_HOST_AUTO_SHUTDOWN:
wake_lock_duration = WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION;
break;
default:
break;
}
return wake_lock_duration;
}
/**
* wma_wow_get_wakelock() - return the wakelock
* for some mgmt packets received.
* @wma_handle: wma handle
* @wake_reason: wow wakeup reason
*
* This function returns the wakelock for some mgmt packets
* received while in wow suspend.
*
* Return: wakelock
*/
static vos_wake_lock_t *wma_wow_get_wakelock(tp_wma_handle wma_handle,
int wake_reason)
{
switch (wake_reason) {
case WOW_REASON_AUTH_REQ_RECV:
return &wma_handle->wow_auth_req_wl;
case WOW_REASON_ASSOC_REQ_RECV:
return &wma_handle->wow_assoc_req_wl;
case WOW_REASON_DEAUTH_RECVD:
return &wma_handle->wow_deauth_rec_wl;
case WOW_REASON_DISASSOC_RECVD:
return &wma_handle->wow_disassoc_rec_wl;
case WOW_REASON_AP_ASSOC_LOST:
return &wma_handle->wow_ap_assoc_lost_wl;
case WOW_REASON_HOST_AUTO_SHUTDOWN:
return &wma_handle->wow_auto_shutdown_wl;
default:
return NULL;
}
}
/*
* Handler to catch wow wakeup host event. This event will have
* reason why the firmware has woken the host.
*/
static int wma_wow_wakeup_host_event(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *param_buf;
WOW_EVENT_INFO_fixed_param *wake_info;
#ifdef FEATURE_WLAN_TDLS
WMI_TDLS_PEER_EVENTID_param_tlvs tdls_param;
#endif
#ifdef FEATURE_WLAN_SCAN_PNO
struct wma_txrx_node *node;
#endif
u_int32_t wake_lock_duration = 0;
u_int32_t wow_buf_pkt_len = 0;
param_buf = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("Invalid wow wakeup host event buf");
return -EINVAL;
}
wake_info = param_buf->fixed_param;
if ((wake_info->wake_reason != WOW_REASON_UNSPECIFIED) ||
(wake_info->wake_reason == WOW_REASON_UNSPECIFIED &&
!wmi_get_runtime_pm_inprogress(wma->wmi_handle))) {
if (wake_info->vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: received invalid vdev_id %d",
__func__, wake_info->vdev_id);
return -EINVAL;
}
WMA_LOGA("WOW wakeup host event received (reason: %s(%d)) for vdev %d",
wma_wow_wake_reason_str(wake_info->wake_reason, wma),
wake_info->wake_reason,
wake_info->vdev_id);
vos_wow_wakeup_host_event(wake_info->wake_reason);
wma_wow_wakeup_stats_event(wma);
}
vos_event_set(&wma->wma_resume_event);
if (param_buf->wow_packet_buffer) {
wow_buf_pkt_len = *(uint32_t *)param_buf->wow_packet_buffer;
if (wow_buf_pkt_len > (param_buf->num_wow_packet_buffer - 4)) {
WMA_LOGE("Invalid wow buf pkt len from firmware, wow_buf_pkt_len: %u, num_wow_packet_buffer: %u",
wow_buf_pkt_len,
param_buf->num_wow_packet_buffer);
return -EINVAL;
}
}
switch (wake_info->wake_reason) {
case WOW_REASON_AUTH_REQ_RECV:
case WOW_REASON_ASSOC_REQ_RECV:
case WOW_REASON_DEAUTH_RECVD:
case WOW_REASON_DISASSOC_RECVD:
case WOW_REASON_ASSOC_RES_RECV:
case WOW_REASON_REASSOC_REQ_RECV:
case WOW_REASON_REASSOC_RES_RECV:
case WOW_REASON_BEACON_RECV:
case WOW_REASON_ACTION_FRAME_RECV:
if (param_buf->wow_packet_buffer) {
if (wow_buf_pkt_len)
wma_wow_dump_mgmt_buffer(
param_buf->wow_packet_buffer,
wow_buf_pkt_len);
else
WMA_LOGE("wow packet buffer is empty");
} else {
WMA_LOGE("No wow packet buffer present");
}
break;
case WOW_REASON_AP_ASSOC_LOST:
wma_wow_ap_lost_helper(wma, param_buf);
break;
#ifdef FEATURE_WLAN_RA_FILTERING
case WOW_REASON_RA_MATCH:
wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_RA_MATCH);
break;
#endif
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
case WOW_REASON_HOST_AUTO_SHUTDOWN:
WMA_LOGA("Received WOW Auto Shutdown trigger in suspend");
if (wma_post_auto_shutdown_msg())
return -EINVAL;
break;
#endif
#ifdef FEATURE_WLAN_SCAN_PNO
case WOW_REASON_NLOD:
wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_NLOD);
node = &wma->interfaces[wake_info->vdev_id];
if (node) {
WMA_LOGD("NLO match happened");
node->nlo_match_evt_received = TRUE;
vos_wake_lock_timeout_acquire(&wma->pno_wake_lock,
WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT,
WIFI_POWER_EVENT_WAKELOCK_PNO);
}
break;
case WOW_REASON_NLO_SCAN_COMPLETE:
{
WMI_NLO_SCAN_COMPLETE_EVENTID_param_tlvs param;
wma_wow_wake_up_stats(wma, NULL, 0,
WOW_REASON_NLO_SCAN_COMPLETE);
WMA_LOGD("Host woken up due to pno scan complete reason");
/* First 4-bytes of wow_packet_buffer is the length */
if (param_buf->wow_packet_buffer) {
param.fixed_param = (wmi_nlo_event *)
(param_buf->wow_packet_buffer + 4);
wma_nlo_scan_cmp_evt_handler(handle,
(u_int8_t *)&param,
sizeof(param));
} else
WMA_LOGD("No wow_packet_buffer present");
}
break;
#endif
case WOW_REASON_CSA_EVENT:
{
WMI_CSA_HANDLING_EVENTID_param_tlvs param;
WMA_LOGD("Host woken up because of CSA IE");
param.fixed_param = (wmi_csa_event_fixed_param *)
(((u_int8_t *) wake_info)
+ sizeof(WOW_EVENT_INFO_fixed_param)
+ WOW_CSA_EVENT_OFFSET);
wma_csa_offload_handler(handle, (u_int8_t *)&param,
sizeof(param));
}
break;
#ifdef FEATURE_WLAN_LPHB
case WOW_REASON_WLAN_HB:
wma_lphb_handler(wma, (u_int8_t *)param_buf->hb_indevt);
break;
#endif
case WOW_REASON_HTT_EVENT:
break;
case WOW_REASON_BPF_ALLOW:
case WOW_REASON_PATTERN_MATCH_FOUND:
WMA_LOGD("Wake up for Rx packet, dump starting from ethernet hdr");
if (param_buf->wow_packet_buffer) {
if (wow_buf_pkt_len) {
uint8_t *data;
wma_wow_wake_up_stats(wma,
param_buf->wow_packet_buffer + 4,
wow_buf_pkt_len,
WOW_REASON_PATTERN_MATCH_FOUND);
vos_trace_hex_dump(VOS_MODULE_ID_WDA,
VOS_TRACE_LEVEL_DEBUG,
param_buf->wow_packet_buffer + 4,
wow_buf_pkt_len);
data = (uint8_t *)
(param_buf->wow_packet_buffer + 4);
wma_wow_parse_data_pkt_buffer(data,
wow_buf_pkt_len);
} else {
WMA_LOGE("wow packet buffer is empty");
}
} else {
WMA_LOGE("No wow packet buffer present");
}
break;
case WOW_REASON_LOW_RSSI:
{
/* WOW_REASON_LOW_RSSI is used for all roaming events.
* WMI_ROAM_REASON_BETTER_AP, WMI_ROAM_REASON_BMISS,
* WMI_ROAM_REASON_SUITABLE_AP will be handled by
* wma_roam_event_callback().
*/
WMI_ROAM_EVENTID_param_tlvs param;
wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_LOW_RSSI);
if (param_buf->wow_packet_buffer) {
/* Roam event is embedded in wow_packet_buffer */
WMA_LOGD("Host woken up because of roam event");
WMA_LOGD("wow_packet_buffer dump");
vos_trace_hex_dump(VOS_MODULE_ID_WDA,
VOS_TRACE_LEVEL_DEBUG,
param_buf->wow_packet_buffer, wow_buf_pkt_len);
if (wow_buf_pkt_len >= sizeof(param)) {
param.fixed_param = (wmi_roam_event_fixed_param *)
(param_buf->wow_packet_buffer +4);
wma_roam_event_callback(handle, (u_int8_t *)&param,
sizeof(param));
} else {
WMA_LOGE("Wrong length for roam event = %d bytes",
wow_buf_pkt_len);
}
} else {
/* No wow_packet_buffer means a better AP beacon
* will follow in a later event.
*/
WMA_LOGD("Host woken up because of better AP beacon");
}
break;
}
case WOW_REASON_CLIENT_KICKOUT_EVENT:
{
WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs param;
if (param_buf->wow_packet_buffer) {
/* station kickout event embedded in wow_packet_buffer */
WMA_LOGD("Host woken up because of sta_kickout event");
WMA_LOGD("wow_packet_buffer dump");
vos_trace_hex_dump(VOS_MODULE_ID_WDA,
VOS_TRACE_LEVEL_DEBUG,
param_buf->wow_packet_buffer, wow_buf_pkt_len);
if (wow_buf_pkt_len >= sizeof(param)) {
param.fixed_param = (wmi_peer_sta_kickout_event_fixed_param *)
(param_buf->wow_packet_buffer + 4);
wma_peer_sta_kickout_event_handler(handle,
(u_int8_t *)&param, sizeof(param));
} else {
WMA_LOGE("Wrong length for sta_kickout event = %d bytes",
wow_buf_pkt_len);
}
} else {
WMA_LOGD("No wow_packet_buffer present");
}
break;
}
#ifdef FEATURE_WLAN_EXTSCAN
case WOW_REASON_EXTSCAN:
WMA_LOGD("Host woken up because of extscan reason");
wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_EXTSCAN);
if (param_buf->wow_packet_buffer) {
wma_extscan_wow_event_callback(handle,
(u_int8_t *)(param_buf->wow_packet_buffer + 4),
wow_buf_pkt_len);
} else
WMA_LOGE("wow_packet_buffer is empty");
break;
#endif
case WOW_REASON_RSSI_BREACH_EVENT:
{
WMI_RSSI_BREACH_EVENTID_param_tlvs param;
wma_wow_wake_up_stats(wma, NULL, 0,
WOW_REASON_RSSI_BREACH_EVENT);
WMA_LOGD("Host woken up because of rssi breach reason");
/* rssi breach event is embedded in wow_packet_buffer */
if (param_buf->wow_packet_buffer) {
if (wow_buf_pkt_len >= sizeof(param)) {
param.fixed_param =
(wmi_rssi_breach_event_fixed_param *)
(param_buf->wow_packet_buffer + 4);
wma_rssi_breached_event_handler(handle,
(u_int8_t *)&param,
sizeof(param));
} else {
WMA_LOGE("%s: Wrong length: %d bytes",
__func__, wow_buf_pkt_len);
}
} else
WMA_LOGD("No wow_packet_buffer present");
}
break;
#ifdef WLAN_FEATURE_NAN
case WOW_REASON_NAN_EVENT:
{
WMI_NAN_EVENTID_param_tlvs param;
WMA_LOGA("Host woken up due to NAN event reason");
/* First 4-bytes of wow_packet_buffer is the length */
param.fixed_param = (wmi_nan_event_hdr *)
(((u_int8_t *) wake_info)
+ sizeof(WOW_EVENT_INFO_fixed_param)
+ WOW_NAN_EVENT_OFFSET);
wma_nan_rsp_event_handler(handle,
(u_int8_t *)&param,
sizeof(param));
}
break;
#endif
case WOW_REASON_NAN_DATA:
WMA_LOGD(FL("Host woken up for NAN data event from FW"));
if (param_buf->wow_packet_buffer) {
WMA_LOGD(FL("wow_packet_buffer dump"));
vos_trace_hex_dump(VOS_MODULE_ID_WDA,
VOS_TRACE_LEVEL_DEBUG,
param_buf->wow_packet_buffer,
wow_buf_pkt_len);
wma_ndp_wow_event_callback(handle,
(u_int8_t *)(param_buf->wow_packet_buffer + 4),
wow_buf_pkt_len);
} else {
WMA_LOGE(FL("wow_packet_buffer is empty"));
}
break;
#ifdef FEATURE_WLAN_TDLS
case WOW_REASON_TDLS_CONN_TRACKER_EVENT:
if (param_buf->wow_packet_buffer) {
WMA_LOGD("Host woken up because of TDLS event");
tdls_param.fixed_param =
(wmi_tdls_peer_event_fixed_param *)
(param_buf->wow_packet_buffer + 4);
wma_tdls_event_handler(handle,
(u_int8_t *)&tdls_param, sizeof(tdls_param));
} else {
WMA_LOGD("No wow_packet_buffer present");
}
break;
#endif
case WOW_REASON_OEM_RESPONSE_EVENT:
wma_wow_wake_up_stats(wma, NULL, 0,
WOW_REASON_OEM_RESPONSE_EVENT);
if (param_buf->wow_packet_buffer) {
WMA_LOGD(FL("Host woken up by OEM Response event"));
vos_trace_hex_dump(VOS_MODULE_ID_WDA,
VOS_TRACE_LEVEL_DEBUG,
param_buf->wow_packet_buffer,
wow_buf_pkt_len);
wma_oem_data_response_handler(handle,
(uint8_t*)(param_buf->wow_packet_buffer),
wow_buf_pkt_len);
} else {
WMA_LOGD(FL("No wow_packet_buffer for OEM response"));
}
break;
case WOW_REASON_CHIP_POWER_FAILURE_DETECT:
{
/* Just update stats and exit */
wma_wow_wake_up_stats(wma, NULL, 0,
WOW_REASON_CHIP_POWER_FAILURE_DETECT);
WMA_LOGD("Host woken up because of chip power save failure");
}
break;
default:
break;
}
wake_lock_duration =
wma_wow_get_wakelock_duration(wake_info->wake_reason);
if (wake_lock_duration) {
vos_wake_lock_t *wake_lock = wma_wow_get_wakelock(wma,
wake_info->wake_reason);
if (wake_lock)
vos_wake_lock_timeout_acquire(wake_lock,
wake_lock_duration,
WIFI_POWER_EVENT_WAKELOCK_WOW);
WMA_LOGA("Holding %d msec wake_lock", wake_lock_duration);
}
return 0;
}
static inline void wma_set_wow_bus_suspend(tp_wma_handle wma, int val) {
adf_os_atomic_set(&wma->is_wow_bus_suspended, val);
}
static inline int wma_get_wow_bus_suspend(tp_wma_handle wma) {
return adf_os_atomic_read(&wma->is_wow_bus_suspended);
}
static const u8 *wma_wow_wakeup_event_str(WOW_WAKE_EVENT_TYPE event)
{
switch (event) {
case WOW_BMISS_EVENT:
return "WOW_BMISS_EVENT";
case WOW_BETTER_AP_EVENT:
return "WOW_BETTER_AP_EVENT";
case WOW_DEAUTH_RECVD_EVENT:
return "WOW_DEAUTH_RECVD_EVENT";
case WOW_MAGIC_PKT_RECVD_EVENT:
return "WOW_MAGIC_PKT_RECVD_EVENT";
case WOW_GTK_ERR_EVENT:
return "WOW_GTK_ERR_EVENT";
case WOW_FOURWAY_HSHAKE_EVENT:
return "WOW_GTK_ERR_EVENT";
case WOW_EAPOL_RECVD_EVENT:
return "WOW_EAPOL_RECVD_EVENT";
case WOW_NLO_DETECTED_EVENT:
return "WOW_NLO_DETECTED_EVENT";
case WOW_DISASSOC_RECVD_EVENT:
return "WOW_DISASSOC_RECVD_EVENT";
case WOW_PATTERN_MATCH_EVENT:
return "WOW_PATTERN_MATCH_EVENT";
case WOW_CSA_IE_EVENT:
return "WOW_CSA_IE_EVENT";
case WOW_PROBE_REQ_WPS_IE_EVENT:
return "WOW_PROBE_REQ_WPS_IE_EVENT";
case WOW_AUTH_REQ_EVENT:
return "WOW_AUTH_REQ_EVENT";
case WOW_ASSOC_REQ_EVENT:
return "WOW_ASSOC_REQ_EVENT";
case WOW_HTT_EVENT:
return "WOW_HTT_EVENT";
case WOW_RA_MATCH_EVENT:
return "WOW_RA_MATCH_EVENT";
case WOW_HOST_AUTO_SHUTDOWN_EVENT:
return "WOW_HOST_AUTO_SHUTDOWN_EVENT";
case WOW_IOAC_MAGIC_EVENT:
return "WOW_IOAC_MAGIC_EVENT";
case WOW_IOAC_SHORT_EVENT:
return "WOW_IOAC_SHORT_EVENT";
case WOW_IOAC_EXTEND_EVENT:
return "WOW_IOAC_EXTEND_EVENT";
case WOW_IOAC_TIMER_EVENT:
return "WOW_IOAC_TIMER_EVENT";
case WOW_DFS_PHYERR_RADAR_EVENT:
return "WOW_DFS_PHYERR_RADAR_EVENT";
case WOW_BEACON_EVENT:
return "WOW_BEACON_EVENT";
case WOW_CLIENT_KICKOUT_EVENT:
return "WOW_CLIENT_KICKOUT_EVENT";
case WOW_NAN_EVENT:
return "WOW_NAN_EVENT";
case WOW_EXTSCAN_EVENT:
return "WOW_EXTSCAN_EVENT";
case WOW_IOAC_REV_KA_FAIL_EVENT:
return "WOW_IOAC_REV_KA_FAIL_EVENT";
case WOW_IOAC_SOCK_EVENT:
return "WOW_IOAC_SOCK_EVENT";
case WOW_NLO_SCAN_COMPLETE_EVENT:
return "WOW_NLO_SCAN_COMPLETE_EVENT";
case WOW_NAN_DATA_EVENT:
return "WOW_NAN_DATA_EVENT";
case WOW_TDLS_CONN_TRACKER_EVENT:
return "WOW_TDLS_CONN_TRACKER_EVENT";
case WOW_OEM_RESPONSE_EVENT:
return "WOW_OEM_RESPONSE_EVENT";
case WOW_CHIP_POWER_FAILURE_DETECT_EVENT:
return "WOW_CHIP_POWER_FAILURE_DETECT_EVENT";
default:
return "UNSPECIFIED_EVENT";
}
}
/**
* wma_add_wow_wakeup_event() - Update WOW wakeup event masks
* @wma: WMA context
* @event: Event number to add
* @enable: 1 to enable and 0 to disable the event
*
* Sets or clears the bits in enable and disable bitmasks for the
* given event number.
*
* Return: none
*/
void wma_add_wow_wakeup_event(tp_wma_handle wma,
WOW_WAKE_EVENT_TYPE event,
bool enable)
{
uint32_t idx, bit_idx;
if (event == 0) {
idx = bit_idx = 0;
}
else {
idx = event / WOW_BITMAP_FIELD_SIZE;
bit_idx = event % WOW_BITMAP_FIELD_SIZE;
}
if (enable) {
wma->wow_wakeup_enable_mask[idx] |= 1 << bit_idx;
wma->wow_wakeup_disable_mask[idx] &= ~(1 << bit_idx);
} else {
wma->wow_wakeup_disable_mask[idx] |= 1 << bit_idx;
wma->wow_wakeup_enable_mask[idx] &= ~(1 << bit_idx);
}
WMA_LOGD(FL("%s event %s"),
enable ? "enable" : "disable",
wma_wow_wakeup_event_str(event));
}
/**
* wma_send_wakeup_mask() - Enable/Disable the wakeup patterns
* @wma: WMA Handle
* @enable: boolean to enable/disable the pattern in FW
*
* The API configures the bitmap mask for WoW wakeup patterns.
* The Patterns are used to filter out packets in FW during APPS
* Power collapse
*
* Return: 0 on success; else failure
*/
static VOS_STATUS wma_send_wakeup_mask(tp_wma_handle wma, bool enable)
{
WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *cmd;
u_int16_t len;
wmi_buf_t buf;
int ret;
len = sizeof(WMI_WOW_ADD_DEL_EVT_CMD_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed to allocate buf for wow wakeup mask",
__func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_ADD_DEL_EVT_CMD_fixed_param));
cmd->vdev_id = 0;
cmd->is_add = enable;
if (cmd->is_add)
vos_mem_copy(cmd->event_bitmaps, wma->wow_wakeup_enable_mask,
WMI_WOW_MAX_EVENT_BM_LEN * sizeof(uint32_t));
else
vos_mem_copy(cmd->event_bitmaps, wma->wow_wakeup_disable_mask,
WMI_WOW_MAX_EVENT_BM_LEN * sizeof(uint32_t));
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID);
if (ret) {
WMA_LOGE("Failed to config wow wakeup event");
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("%s Wakeup pattern 0x%x %s in fw", __func__,
cmd->event_bitmap, enable ? "enabled":"disabled");
return VOS_STATUS_SUCCESS;
}
/* Sends WOW patterns to FW. */
static VOS_STATUS wma_send_wow_patterns_to_fw(tp_wma_handle wma,
u_int8_t vdev_id, u_int8_t ptrn_id,
const u_int8_t *ptrn, const u_int8_t ptrn_len,
const u_int8_t ptrn_offset, const u_int8_t *mask,
u_int8_t mask_len)
{
WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd;
WOW_BITMAP_PATTERN_T *bitmap_pattern;
wmi_buf_t buf;
u_int8_t *buf_ptr;
#ifdef WMA_DUMP_WOW_PTRN
u_int8_t pos;
u_int8_t *tmp;
#endif
int32_t len;
int ret;
len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) +
WMI_TLV_HDR_SIZE +
1 * sizeof(WOW_BITMAP_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_MAGIC_PATTERN_CMD) +
WMI_TLV_HDR_SIZE +
0 * sizeof(A_UINT32) +
WMI_TLV_HDR_SIZE +
1 * sizeof(A_UINT32);
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_WOW_ADD_PATTERN_CMD_fixed_param *)wmi_buf_data(buf);
buf_ptr = (u_int8_t *)cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_ADD_PATTERN_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->pattern_id = ptrn_id;
cmd->pattern_type = WOW_BITMAP_PATTERN;
buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(WOW_BITMAP_PATTERN_T));
buf_ptr += WMI_TLV_HDR_SIZE;
bitmap_pattern = (WOW_BITMAP_PATTERN_T *)buf_ptr;
WMITLV_SET_HDR(&bitmap_pattern->tlv_header,
WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T,
WMITLV_GET_STRUCT_TLVLEN(WOW_BITMAP_PATTERN_T));
vos_mem_copy(&bitmap_pattern->patternbuf[0], ptrn, ptrn_len);
vos_mem_copy(&bitmap_pattern->bitmaskbuf[0], mask, mask_len);
bitmap_pattern->pattern_offset = ptrn_offset;
bitmap_pattern->pattern_len = ptrn_len;
if(bitmap_pattern->pattern_len > WOW_DEFAULT_BITMAP_PATTERN_SIZE)
bitmap_pattern->pattern_len = WOW_DEFAULT_BITMAP_PATTERN_SIZE;
if(bitmap_pattern->pattern_len > WOW_DEFAULT_BITMASK_SIZE)
bitmap_pattern->pattern_len = WOW_DEFAULT_BITMASK_SIZE;
bitmap_pattern->bitmask_len = bitmap_pattern->pattern_len;
bitmap_pattern->pattern_id = ptrn_id;
WMA_LOGD("vdev id : %d, ptrn id: %d, ptrn len: %d, ptrn offset: %d",
cmd->vdev_id, cmd->pattern_id, bitmap_pattern->pattern_len,
bitmap_pattern->pattern_offset);
#ifdef WMA_DUMP_WOW_PTRN
printk("Pattern : ");
tmp = (u_int8_t *) &bitmap_pattern->patternbuf[0];
for (pos = 0; pos < bitmap_pattern->pattern_len; pos++)
printk("%02X ", tmp[pos]);
printk("\nMask : ");
tmp = (u_int8_t *) &bitmap_pattern->bitmaskbuf[0];
for (pos = 0; pos < bitmap_pattern->pattern_len; pos++)
printk("%02X ", tmp[pos]);
#endif
buf_ptr += sizeof(WOW_BITMAP_PATTERN_T);
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for pattern_info_timeout but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for ra_ratelimit_interval with dummy data as this fix elem*/
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 1 * sizeof(A_UINT32));
buf_ptr += WMI_TLV_HDR_SIZE;
*(A_UINT32 *)buf_ptr = 0;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_WOW_ADD_WAKE_PATTERN_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send wow ptrn to fw", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/* Sends delete pattern request to FW for given pattern ID on particular vdev */
static VOS_STATUS wma_del_wow_pattern_in_fw(tp_wma_handle wma,
u_int8_t ptrn_id)
{
WMI_WOW_DEL_PATTERN_CMD_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
len = sizeof(WMI_WOW_DEL_PATTERN_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_WOW_DEL_PATTERN_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_DEL_PATTERN_CMD_fixed_param));
cmd->vdev_id = 0;
cmd->pattern_id = ptrn_id;
cmd->pattern_type = WOW_BITMAP_PATTERN;
WMA_LOGD("Deleting pattern id: %d in fw", cmd->pattern_id);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_WOW_DEL_WAKE_PATTERN_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to delete wow ptrn from fw", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_D0WOW
void wma_set_d0wow_flag(tp_wma_handle wma_handle, A_BOOL flag)
{
atomic_set(&wma_handle->in_d0wow, flag);
}
A_BOOL wma_read_d0wow_flag(tp_wma_handle wma_handle)
{
return atomic_read(&wma_handle->in_d0wow);
}
/* Enable D0-WOW in firmware. */
VOS_STATUS wma_enable_d0wow_in_fw(tp_wma_handle wma)
{
wmi_d0_wow_enable_disable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int host_credits;
int wmi_pending_cmds;
int ret = 0;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
len = sizeof(wmi_d0_wow_enable_disable_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed to allocate WMI buffer!", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_d0_wow_enable_disable_cmd_fixed_param));
cmd->enable = 1;
vos_event_reset(&wma->target_suspend);
wma->wow_nack = 0;
host_credits = wmi_get_host_credits(wma->wmi_handle);
wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle);
if (host_credits < WMI_WOW_REQUIRED_CREDITS) {
WMA_LOGE("%s: Not enough credits to post "
"WMI_D0_WOW_ENABLE_DISABLE_CMDID, try anyway! "
"Credits: %d, pending_cmds: %d", __func__,
host_credits, wmi_pending_cmds);
}
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_D0_WOW_ENABLE_DISABLE_CMDID);
if (ret) {
WMA_LOGE("Failed to enable D0-WOW in FW!");
goto error;
}
vos_status = vos_wait_single_event(&wma->target_suspend,
WMA_TGT_SUSPEND_COMPLETE_TIMEOUT);
if (VOS_STATUS_SUCCESS != vos_status) {
WMA_LOGE("Failed to receive D0-WoW enable HTC ACK from FW! "
"Credits: %d, pending_cmds: %d",
wmi_get_host_credits(wma->wmi_handle),
wmi_get_pending_cmds(wma->wmi_handle));
if (vos_is_logp_in_progress(VOS_MODULE_ID_WDA, NULL)) {
VOS_ASSERT(0);
return VOS_STATUS_E_FAILURE;
} else {
VOS_BUG(0);
return VOS_STATUS_E_FAILURE;
}
}
if (wma->wow_nack) {
WMA_LOGE("FW not ready for D0WOW.");
return VOS_STATUS_E_AGAIN;
}
host_credits = wmi_get_host_credits(wma->wmi_handle);
wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle);
if (host_credits < WMI_WOW_REQUIRED_CREDITS) {
WMA_LOGE("%s: No credits after HTC ACK: %d, pending_cmds: %d, "
"cannot resume back!", __func__, host_credits,
wmi_pending_cmds);
HTC_dump_counter_info(wma->htc_handle);
}
wma->wow.wow_enable_cmd_sent = TRUE;
wmi_set_d0wow_flag(wma->wmi_handle, TRUE);
wma_set_d0wow_flag(wma, TRUE);
WMA_LOGD("D0-WOW is enabled successfully in FW.");
return vos_status;
error:
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
#endif /* FEATURE_WLAN_D0WOW */
/* Enables WOW in firmware. */
int wma_enable_wow_in_fw(WMA_HANDLE handle, int runtime_pm)
{
tp_wma_handle wma = handle;
wmi_wow_enable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int ret;
struct ol_softc *scn;
int host_credits;
int wmi_pending_cmds;
#ifdef CONFIG_CNSS
tpAniSirGlobal pMac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == pMac) {
WMA_LOGE("%s: Unable to get PE context", __func__);
return VOS_STATUS_E_FAILURE;
}
#endif
#ifdef FEATURE_WLAN_D0WOW
if (wma->ap_client_cnt > 0) {
WMA_LOGD("Entering D0-WOW since client count is %d.",
wma->ap_client_cnt);
return wma_enable_d0wow_in_fw(wma);
}
#endif
len = sizeof(wmi_wow_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_wow_enable_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_wow_enable_cmd_fixed_param));
cmd->enable = TRUE;
vos_event_reset(&wma->target_suspend);
vos_event_reset(&wma->wow_tx_complete);
wma->wow_nack = 0;
host_credits = wmi_get_host_credits(wma->wmi_handle);
wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle);
WMA_LOGD("Credits:%d; Pending_Cmds: %d",
host_credits, wmi_pending_cmds);
#if !defined(HIF_SDIO)
if (!runtime_pm && host_credits < WMI_WOW_REQUIRED_CREDITS) {
WMA_LOGE("%s: Not enough credits but trying to send WoW enable"
" anyway! Credits:%d, pending_cmds:%d\n", __func__,
host_credits, wmi_pending_cmds);
}
#endif
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_WOW_ENABLE_CMDID);
if (ret) {
WMA_LOGE("Failed to enable wow in fw");
goto error;
}
wmi_set_target_suspend(wma->wmi_handle, TRUE);
if (vos_wait_single_event(&wma->target_suspend,
WMA_TGT_SUSPEND_COMPLETE_TIMEOUT)
!= VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to receive WoW Enable Ack from FW");
if (wma_did_ssr_happen(wma)) {
WMA_LOGE("%s: SSR happened while waiting for response",
__func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGE("Credits:%d; Pending_Cmds: %d",
wmi_get_host_credits(wma->wmi_handle),
wmi_get_pending_cmds(wma->wmi_handle));
wmi_set_target_suspend(wma->wmi_handle, FALSE);
if (!vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)) {
#ifdef CONFIG_CNSS
if (pMac->sme.enableSelfRecovery) {
vos_trigger_recovery(false);
} else {
vos_force_fw_dump();
}
#else
vos_force_fw_dump();
#endif
} else {
WMA_LOGE("%s: LOGP is in progress, ignore!", __func__);
}
return VOS_STATUS_E_FAILURE;
}
if (wma->wow_nack) {
WMA_LOGE("FW not ready to WOW");
wmi_set_target_suspend(wma->wmi_handle, FALSE);
return VOS_STATUS_E_AGAIN;
}
host_credits = wmi_get_host_credits(wma->wmi_handle);
wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle);
if (host_credits < WMI_WOW_REQUIRED_CREDITS) {
WMA_LOGE("%s: No Credits after HTC ACK:%d, pending_cmds:%d, "
"cannot resume back", __func__, host_credits, wmi_pending_cmds);
HTC_dump_counter_info(wma->htc_handle);
if (!vos_is_logp_in_progress(VOS_MODULE_ID_HIF, NULL))
VOS_BUG(0);
else
WMA_LOGE("%s: SSR in progress, ignore no credit issue", __func__);
}
WMA_LOGD("WOW enabled successfully in fw: credits:%d"
"pending_cmds: %d", host_credits, wmi_pending_cmds);
scn = vos_get_context(VOS_MODULE_ID_HIF, wma->vos_context);
if (scn == NULL) {
WMA_LOGE("%s: Failed to get HIF context", __func__);
VOS_ASSERT(0);
return VOS_STATUS_E_FAULT;
}
wma->wow.wow_enable_cmd_sent = TRUE;
return VOS_STATUS_SUCCESS;
error:
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
/* Sends user configured WOW patterns to the firmware. */
static VOS_STATUS wma_wow_usr(tp_wma_handle wma, u_int8_t vdev_id,
u_int8_t *enable_ptrn_match)
{
struct wma_wow_ptrn_cache *cache;
VOS_STATUS ret = VOS_STATUS_SUCCESS;
u_int8_t new_mask[SIR_WOWL_BCAST_PATTERN_MAX_SIZE];
u_int8_t bit_to_check, ptrn_id, pos;
WMA_LOGD("Configuring user wow patterns for vdev %d", vdev_id);
for (ptrn_id = 0; ptrn_id < WOW_MAX_BITMAP_FILTERS; ptrn_id++) {
cache = wma->wow.cache[ptrn_id];
if (!cache)
continue;
if (cache->vdev_id != vdev_id)
continue;
/*
* Convert received pattern mask value from bit representaion
* to byte representation.
*
* For example, received value from umac,
*
* Mask value : A1 (equivalent binary is "1010 0001")
* Pattern value : 12:00:13:00:00:00:00:44
*
* The value which goes to FW after the conversion from this
* function (1 in mask value will become FF and 0 will
* become 00),
*
* Mask value : FF:00:FF:00:0:00:00:FF
* Pattern value : 12:00:13:00:00:00:00:44
*/
vos_mem_zero(new_mask, sizeof(new_mask));
for (pos = 0; pos < cache->ptrn_len; pos++) {
bit_to_check = (WMA_NUM_BITS_IN_BYTE - 1) -
(pos % WMA_NUM_BITS_IN_BYTE);
bit_to_check = 0x1 << bit_to_check;
if (cache->mask[pos / WMA_NUM_BITS_IN_BYTE] & bit_to_check)
new_mask[pos] = WMA_WOW_PTRN_MASK_VALID;
}
ret = wma_send_wow_patterns_to_fw(wma, vdev_id, ptrn_id,
cache->ptrn, cache->ptrn_len,
cache->ptrn_offset, new_mask,
cache->ptrn_len);
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to submit wow pattern to fw (ptrn_id %d)",
ptrn_id);
break;
}
}
*enable_ptrn_match = 1 << vdev_id;
return ret;
}
/* Configures default WOW pattern for the given vdev_id which is in AP mode. */
static VOS_STATUS wma_wow_ap(tp_wma_handle wma, u_int8_t vdev_id,
u_int8_t *enable_ptrn_match)
{
static const u_int8_t arp_ptrn[] = { 0x08, 0x06 };
static const u_int8_t arp_mask[] = { 0xff, 0xff };
static const u_int8_t arp_offset = 20;
VOS_STATUS ret;
/* Setup all ARP pkt pattern. This is dummy pattern hence the lenght
is zero */
ret = wma_send_wow_patterns_to_fw(wma, vdev_id,
wma->wow.free_ptrn_id[wma->wow.used_free_ptrn_id++],
arp_ptrn, 0, arp_offset,
arp_mask, 0);
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to add WOW ARP pattern");
return ret;
}
*enable_ptrn_match = 1 << vdev_id;
return ret;
}
#ifdef FEATURE_WLAN_RA_FILTERING
static VOS_STATUS wma_wow_sta_ra_filter(tp_wma_handle wma, u_int8_t vdev_id)
{
WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int32_t len;
int ret;
len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_BITMAP_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) +
WMI_TLV_HDR_SIZE +
0 * sizeof(WOW_MAGIC_PATTERN_CMD) +
WMI_TLV_HDR_SIZE +
0 * sizeof(A_UINT32) +
WMI_TLV_HDR_SIZE +
1 * sizeof(A_UINT32);
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_WOW_ADD_PATTERN_CMD_fixed_param *)wmi_buf_data(buf);
buf_ptr = (u_int8_t *)cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_ADD_PATTERN_CMD_fixed_param));
cmd->vdev_id = vdev_id;
cmd->pattern_id = 0;
cmd->pattern_type = WOW_IPV6_RA_PATTERN;
buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param);
/* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for pattern_info_timeout but no data. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill TLV for ra_ratelimit_interval. */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(A_UINT32));
buf_ptr += WMI_TLV_HDR_SIZE;
*((A_UINT32 *)buf_ptr) = wma->RArateLimitInterval;
WMA_LOGD("%s: send RA rate limit [%d] to fw vdev = %d", __func__,
wma->RArateLimitInterval, vdev_id);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_WOW_ADD_WAKE_PATTERN_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send RA rate limit to fw", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#endif /* FEATURE_WLAN_RA_FILTERING */
/**
* wma_configure_wow_ssdp() - API to configure WoW SSDP
* @wma: WMA Handle
* @vdev_id: Vdev Id
*
* API to configure SSDP pattern as WoW pattern
*
* Return: Success/Failure
*/
static VOS_STATUS wma_configure_wow_ssdp(tp_wma_handle wma, uint8_t vdev_id)
{
VOS_STATUS status = VOS_STATUS_SUCCESS;
static const uint8_t discvr_ptrn[] = { 0xe0, 0x00, 0x00, 0xf8 };
static const uint8_t discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
static const uint8_t discvr_offset = 30;
status = wma_send_wow_patterns_to_fw(wma, vdev_id,
wma->wow.free_ptrn_id[wma->
wow.used_free_ptrn_id++],
discvr_ptrn, sizeof(discvr_ptrn),
discvr_offset, discvr_mask,
sizeof(discvr_ptrn));
if (status != VOS_STATUS_SUCCESS)
WMA_LOGE("Failed to add WOW mDNS/SSDP/LLMNR pattern");
return status;
}
/**
* wma_configure_mc_ssdp() - API to configure SSDP address as MC list
* @wma: WMA Handle
* @vdev_id: Vdev Id
*
* SSDP address 239.255.255.250 is converted to Multicast Mac address
* and configure it to FW. Firmware will apply this pattern on the incoming
* packets to filter them out during chatter/wow mode.
*
* Return: Success/Failure
*/
static VOS_STATUS wma_configure_mc_ssdp(tp_wma_handle wma, uint8_t vdev_id)
{
WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd;
wmi_buf_t buf;
const tSirMacAddr ssdp_addr = {0x01, 0x00, 0x5e, 0x7f, 0xff, 0xfa};
int ret;
uint32_t tag =
WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param;
WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param fixed_param;
buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("%s No Memory for MC address", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header, tag,
WMITLV_GET_STRUCT_TLVLEN(fixed_param));
cmd->action = WMI_MCAST_FILTER_SET;
cmd->vdev_id = vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(ssdp_addr, &cmd->mcastbdcastaddr);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, sizeof(*cmd),
WMI_SET_MCASTBCAST_FILTER_CMDID);
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s Failed to configure FW with SSDP MC address",
__func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_configure_ssdp() - API to Configure SSDP pattern to FW
* @wma: WMA Handle
* @vdev_id: Vdev Id
*
* Setup multicast pattern for mDNS 224.0.0.251,
* SSDP 239.255.255.250 and LLMNR 224.0.0.252
*
* Return: Success/Failure.
*/
static VOS_STATUS wma_configure_ssdp(tp_wma_handle wma, uint8_t vdev_id)
{
if (!wma->ssdp) {
WMA_LOGD("mDNS, SSDP, LLMNR patterns are disabled from ini");
return VOS_STATUS_SUCCESS;
}
WMA_LOGD("%s, enable_mc_list:%d", __func__, wma->enable_mc_list);
if (wma->enable_mc_list)
return wma_configure_mc_ssdp(wma, vdev_id);
else
return wma_configure_wow_ssdp(wma, vdev_id);
}
/* Configures default WOW pattern for the given vdev_id which is in STA mode. */
static VOS_STATUS wma_wow_sta(tp_wma_handle wma, u_int8_t vdev_id,
u_int8_t *enable_ptrn_match, bool runtime_pm)
{
u_int8_t mac_mask[ETH_ALEN], free_slot;
VOS_STATUS ret = VOS_STATUS_SUCCESS;
static const u_int8_t arp_ptrn[] = { 0x08, 0x06 };
static const u_int8_t arp_mask[] = { 0xff, 0xff };
static const u_int8_t arp_offset = 12;
static const u_int8_t ns_ptrn[] = {0x86, 0xDD};
static const u_int8_t bcst_ptrn[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static const u_int8_t bcst_mask[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static const u_int8_t bcst_offset = 0;
free_slot = wma->wow.total_free_ptrn_id - wma->wow.used_free_ptrn_id ;
if (free_slot < WMA_STA_WOW_DEFAULT_PTRN_MAX) {
WMA_LOGD("Free slots are not enough, avail:%d, need: %d",
free_slot, WMA_STA_WOW_DEFAULT_PTRN_MAX);
WMA_LOGD("Ignoring default STA mode wow pattern for vdev : %d",
vdev_id);
return ret;
}
WMA_LOGD("Configuring default STA mode wow pattern for vdev %d",
vdev_id);
/* Setup unicast pkt pattern */
vos_mem_set(&mac_mask, ETH_ALEN, 0xFF);
ret = wma_send_wow_patterns_to_fw(wma, vdev_id,
wma->wow.free_ptrn_id[wma->wow.used_free_ptrn_id++],
wma->interfaces[vdev_id].addr, ETH_ALEN, 0,
mac_mask, ETH_ALEN);
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to add WOW unicast pattern");
return ret;
}
if (runtime_pm && wma->enable_bcst_ptrn) {
ret = wma_send_wow_patterns_to_fw(wma, vdev_id,
wma->wow.free_ptrn_id[wma->wow.used_free_ptrn_id++],
bcst_ptrn, sizeof(bcst_ptrn), bcst_offset,
bcst_mask, sizeof(bcst_mask));
if (ret != VOS_STATUS_SUCCESS)
WMA_LOGE("Failed to add BCAST wakeup pattern");
}
ret = wma_configure_ssdp(wma, vdev_id);
if (ret != VOS_STATUS_SUCCESS)
WMA_LOGE("Failed to configure SSDP patterns to FW");
/* when arp offload or ns offloaded is disabled
* from ini file, configure broad cast arp pattern
* to fw, so that host can wake up
*/
if (runtime_pm || !(wma->ol_ini_info & 0x1)) {
/* Setup all ARP pkt pattern */
ret = wma_send_wow_patterns_to_fw(wma, vdev_id,
wma->wow.free_ptrn_id[wma->wow.used_free_ptrn_id++],
arp_ptrn, sizeof(arp_ptrn), arp_offset,
arp_mask, sizeof(arp_mask));
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to add WOW ARP pattern");
return ret;
}
}
/* for NS or NDP offload packets */
if (runtime_pm || !(wma->ol_ini_info & 0x2)) {
/* Setup all NS pkt pattern */
ret = wma_send_wow_patterns_to_fw(wma, vdev_id,
wma->wow.free_ptrn_id[wma->wow.used_free_ptrn_id++],
ns_ptrn, sizeof(arp_ptrn), arp_offset,
arp_mask, sizeof(arp_mask));
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to add WOW NS pattern");
return ret;
}
}
*enable_ptrn_match = 1 << vdev_id;
return ret;
}
/* Finds out list of unused slots in wow pattern cache. Those free slots number
* can be used as pattern ID while configuring default wow pattern. */
static void wma_update_free_wow_ptrn_id(tp_wma_handle wma)
{
struct wma_wow_ptrn_cache *cache;
u_int8_t ptrn_id;
vos_mem_zero(wma->wow.free_ptrn_id, sizeof(wma->wow.free_ptrn_id));
wma->wow.total_free_ptrn_id = 0;
wma->wow.used_free_ptrn_id = 0;
for (ptrn_id = 0; ptrn_id < wma->wlan_resource_config.num_wow_filters;
ptrn_id++) {
cache = wma->wow.cache[ptrn_id];
if (!cache) {
wma->wow.free_ptrn_id[wma->wow.total_free_ptrn_id] =
ptrn_id;
wma->wow.total_free_ptrn_id += 1;
}
}
/*
* Clear the wakeup pattern mask to ensure, we configure the
* wakeup patterns properly to FW.
*/
vos_mem_zero(wma->wow_wakeup_enable_mask,
sizeof(wma->wow_wakeup_enable_mask));
vos_mem_zero(wma->wow_wakeup_disable_mask,
sizeof(wma->wow_wakeup_enable_mask));
WMA_LOGD("Total free wow pattern id for default patterns: %d",
wma->wow.total_free_ptrn_id );
}
/* Returns true if the user configured any wow pattern for given vdev id */
static bool wma_is_wow_prtn_cached(tp_wma_handle wma, u_int8_t vdev_id)
{
struct wma_wow_ptrn_cache *cache;
u_int8_t ptrn_id;
for (ptrn_id = 0; ptrn_id < WOW_MAX_BITMAP_FILTERS; ptrn_id++) {
cache = wma->wow.cache[ptrn_id];
if (!cache)
continue;
if (cache->vdev_id == vdev_id)
return true;
}
return false;
}
/* Unpause all the vdev after resume */
static void wma_unpause_vdev(tp_wma_handle wma) {
int8_t vdev_id;
struct wma_txrx_node *iface;
for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) {
if (!wma->interfaces[vdev_id].handle)
continue;
#if defined(CONFIG_HL_SUPPORT) || defined(QCA_SUPPORT_TXRX_VDEV_PAUSE_LL)
/* When host resume, by default, unpause all active vdev */
if (wma->interfaces[vdev_id].pause_bitmap) {
wdi_in_vdev_unpause(wma->interfaces[vdev_id].handle,
0xffffffff);
wma->interfaces[vdev_id].pause_bitmap = 0;
}
#endif /* QCA_SUPPORT_TXRX_VDEV_PAUSE_LL || CONFIG_HL_SUPPORT */
iface = &wma->interfaces[vdev_id];
iface->conn_state = FALSE;
}
}
static VOS_STATUS wma_resume_req(tp_wma_handle wma, bool runtime_pm)
{
VOS_STATUS ret = VOS_STATUS_E_AGAIN;
u_int8_t ptrn_id;
if (runtime_pm)
goto skip_vdev_suspend;
wma->no_of_resume_ind++;
if (wma->no_of_resume_ind < wma_get_vdev_count(wma))
return VOS_STATUS_SUCCESS;
wma->no_of_resume_ind = 0;
skip_vdev_suspend:
WMA_LOGD("Clearing already configured wow patterns in fw%s,"
" wow_enable: %d, wow_enable_cmd_sent: %d",
runtime_pm ? " for runtime PM" : "",
wma->wow.wow_enable, wma->wow.wow_enable_cmd_sent);
if (wma->wow.wow_enable_cmd_sent) {
WMA_LOGD("Firmware is still in WoW mode, don't delete WoW"
" patterns");
VOS_ASSERT(0);
return ret;
}
if (!wma->wow.wow_enable) {
WMA_LOGD("WoW pattern not configured in FW during suspend,"
" skip delete!");
ret = VOS_STATUS_SUCCESS;
goto pdev_resume;
}
/* Clear existing wow patterns in FW. */
for (ptrn_id = 0; ptrn_id < wma->wlan_resource_config.num_wow_filters;
ptrn_id++) {
ret = wma_del_wow_pattern_in_fw(wma, ptrn_id);
if (ret != VOS_STATUS_SUCCESS)
goto end;
}
end:
wma->wow.wow_enable = FALSE;
/* Reset the DTIM Parameters */
wma_set_resume_dtim(wma);
pdev_resume:
wmi_set_runtime_pm_inprogress(wma->wmi_handle, FALSE);
/* need to reset if hif_pci_suspend_fails */
wma_set_wow_bus_suspend(wma, 0);
/* unpause the vdev if left paused and hif_pci_suspend fails */
wma_unpause_vdev(wma);
if (runtime_pm)
vos_runtime_pm_allow_suspend(wma->runtime_context.resume);
return ret;
}
/**
* wma_feed_allowed_action_frame_patterns() - config action frame map to fw
* @wma: wma handler
*
* This is called to push action frames wow patterns from local
* cache to firmware.
*
* Return: VOS_STATUS
*/
static VOS_STATUS wma_feed_allowed_action_frame_patterns(tp_wma_handle wma)
{
WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *cmd;
u_int16_t len;
wmi_buf_t buf;
int ret;
int i;
uint8_t *buf_ptr;
uint32_t *cmd_args;
len = sizeof(WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param) +
WMI_TLV_HDR_SIZE + (MAX_SUPPORTED_ACTION_CATEGORY *
sizeof(A_UINT32));
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed to allocate buf for wow action frame map",
__func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *) wmi_buf_data(buf);
buf_ptr = (uint8_t *)cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_wow_set_action_wake_up_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param));
cmd->vdev_id = 0;
cmd->operation = wma->allowed_action_frames.operation;
for (i = 0; i < MAX_SUPPORTED_ACTION_CATEGORY_ELE_LIST; i++) {
if (i < (SIR_MAC_ACTION_MAX / 32))
cmd->action_category_map[i] =
wma->allowed_action_frames.action_category_map[i];
else
cmd->action_category_map[i] = 0;
WMA_LOGD("%s: %d action Wakeup pattern 0x%x in fw",
__func__, i, cmd->action_category_map[i]);
}
buf_ptr += sizeof(WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(MAX_SUPPORTED_ACTION_CATEGORY * sizeof(A_UINT32)));
buf_ptr += WMI_TLV_HDR_SIZE;
cmd_args = (uint32_t *) buf_ptr;
for (i = 0; i < MAX_SUPPORTED_ACTION_CATEGORY; i++)
cmd_args[i] = wma->allowed_action_frames.action_per_category[i];
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_WOW_SET_ACTION_WAKE_UP_CMDID);
if (ret) {
WMA_LOGE("Failed to config wow action frame map, ret %d", ret);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/*
* Pushes wow patterns from local cache to FW and configures
* wakeup trigger events.
*/
static VOS_STATUS wma_feed_wow_config_to_fw(tp_wma_handle wma,
v_BOOL_t pno_in_progress,
bool extscan_in_progress, bool pno_matched,
bool runtime_pm)
{
struct wma_txrx_node *iface;
VOS_STATUS ret = VOS_STATUS_SUCCESS;
u_int8_t vdev_id;
u_int8_t enable_ptrn_match = 0;
v_BOOL_t ap_vdev_available = FALSE;
#ifdef QCA_IBSS_SUPPORT
v_BOOL_t ibss_vdev_available = FALSE;
#endif
bool wps_enable = false;
if (wma->wow.wow_enable) {
WMA_LOGD("Already%s Fatal Error!",
runtime_pm ? " runtime suspended" : " cfg suspended");
VOS_BUG(0);
return VOS_STATUS_E_AGAIN;
}
/* Gather list of free ptrn id. This is needed while configuring
* default wow patterns.
*/
wma_update_free_wow_ptrn_id(wma);
for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) {
iface = &wma->interfaces[vdev_id];
if (!iface->handle ||
!iface->ptrn_match_enable ||
(!(wma_is_vdev_in_ap_mode(wma, vdev_id)
#ifdef QCA_IBSS_SUPPORT
|| wma_is_vdev_in_ibss_mode(wma, vdev_id)
#endif
) && !iface->conn_state))
continue;
if (wma_is_vdev_in_ap_mode(wma, vdev_id)
#ifdef QCA_IBSS_SUPPORT
|| wma_is_vdev_in_ibss_mode(wma, vdev_id)
#endif
) {
ap_vdev_available = TRUE;
if (SAP_WPS_DISABLED != iface->wps_state)
wps_enable = true;
}
#ifdef QCA_IBSS_SUPPORT
if (wma_is_vdev_in_ibss_mode(wma, vdev_id))
ibss_vdev_available = TRUE;
#endif
if (wma_is_wow_prtn_cached(wma, vdev_id)) {
/* Configure wow patterns provided by the user */
ret = wma_wow_usr(wma, vdev_id, &enable_ptrn_match);
} else if (wma_is_vdev_in_ap_mode(wma, vdev_id)
#ifdef QCA_IBSS_SUPPORT
||wma_is_vdev_in_ibss_mode(wma, vdev_id)
#endif
)
{
/* Configure AP mode default wow patterns */
ret = wma_wow_ap(wma, vdev_id, &enable_ptrn_match);
}
else
{
/* Configure STA mode default wow patterns */
ret = wma_wow_sta(wma, vdev_id, &enable_ptrn_match,
runtime_pm);
}
#ifdef FEATURE_WLAN_RA_FILTERING
if ((ap_vdev_available == FALSE) && (wma->IsRArateLimitEnabled))
{
ret = wma_wow_sta_ra_filter(wma, vdev_id);
}
#endif
if (ret != VOS_STATUS_SUCCESS)
goto end;
}
/*
* Configure csa ie wakeup event.
*/
wma_add_wow_wakeup_event(wma, WOW_CSA_IE_EVENT, TRUE);
wma_add_wow_wakeup_event(wma, WOW_CLIENT_KICKOUT_EVENT, TRUE);
/*
* Configure pattern match wakeup event. FW does pattern match
* only if pattern match event is enabled.
*/
wma_add_wow_wakeup_event(wma, WOW_PATTERN_MATCH_EVENT,
enable_ptrn_match ? TRUE : FALSE);
/* Configure magic pattern wakeup event */
wma_add_wow_wakeup_event(wma, WOW_MAGIC_PKT_RECVD_EVENT,
wma->wow.magic_ptrn_enable);
/* Configure deauth based wakeup */
wma_add_wow_wakeup_event(wma, WOW_DEAUTH_RECVD_EVENT,
wma->wow.deauth_enable);
/* Configure disassoc based wakeup */
wma_add_wow_wakeup_event(wma, WOW_DISASSOC_RECVD_EVENT,
wma->wow.disassoc_enable);
/* Configure beacon miss based wakeup */
wma_add_wow_wakeup_event(wma, WOW_BMISS_EVENT,
wma->wow.bmiss_enable);
#ifdef WLAN_FEATURE_GTK_OFFLOAD
/* Configure GTK based wakeup. Passing vdev_id 0 because
wma_add_wow_wakeup_event always uses vdev 0 for wow wake event id*/
wma_add_wow_wakeup_event(wma, WOW_GTK_ERR_EVENT,
wma->wow.gtk_pdev_enable);
#endif
/* Configure probe req based wakeup */
if (ap_vdev_available)
wma_add_wow_wakeup_event(wma, WOW_PROBE_REQ_WPS_IE_EVENT,
wps_enable);
/* Configure auth req based wakeup */
wma_add_wow_wakeup_event(wma, WOW_AUTH_REQ_EVENT,
ap_vdev_available);
/* Configure assoc req based wakeup */
wma_add_wow_wakeup_event(wma, WOW_ASSOC_REQ_EVENT,
ap_vdev_available);
#ifdef FEATURE_WLAN_SCAN_PNO
/* Configure pno based wakeup */
wma_add_wow_wakeup_event(wma, WOW_NLO_DETECTED_EVENT,
pno_in_progress);
/* Configure pno scan complete wakeup */
wma_add_wow_wakeup_event(wma,
WOW_NLO_SCAN_COMPLETE_EVENT, pno_matched);
#endif
/* Configure roaming scan better AP based wakeup */
wma_add_wow_wakeup_event(wma, WOW_BETTER_AP_EVENT,
TRUE);
/* Configure ADDBA/DELBA wakeup */
wma_add_wow_wakeup_event(wma, WOW_HTT_EVENT, TRUE);
#ifdef FEATURE_WLAN_RA_FILTERING
/* Configure RA filter wakeup */
if (wma->IsRArateLimitEnabled)
wma_add_wow_wakeup_event(wma, WOW_RA_MATCH_EVENT, TRUE);
else
WMA_LOGD("gRAFilterEnable is not set, RA filterning is disabled");
#endif
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
wma_add_wow_wakeup_event(wma, WOW_HOST_AUTO_SHUTDOWN_EVENT, TRUE);
#endif
#ifdef QCA_IBSS_SUPPORT
/* Configure beacon based wakeup */
wma_add_wow_wakeup_event(wma, WOW_BEACON_EVENT, ibss_vdev_available);
#endif
#ifdef FEATURE_WLAN_EXTSCAN
wma_add_wow_wakeup_event(wma, WOW_EXTSCAN_EVENT, extscan_in_progress);
#endif
wma_ndp_add_wow_wakeup_event(wma, true);
#ifdef FEATURE_WLAN_TDLS
/* configure TDLS based wakeup */
wma_add_wow_wakeup_event(wma, WOW_TDLS_CONN_TRACKER_EVENT, TRUE);
#endif
wma_add_wow_wakeup_event(wma, WOW_OEM_RESPONSE_EVENT, TRUE);
/*
* Configure WOW for WOW_CHIP_POWER_FAILURE_DETECT_EVENT
* We will only check vdev 0 to configure WOW wakeup.
*/
if (wma->interfaces[0].in_bmps == true ||
wma->interfaces[0].in_imps == true)
wma_add_wow_wakeup_event(wma,
WOW_CHIP_POWER_FAILURE_DETECT_EVENT,
TRUE);
/* Enable wow wakeup events in FW */
ret = wma_send_wakeup_mask(wma, TRUE);
if (ret) {
WMA_LOGE("%s Failed to enable wow pattern mask\n", __func__);
goto end;
}
/* Disable wow wakeup events in FW */
ret = wma_send_wakeup_mask(wma, FALSE);
if (ret) {
WMA_LOGE("%s Failed to disable wow pattern mask\n", __func__);
goto end;
}
/* WOW is enabled in pcie suspend callback */
wma->wow.wow_enable = TRUE;
wma->wow.wow_enable_cmd_sent = FALSE;
end:
return ret;
}
/* Adds received wow patterns in local wow pattern cache. */
static VOS_STATUS wma_wow_add_pattern(tp_wma_handle wma,
tpSirWowlAddBcastPtrn ptrn)
{
struct wma_wow_ptrn_cache *cache;
WMA_LOGD("wow add pattern");
/* Free if there are any pattern cached already in the same slot. */
if (wma->wow.cache[ptrn->ucPatternId])
wma_free_wow_ptrn(wma, ptrn->ucPatternId);
wma->wow.cache[ptrn->ucPatternId] = (struct wma_wow_ptrn_cache *)
vos_mem_malloc(sizeof(*cache));
cache = wma->wow.cache[ptrn->ucPatternId];
if (!cache) {
WMA_LOGE("Unable to alloc memory for wow");
return VOS_STATUS_E_NOMEM;
}
cache->ptrn = (u_int8_t *) vos_mem_malloc(ptrn->ucPatternSize);
if (!cache->ptrn) {
WMA_LOGE("Unable to alloce memory to cache wow pattern");
vos_mem_free(cache);
wma->wow.cache[ptrn->ucPatternId] = NULL;
return VOS_STATUS_E_NOMEM;
}
cache->mask = (u_int8_t *) vos_mem_malloc(ptrn->ucPatternMaskSize);
if (!cache->mask) {
WMA_LOGE("Unable to alloc memory to cache wow ptrn mask");
vos_mem_free(cache->ptrn);
vos_mem_free(cache);
wma->wow.cache[ptrn->ucPatternId] = NULL;
return VOS_STATUS_E_NOMEM;
}
/* Cache wow pattern info until platform goes to suspend. */
cache->vdev_id = ptrn->sessionId;
cache->ptrn_len = ptrn->ucPatternSize;
cache->ptrn_offset = ptrn->ucPatternByteOffset;
cache->mask_len = ptrn->ucPatternMaskSize;
vos_mem_copy(cache->ptrn, ptrn->ucPattern, cache->ptrn_len);
vos_mem_copy(cache->mask, ptrn->ucPatternMask, cache->mask_len);
wma->wow.no_of_ptrn_cached++;
WMA_LOGD("wow pattern stored in cache (slot_id: %d, vdev id: %d)",
ptrn->ucPatternId, cache->vdev_id);
return VOS_STATUS_SUCCESS;
}
/* Deletes given pattern from local wow pattern cache. */
static VOS_STATUS wma_wow_del_pattern(tp_wma_handle wma,
tpSirWowlDelBcastPtrn ptrn)
{
WMA_LOGD("wow delete pattern");
if (!wma->wow.cache[ptrn->ucPatternId]) {
WMA_LOGE("wow pattern not found (pattern id: %d) in cache",
ptrn->ucPatternId);
return VOS_STATUS_E_INVAL;
}
wma_free_wow_ptrn(wma, ptrn->ucPatternId);
return VOS_STATUS_SUCCESS;
}
/*
* Records pattern enable/disable status locally. This choice will
* take effect when the driver enter into suspend state.
*/
static VOS_STATUS wma_wow_enter(tp_wma_handle wma,
tpSirHalWowlEnterParams info)
{
struct wma_txrx_node *iface;
WMA_LOGD("wow enable req received for vdev id: %d", info->sessionId);
if (info->sessionId >= wma->max_bssid) {
WMA_LOGE("Invalid vdev id (%d)", info->sessionId);
vos_mem_free(info);
return VOS_STATUS_E_INVAL;
}
iface = &wma->interfaces[info->sessionId];
iface->ptrn_match_enable = info->ucPatternFilteringEnable ?
TRUE : FALSE;
wma->wow.magic_ptrn_enable = info->ucMagicPktEnable ? TRUE : FALSE;
wma->wow.deauth_enable = info->ucWowDeauthRcv ? TRUE : FALSE;
wma->wow.disassoc_enable = info->ucWowDeauthRcv ? TRUE : FALSE;
wma->wow.bmiss_enable = info->ucWowMaxMissedBeacons ? TRUE : FALSE;
vos_mem_free(info);
return VOS_STATUS_SUCCESS;
}
/* Clears all wow states */
static VOS_STATUS wma_wow_exit(tp_wma_handle wma,
tpSirHalWowlExitParams info)
{
struct wma_txrx_node *iface;
WMA_LOGD("wow disable req received for vdev id: %d", info->sessionId);
if (info->sessionId >= wma->max_bssid) {
WMA_LOGE("Invalid vdev id (%d)", info->sessionId);
vos_mem_free(info);
return VOS_STATUS_E_INVAL;
}
iface = &wma->interfaces[info->sessionId];
iface->ptrn_match_enable = FALSE;
wma->wow.magic_ptrn_enable = FALSE;
vos_mem_free(info);
return VOS_STATUS_SUCCESS;
}
/* Handles suspend indication request received from umac. */
static VOS_STATUS wma_suspend_req(tp_wma_handle wma, tpSirWlanSuspendParam info)
{
v_BOOL_t pno_in_progress = FALSE;
VOS_STATUS ret;
u_int8_t i;
bool extscan_in_progress = false;
bool pno_matched = false;
struct wma_txrx_node *iface;
bool enable_wow = false;
if (info == NULL) {
WMA_LOGD("runtime PM: Request to suspend all interfaces");
wmi_set_runtime_pm_inprogress(wma->wmi_handle, TRUE);
goto suspend_all_iface;
}
wma->no_of_suspend_ind++;
if (info->sessionId >= wma->max_bssid) {
WMA_LOGE("Invalid vdev id (%d)", info->sessionId);
vos_mem_free(info);
return VOS_STATUS_E_INVAL;
}
iface = &wma->interfaces[info->sessionId];
if (!iface) {
WMA_LOGD("vdev %d node is not found", info->sessionId);
vos_mem_free(info);
return VOS_STATUS_SUCCESS;
}
if (!wma->wow.magic_ptrn_enable && !iface->ptrn_match_enable) {
vos_mem_free(info);
if (wma->no_of_suspend_ind == wma_get_vdev_count(wma)) {
WMA_LOGD("Both magic and pattern byte match are disabled");
wma->no_of_suspend_ind = 0;
goto send_ready_to_suspend;
}
return VOS_STATUS_SUCCESS;
}
iface->conn_state = (info->connectedState) ? TRUE : FALSE;
/*
* Once WOW is enabled in FW, host can't send anymore
* data to fw. umac sends suspend indication on each
* vdev during platform suspend. WMA has to wait until
* suspend indication received on last vdev before
* enabling wow in fw.
*/
/*
* While processing suspend indication, there is a possibility of
* vdev(SAP/P2P-GO) deletion due to stop_ap. This may lead, Host to
* send WoW indication twice to FW, as vdev is one but HDD sends
* suspend indication twice to WMA. To fix this race condition check
* for wow_enable along with vdev count.
*/
if (wma->no_of_suspend_ind < wma_get_vdev_count(wma) ||
wma->wow.wow_enable) {
vos_mem_free(info);
return VOS_STATUS_SUCCESS;
}
wma->no_of_suspend_ind = 0;
wma->wow.gtk_pdev_enable = 0;
suspend_all_iface:
if (info == NULL) {
for (i = 0; i < wma->max_bssid; i++) {
wma->interfaces[i].conn_state =
!!(wma->interfaces[i].vdev_up &&
!wma_is_vdev_in_ap_mode(wma, i));
}
}
/*
* Enable WOW if any one of the condition meets,
* 1) Is any one of vdev in beaconning mode (in AP mode) ?
* 2) Is any one of vdev in connected state (in STA mode) ?
* 3) Is PNO in progress in any one of vdev ?
* 4) Is Extscan in progress in any one of vdev ?
* 5) Is any vdev in NAN data mode? BSS is already started at the
* the time of device creation. It is ready to accept data
* requests.
*/
for (i = 0; i < wma->max_bssid; i++) {
if ((wma_is_vdev_in_ap_mode(wma, i)
#ifdef QCA_IBSS_SUPPORT
|| wma_is_vdev_in_ibss_mode(wma, i)
#endif
) && wma->interfaces[i].vdev_up &&
WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_BEACON_OFFLOAD)) {
WMA_LOGD("vdev %d is in beaconning mode, enabling wow",
i);
enable_wow = true;
}
if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, i)) {
WMA_LOGD("vdev %d is in NAN data mode, enabling wow",
i);
enable_wow = true;
}
}
for (i = 0; i < wma->max_bssid; i++) {
if (wma->interfaces[i].conn_state)
enable_wow = true;
#ifdef FEATURE_WLAN_SCAN_PNO
if (wma->interfaces[i].pno_in_progress) {
WMA_LOGD("PNO is in progress, enabling wow");
pno_in_progress = TRUE;
if (wma->interfaces[i].nlo_match_evt_received)
pno_matched = true;
break;
}
#endif
}
#ifdef FEATURE_WLAN_EXTSCAN
for (i = 0; i < wma->max_bssid; i++) {
if (wma->interfaces[i].extscan_in_progress) {
WMA_LOGD("Extscan is in progress, enabling wow");
enable_wow = true;
extscan_in_progress = true;
break;
}
}
#endif
for (i = 0; i < wma->max_bssid; i++) {
wma->wow.gtk_pdev_enable |= wma->wow.gtk_err_enable[i];
WMA_LOGD("VDEV_ID:%d, gtk_err_enable[%d]:%d, gtk_pdev_enable:%d",
i, i, wma->wow.gtk_err_enable[i],
wma->wow.gtk_pdev_enable);
}
if (!enable_wow && !pno_in_progress && !extscan_in_progress) {
WMA_LOGD("All vdev are in disconnected state and pno/extscan is not in progress, skipping wow");
vos_mem_free(info);
goto send_ready_to_suspend;
}
WMA_LOGD("%sWOW Suspend", info ? "" : "Runtime PM ");
/*
* At this point, suspend indication is received on
* last vdev. It's the time to enable wow in fw.
*/
#ifdef FEATURE_WLAN_LPHB
/* LPHB cache, if any item was enabled, should be
* applied.
*/
WMA_LOGD("%s: checking LPHB cache", __func__);
for (i = 0; i < 2; i++) {
if (wma->wow.lphb_cache[i].params.lphbEnableReq.enable) {
WMA_LOGD("%s: LPHB cache for item %d is marked as enable",
__func__, i + 1);
wma_lphb_conf_hbenable(
wma,
&(wma->wow.lphb_cache[i]),
FALSE);
}
}
#endif
wma_feed_allowed_action_frame_patterns(wma);
ret = wma_feed_wow_config_to_fw(wma, pno_in_progress,
extscan_in_progress, pno_matched,
info == NULL);
if (ret != VOS_STATUS_SUCCESS) {
wma_send_status_to_suspend_ind(wma, FALSE, info == NULL);
vos_mem_free(info);
return ret;
}
vos_mem_free(info);
send_ready_to_suspend:
/* Set the Suspend DTIM Parameters */
wma_set_suspend_dtim(wma);
/* to handle race between hif_pci_suspend and
* unpause/pause tx handler
*/
wma_set_wow_bus_suspend(wma, 1);
wma_send_status_to_suspend_ind(wma, TRUE, info == NULL);
return VOS_STATUS_SUCCESS;
}
/*
* Sends host wakeup indication to FW. On receiving this indication,
* FW will come out of WOW.
*/
static VOS_STATUS wma_send_host_wakeup_ind_to_fw(tp_wma_handle wma)
{
wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *cmd;
wmi_buf_t buf;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int32_t len;
int ret;
#ifdef CONFIG_CNSS
struct ol_softc *scn =
vos_get_context(VOS_MODULE_ID_HIF, wma->vos_context);
tpAniSirGlobal pMac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == pMac) {
WMA_LOGE("%s: Unable to get PE context", __func__);
return VOS_STATUS_E_FAILURE;
}
#endif
len = sizeof(wmi_wow_hostwakeup_from_sleep_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_wow_hostwakeup_from_sleep_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_wow_hostwakeup_from_sleep_cmd_fixed_param));
vos_event_reset(&wma->wma_resume_event);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID);
if (ret) {
WMA_LOGE("Failed to send host wakeup indication to fw");
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Host wakeup indication sent to fw");
vos_status = vos_wait_single_event(&(wma->wma_resume_event),
WMA_RESUME_TIMEOUT);
if (VOS_STATUS_SUCCESS != vos_status) {
WMA_LOGE("%s: Timeout waiting for resume event from FW",
__func__);
if (wma_did_ssr_happen(wma)) {
WMA_LOGE("%s: SSR happened while waiting for response",
__func__);
return VOS_STATUS_E_ALREADY;
}
WMA_LOGE("%s: Pending commands %d credits %d", __func__,
wmi_get_pending_cmds(wma->wmi_handle),
wmi_get_host_credits(wma->wmi_handle));
if (!vos_is_logp_in_progress(VOS_MODULE_ID_WDA, NULL)) {
#ifdef CONFIG_CNSS
if (pMac->sme.enableSelfRecovery) {
wmi_tag_crash_inject(wma->wmi_handle, true);
vos_trigger_recovery(false);
} else {
if (scn && scn->adf_dev)
vos_device_crashed(scn->adf_dev->dev);
else
VOS_BUG(0);
}
#else
VOS_BUG(0);
#endif
} else {
WMA_LOGE("%s: SSR in progress, ignore resume timeout", __func__);
}
} else {
WMA_LOGD("Host wakeup received");
}
if (VOS_STATUS_SUCCESS == vos_status)
wmi_set_target_suspend(wma->wmi_handle, FALSE);
return vos_status;
}
#ifdef FEATURE_WLAN_D0WOW
/* Disable D0-WOW in firmware. */
VOS_STATUS wma_disable_d0wow_in_fw(tp_wma_handle wma)
{
wmi_d0_wow_enable_disable_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len;
int host_credits;
int wmi_pending_cmds;
int ret = 0;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
#ifdef CONFIG_CNSS
tpAniSirGlobal pmac;
pmac = vos_get_context(VOS_MODULE_ID_PE, wma->vos_context);
if (!pmac) {
WMA_LOGE("%s: Unable to get PE context!", __func__);
return VOS_STATUS_E_FAILURE;
}
#endif
len = sizeof(wmi_d0_wow_enable_disable_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed to allocate WMI buffer!", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_d0_wow_enable_disable_cmd_fixed_param));
cmd->enable = 0;
host_credits = wmi_get_host_credits(wma->wmi_handle);
wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle);
if (host_credits < WMI_WOW_REQUIRED_CREDITS) {
WMA_LOGE("%s: No Credits when resume: %d, pending_cmds: %d, "
"cannot resume back", __func__, host_credits,
wmi_pending_cmds);
HTC_dump_counter_info(wma->htc_handle);
if (vos_is_logp_in_progress(VOS_MODULE_ID_WDA, NULL)) {
VOS_ASSERT(0);
} else {
#ifdef CONFIG_CNSS
if (pmac->sme.enableSelfRecovery) {
vos_trigger_recovery(false);
} else {
VOS_BUG(0);
}
#endif
}
return VOS_STATUS_E_FAILURE;
}
vos_event_reset(&wma->wma_resume_event);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_D0_WOW_ENABLE_DISABLE_CMDID);
if (ret) {
WMA_LOGE("Failed to disable D0-WOW in FW!");
goto error;
}
vos_status = vos_wait_single_event(&(wma->wma_resume_event),
WMA_RESUME_TIMEOUT);
if (VOS_STATUS_SUCCESS != vos_status) {
WMA_LOGP("%s: Timeout waiting for resume event from FW!",
__func__);
WMA_LOGP("%s: Pending commands: %d credits: %d", __func__,
wmi_get_pending_cmds(wma->wmi_handle),
wmi_get_host_credits(wma->wmi_handle));
if (vos_is_logp_in_progress(VOS_MODULE_ID_WDA, NULL)) {
VOS_ASSERT(0);
} else {
#ifdef CONFIG_CNSS
if (pmac->sme.enableSelfRecovery) {
vos_trigger_recovery(false);
} else {
VOS_BUG(0);
}
#endif
}
return VOS_STATUS_E_FAILURE;
}
wma->wow.wow_enable_cmd_sent = FALSE;
wmi_set_d0wow_flag(wma->wmi_handle, FALSE);
WMA_LOGD("D0-WOW is disabled successfully in FW.");
return vos_status;
error:
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
#endif /* FEATURE_WLAN_D0WOW */
/* Disable wow in PCIe resume context. */
int wma_disable_wow_in_fw(WMA_HANDLE handle, int runtime_pm)
{
tp_wma_handle wma = handle;
VOS_STATUS ret;
if (!wma->wow.wow_enable_cmd_sent) {
return VOS_STATUS_SUCCESS;
}
WMA_LOGD("WoW Resume in PCIe Context\n");
#ifdef FEATURE_WLAN_D0WOW
if (wma->ap_client_cnt > 0) {
WMA_LOGD("Exiting D0-WOW since client count is %d.",
wma->ap_client_cnt);
return wma_disable_d0wow_in_fw(wma);
}
#endif
ret = wma_send_host_wakeup_ind_to_fw(wma);
if (ret != VOS_STATUS_SUCCESS)
return ret;
wma->wow.wow_enable_cmd_sent = FALSE;
/* To allow the tx pause/unpause events */
wma_set_wow_bus_suspend(wma, 0);
/* Unpause the vdev as we are resuming */
wma_unpause_vdev(wma);
return ret;
}
#ifdef WLAN_FEATURE_LPSS
/**
* wma_is_lpass_enabled() - check if lpass is enabled
* @handle: Pointer to wma handle
*
* WoW is needed if LPASS or NaN feature is enabled in INI because
* target can't wake up itself if its put in PDEV suspend when LPASS
* or NaN features are supported
*
* Return: true if lpass is enabled else false
*/
bool static wma_is_lpass_enabled(tp_wma_handle wma)
{
if (wma->is_lpass_enabled)
return true;
else
return false;
}
#else
bool static wma_is_lpass_enabled(tp_wma_handle wma)
{
return false;
}
#endif
#ifdef WLAN_FEATURE_NAN
/**
* wma_is_nan_enabled() - check if NaN is enabled
* @handle: Pointer to wma handle
*
* WoW is needed if LPASS or NaN feature is enabled in INI because
* target can't wake up itself if its put in PDEV suspend when LPASS
* or NaN features are supported
*
* Return: true if NaN is enabled else false
*/
bool static wma_is_nan_enabled(tp_wma_handle wma)
{
if (wma->is_nan_enabled)
return true;
else
return false;
}
#else
bool static wma_is_nan_enabled(tp_wma_handle wma)
{
return false;
}
#endif
/**
* wma_is_wow_mode_selected() - check if wow needs to be enabled in fw
* @handle: Pointer to wma handle
*
* If lpass is enabled then always do wow else check wow_enable config
*
* Return: true is wow mode is needed else false
*/
int wma_is_wow_mode_selected(WMA_HANDLE handle)
{
tp_wma_handle wma = (tp_wma_handle) handle;
if (wma_is_lpass_enabled(wma)) {
WMA_LOGD("LPASS is enabled select WoW");
return true;
} else if (wma_is_nan_enabled(wma)) {
WMA_LOGD("NAN is enabled select WoW");
return true;
} else {
WMA_LOGD("WoW enable %d", wma->wow.wow_enable);
return wma->wow.wow_enable;
}
}
#ifdef WLAN_FEATURE_APFIND
/**
* wma_apfind_set_cmd() - set APFIND configuration to firmware
* @wda_handle: pointer to wma handle.
* @apfind_req: pointer to apfind configuration request.
*
* This is called to send APFIND configuations to firmware via WMI command.
*
* Return: VOS_STATUS.
*/
static VOS_STATUS wma_apfind_set_cmd(void *wda_handle,
struct hal_apfind_request *apfind_req)
{
int ret;
tp_wma_handle wma_handle = (tp_wma_handle)wda_handle;
wmi_apfind_cmd_param *cmd;
wmi_buf_t buf;
u_int16_t len = sizeof(*cmd);
u_int16_t apfind_data_len, apfind_data_len_aligned;
u_int8_t *buf_ptr;
if (!apfind_req) {
WMA_LOGE("%s:apfind req is not valid", __func__);
return VOS_STATUS_E_FAILURE;
}
apfind_data_len = apfind_req->request_data_len;
apfind_data_len_aligned = roundup(apfind_req->request_data_len,
sizeof(u_int32_t));
len += WMI_TLV_HDR_SIZE + apfind_data_len_aligned;
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 = (wmi_apfind_cmd_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_apfind_cmd_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_apfind_cmd_param));
cmd->data_len = apfind_req->request_data_len;
WMA_LOGD("%s: The data len value is %u",
__func__, apfind_req->request_data_len);
buf_ptr += sizeof(wmi_apfind_cmd_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, apfind_data_len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, apfind_req->request_data,
cmd->data_len);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_APFIND_CMDID);
if (ret != EOK) {
WMA_LOGE("%s Failed to send set param command ret = %d", __func__, ret);
wmi_buf_free(buf);
}
return ret;
}
#endif /* WLAN_FEATURE_APFIND */
tAniGetPEStatsRsp * wma_get_stats_rsp_buf(tAniGetPEStatsReq *get_stats_param)
{
tAniGetPEStatsRsp *stats_rsp_params;
tANI_U32 len, temp_mask, counter = 0;
len= sizeof(tAniGetPEStatsRsp);
temp_mask = get_stats_param->statsMask;
while (temp_mask) {
if (temp_mask & 1) {
switch (counter) {
case eCsrSummaryStats:
len += sizeof(tCsrSummaryStatsInfo);
break;
case eCsrGlobalClassAStats:
len += sizeof(tCsrGlobalClassAStatsInfo);
break;
case eCsrGlobalClassBStats:
len += sizeof(tCsrGlobalClassBStatsInfo);
break;
case eCsrGlobalClassCStats:
len += sizeof(tCsrGlobalClassCStatsInfo);
break;
case eCsrGlobalClassDStats:
len += sizeof(tCsrGlobalClassDStatsInfo);
break;
case eCsrPerStaStats:
len += sizeof(tCsrPerStaStatsInfo);
break;
case csr_per_chain_rssi_stats:
len +=
sizeof(struct csr_per_chain_rssi_stats_info);
break;
}
}
counter++;
temp_mask >>= 1;
}
stats_rsp_params = (tAniGetPEStatsRsp *)vos_mem_malloc(len);
if (!stats_rsp_params) {
WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp");
VOS_ASSERT(0);
return NULL;
}
vos_mem_zero(stats_rsp_params, len);
stats_rsp_params->staId = get_stats_param->staId;
stats_rsp_params->statsMask = get_stats_param->statsMask;
stats_rsp_params->msgType = WDA_GET_STATISTICS_RSP;
stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp);
stats_rsp_params->rc = eHAL_STATUS_SUCCESS;
return stats_rsp_params;
}
/* function : wma_get_stats_req
* Description : return the statistics
* Args : wma handle, pointer to tAniGetPEStatsReq
* Returns : nothing
*/
static void wma_get_stats_req(WMA_HANDLE handle,
tAniGetPEStatsReq *get_stats_param)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
struct wma_txrx_node *node;
wmi_buf_t buf;
wmi_request_stats_cmd_fixed_param *cmd;
tAniGetPEStatsRsp *pGetPEStatsRspParams;
u_int8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
WMA_LOGD("%s: Enter", __func__);
node = &wma_handle->interfaces[get_stats_param->sessionId];
if (node->stats_rsp) {
pGetPEStatsRspParams = node->stats_rsp;
if (pGetPEStatsRspParams->staId == get_stats_param->staId &&
pGetPEStatsRspParams->statsMask ==
get_stats_param->statsMask) {
WMA_LOGI("Stats for staId %d with stats mask %d "
"is pending.... ignore new request",
get_stats_param->staId,
get_stats_param->statsMask);
goto end;
} else {
vos_mem_free(node->stats_rsp);
node->stats_rsp = NULL;
node->fw_stats_set = 0;
}
}
pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param);
if (!pGetPEStatsRspParams)
goto end;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed to allocate wmi buffer", __func__);
goto failed;
}
node->fw_stats_set = 0;
node->stats_rsp = pGetPEStatsRspParams;
wma_handle->get_sta_peer_info = FALSE;
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_PEER_STAT|WMI_REQUEST_PDEV_STAT|
WMI_REQUEST_VDEV_STAT|WMI_REQUEST_RSSI_PER_CHAIN_STAT;
cmd->vdev_id = get_stats_param->sessionId;
WMI_CHAR_ARRAY_TO_MAC_ADDR(node->bssid, &cmd->peer_macaddr);
WMA_LOGD("STATS REQ VDEV_ID:%d-->", cmd->vdev_id);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_REQUEST_STATS_CMDID)) {
WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID",
__func__);
wmi_buf_free(buf);
goto failed;
}
goto end;
failed:
pGetPEStatsRspParams->rc = eHAL_STATUS_FAILURE;
node->stats_rsp = NULL;
/* send response to UMAC*/
wma_send_msg(wma_handle, WDA_GET_STATISTICS_RSP, pGetPEStatsRspParams,
0) ;
end:
vos_mem_free(get_stats_param);
WMA_LOGD("%s: Exit", __func__);
return;
}
/**
* wma_process_mib_stats_req() - Mib stats request
* @wda_handle: pointer to wma handle.
* @get_mib_stats_param: mib stats request parameters
*
* This API calls the FW to get the latest Mib stats.
*
* Return:
*/
static void wma_process_mib_stats_req(WMA_HANDLE handle,
struct get_mib_stats_req *get_mib_stats_param)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_buf_t buf;
wmi_request_stats_cmd_fixed_param *cmd;
u_int8_t len = sizeof(wmi_request_stats_cmd_fixed_param);
WMA_LOGD("%s: Enter", __func__);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed to allocate wmi buffer", __func__);
return;
}
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_MIB_STAT;
cmd->vdev_id = get_mib_stats_param->session_id;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_REQUEST_STATS_CMDID)) {
WMA_LOGE("Failed to send WMI Mib Stats request to fw");
wmi_buf_free(buf);
return;
}
return;
}
static void wma_init_scan_req(tp_wma_handle wma_handle,
tInitScanParams *init_scan_param)
{
WMA_LOGD("%s: Send dummy init scan response for legacy scan request",
__func__);
init_scan_param->status = eHAL_STATUS_SUCCESS;
/* send ini scan response message back to PE */
wma_send_msg(wma_handle, WDA_INIT_SCAN_RSP, (void *)init_scan_param,
0);
}
static void wma_finish_scan_req(tp_wma_handle wma_handle,
tFinishScanParams *finish_scan_param)
{
WMA_LOGD("%s: Send dummy finish scan response for legacy scan request",
__func__);
finish_scan_param->status = eHAL_STATUS_SUCCESS;
/* send finish scan response message back to PE */
wma_send_msg(wma_handle, WDA_FINISH_SCAN_RSP, (void *)finish_scan_param,
0);
}
static void wma_process_update_opmode(tp_wma_handle wma_handle,
tUpdateVHTOpMode *update_vht_opmode)
{
struct wma_txrx_node *iface;
WLAN_PHY_MODE chanMode;
wmi_channel_width chanwidth;
iface = &wma_handle->interfaces[update_vht_opmode->smesessionId];
if (update_vht_opmode->chanMode == MODE_MAX)
chanMode = iface->chanmode;
else
chanMode = update_vht_opmode->chanMode;
WMA_LOGD("%s: opMode = %d, chanMode = %d",
__func__, update_vht_opmode->opMode, chanMode);
chanwidth = chanmode_to_chanwidth(chanMode);
if (chanwidth < update_vht_opmode->opMode) {
WMA_LOGE("%s: stop changing chanwidth from %d to %d,",
__func__,
chanwidth, update_vht_opmode->opMode);
} else {
iface->chanmode = chanMode;
wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac,
WMI_PEER_PHYMODE, chanMode,
update_vht_opmode->smesessionId);
wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac,
WMI_PEER_CHWIDTH, update_vht_opmode->opMode,
update_vht_opmode->smesessionId);
}
}
static void wma_process_update_rx_nss(tp_wma_handle wma_handle,
tUpdateRxNss *update_rx_nss)
{
struct wma_txrx_node *intr =
&wma_handle->interfaces[update_rx_nss->smesessionId];
int rxNss = update_rx_nss->rxNss;
if (wma_handle->per_band_chainmask_supp) {
if (intr->mhz < WMA_2_4_GHZ_MAX_FREQ)
wma_update_txrx_chainmask(intr->nss_2g, &rxNss);
else
wma_update_txrx_chainmask(intr->nss_5g, &rxNss);
}
else
wma_update_txrx_chainmask(wma_handle->num_rf_chains, &rxNss);
intr->nss = (tANI_U8) rxNss;
update_rx_nss->rxNss = (tANI_U32) rxNss;
WMA_LOGD("%s: Rx Nss = %d", __func__, update_rx_nss->rxNss);
wma_set_peer_param(wma_handle, update_rx_nss->peer_mac,
WMI_PEER_NSS, update_rx_nss->rxNss,
update_rx_nss->smesessionId);
}
#ifdef FEATURE_OEM_DATA_SUPPORT
static void wma_start_oem_data_req(tp_wma_handle wma_handle,
tStartOemDataReq *startOemDataReq)
{
wmi_buf_t buf;
u_int8_t *cmd;
int ret = 0;
tStartOemDataRsp *pStartOemDataRsp;
WMA_LOGD("%s: Send OEM Data Request to target", __func__);
if (!startOemDataReq || !startOemDataReq->data) {
WMA_LOGE("%s: startOemDataReq is null", __func__);
goto out;
}
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not send Oem data request cmd", __func__);
return;
}
buf = wmi_buf_alloc(wma_handle->wmi_handle,
(startOemDataReq->data_len + WMI_TLV_HDR_SIZE));
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
goto out;
}
cmd = (u_int8_t *)wmi_buf_data(buf);
WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE,
startOemDataReq->data_len);
cmd += WMI_TLV_HDR_SIZE;
vos_mem_copy(cmd, &startOemDataReq->data[0],
startOemDataReq->data_len);
WMA_LOGI("%s: Sending OEM Data Request to target, data len (%d)",
__func__, startOemDataReq->data_len);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
(startOemDataReq->data_len +
WMI_TLV_HDR_SIZE),
WMI_OEM_REQ_CMDID);
if (ret != EOK) {
WMA_LOGE("%s:wmi cmd send failed", __func__);
wmi_buf_free(buf);
}
out:
/* free oem data req buffer received from UMAC */
if (startOemDataReq) {
if (startOemDataReq->data)
vos_mem_free(startOemDataReq->data);
vos_mem_free(startOemDataReq);
}
/* Now send data resp back to PE/SME with message sub-type of
* WMI_OEM_INTERNAL_RSP. This is required so that PE/SME clears
* up pending active command. Later when desired oem response(s)
* comes as wmi event from target then those shall be passed
* to oem application
*/
pStartOemDataRsp = vos_mem_malloc(sizeof(*pStartOemDataRsp));
if (!pStartOemDataRsp)
{
WMA_LOGE("%s:failed to allocate memory for OEM Data Resp to PE",
__func__);
return;
}
vos_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp));
pStartOemDataRsp->target_rsp = false;
pStartOemDataRsp->oem_data_rsp = NULL;
WMA_LOGI("%s: Sending WDA_START_OEM_DATA_RSP to clear up PE/SME pending cmd",
__func__);
wma_send_msg(wma_handle, WDA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0);
return;
}
#endif /* FEATURE_OEM_DATA_SUPPORT */
#ifdef FEATURE_WLAN_ESE
#define TSM_DELAY_HISTROGRAM_BINS 4
/*
* @brief: A parallel function to WDA_ProcessTsmStatsReq for pronto. This
* function fetches stats from data path APIs and post
* WDA_TSM_STATS_RSP msg back to LIM.
* @param: wma_handler - handle to wma
* @param: pTsmStatsMsg - TSM stats struct that needs to be populated and
* passed in message.
*/
VOS_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler,
void *pTsmStatsMsg)
{
u_int8_t counter;
u_int32_t queue_delay_microsec = 0;
u_int32_t tx_delay_microsec = 0;
u_int16_t packet_count = 0;
u_int16_t packet_loss_count = 0;
tpAniTrafStrmMetrics pTsmMetric = NULL;
#ifdef FEATURE_WLAN_ESE_UPLOAD
tpAniGetTsmStatsReq pStats = (tpAniGetTsmStatsReq)pTsmStatsMsg;
tpAniGetTsmStatsRsp pTsmRspParams = NULL;
#else
tpTSMStats pStats = (tpTSMStats)pTsmStatsMsg;
#endif
int tid = pStats->tid;
/*
* The number of histrogram bin report by data path api are different
* than required by TSM, hence different (6) size array used
*/
u_int16_t bin_values[QCA_TX_DELAY_HIST_REPORT_BINS] = {0,};
ol_txrx_pdev_handle pdev = vos_get_context(VOS_MODULE_ID_TXRX,
wma_handler->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
vos_mem_free(pTsmStatsMsg);
return VOS_STATUS_E_INVAL;
}
/* get required values from data path APIs */
ol_tx_delay(pdev, &queue_delay_microsec, &tx_delay_microsec, tid);
ol_tx_delay_hist(pdev, bin_values, tid);
ol_tx_packet_count(pdev, &packet_count, &packet_loss_count, tid );
#ifdef FEATURE_WLAN_ESE_UPLOAD
pTsmRspParams =
(tpAniGetTsmStatsRsp)vos_mem_malloc(sizeof(tAniGetTsmStatsRsp));
if(NULL == pTsmRspParams)
{
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"%s: VOS MEM Alloc Failure", __func__);
VOS_ASSERT(0);
vos_mem_free(pTsmStatsMsg);
return VOS_STATUS_E_NOMEM;
}
pTsmRspParams->staId = pStats->staId;
pTsmRspParams->rc = eSIR_FAILURE;
pTsmRspParams->tsmStatsReq = pStats;
pTsmMetric = &pTsmRspParams->tsmMetrics;
#else
pTsmMetric = (tpAniTrafStrmMetrics)&pStats->tsmMetrics;
#endif
/* populate pTsmMetric */
pTsmMetric->UplinkPktQueueDly = queue_delay_microsec;
/* store only required number of bin values */
for ( counter = 0; counter < TSM_DELAY_HISTROGRAM_BINS; counter++)
{
pTsmMetric->UplinkPktQueueDlyHist[counter] = bin_values[counter];
}
pTsmMetric->UplinkPktTxDly = tx_delay_microsec;
pTsmMetric->UplinkPktLoss = packet_loss_count;
pTsmMetric->UplinkPktCount = packet_count;
/*
* No need to populate roaming delay and roaming count as they are
* being populated just before sending IAPP frame out
*/
/* post this message to LIM/PE */
#ifdef FEATURE_WLAN_ESE_UPLOAD
wma_send_msg(wma_handler, WDA_TSM_STATS_RSP, (void *)pTsmRspParams , 0) ;
#else
wma_send_msg(wma_handler, WDA_TSM_STATS_RSP, (void *)pTsmStatsMsg , 0) ;
#endif
return VOS_STATUS_SUCCESS;
}
#endif /* FEATURE_WLAN_ESE */
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
static void wma_set_ric_req(tp_wma_handle wma, void *msg, tANI_U8 is_add_ts)
{
wmi_ric_request_fixed_param *cmd;
wmi_ric_tspec *tspec_param;
wmi_buf_t buf;
u_int8_t *buf_ptr;
tSirMacTspecIE *ptspecIE;
int32_t len = sizeof(wmi_ric_request_fixed_param)+
WMI_TLV_HDR_SIZE +
sizeof(wmi_ric_tspec);
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);
cmd = (wmi_ric_request_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_ric_request_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_ric_request_fixed_param));
if (is_add_ts)
cmd->vdev_id = ((tAddTsParams *)msg)->sessionId;
else
cmd->vdev_id = ((tDelTsParams *)msg)->sessionId;
cmd->num_ric_request = 1; /* Today we are sending only 1 ric at once */
cmd->is_add_ric = is_add_ts;
buf_ptr += sizeof(wmi_ric_request_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_ric_tspec));
buf_ptr += WMI_TLV_HDR_SIZE;
tspec_param = (wmi_ric_tspec *)buf_ptr;
WMITLV_SET_HDR(&tspec_param->tlv_header,
WMITLV_TAG_STRUC_wmi_ric_tspec,
WMITLV_GET_STRUCT_TLVLEN(wmi_ric_tspec));
if(is_add_ts)
ptspecIE = &(((tAddTsParams *)msg)->tspec);
else
ptspecIE = &(((tDelTsParams *)msg)->delTsInfo.tspec);
/* Fill the tsinfo in the format expected by firmware */
#ifndef ANI_LITTLE_BIT_ENDIAN
vos_mem_copy(((tANI_U8 *)&tspec_param->ts_info)+1,
((tANI_U8 *)&ptspecIE->tsinfo)+1, 2);
#else
vos_mem_copy(((tANI_U8 *)&tspec_param->ts_info),
((tANI_U8 *)&ptspecIE->tsinfo)+1, 2);
#endif
tspec_param->nominal_msdu_size = ptspecIE->nomMsduSz;
tspec_param->maximum_msdu_size = ptspecIE->maxMsduSz;
tspec_param->min_service_interval = ptspecIE->minSvcInterval;
tspec_param->max_service_interval = ptspecIE->maxSvcInterval;
tspec_param->inactivity_interval = ptspecIE->inactInterval;
tspec_param->suspension_interval = ptspecIE->suspendInterval;
tspec_param->svc_start_time = ptspecIE->svcStartTime;
tspec_param->min_data_rate = ptspecIE->minDataRate;
tspec_param->mean_data_rate = ptspecIE->meanDataRate;
tspec_param->peak_data_rate = ptspecIE->peakDataRate;
tspec_param->max_burst_size = ptspecIE->maxBurstSz;
tspec_param->delay_bound = ptspecIE->delayBound;
tspec_param->min_phy_rate = ptspecIE->minPhyRate;
tspec_param->surplus_bw_allowance = ptspecIE->surplusBw;
tspec_param->medium_time = 0;
WMA_LOGI("%s: Set RIC Req is_add_ts:%d", __func__, is_add_ts);
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_ROAM_SET_RIC_REQUEST_CMDID)) {
WMA_LOGP("%s: Failed to send vdev Set RIC Req command", __func__);
if(is_add_ts)
((tAddTsParams *)msg)->status = eHAL_STATUS_FAILURE;
wmi_buf_free(buf);
}
}
#endif
static void wma_del_ts_req(tp_wma_handle wma, tDelTsParams *msg)
{
wmi_vdev_wmm_delts_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
goto err;
}
cmd = (wmi_vdev_wmm_delts_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_wmm_delts_cmd_fixed_param));
cmd->vdev_id = msg->sessionId;
cmd->ac = TID_TO_WME_AC(msg->userPrio);
WMA_LOGD("Delts vdev:%d, ac:%d, %s:%d",
cmd->vdev_id, cmd->ac, __FUNCTION__, __LINE__);
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_WMM_DELTS_CMDID)) {
WMA_LOGP("%s: Failed to send vdev DELTS command", __func__);
wmi_buf_free(buf);
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if(msg->setRICparams == true)
wma_set_ric_req(wma, msg, false);
#endif
err:
vos_mem_free(msg);
}
/*
* @brief: A function to handle WDA_AGGR_QOS_REQ. This will send out
* ADD_TS requestes to firmware in loop for all the ACs with
* active flow.
* @param: wma_handler - handle to wma
* @param: pAggrQosRspMsg - combined struct for all ADD_TS requests.
*/
static void wma_aggr_qos_req(tp_wma_handle wma, tAggrAddTsParams *pAggrQosRspMsg)
{
int i = 0;
wmi_vdev_wmm_addts_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
for( i = 0; i < HAL_QOS_NUM_AC_MAX; i++ )
{
// if flow in this AC is active
if ( ((1 << i) & pAggrQosRspMsg->tspecIdx) )
{
/*
* as per implementation of wma_add_ts_req() we
* are not waiting any response from firmware so
* apart from sending ADDTS to firmware just send
* success to upper layers
*/
pAggrQosRspMsg->status[i] = eHAL_STATUS_SUCCESS;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
goto aggr_qos_exit;
}
cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_wmm_addts_cmd_fixed_param));
cmd->vdev_id = pAggrQosRspMsg->sessionId;
cmd->ac = TID_TO_WME_AC(pAggrQosRspMsg->tspec[i].tsinfo.traffic.userPrio);
cmd->medium_time_us = pAggrQosRspMsg->tspec[i].mediumTime * 32;
cmd->downgrade_type = WMM_AC_DOWNGRADE_DEPRIO;
WMA_LOGD("%s:%d: Addts vdev:%d, ac:%d, mediumTime:%d downgrade_type:%d",
__func__, __LINE__, cmd->vdev_id, cmd->ac,
cmd->medium_time_us, cmd->downgrade_type);
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_WMM_ADDTS_CMDID)) {
WMA_LOGP("%s: Failed to send vdev ADDTS command", __func__);
pAggrQosRspMsg->status[i] = eHAL_STATUS_FAILURE;
wmi_buf_free(buf);
}
}
}
aggr_qos_exit:
// send reponse to upper layers from here only.
wma_send_msg(wma, WDA_AGGR_QOS_RSP, pAggrQosRspMsg, 0);
}
static void wma_add_ts_req(tp_wma_handle wma, tAddTsParams *msg)
{
wmi_vdev_wmm_addts_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t len = sizeof(*cmd);
#ifdef FEATURE_WLAN_ESE
/*
* msmt_interval is in unit called TU (1 TU = 1024 us)
* max value of msmt_interval cannot make resulting
* interval_miliseconds overflow 32 bit
*/
tANI_U32 intervalMiliseconds;
ol_txrx_pdev_handle pdev =
vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
goto err;
}
intervalMiliseconds = (msg->tsm_interval*1024)/1000;
ol_tx_set_compute_interval(pdev, intervalMiliseconds);
#endif
msg->status = eHAL_STATUS_SUCCESS;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
goto err;
}
cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_wmm_addts_cmd_fixed_param));
cmd->vdev_id = msg->sme_session_id;
cmd->ac = TID_TO_WME_AC(msg->tspec.tsinfo.traffic.userPrio);
cmd->medium_time_us = msg->tspec.mediumTime * 32;
cmd->downgrade_type = WMM_AC_DOWNGRADE_DROP;
WMA_LOGD("Addts vdev:%d, ac:%d, mediumTime:%d, downgrade_type:%d %s:%d",
cmd->vdev_id, cmd->ac, cmd->medium_time_us,
cmd->downgrade_type, __func__, __LINE__);
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_WMM_ADDTS_CMDID)) {
WMA_LOGP("%s: Failed to send vdev ADDTS command", __func__);
msg->status = eHAL_STATUS_FAILURE;
wmi_buf_free(buf);
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if(msg->setRICparams == true)
wma_set_ric_req(wma, msg, true);
#endif
err:
wma_send_msg(wma, WDA_ADD_TS_RSP, msg, 0);
}
static int wma_process_receive_filter_set_filter_req(tp_wma_handle wma_handle,
tSirRcvPktFilterCfgType *rcv_filter_param)
{
wmi_chatter_coalescing_add_filter_cmd_fixed_param *cmd;
chatter_pkt_coalescing_filter *cmd_filter;
u_int8_t *buf_ptr;
wmi_buf_t buf;
int num_rules = 1; /* Only one rule at a time */
int len;
int err;
int i;
/* allocate the memory */
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + sizeof(*cmd_filter) * num_rules;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set_param cmd");
vos_mem_free(rcv_filter_param);
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
/* fill the fixed part */
cmd = (wmi_chatter_coalescing_add_filter_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_chatter_coalescing_add_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_chatter_coalescing_add_filter_cmd_fixed_param));
cmd->num_of_filters = num_rules;
/* specify the type of data in the subsequent buffer */
buf_ptr += sizeof(*cmd);
cmd_filter = (chatter_pkt_coalescing_filter *) buf_ptr;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
num_rules * sizeof(chatter_pkt_coalescing_filter));
/* fill the actual filter data */
buf_ptr += WMI_TLV_HDR_SIZE;
cmd_filter = (chatter_pkt_coalescing_filter *) buf_ptr;
WMITLV_SET_HDR(&cmd_filter->tlv_header,
WMITLV_TAG_STRUC_wmi_chatter_pkt_coalescing_filter,
WMITLV_GET_STRUCT_TLVLEN(chatter_pkt_coalescing_filter));
cmd_filter->filter_id = rcv_filter_param->filterId;
cmd_filter->max_coalescing_delay = rcv_filter_param->coalesceTime;
cmd_filter->pkt_type = CHATTER_COALESCING_PKT_TYPE_UNICAST |
CHATTER_COALESCING_PKT_TYPE_MULTICAST |
CHATTER_COALESCING_PKT_TYPE_BROADCAST;
cmd_filter->num_of_test_field = MIN(rcv_filter_param->numFieldParams,
CHATTER_MAX_FIELD_TEST);
for (i = 0; i < cmd_filter->num_of_test_field; i++) {
cmd_filter->test_fields[i].offset = rcv_filter_param->paramsData[i].dataOffset;
cmd_filter->test_fields[i].length = MIN(rcv_filter_param->paramsData[i].dataLength,
CHATTER_MAX_TEST_FIELD_LEN32);
cmd_filter->test_fields[i].test = rcv_filter_param->paramsData[i].cmpFlag;
memcpy(&cmd_filter->test_fields[i].value, rcv_filter_param->paramsData[i].compareData,
cmd_filter->test_fields[i].length);
memcpy(&cmd_filter->test_fields[i].mask, rcv_filter_param->paramsData[i].dataMask,
cmd_filter->test_fields[i].length);
}
WMA_LOGD("Chatter packets, adding filter with id: %d, num_test_fields=%d",cmd_filter->filter_id,
cmd_filter->num_of_test_field);
/* send the command along with data */
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_CHATTER_ADD_COALESCING_FILTER_CMDID);
if (err) {
WMA_LOGE("Failed to send set_param cmd");
wmi_buf_free(buf);
vos_mem_free(rcv_filter_param);
return -EIO;
}
vos_mem_free(rcv_filter_param);
return 0; /* SUCCESS */
}
static int wma_process_receive_filter_clear_filter_req(tp_wma_handle wma_handle,
tSirRcvFltPktClearParam *rcv_clear_param)
{
wmi_chatter_coalescing_delete_filter_cmd_fixed_param *cmd;
wmi_buf_t buf;
int err;
/* allocate the memory */
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set_param cmd");
vos_mem_free(rcv_clear_param);
return -ENOMEM;
}
/* fill the fixed part */
cmd = (wmi_chatter_coalescing_delete_filter_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_chatter_coalescing_delete_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_chatter_coalescing_delete_filter_cmd_fixed_param));
cmd->filter_id = rcv_clear_param->filterId;
WMA_LOGD("Chatter packets, clearing filter with id: %d",cmd->filter_id);
/* send the command along with data */
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID);
if (err) {
WMA_LOGE("Failed to send set_param cmd");
wmi_buf_free(buf);
vos_mem_free(rcv_clear_param);
return -EIO;
}
vos_mem_free(rcv_clear_param);
return 0; /* SUCCESS */
}
static int wma_set_base_macaddr_indicate(tp_wma_handle wma_handle,
tSirMacAddr *customAddr)
{
wmi_pdev_set_base_macaddr_cmd_fixed_param *cmd;
wmi_buf_t buf;
int err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set_base_macaddr cmd");
return -ENOMEM;
}
cmd = (wmi_pdev_set_base_macaddr_cmd_fixed_param *) wmi_buf_data(buf);
vos_mem_zero(cmd, sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_base_macaddr_cmd_fixed_param));
WMI_CHAR_ARRAY_TO_MAC_ADDR(*customAddr, &cmd->base_macaddr);
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_PDEV_SET_BASE_MACADDR_CMDID);
if (err) {
WMA_LOGE("Failed to send set_base_macaddr cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Base MAC Addr: "MAC_ADDRESS_STR,
MAC_ADDR_ARRAY((*customAddr)));
return 0;
}
static void wma_data_tx_ack_work_handler(struct work_struct *ack_work)
{
struct wma_tx_ack_work_ctx *work;
tp_wma_handle wma_handle;
pWDAAckFnTxComp ack_cb;
if (vos_is_load_unload_in_progress(VOS_MODULE_ID_WDA, NULL)) {
WMA_LOGE("%s: Driver load/unload in progress", __func__);
return;
}
work = container_of(ack_work, struct wma_tx_ack_work_ctx, ack_cmp_work);
wma_handle = work->wma_handle;
ack_cb = wma_handle->umac_data_ota_ack_cb;
if (work->status)
WMA_LOGE("Data Tx Ack Cb Status %d", work->status);
else
WMA_LOGD("Data Tx Ack Cb Status %d", work->status);
/* Call the Ack Cb registered by UMAC */
if (ack_cb)
ack_cb((tpAniSirGlobal)(wma_handle->mac_context),
work->status ? 0 : 1);
else
WMA_LOGE("Data Tx Ack Cb is NULL");
wma_handle->umac_data_ota_ack_cb = NULL;
wma_handle->last_umac_data_nbuf = NULL;
adf_os_mem_free(work);
wma_handle->ack_work_ctx = NULL;
}
/**
* wma_data_tx_ack_comp_hdlr - handles tx data ack completion
* @context: context with which the handler is registered
* @netbuf: tx data nbuf
* @err: status of tx completion
*
* This is the cb registered with TxRx for
* Ack Complete
*/
static void
wma_data_tx_ack_comp_hdlr(void *wma_context,
adf_nbuf_t netbuf, int32_t status)
{
ol_txrx_pdev_handle pdev;
tp_wma_handle wma_handle = (tp_wma_handle)wma_context;
if (NULL == wma_handle) {
WMA_LOGE("%s: Invalid WMA Handle", __func__);
return;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma_handle->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
return;
}
/*
* if netBuf does not match with pending nbuf then just free the
* netbuf and do not call ack cb
*/
if (wma_handle->last_umac_data_nbuf != netbuf) {
if (wma_handle->umac_data_ota_ack_cb) {
WMA_LOGE("%s: nbuf does not match but umac_data_ota_ack_cb is not null",
__func__);
} else {
WMA_LOGE("%s: nbuf does not match and umac_data_ota_ack_cb is also null",
__func__);
}
goto free_nbuf;
}
if(wma_handle && wma_handle->umac_data_ota_ack_cb) {
struct wma_tx_ack_work_ctx *ack_work;
ack_work =
adf_os_mem_alloc(NULL, sizeof(struct wma_tx_ack_work_ctx));
wma_handle->ack_work_ctx = ack_work;
if(ack_work) {
vos_init_work(&ack_work->ack_cmp_work,
wma_data_tx_ack_work_handler);
ack_work->wma_handle = wma_handle;
ack_work->sub_type = 0;
ack_work->status = status;
/* Schedue the Work */
schedule_work(&ack_work->ack_cmp_work);
}
}
free_nbuf:
/* unmap and freeing the tx buf as txrx is not taking care */
adf_nbuf_unmap_single(pdev->osdev, netbuf, ADF_OS_DMA_TO_DEVICE);
adf_nbuf_free(netbuf);
}
static int wma_add_clear_mcbc_filter(tp_wma_handle wma_handle, uint8_t vdev_id,
tSirMacAddr multicastAddr, bool clearList)
{
WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd;
wmi_buf_t buf;
int err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set_param cmd");
return -ENOMEM;
}
cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf);
vos_mem_zero(cmd, sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param));
cmd->action = (clearList? WMI_MCAST_FILTER_DELETE : WMI_MCAST_FILTER_SET);
cmd->vdev_id = vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(multicastAddr, &cmd->mcastbdcastaddr);
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_SET_MCASTBCAST_FILTER_CMDID);
if (err) {
WMA_LOGE("Failed to send set_param cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Action:%d; vdev_id:%d; clearList:%d\n",
cmd->action, vdev_id, clearList);
WMA_LOGD("MCBC MAC Addr: %0x:%0x:%0x:%0x:%0x:%0x\n",
multicastAddr[0], multicastAddr[1], multicastAddr[2],
multicastAddr[3], multicastAddr[4], multicastAddr[5]);
return 0;
}
static VOS_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle,
tSirRcvFltMcAddrList *mcbc_param)
{
uint8_t vdev_id = 0;
int i;
if (mcbc_param->ulMulticastAddrCnt <= 0 ||
mcbc_param->ulMulticastAddrCnt >
CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES) {
WMA_LOGE("Number of multicast addresses: %u",
mcbc_param->ulMulticastAddrCnt);
WARN_ON(1);
return VOS_STATUS_E_FAILURE;
}
if (!wma_find_vdev_by_addr(wma_handle, mcbc_param->selfMacAddr, &vdev_id)) {
WMA_LOGE("%s: Failed to find vdev id for %pM",
__func__, mcbc_param->bssId);
return VOS_STATUS_E_FAILURE;
}
/* set mcbc_param->action to clear MCList and reset
* to configure the MCList in FW
*/
for (i = 0; i < mcbc_param->ulMulticastAddrCnt; i++) {
wma_add_clear_mcbc_filter(wma_handle, vdev_id,
mcbc_param->multicastAddr[i],
(mcbc_param->action == 0));
}
return VOS_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_GTK_OFFLOAD
#define GTK_OFFLOAD_ENABLE 0
#define GTK_OFFLOAD_DISABLE 1
static VOS_STATUS wma_send_gtk_offload_req(tp_wma_handle wma, u_int8_t vdev_id,
tpSirGtkOffloadParams params)
{
int len;
wmi_buf_t buf;
WMI_GTK_OFFLOAD_CMD_fixed_param *cmd;
VOS_STATUS status = VOS_STATUS_SUCCESS;
WMA_LOGD("%s Enter", __func__);
len = sizeof(*cmd);
/* alloc wmi buffer */
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD");
status = VOS_STATUS_E_NOMEM;
goto out;
}
cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_GTK_OFFLOAD_CMD_fixed_param));
cmd->vdev_id = vdev_id;
/* Request target to enable GTK offload */
if (params->ulFlags == GTK_OFFLOAD_ENABLE) {
cmd->flags = GTK_OFFLOAD_ENABLE_OPCODE;
wma->wow.gtk_err_enable[vdev_id] = TRUE;
/* Copy the keys and replay counter */
vos_mem_copy(cmd->KCK, params->aKCK, GTK_OFFLOAD_KCK_BYTES);
vos_mem_copy(cmd->KEK, params->aKEK, GTK_OFFLOAD_KEK_BYTES);
vos_mem_copy(cmd->replay_counter, &params->ullKeyReplayCounter,
GTK_REPLAY_COUNTER_BYTES);
} else {
wma->wow.gtk_err_enable[vdev_id] = FALSE;
cmd->flags = GTK_OFFLOAD_DISABLE_OPCODE;
}
/* send the wmi command */
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_GTK_OFFLOAD_CMDID)) {
WMA_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID");
wmi_buf_free(buf);
status = VOS_STATUS_E_FAILURE;
}
WMA_LOGD("VDEVID: %d, GTK_FLAGS: x%x", vdev_id, cmd->flags);
out:
WMA_LOGD("%s Exit", __func__);
return status;
}
static VOS_STATUS wma_process_gtk_offload_req(tp_wma_handle wma,
tpSirGtkOffloadParams params)
{
u_int8_t vdev_id;
VOS_STATUS status = VOS_STATUS_SUCCESS;
WMA_LOGD("%s Enter", __func__);
/* Get the vdev id */
if (!wma_find_vdev_by_bssid(wma, params->bssId, &vdev_id)) {
WMA_LOGE("vdev handle is invalid for %pM", params->bssId);
status = VOS_STATUS_E_INVAL;
goto out;
}
/* Validate vdev id */
if (vdev_id >= wma->max_bssid){
WMA_LOGE("invalid vdev_id %d for %pM", vdev_id, params->bssId);
status = VOS_STATUS_E_INVAL;
goto out;
}
if ((params->ulFlags == GTK_OFFLOAD_ENABLE) &&
(wma->wow.gtk_err_enable[vdev_id] == TRUE)) {
WMA_LOGE("%s GTK Offload already enabled. Disable it first "
"vdev_id %d", __func__, vdev_id);
params->ulFlags = GTK_OFFLOAD_DISABLE;
status = wma_send_gtk_offload_req(wma, vdev_id, params);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s Failed to disable GTK Offload", __func__);
goto out;
}
WMA_LOGD("%s Enable GTK Offload again with updated inputs",
__func__);
params->ulFlags = GTK_OFFLOAD_ENABLE;
}
status = wma_send_gtk_offload_req(wma, vdev_id, params);
out:
vos_mem_free(params);
WMA_LOGD("%s Exit", __func__);
return status;
}
static VOS_STATUS wma_process_gtk_offload_getinfo_req(tp_wma_handle wma,
tpSirGtkOffloadGetInfoRspParams params)
{
u_int8_t vdev_id;
int len;
wmi_buf_t buf;
WMI_GTK_OFFLOAD_CMD_fixed_param *cmd;
VOS_STATUS status = VOS_STATUS_SUCCESS;
WMA_LOGD("%s Enter", __func__);
/* Get the vdev id */
if (!wma_find_vdev_by_bssid(wma, params->bssId, &vdev_id)) {
WMA_LOGE("vdev handle is invalid for %pM", params->bssId);
status = VOS_STATUS_E_INVAL;
goto out;
}
len = sizeof(*cmd);
/* alloc wmi buffer */
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD");
status = VOS_STATUS_E_NOMEM;
goto out;
}
cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_GTK_OFFLOAD_CMD_fixed_param));
/* Request for GTK offload status */
cmd->flags = GTK_OFFLOAD_REQUEST_STATUS_OPCODE;
cmd->vdev_id = vdev_id;
/* send the wmi command */
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_GTK_OFFLOAD_CMDID)) {
WMA_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID for req info");
wmi_buf_free(buf);
status = VOS_STATUS_E_FAILURE;
}
out:
vos_mem_free(params);
WMA_LOGD("%s Exit", __func__);
return status;
}
#endif
/**
* wma_fill_arp_offload_params() - Fill ARP offload data
* @wma: wma handle
* @tpSirHostOffloadReq: offload request
* @buf_ptr: buffer pointer
*
* To fill ARP offload data to firmware
* when target goes to wow mode.
*
* Return: None
*/
static void wma_fill_arp_offload_params(tp_wma_handle wma,
tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr)
{
int32_t i;
WMI_ARP_OFFLOAD_TUPLE *arp_tuple;
bool enableOrDisable = hostoffloadreq->enableOrDisable;
WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC,
(WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE)));
*buf_ptr += WMI_TLV_HDR_SIZE;
for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) {
arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *)*buf_ptr;
WMITLV_SET_HDR(&arp_tuple->tlv_header,
WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE,
WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE));
/* Fill data for ARP and NS in the first tupple for LA */
if ((enableOrDisable & SIR_OFFLOAD_ENABLE) && (i == 0)) {
/* Copy the target ip addr and flags */
arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID;
A_MEMCPY(&arp_tuple->target_ipaddr,
hostoffloadreq->params.hostIpv4Addr,
SIR_IPV4_ADDR_LEN);
WMA_LOGD("ARPOffload IP4 address: %pI4",
hostoffloadreq->params.hostIpv4Addr);
}
*buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE);
}
}
#ifdef WLAN_NS_OFFLOAD
/**
* wma_fill_ns_offload_params() - Fill NS offload data
* @wma: wma handle
* @tpSirHostOffloadReq: offload request
* @buf_ptr: buffer pointer
*
* To fill NS offload data to firmware
* when target goes to wow mode.
*
* Return: None
*/
static void wma_fill_ns_offload_params(tp_wma_handle wma,
tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr)
{
int32_t i;
WMI_NS_OFFLOAD_TUPLE *ns_tuple;
tSirNsOffloadReq ns_req;
ns_req = hostoffloadreq->nsOffloadInfo;
WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC,
(WMI_MAX_NS_OFFLOADS*sizeof(WMI_NS_OFFLOAD_TUPLE)));
*buf_ptr += WMI_TLV_HDR_SIZE;
for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) {
ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr;
WMITLV_SET_HDR(&ns_tuple->tlv_header,
WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE,
(sizeof(WMI_NS_OFFLOAD_TUPLE) - WMI_TLV_HDR_SIZE));
/*
* Fill data only for NS offload in the first ARP tuple for LA
*/
if ((hostoffloadreq->enableOrDisable & SIR_OFFLOAD_ENABLE)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID;
/* Copy the target/solicitation/remote ip addr */
if (ns_req.targetIPv6AddrValid[i])
A_MEMCPY(&ns_tuple->target_ipaddr[0],
&ns_req.targetIPv6Addr[i],
sizeof(WMI_IPV6_ADDR));
A_MEMCPY(&ns_tuple->solicitation_ipaddr,
&ns_req.selfIPv6Addr[i],
sizeof(WMI_IPV6_ADDR));
if (ns_req.target_ipv6_addr_type[i]) {
ns_tuple->flags |=
WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST;
}
WMA_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6",
i, &ns_req.selfIPv6Addr[i],
&ns_req.targetIPv6Addr[i]);
/* target MAC is optional, check if it is valid,
* if this is not valid, the target will use the known
* local MAC address rather than the tuple
*/
WMI_CHAR_ARRAY_TO_MAC_ADDR(
ns_req.selfMacAddr,
&ns_tuple->target_mac);
if ((ns_tuple->target_mac.mac_addr31to0 != 0) ||
(ns_tuple->target_mac.mac_addr47to32 != 0)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID;
}
}
*buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE);
}
}
/**
* wma_fill_nsoffload_ext() - Fill NS offload ext data
* @wma: wma handle
* @tpSirHostOffloadReq: offload request
* @buf_ptr: buffer pointer
*
* To fill extended NS offload extended data to firmware
* when target goes to wow mode.
*
* Return: None
*/
static void wma_fill_nsoffload_ext(tp_wma_handle wma, tpSirHostOffloadReq
hostoffloadreq, uint8_t **buf_ptr)
{
int32_t i;
WMI_NS_OFFLOAD_TUPLE *ns_tuple;
uint32_t count, num_ns_ext_tuples;
tSirNsOffloadReq ns_req;
ns_req = hostoffloadreq->nsOffloadInfo;
count = hostoffloadreq->num_ns_offload_count;
num_ns_ext_tuples = hostoffloadreq->num_ns_offload_count -
WMI_MAX_NS_OFFLOADS;
/* Populate extended NS offload tuples */
WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC,
(num_ns_ext_tuples * sizeof(WMI_NS_OFFLOAD_TUPLE)));
*buf_ptr += WMI_TLV_HDR_SIZE;
for (i = WMI_MAX_NS_OFFLOADS; i < count; i++) {
ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr;
WMITLV_SET_HDR(&ns_tuple->tlv_header,
WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE,
(sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE));
/*
* Fill data only for NS offload in the first ARP tuple for LA
*/
if ((hostoffloadreq->enableOrDisable & SIR_OFFLOAD_ENABLE)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID;
/* Copy the target/solicitation/remote ip addr */
if (ns_req.targetIPv6AddrValid[i])
A_MEMCPY(&ns_tuple->target_ipaddr[0],
&ns_req.targetIPv6Addr[i],
sizeof(WMI_IPV6_ADDR));
A_MEMCPY(&ns_tuple->solicitation_ipaddr,
&ns_req.selfIPv6Addr[i],
sizeof(WMI_IPV6_ADDR));
if (ns_req.target_ipv6_addr_type[i]) {
ns_tuple->flags |=
WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST;
}
WMA_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6",
i, &ns_req.selfIPv6Addr[i],
&ns_req.targetIPv6Addr[i]);
/* target MAC is optional, check if it is valid,
* if this is not valid, the target will use the
* known local MAC address rather than the tuple
*/
WMI_CHAR_ARRAY_TO_MAC_ADDR(
ns_req.selfMacAddr,
&ns_tuple->target_mac);
if ((ns_tuple->target_mac.mac_addr31to0 != 0) ||
(ns_tuple->target_mac.mac_addr47to32 != 0)) {
ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID;
}
}
*buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE);
}
}
#else
static inline void wma_fill_ns_offload_params(tp_wma_handle wma,
tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr)
{
return;
}
static inline void wma_fill_nsoffload_ext(tp_wma_handle wma,
tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr)
{
return;
}
#endif
/**
* wma_enable_arp_ns_offload() - enable ARP NS offload
* @wma: wma handle
* @tpSirHostOffloadReq: offload request
* @config_arp: flag
*
* To configure ARP NS off load data to firmware
* when target goes to wow mode.
*
* Return: VOS Status
*/
static VOS_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma,
tpSirHostOffloadReq hostoffloadreq, bool config_arp)
{
int32_t res;
WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *cmd;
A_UINT8* buf_ptr;
wmi_buf_t buf;
uint32_t len;
VOS_STATUS status = VOS_STATUS_SUCCESS;
u_int8_t vdev_id;
tpSirHostOffloadReq ns_offload_req;
tpSirHostOffloadReq arp_offload_req;
uint32_t count = 0, num_ns_ext_tuples = 0;
/* Get the vdev id */
if (!wma_find_vdev_by_bssid(wma, hostoffloadreq->bssId, &vdev_id)) {
WMA_LOGE("Invalid vdev handle for %pM", hostoffloadreq->bssId);
status = VOS_STATUS_E_FAILURE;
goto err_vdev;
}
if (!wma->interfaces[vdev_id].vdev_up) {
WMA_LOGE("vdev %d is not up skipping arp/ns offload", vdev_id);
status = VOS_STATUS_E_FAILURE;
goto err_vdev;
}
/*
* config_arp is true means arp request comes from upper layer
* Hence ns request need to used from wma cached request.
*/
if (config_arp) {
arp_offload_req = hostoffloadreq;
ns_offload_req = &wma->interfaces[vdev_id].ns_offload_req;
count = ns_offload_req->num_ns_offload_count;
} else {
ns_offload_req = hostoffloadreq;
arp_offload_req = &wma->interfaces[vdev_id].arp_offload_req;
count = hostoffloadreq->num_ns_offload_count;
}
if (count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) {
status = VOS_STATUS_E_INVAL;
goto err_vdev;
}
len = sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param) +
WMI_TLV_HDR_SIZE + /* Add size for array of NS tuples */
WMI_MAX_NS_OFFLOADS*sizeof(WMI_NS_OFFLOAD_TUPLE) +
WMI_TLV_HDR_SIZE + /* Add size for array of ARP tuples */
WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE);
if (count > WMI_MAX_NS_OFFLOADS) {
num_ns_ext_tuples = count - WMI_MAX_NS_OFFLOADS;
len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples
* sizeof(WMI_NS_OFFLOAD_TUPLE);
}
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
status = VOS_STATUS_E_NOMEM;
goto err_vdev;
}
buf_ptr = (A_UINT8*)wmi_buf_data(buf);
cmd = (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param));
cmd->flags = 0;
cmd->vdev_id = vdev_id;
cmd->num_ns_ext_tuples = num_ns_ext_tuples;
buf_ptr += sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param);
if (config_arp)
WMA_LOGD(" %s: ARP Offload vdev_id: %d enable: %d ns_count: %u",
__func__, cmd->vdev_id,
hostoffloadreq->enableOrDisable,
hostoffloadreq->num_ns_offload_count);
else
WMA_LOGD(" %s: NS Offload vdev_id: %d enable: %d ns_count: %u",
__func__, cmd->vdev_id,
hostoffloadreq->enableOrDisable,
hostoffloadreq->num_ns_offload_count);
wma_fill_ns_offload_params(wma, ns_offload_req, &buf_ptr);
wma_fill_arp_offload_params(wma, arp_offload_req, &buf_ptr);
if (count > WMI_MAX_NS_OFFLOADS)
wma_fill_nsoffload_ext(wma, ns_offload_req, &buf_ptr);
res = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_SET_ARP_NS_OFFLOAD_CMDID);
if (res) {
WMA_LOGW("Failed to enable ARP NDP/NSffload");
goto err_cmd_send;
}
if (config_arp) {
vos_mem_copy(&wma->interfaces[vdev_id].arp_offload_req,
hostoffloadreq, sizeof(tSirHostOffloadReq));
} else {
vos_mem_copy(&wma->interfaces[vdev_id].ns_offload_req,
hostoffloadreq, sizeof(tSirHostOffloadReq));
}
vos_mem_free(hostoffloadreq);
return status;
err_cmd_send:
wmi_buf_free(buf);
err_vdev:
vos_mem_free(hostoffloadreq);
return status;
}
typedef struct {
int32_t rate;
tANI_U8 flag;
} wma_search_rate_t;
#define WMA_MAX_OFDM_CCK_RATE_TBL_SIZE 12
/* In ofdm_cck_rate_tbl->flag, if bit 7 is 1 it's CCK, otherwise it ofdm.
* Lower bit carries the ofdm/cck index for encoding the rate */
static wma_search_rate_t ofdm_cck_rate_tbl[WMA_MAX_OFDM_CCK_RATE_TBL_SIZE] = {
{540, 4}, /* 4: OFDM 54 Mbps */
{480, 0}, /* 0: OFDM 48 Mbps */
{360, 5}, /* 5: OFDM 36 Mbps */
{240, 1}, /* 1: OFDM 24 Mbps */
{180, 6}, /* 6: OFDM 18 Mbps */
{120, 2}, /* 2: OFDM 12 Mbps */
{110, (1 << 7)}, /* 0: CCK 11 Mbps Long */
{90, 7}, /* 7: OFDM 9 Mbps */
{60, 3}, /* 3: OFDM 6 Mbps */
{55, ((1 << 7)|1)}, /* 1: CCK 5.5 Mbps Long */
{20, ((1 << 7)|2)}, /* 2: CCK 2 Mbps Long */
{10, ((1 << 7)|3)} /* 3: CCK 1 Mbps Long */
};
#define WMA_MAX_VHT20_RATE_TBL_SIZE 9
/* In vht20_400ns_rate_tbl flag carries the mcs index for encoding the rate */
static wma_search_rate_t vht20_400ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = {
{867, 8}, /* MCS8 1SS short GI */
{722, 7}, /* MCS7 1SS short GI */
{650, 6}, /* MCS6 1SS short GI */
{578, 5}, /* MCS5 1SS short GI */
{433, 4}, /* MCS4 1SS short GI */
{289, 3}, /* MCS3 1SS short GI */
{217, 2}, /* MCS2 1SS short GI */
{144, 1}, /* MCS1 1SS short GI */
{72, 0} /* MCS0 1SS short GI */
};
/* In vht20_800ns_rate_tbl flag carries the mcs index for encoding the rate */
static wma_search_rate_t vht20_800ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = {
{780, 8}, /* MCS8 1SS long GI */
{650, 7}, /* MCS7 1SS long GI */
{585, 6}, /* MCS6 1SS long GI */
{520, 5}, /* MCS5 1SS long GI */
{390, 4}, /* MCS4 1SS long GI */
{260, 3}, /* MCS3 1SS long GI */
{195, 2}, /* MCS2 1SS long GI */
{130, 1}, /* MCS1 1SS long GI */
{65, 0} /* MCS0 1SS long GI */
};
#define WMA_MAX_VHT40_RATE_TBL_SIZE 10
/* In vht40_400ns_rate_tbl flag carries the mcs index for encoding the rate */
static wma_search_rate_t vht40_400ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = {
{2000, 9}, /* MCS9 1SS short GI */
{1800, 8}, /* MCS8 1SS short GI */
{1500, 7}, /* MCS7 1SS short GI */
{1350, 6}, /* MCS6 1SS short GI */
{1200, 5}, /* MCS5 1SS short GI */
{900, 4}, /* MCS4 1SS short GI */
{600, 3}, /* MCS3 1SS short GI */
{450, 2}, /* MCS2 1SS short GI */
{300, 1}, /* MCS1 1SS short GI */
{150, 0}, /* MCS0 1SS short GI */
};
static wma_search_rate_t vht40_800ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = {
{1800, 9}, /* MCS9 1SS long GI */
{1620, 8}, /* MCS8 1SS long GI */
{1350, 7}, /* MCS7 1SS long GI */
{1215, 6}, /* MCS6 1SS long GI */
{1080, 5}, /* MCS5 1SS long GI */
{810, 4}, /* MCS4 1SS long GI */
{540, 3}, /* MCS3 1SS long GI */
{405, 2}, /* MCS2 1SS long GI */
{270, 1}, /* MCS1 1SS long GI */
{135, 0} /* MCS0 1SS long GI */
};
#define WMA_MAX_VHT80_RATE_TBL_SIZE 10
static wma_search_rate_t vht80_400ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = {
{4333, 9}, /* MCS9 1SS short GI */
{3900, 8}, /* MCS8 1SS short GI */
{3250, 7}, /* MCS7 1SS short GI */
{2925, 6}, /* MCS6 1SS short GI */
{2600, 5}, /* MCS5 1SS short GI */
{1950, 4}, /* MCS4 1SS short GI */
{1300, 3}, /* MCS3 1SS short GI */
{975, 2}, /* MCS2 1SS short GI */
{650, 1}, /* MCS1 1SS short GI */
{325, 0} /* MCS0 1SS short GI */
};
static wma_search_rate_t vht80_800ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = {
{3900, 9}, /* MCS9 1SS long GI */
{3510, 8}, /* MCS8 1SS long GI */
{2925, 7}, /* MCS7 1SS long GI */
{2633, 6}, /* MCS6 1SS long GI */
{2340, 5}, /* MCS5 1SS long GI */
{1755, 4}, /* MCS4 1SS long GI */
{1170, 3}, /* MCS3 1SS long GI */
{878, 2}, /* MCS2 1SS long GI */
{585, 1}, /* MCS1 1SS long GI */
{293, 0} /* MCS0 1SS long GI */
};
#define WMA_MAX_HT20_RATE_TBL_SIZE 8
static wma_search_rate_t ht20_400ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = {
{722, 7}, /* MCS7 1SS short GI */
{650, 6}, /* MCS6 1SS short GI */
{578, 5}, /* MCS5 1SS short GI */
{433, 4}, /* MCS4 1SS short GI */
{289, 3}, /* MCS3 1SS short GI */
{217, 2}, /* MCS2 1SS short GI */
{144, 1}, /* MCS1 1SS short GI */
{72, 0} /* MCS0 1SS short GI */
};
static wma_search_rate_t ht20_800ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = {
{650, 7}, /* MCS7 1SS long GI */
{585, 6}, /* MCS6 1SS long GI */
{520, 5}, /* MCS5 1SS long GI */
{390, 4}, /* MCS4 1SS long GI */
{260, 3}, /* MCS3 1SS long GI */
{195, 2}, /* MCS2 1SS long GI */
{130, 1}, /* MCS1 1SS long GI */
{65, 0} /* MCS0 1SS long GI */
};
#define WMA_MAX_HT40_RATE_TBL_SIZE 8
static wma_search_rate_t ht40_400ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = {
{1500, 7}, /* MCS7 1SS short GI */
{1350, 6}, /* MCS6 1SS short GI */
{1200, 5}, /* MCS5 1SS short GI */
{900, 4}, /* MCS4 1SS short GI */
{600, 3}, /* MCS3 1SS short GI */
{450, 2}, /* MCS2 1SS short GI */
{300, 1}, /* MCS1 1SS short GI */
{150, 0} /* MCS0 1SS short GI */
};
static wma_search_rate_t ht40_800ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = {
{1350, 7}, /* MCS7 1SS long GI */
{1215, 6}, /* MCS6 1SS long GI */
{1080, 5}, /* MCS5 1SS long GI */
{810, 4}, /* MCS4 1SS long GI */
{540, 3}, /* MCS3 1SS long GI */
{405, 2}, /* MCS2 1SS long GI */
{270, 1}, /* MCS1 1SS long GI */
{135, 0} /* MCS0 1SS long GI */
};
static void wma_bin_search_rate(wma_search_rate_t *tbl, int32_t tbl_size,
tANI_S32 *mbpsx10_rate, tANI_U8 *ret_flag)
{
int32_t upper, lower, mid;
/* the table is descenting. index holds the largest value and the
* bottom index holds the smallest value */
upper = 0; /* index 0 */
lower = tbl_size -1; /* last index */
if (*mbpsx10_rate >= tbl[upper].rate) {
/* use the largest rate */
*mbpsx10_rate = tbl[upper].rate;
*ret_flag = tbl[upper].flag;
return;
} else if (*mbpsx10_rate <= tbl[lower].rate) {
/* use the smallest rate */
*mbpsx10_rate = tbl[lower].rate;
*ret_flag = tbl[lower].flag;
return;
}
/* now we do binery search to get the floor value */
while (lower - upper > 1) {
mid = (upper + lower) >> 1;
if (*mbpsx10_rate == tbl[mid].rate) {
/* found the exact match */
*mbpsx10_rate = tbl[mid].rate;
*ret_flag = tbl[mid].flag;
return;
} else {
/* not found. if mid's rate is larger than input move
* upper to mid. If mid's rate is larger than input
* move lower to mid. */
if (*mbpsx10_rate > tbl[mid].rate)
lower = mid;
else
upper = mid;
}
}
/* after the bin search the index is the ceiling of rate */
*mbpsx10_rate = tbl[upper].rate;
*ret_flag = tbl[upper].flag;
return;
}
static VOS_STATUS wma_fill_ofdm_cck_mcast_rate(tANI_S32 mbpsx10_rate,
tANI_U8 nss, tANI_U8 *rate)
{
tANI_U8 idx = 0;
wma_bin_search_rate(ofdm_cck_rate_tbl, WMA_MAX_OFDM_CCK_RATE_TBL_SIZE,
&mbpsx10_rate, &idx);
/* if bit 7 is set it uses CCK */
if (idx & 0x80)
*rate |= (1 << 6) | (idx & 0xF); /* set bit 6 to 1 for CCK */
else
*rate |= (idx & 0xF);
return VOS_STATUS_SUCCESS;
}
static void wma_set_ht_vht_mcast_rate(u_int32_t shortgi, tANI_S32 mbpsx10_rate,
tANI_U8 sgi_idx, tANI_S32 sgi_rate, tANI_U8 lgi_idx, tANI_S32 lgi_rate,
tANI_U8 premable, tANI_U8 *rate, tANI_S32 *streaming_rate)
{
if (shortgi == 0) {
*rate |= (premable << 6) | (lgi_idx & 0xF);
*streaming_rate = lgi_rate;
} else {
*rate |= (premable << 6) | (sgi_idx & 0xF);
*streaming_rate = sgi_rate;
}
}
static VOS_STATUS wma_fill_ht20_mcast_rate(u_int32_t shortgi,
tANI_S32 mbpsx10_rate, tANI_U8 nss, tANI_U8 *rate,
tANI_S32 *streaming_rate)
{
tANI_U8 sgi_idx = 0, lgi_idx = 0;
tANI_S32 sgi_rate, lgi_rate;
if (nss == 1)
mbpsx10_rate= mbpsx10_rate >> 1;
sgi_rate = mbpsx10_rate;
lgi_rate = mbpsx10_rate;
if (shortgi)
wma_bin_search_rate(ht20_400ns_rate_tbl,
WMA_MAX_HT20_RATE_TBL_SIZE, &sgi_rate, &sgi_idx);
else
wma_bin_search_rate(ht20_800ns_rate_tbl,
WMA_MAX_HT20_RATE_TBL_SIZE, &lgi_rate, &lgi_idx);
wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate,
lgi_idx, lgi_rate, 2, rate, streaming_rate);
if (nss == 1)
*streaming_rate = *streaming_rate << 1;
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_fill_ht40_mcast_rate(u_int32_t shortgi,
tANI_S32 mbpsx10_rate, tANI_U8 nss, tANI_U8 *rate,
tANI_S32 *streaming_rate)
{
tANI_U8 sgi_idx = 0, lgi_idx = 0;
tANI_S32 sgi_rate, lgi_rate;
/* for 2x2 divide the rate by 2 */
if (nss == 1)
mbpsx10_rate= mbpsx10_rate >> 1;
sgi_rate = mbpsx10_rate;
lgi_rate = mbpsx10_rate;
if (shortgi)
wma_bin_search_rate(ht40_400ns_rate_tbl,
WMA_MAX_HT40_RATE_TBL_SIZE, &sgi_rate, &sgi_idx);
else
wma_bin_search_rate(ht40_800ns_rate_tbl,
WMA_MAX_HT40_RATE_TBL_SIZE, &lgi_rate, &lgi_idx);
wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate,
lgi_idx, lgi_rate, 2, rate, streaming_rate);
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_fill_vht20_mcast_rate(u_int32_t shortgi,
tANI_S32 mbpsx10_rate, tANI_U8 nss, tANI_U8 *rate,
tANI_S32 *streaming_rate)
{
tANI_U8 sgi_idx = 0, lgi_idx = 0;
tANI_S32 sgi_rate, lgi_rate;
/* for 2x2 divide the rate by 2 */
if (nss == 1)
mbpsx10_rate= mbpsx10_rate >> 1;
sgi_rate = mbpsx10_rate;
lgi_rate = mbpsx10_rate;
if (shortgi)
wma_bin_search_rate(vht20_400ns_rate_tbl,
WMA_MAX_VHT20_RATE_TBL_SIZE, &sgi_rate, &sgi_idx);
else
wma_bin_search_rate(vht20_800ns_rate_tbl,
WMA_MAX_VHT20_RATE_TBL_SIZE, &lgi_rate, &lgi_idx);
wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate,
lgi_idx, lgi_rate, 3, rate, streaming_rate);
if (nss == 1)
*streaming_rate = *streaming_rate << 1;
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_fill_vht40_mcast_rate(u_int32_t shortgi,
tANI_S32 mbpsx10_rate, tANI_U8 nss, tANI_U8 *rate,
tANI_S32 *streaming_rate)
{
tANI_U8 sgi_idx = 0, lgi_idx = 0;
tANI_S32 sgi_rate, lgi_rate;
/* for 2x2 divide the rate by 2 */
if (nss == 1)
mbpsx10_rate= mbpsx10_rate >> 1;
sgi_rate = mbpsx10_rate;
lgi_rate = mbpsx10_rate;
if (shortgi)
wma_bin_search_rate(vht40_400ns_rate_tbl,
WMA_MAX_VHT40_RATE_TBL_SIZE, &sgi_rate, &sgi_idx);
else
wma_bin_search_rate(vht40_800ns_rate_tbl,
WMA_MAX_VHT40_RATE_TBL_SIZE, &lgi_rate, &lgi_idx);
wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate,
sgi_idx, sgi_rate, lgi_idx, lgi_rate,
3, rate, streaming_rate);
if (nss == 1)
*streaming_rate = *streaming_rate << 1;
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_fill_vht80_mcast_rate(u_int32_t shortgi,
tANI_S32 mbpsx10_rate, tANI_U8 nss, tANI_U8 *rate,
tANI_S32 *streaming_rate)
{
tANI_U8 sgi_idx = 0, lgi_idx = 0;
tANI_S32 sgi_rate, lgi_rate;
/* for 2x2 divide the rate by 2 */
if (nss == 1)
mbpsx10_rate= mbpsx10_rate >> 1;
sgi_rate = mbpsx10_rate;
lgi_rate = mbpsx10_rate;
if (shortgi)
wma_bin_search_rate(vht80_400ns_rate_tbl,
WMA_MAX_VHT80_RATE_TBL_SIZE, &sgi_rate, &sgi_idx);
else
wma_bin_search_rate(vht80_800ns_rate_tbl,
WMA_MAX_VHT80_RATE_TBL_SIZE, &lgi_rate, &lgi_idx);
wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate,
lgi_idx, lgi_rate, 3, rate, streaming_rate);
if (nss == 1)
*streaming_rate = *streaming_rate << 1;
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_fill_ht_mcast_rate(u_int32_t shortgi,
u_int32_t chwidth, tANI_S32 mbpsx10_rate, tANI_U8 nss,
WLAN_PHY_MODE chanmode, tANI_U8 *rate, tANI_S32 *streaming_rate)
{
int32_t ret = 0;
*streaming_rate = 0;
if (chwidth== 0)
ret = wma_fill_ht20_mcast_rate(shortgi, mbpsx10_rate,
nss, rate, streaming_rate);
else if (chwidth == 1)
ret = wma_fill_ht40_mcast_rate(shortgi, mbpsx10_rate,
nss, rate, streaming_rate);
else
WMA_LOGE("%s: Error, Invalid chwidth enum %d", __func__, chwidth);
return (*streaming_rate != 0) ? VOS_STATUS_SUCCESS : VOS_STATUS_E_INVAL;
}
static VOS_STATUS wma_fill_vht_mcast_rate(u_int32_t shortgi,
u_int32_t chwidth, tANI_S32 mbpsx10_rate, tANI_U8 nss,
WLAN_PHY_MODE chanmode, tANI_U8 *rate, tANI_S32 *streaming_rate)
{
int32_t ret = 0;
*streaming_rate = 0;
if (chwidth== 0)
ret = wma_fill_vht20_mcast_rate(shortgi, mbpsx10_rate, nss,
rate, streaming_rate);
else if (chwidth == 1)
ret = wma_fill_vht40_mcast_rate(shortgi, mbpsx10_rate, nss,
rate, streaming_rate);
else if (chwidth == 2)
ret = wma_fill_vht80_mcast_rate(shortgi, mbpsx10_rate, nss,
rate, streaming_rate);
else
WMA_LOGE("%s: chwidth enum %d not supported",
__func__, chwidth);
return (*streaming_rate != 0) ? VOS_STATUS_SUCCESS : VOS_STATUS_E_INVAL;
}
#define WMA_MCAST_1X1_CUT_OFF_RATE 2000
/*
* FUNCTION: wma_encode_mc_rate
*
*/
static VOS_STATUS wma_encode_mc_rate(u_int32_t shortgi, u_int32_t chwidth,
WLAN_PHY_MODE chanmode, A_UINT32 mhz, tANI_S32 mbpsx10_rate,
tANI_U8 nss, tANI_U8 *rate)
{
int32_t ret = 0;
/* nss input value: 0 - 1x1; 1 - 2x2; 2 - 3x3
* the phymode selection is based on following assumption:
* (1) if the app specifically requested 1x1 or 2x2 we hornor it
* (2) if mbpsx10_rate <= 540: always use BG
* (3) 540 < mbpsx10_rate <= 2000: use 1x1 HT/VHT
* (4) 2000 < mbpsx10_rate: use 2x2 HT/VHT
*/
WMA_LOGE("%s: Input: nss = %d, chanmode = %d, "
"mbpsx10 = 0x%x, chwidth = %d, shortgi = %d",
__func__, nss, chanmode, mbpsx10_rate, chwidth, shortgi);
if ((mbpsx10_rate & 0x40000000) && nss > 0) {
/* bit 30 indicates user inputed nss,
* bit 28 and 29 used to encode nss */
tANI_U8 user_nss = (mbpsx10_rate & 0x30000000) >> 28;
nss = (user_nss < nss) ? user_nss : nss;
/* zero out bits 19 - 21 to recover the actual rate */
mbpsx10_rate &= ~0x70000000;
} else if (mbpsx10_rate <= WMA_MCAST_1X1_CUT_OFF_RATE) {
/* if the input rate is less or equal to the
* 1x1 cutoff rate we use 1x1 only */
nss = 0;
}
/* encode NSS bits (bit 4, bit 5) */
*rate = (nss & 0x3) << 4;
/* if mcast input rate exceeds the ofdm/cck max rate 54mpbs
* we try to choose best ht/vht mcs rate */
if (540 < mbpsx10_rate) {
/* cannot use ofdm/cck, choose closest ht/vht mcs rate */
tANI_U8 rate_ht = *rate;
tANI_U8 rate_vht = *rate;
tANI_S32 stream_rate_ht = 0;
tANI_S32 stream_rate_vht = 0;
tANI_S32 stream_rate = 0;
ret = wma_fill_ht_mcast_rate(shortgi, chwidth, mbpsx10_rate,
nss, chanmode, &rate_ht, &stream_rate_ht);
if (ret != VOS_STATUS_SUCCESS) {
stream_rate_ht = 0;
}
if (mhz < WMA_2_4_GHZ_MAX_FREQ) {
/* not in 5 GHZ frequency */
*rate = rate_ht;
stream_rate = stream_rate_ht;
goto ht_vht_done;
}
/* capable doing 11AC mcast so that search vht tables */
ret = wma_fill_vht_mcast_rate(shortgi, chwidth, mbpsx10_rate,
nss, chanmode, &rate_vht, &stream_rate_vht);
if (ret != VOS_STATUS_SUCCESS) {
if (stream_rate_ht != 0)
ret = VOS_STATUS_SUCCESS;
*rate = rate_ht;
stream_rate = stream_rate_ht;
goto ht_vht_done;
}
if (stream_rate_ht == 0) {
/* only vht rate available */
*rate = rate_vht;
stream_rate = stream_rate_vht;
} else {
/* set ht as default first */
*rate = rate_ht;
stream_rate = stream_rate_ht;
if (stream_rate < mbpsx10_rate) {
if (mbpsx10_rate <= stream_rate_vht ||
stream_rate < stream_rate_vht) {
*rate = rate_vht;
stream_rate = stream_rate_vht;
}
} else {
if (stream_rate_vht >= mbpsx10_rate &&
stream_rate_vht < stream_rate) {
*rate = rate_vht;
stream_rate = stream_rate_vht;
}
}
}
ht_vht_done:
WMA_LOGE("%s: NSS = %d, ucast_chanmode = %d, "
"freq = %d, input_rate = %d, chwidth = %d "
"rate = 0x%x, streaming_rate = %d",
__func__, nss, chanmode, mhz,
mbpsx10_rate, chwidth, *rate, stream_rate);
} else {
if (mbpsx10_rate > 0)
ret = wma_fill_ofdm_cck_mcast_rate(mbpsx10_rate,
nss, rate);
else
*rate = 0xFF;
WMA_LOGE("%s: NSS = %d, ucast_chanmode = %d, "
"input_rate = %d, rate = 0x%x",
__func__, nss, chanmode, mbpsx10_rate, *rate);
}
return ret;
}
/*
* FUNCTION: wma_process_rate_update_indate
*
*/
VOS_STATUS wma_process_rate_update_indicate(tp_wma_handle wma,
tSirRateUpdateInd *pRateUpdateParams)
{
int32_t ret = 0;
u_int8_t vdev_id = 0;
void *pdev;
tANI_S32 mbpsx10_rate = -1;
tANI_U32 paramId;
tANI_U8 rate = 0;
u_int32_t short_gi;
struct wma_txrx_node *intr = wma->interfaces;
/* Get the vdev id */
pdev = wma_find_vdev_by_addr(wma, pRateUpdateParams->bssid, &vdev_id);
if (!pdev) {
WMA_LOGE("vdev handle is invalid for %pM", pRateUpdateParams->bssid);
vos_mem_free(pRateUpdateParams);
return VOS_STATUS_E_INVAL;
}
short_gi = intr[vdev_id].config.shortgi;
if (short_gi == 0)
short_gi = (intr[vdev_id].rate_flags & eHAL_TX_RATE_SGI) ? TRUE : FALSE;
/* first check if reliable TX mcast rate is used. If not check the bcast.
* Then is mcast. Mcast rate is saved in mcastDataRate24GHz */
if (pRateUpdateParams->reliableMcastDataRateTxFlag > 0) {
mbpsx10_rate = pRateUpdateParams->reliableMcastDataRate;
paramId = WMI_VDEV_PARAM_MCAST_DATA_RATE;
if (pRateUpdateParams->reliableMcastDataRateTxFlag & eHAL_TX_RATE_SGI)
short_gi = 1; /* upper layer specified short GI */
} else if (pRateUpdateParams->bcastDataRate > -1) {
mbpsx10_rate = pRateUpdateParams->bcastDataRate;
paramId = WMI_VDEV_PARAM_BCAST_DATA_RATE;
} else {
mbpsx10_rate = pRateUpdateParams->mcastDataRate24GHz;
paramId = WMI_VDEV_PARAM_MCAST_DATA_RATE;
if (pRateUpdateParams->mcastDataRate24GHzTxFlag & eHAL_TX_RATE_SGI)
short_gi = 1; /* upper layer specified short GI */
}
WMA_LOGE("%s: dev_id = %d, dev_type = %d, dev_mode = %d, "
"mac = %pM, config.shortgi = %d, rate_flags = 0x%x",
__func__, vdev_id, intr[vdev_id].type,
pRateUpdateParams->dev_mode, pRateUpdateParams->bssid,
intr[vdev_id].config.shortgi, intr[vdev_id].rate_flags);
ret = wma_encode_mc_rate(short_gi, intr[vdev_id].config.chwidth,
intr[vdev_id].chanmode, intr[vdev_id].mhz,
mbpsx10_rate, pRateUpdateParams->nss, &rate);
if (ret != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Error, Invalid input rate value", __func__);
vos_mem_free(pRateUpdateParams);
return ret;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_SGI, short_gi);
if (ret) {
WMA_LOGE("%s: Failed to Set WMI_VDEV_PARAM_SGI (%d), ret = %d",
__func__, short_gi, ret);
vos_mem_free(pRateUpdateParams);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
vdev_id, paramId, rate);
vos_mem_free(pRateUpdateParams);
if (ret) {
WMA_LOGE("%s: Failed to Set rate, ret = %d", __func__, ret);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_11AC
static void wma_process_update_membership(tp_wma_handle wma_handle,
tUpdateMembership *membership)
{
WMA_LOGD("%s: membership = %x ", __func__,
membership->membership);
wma_set_peer_param(wma_handle, membership->peer_mac,
WMI_PEER_MEMBERSHIP, membership->membership,
membership->smesessionId);
}
static void wma_process_update_userpos(tp_wma_handle wma_handle,
tUpdateUserPos *userpos)
{
WMA_LOGD("%s: userPos = %x ", __func__, userpos->userPos);
wma_set_peer_param(wma_handle, userpos->peer_mac,
WMI_PEER_USERPOS, userpos->userPos,
userpos->smesessionId);
/* Now that membership/userpos is updated in fw,
* enable GID PPS.
*/
wma_set_ppsconfig(userpos->smesessionId,
WMA_VHT_PPS_GID_MATCH, 1);
}
#endif
/*
* FUNCTION: wma_find_ibss_vdev
* This function finds vdev_id based on input type
*/
int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type)
{
int32_t vdev_id = 0;
struct wma_txrx_node *intf = wma->interfaces;
for(vdev_id = 0; vdev_id < wma->max_bssid ; vdev_id++)
{
if (NULL != intf)
{
if (intf[vdev_id].type == type)
return vdev_id;
}
}
return -1;
}
/*
* FUNCTION: wma_process_cesium_enable_ind
* This function enables cesium functionality in target
*/
VOS_STATUS wma_process_cesium_enable_ind(tp_wma_handle wma)
{
int32_t ret;
int32_t vdev_id;
vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS);
if (vdev_id < 0)
{
WMA_LOGE("%s: IBSS vdev does not exist could not enable cesium",
__func__);
return VOS_STATUS_E_FAILURE;
}
/* Send enable cesium command to target */
WMA_LOGE("Enable cesium in target for vdevId %d ", vdev_id);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_ENABLE_RMC, 1);
if (ret)
{
WMA_LOGE("Enable cesium failed for vdevId %d", vdev_id);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/*
* FUNCTION: wma_process_get_peer_info_req
* This function sends get peer info cmd to target
*/
VOS_STATUS wma_process_get_peer_info_req
(
tp_wma_handle wma,
tSirIbssGetPeerInfoReqParams *pReq
)
{
int32_t ret;
u_int8_t *p;
u_int16_t len;
wmi_buf_t buf;
int32_t vdev_id;
ol_txrx_pdev_handle pdev;
struct ol_txrx_peer_t *peer;
u_int8_t peer_mac[IEEE80211_ADDR_LEN];
wmi_peer_info_req_cmd_fixed_param *p_get_peer_info_cmd;
u_int8_t bcast_mac[IEEE80211_ADDR_LEN] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS);
if (vdev_id < 0)
{
WMA_LOGE("%s: IBSS vdev does not exist could not get peer info",
__func__);
return VOS_STATUS_E_FAILURE;
}
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: Failed to get pdev context", __func__);
return VOS_STATUS_E_FAILURE;
}
if (0xFF == pReq->staIdx)
{
/*get info for all peers*/
vos_mem_copy(peer_mac, bcast_mac, IEEE80211_ADDR_LEN);
}
else
{
/*get info for a single peer*/
peer = ol_txrx_peer_find_by_local_id(pdev, pReq->staIdx);
if (!peer)
{
WMA_LOGE("%s: Failed to get peer handle using peer id %d",
__func__, pReq->staIdx);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGE("%s: staIdx %d peer mac: 0x%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x",
__func__, pReq->staIdx, 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]);
vos_mem_copy(peer_mac, peer->mac_addr.raw, IEEE80211_ADDR_LEN);
}
len = sizeof(wmi_peer_info_req_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf)
{
WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__);
return VOS_STATUS_E_FAILURE;
}
p = (u_int8_t *) wmi_buf_data(buf);
vos_mem_zero(p, len);
p_get_peer_info_cmd = (wmi_peer_info_req_cmd_fixed_param *)p;
WMITLV_SET_HDR(&p_get_peer_info_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_peer_info_req_cmd_fixed_param));
p_get_peer_info_cmd->vdev_id = vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_mac,&p_get_peer_info_cmd->peer_mac_address);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PEER_INFO_REQ_CMDID);
WMA_LOGE("IBSS get peer info cmd sent len: %d, vdev %d"
" command id: %d, status: %d", len, p_get_peer_info_cmd->vdev_id,
WMI_PEER_INFO_REQ_CMDID, ret);
return VOS_STATUS_SUCCESS;
}
/*
* FUNCTION: wma_process_tx_fail_monitor_ind
* This function sends tx fail monitor cmd to target
*/
VOS_STATUS wma_process_tx_fail_monitor_ind
(
tp_wma_handle wma,
tAniTXFailMonitorInd *pReq)
{
int32_t ret;
int32_t vdev_id;
vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS);
if (vdev_id < 0)
{
WMA_LOGE("%s: IBSS vdev does not exist could not send fast tx fail"
" monitor indication message to target", __func__);
return VOS_STATUS_E_FAILURE;
}
/* Send enable cesium command to target */
WMA_LOGE("send fast tx fail monitor ind cmd target for vdevId %d val %d",
vdev_id, pReq->tx_fail_count);
if (0 == pReq->tx_fail_count)
{
wma->hddTxFailCb = NULL;
}
else
{
wma->hddTxFailCb = pReq->txFailIndCallback;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, pReq->tx_fail_count);
if (ret)
{
WMA_LOGE("tx fail monitor failed for vdevId %d", vdev_id);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/*
* FUNCTION: wma_process_rmc_enable_ind
* This function enables RMC functionality in target
*/
VOS_STATUS wma_process_rmc_enable_ind(tp_wma_handle wma)
{
int ret;
u_int8_t *p;
u_int16_t len;
wmi_buf_t buf;
int32_t vdev_id;
wmi_rmc_set_mode_cmd_fixed_param *p_rmc_enable_cmd;
vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS);
if (vdev_id < 0)
{
WMA_LOGE("%s: IBSS vdev does not exist could not enable RMC",
__func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(wmi_rmc_set_mode_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf)
{
WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__);
return VOS_STATUS_E_FAILURE;
}
p = (u_int8_t *) wmi_buf_data(buf);
vos_mem_zero(p, len);
p_rmc_enable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *)p;
WMITLV_SET_HDR(&p_rmc_enable_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_rmc_set_mode_cmd_fixed_param));
p_rmc_enable_cmd->vdev_id = vdev_id;
p_rmc_enable_cmd->enable_rmc = WMI_RMC_MODE_ENABLED;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RMC_SET_MODE_CMDID);
WMA_LOGE("Enable RMC cmd sent len: %d, vdev %d" " command id: %d,"
" status: %d", len, p_rmc_enable_cmd->vdev_id, WMI_RMC_SET_MODE_CMDID,
ret);
return VOS_STATUS_SUCCESS;
}
/*
* FUNCTION: wma_process_rmc_disable_ind
* This function disables cesium functionality in target
*/
VOS_STATUS wma_process_rmc_disable_ind(tp_wma_handle wma)
{
int ret;
u_int8_t *p;
u_int16_t len;
wmi_buf_t buf;
int32_t vdev_id;
wmi_rmc_set_mode_cmd_fixed_param *p_rmc_disable_cmd;
vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS);
if (vdev_id < 0)
{
WMA_LOGE("%s: IBSS vdev does not exist could not disable RMC",
__func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(wmi_rmc_set_mode_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf)
{
WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__);
return VOS_STATUS_E_FAILURE;
}
p = (u_int8_t *) wmi_buf_data(buf);
vos_mem_zero(p, len);
p_rmc_disable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *)p;
WMITLV_SET_HDR(&p_rmc_disable_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_rmc_set_mode_cmd_fixed_param));
p_rmc_disable_cmd->vdev_id = vdev_id;
p_rmc_disable_cmd->enable_rmc = WMI_RMC_MODE_DISABLED;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RMC_SET_MODE_CMDID);
WMA_LOGE("Disable RMC cmd sent len: %d, vdev %d" " command id: %d,"
" status: %d", len, p_rmc_disable_cmd->vdev_id, WMI_RMC_SET_MODE_CMDID,
ret);
return VOS_STATUS_SUCCESS;
}
/*
* FUNCTION: wma_process_rmc_action_period_ind
* This function sends RMC action period to target
*/
VOS_STATUS wma_process_rmc_action_period_ind(tp_wma_handle wma)
{
int ret;
u_int8_t *p;
u_int16_t len;
u_int32_t val;
wmi_buf_t buf;
int32_t vdev_id;
wmi_rmc_set_action_period_cmd_fixed_param *p_rmc_cmd;
struct sAniSirGlobal *mac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (NULL == mac) {
WMA_LOGE("%s: MAC mac does not exist", __func__);
return VOS_STATUS_E_FAILURE;
}
vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS);
if (vdev_id < 0)
{
WMA_LOGE("%s: IBSS vdev does not exist could not send"
" RMC action period to target", __func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(wmi_rmc_set_action_period_cmd_fixed_param);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf)
{
WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__);
return VOS_STATUS_E_FAILURE;
}
p = (u_int8_t *) wmi_buf_data(buf);
vos_mem_zero(p, len);
p_rmc_cmd = (wmi_rmc_set_action_period_cmd_fixed_param *)p;
WMITLV_SET_HDR(&p_rmc_cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_rmc_set_action_period_cmd_fixed_param));
if (wlan_cfgGetInt(mac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, &val)
!= eSIR_SUCCESS)
{
WMA_LOGE("Failed to get value for RMC action period using default");
val = WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF;
}
p_rmc_cmd->vdev_id = vdev_id;
p_rmc_cmd->periodicity_msec = val;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RMC_SET_ACTION_PERIOD_CMDID);
WMA_LOGE("RMC action period %d cmd sent len: %d, vdev %d"
" command id: %d, status: %d", p_rmc_cmd->periodicity_msec, len,
p_rmc_cmd->vdev_id, WMI_RMC_SET_ACTION_PERIOD_CMDID, ret);
return VOS_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
static VOS_STATUS wma_set_thermal_suspend_params(tp_wma_handle wma)
{
wmi_thermal_mgmt_cmd_fixed_param *cmd;
wmi_buf_t buf;
int status;
u_int32_t len;
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set key cmd");
return eHAL_STATUS_FAILURE;
}
cmd = (wmi_thermal_mgmt_cmd_fixed_param *) wmi_buf_data (buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_thermal_mgmt_cmd_fixed_param));
cmd->lower_thresh_degreeC =
wma->thermal_mgmt_info.thermal_resume_threshold;
cmd->threshold_warning_degreeC =
wma->thermal_mgmt_info.thermal_warning_threshold;
cmd->upper_thresh_degreeC =
wma->thermal_mgmt_info.thermal_suspend_threshold;
cmd->enable = wma->thermal_mgmt_info.thermal_shutdown_enabled;
cmd->action = WMI_THERMAL_MGMT_ACTION_NOTIFY_HOST;
cmd->sample_rate_ms = wma->thermal_mgmt_info.thermal_sample_rate;
WMA_LOGD("thermal shutdown params: resume:%d, warning:%d, suspend:%d, "
"enable:%d, action:%d, sample rate:%d ms\n",
cmd->lower_thresh_degreeC, cmd->threshold_warning_degreeC,
cmd->upper_thresh_degreeC, cmd->enable, cmd->action,
cmd->sample_rate_ms);
status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_THERMAL_MGMT_CMDID);
if (status) {
wmi_buf_free(buf);
WMA_LOGE("%s:Failed to send thermal mgmt command", __func__);
return eHAL_STATUS_FAILURE;
}
return eHAL_STATUS_SUCCESS;
}
static void wma_thermal_temperature_ind(int32_t degree_c)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
vos_msg_t sme_msg = {0};
sme_msg.type = eWNI_SME_THERMAL_TEMPERATURE_IND;
sme_msg.bodyptr = NULL;
sme_msg.bodyval = (u_int32_t)degree_c;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
WMA_LOGE(FL("Fail to post temperature ind msg"));
}
#define CELSIUS_MIN_DEGREE (-273)
static bool need_thermal_temperature_ind(tp_thermal_mgmt info, int32_t degree_c)
{
static int32_t t_last = CELSIUS_MIN_DEGREE;
int ret = false;
int32_t t_curr = degree_c;
int32_t t_r = (int32_t)info->thermal_resume_threshold;
int32_t t_w = (int32_t)info->thermal_warning_threshold;
int32_t t_s = (int32_t)info->thermal_suspend_threshold;
if ((t_last >= t_r && t_curr < t_r) ||
(t_last < t_w && t_curr >= t_w) ||
(t_last < t_s && t_curr >= t_s) ||
(t_last == CELSIUS_MIN_DEGREE))
ret = true;
t_last = t_curr;
return ret;
}
#endif /* FEATURE_WLAN_THERMAL_SHUTDOWN */
#ifdef FEATURE_WLAN_THERMAL_SHUTDOWN
static void
wma_thermal_shutdown_evt_handler(tp_thermal_mgmt info, int32_t degree_c)
{
if (!info->thermal_shutdown_enabled)
return;
if (need_thermal_temperature_ind(info, degree_c))
wma_thermal_temperature_ind(degree_c);
}
static void wma_fetch_set_thermal_params(tp_wma_handle wma,
t_thermal_mgmt *pThermalParams)
{
wma->thermal_mgmt_info.thermal_shutdown_enabled =
pThermalParams->thermal_shutdown_enabled;
wma->thermal_mgmt_info.thermal_shutdown_auto_enabled =
pThermalParams->thermal_shutdown_auto_enabled;
wma->thermal_mgmt_info.thermal_resume_threshold =
pThermalParams->thermal_resume_threshold;
wma->thermal_mgmt_info.thermal_warning_threshold =
pThermalParams->thermal_warning_threshold;
wma->thermal_mgmt_info.thermal_suspend_threshold =
pThermalParams->thermal_suspend_threshold;
wma->thermal_mgmt_info.thermal_sample_rate =
pThermalParams->thermal_sample_rate;
if (wma->thermal_mgmt_info.thermal_shutdown_enabled)
wma_set_thermal_suspend_params(wma);
}
#else
static inline void wma_fetch_set_thermal_params(tp_wma_handle wma,
t_thermal_mgmt *pThermalParams)
{
return;
}
static inline void
wma_thermal_shutdown_evt_handler(tp_thermal_mgmt info, int32_t degree_c)
{
return;
}
#endif
/* function : wma_process_init_thermal_info
* Description : This function initializes the thermal management table in WMA,
sends down the initial temperature thresholds to the firmware and
configures the throttle period in the tx rx module
* Args :
wma : Pointer to WMA handle
* pThermalParams : Pointer to thermal mitigation parameters
* Returns :
* VOS_STATUS_SUCCESS for success otherwise failure
*/
VOS_STATUS wma_process_init_thermal_info(tp_wma_handle wma,
t_thermal_mgmt *pThermalParams)
{
t_thermal_cmd_params thermal_params;
ol_txrx_pdev_handle curr_pdev;
if (NULL == wma || NULL == pThermalParams) {
WMA_LOGE("TM Invalid input");
return VOS_STATUS_E_FAILURE;
}
curr_pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == curr_pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("TM enable %d period %d", pThermalParams->thermalMgmtEnabled,
pThermalParams->throttlePeriod);
WMA_LOGD("Throttle Duty Cycle Level in percentage:\n"
"0 %d\n"
"1 %d\n"
"2 %d\n"
"3 %d",
pThermalParams->throttle_duty_cycle_tbl[0],
pThermalParams->throttle_duty_cycle_tbl[1],
pThermalParams->throttle_duty_cycle_tbl[2],
pThermalParams->throttle_duty_cycle_tbl[3]);
wma->thermal_mgmt_info.thermalMgmtEnabled =
pThermalParams->thermalMgmtEnabled;
wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold =
pThermalParams->thermalLevels[0].minTempThreshold;
wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold =
pThermalParams->thermalLevels[0].maxTempThreshold;
wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold =
pThermalParams->thermalLevels[1].minTempThreshold;
wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold =
pThermalParams->thermalLevels[1].maxTempThreshold;
wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold =
pThermalParams->thermalLevels[2].minTempThreshold;
wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold =
pThermalParams->thermalLevels[2].maxTempThreshold;
wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold =
pThermalParams->thermalLevels[3].minTempThreshold;
wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold =
pThermalParams->thermalLevels[3].maxTempThreshold;
wma->thermal_mgmt_info.thermalCurrLevel = WLAN_WMA_THERMAL_LEVEL_0;
WMA_LOGD("TM level min max:\n"
"0 %d %d\n"
"1 %d %d\n"
"2 %d %d\n"
"3 %d %d",
wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold,
wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold,
wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold,
wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold,
wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold,
wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold,
wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold,
wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold);
if (wma->thermal_mgmt_info.thermalMgmtEnabled)
{
ol_tx_throttle_init_period(curr_pdev,
pThermalParams->throttlePeriod,
&pThermalParams->throttle_duty_cycle_tbl[0]);
/* Get the temperature thresholds to set in firmware */
thermal_params.minTemp = wma->thermal_mgmt_info.
thermalLevels[WLAN_WMA_THERMAL_LEVEL_0].minTempThreshold;
thermal_params.maxTemp = wma->thermal_mgmt_info.
thermalLevels[WLAN_WMA_THERMAL_LEVEL_0].maxTempThreshold;
thermal_params.thermalEnable =
wma->thermal_mgmt_info.thermalMgmtEnabled;
WMA_LOGE("TM sending the following to firmware: min %d max %d enable %d",
thermal_params.minTemp, thermal_params.maxTemp,
thermal_params.thermalEnable);
if(VOS_STATUS_SUCCESS != wma_set_thermal_mgmt(wma, thermal_params))
{
WMA_LOGE("Could not send thermal mgmt command to the firmware!");
}
}
wma_fetch_set_thermal_params(wma, pThermalParams);
return VOS_STATUS_SUCCESS;
}
static void wma_set_thermal_level_ind(u_int8_t level)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
vos_msg_t sme_msg = {0};
WMA_LOGI(FL("Thermal level: %d"), level);
sme_msg.type = eWNI_SME_SET_THERMAL_LEVEL_IND;
sme_msg.bodyptr = NULL;
sme_msg.bodyval = level;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
WMA_LOGE(FL("Fail to post set temperaturml level ind msg"));
}
/**
* wma_process_set_thermal_level() - Sets new thermal throttle level
* wma: Pointer to wma handle
* thermal_level: Thermal level to set
*
* This function sets new thermal throttle level in the txrx module and sends
* down the corresponding temperature thresholds to the firmware.
*
* Return: VOS_STATUS_SUCCESS for success otherwise failure.
*
*/
VOS_STATUS wma_process_set_thermal_level(tp_wma_handle wma,
uint8_t thermal_level)
{
ol_txrx_pdev_handle curr_pdev;
if (NULL == wma) {
WMA_LOGE("TM Invalid input");
return VOS_STATUS_E_FAILURE;
}
curr_pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == curr_pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGE("TM set level %d", thermal_level);
/* Check if thermal mitigation is enabled */
if (!wma->thermal_mgmt_info.thermalMgmtEnabled) {
WMA_LOGE("Thermal mgmt is not enabled, ignoring set level cmd");
return VOS_STATUS_E_FAILURE;
}
if (thermal_level >= WLAN_WMA_MAX_THERMAL_LEVELS) {
WMA_LOGE("Invalid thermal level set %d", thermal_level);
return VOS_STATUS_E_FAILURE;
}
if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) {
WMA_LOGD("Current level %d is same as the set level, ignoring",
wma->thermal_mgmt_info.thermalCurrLevel);
return VOS_STATUS_SUCCESS;
}
wma->thermal_mgmt_info.thermalCurrLevel = thermal_level;
ol_tx_throttle_set_level(curr_pdev, thermal_level);
/* Send SME SET_THERMAL_LEVEL_IND message */
wma_set_thermal_level_ind(thermal_level);
return VOS_STATUS_SUCCESS;
}
/* function : wma_ProcessTxPowerLimits
* Description : This function sends the power limits for 2g/5g to firmware
* Args :
handle : Pointer to WMA handle
* ptxlim : Pointer to power limit values
* Returns : VOS_STATUS based on values sent to firmware
*
*/
VOS_STATUS wma_ProcessTxPowerLimits(WMA_HANDLE handle,
tSirTxPowerLimit *ptxlim)
{
tp_wma_handle wma = (tp_wma_handle)handle;
int32_t ret = 0;
u_int32_t txpower_params2g = 0;
u_int32_t txpower_params5g = 0;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue tx power limit",
__func__);
return VOS_STATUS_E_INVAL;
}
/* Set value and reason code for 2g and 5g power limit */
SET_PDEV_PARAM_TXPOWER_REASON(txpower_params2g,
WMI_PDEV_PARAM_TXPOWER_REASON_SAR);
SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params2g,
ptxlim->txPower2g);
SET_PDEV_PARAM_TXPOWER_REASON(txpower_params5g,
WMI_PDEV_PARAM_TXPOWER_REASON_SAR);
SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params5g,
ptxlim->txPower5g);
WMA_LOGD("%s: txpower2g: %x txpower5g: %x",
__func__, txpower_params2g, txpower_params5g);
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_TXPOWER_LIMIT2G, txpower_params2g);
if (ret) {
WMA_LOGE("%s: Failed to set txpower 2g (%d)",
__func__, ret);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_TXPOWER_LIMIT5G, txpower_params5g);
if (ret) {
WMA_LOGE("%s: Failed to set txpower 5g (%d)",
__func__, ret);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)
/**
* wma_set_peer_rate_report_condition -
* this function set peer rate report
* condition info to firmware.
* @handle: Handle of WMA
* @config: Bad peer configuration from SIR module
*
* It is a wrapper function to sent WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID
* to the firmare\target.If the command sent to firmware failed, free the
* buffer that allocated.
*
* Return: VOS_STATUS based on values sent to firmware
*/
VOS_STATUS wma_set_peer_rate_report_condition(WMA_HANDLE handle,
struct t_bad_peer_txtcl_config *config)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
wmi_peer_set_rate_report_condition_fixed_param *cmd = NULL;
wmi_buf_t buf = NULL;
int status = 0;
u_int32_t len = 0;
u_int32_t i, j;
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to alloc buf to peer_set_condition cmd\n");
return eHAL_STATUS_FAILURE;
}
cmd = (wmi_peer_set_rate_report_condition_fixed_param *)
wmi_buf_data (buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_set_rate_report_condition_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_peer_set_rate_report_condition_fixed_param));
cmd->enable_rate_report = config->enable;
cmd->report_backoff_time = config->tgt_backoff;
cmd->report_timer_period = config->tgt_report_prd;
for (i = 0; i < PEER_RATE_REPORT_COND_MAX_NUM; i++) {
cmd->cond_per_phy[i].val_cond_flags =
config->threshold[i].cond;
cmd->cond_per_phy[i].rate_delta.min_delta =
config->threshold[i].delta;
cmd->cond_per_phy[i].rate_delta.percentage =
config->threshold[i].percentage;
for (j = 0; j < MAX_NUM_OF_RATE_THRESH; j++) {
cmd->cond_per_phy[i].rate_threshold[j] =
config->threshold[i].thresh[j];
}
}
WMA_LOGE("%s enable %d backoff_time %d period %d\n", __func__,
cmd->enable_rate_report,
cmd->report_backoff_time, cmd->report_timer_period);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID);
if (status) {
wmi_buf_free(buf);
WMA_LOGE("%s:Failed to send peer_set_report_cond command",
__func__);
return eHAL_STATUS_FAILURE;
}
return eHAL_STATUS_SUCCESS;
}
/**
* wma_process_init_bad_peer_tx_ctl_info -
* this function to initialize peer rate report config info.
* @handle: Handle of WMA
* @config: Bad peer configuration from SIR module
*
* This function initializes the bad peer tx control data structure in WMA,
* sends down the initial configuration to the firmware and configures
* the peer status update seeting in the tx_rx module.
*
* Return: VOS_STATUS based on procedure status
*/
static VOS_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma,
struct t_bad_peer_txtcl_config *config)
{
/* Parameter sanity check */
ol_txrx_pdev_handle curr_pdev;
if (NULL == wma || NULL == config) {
WMA_LOGE("%s Invalid input\n", __func__);
return VOS_STATUS_E_FAILURE;
}
curr_pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == curr_pdev) {
WMA_LOGE("%s: Failed to get pdev\n", __func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGE("%s enable %d period %d txq limit %d\n", __func__,
config->enable,
config->period,
config->txq_limit);
/* Only need to initialize the setting
when the feature is enabled */
if (config->enable) {
int i = 0;
ol_txrx_bad_peer_txctl_set_setting(curr_pdev,
config->enable,
config->period,
config->txq_limit);
for (i = 0; i < WLAN_WMA_IEEE80211_MAX_LEVEL; i++) {
u_int32_t threshold, limit;
threshold =
config->threshold[i].thresh[0];
limit = config->threshold[i].txlimit;
ol_txrx_bad_peer_txctl_update_threshold(curr_pdev, i,
threshold, limit);
}
}
return wma_set_peer_rate_report_condition(wma, config);
}
#else
static inline
VOS_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma,
struct t_bad_peer_txtcl_config *config)
{
return eHAL_STATUS_SUCCESS;
}
#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */
/*
* FUNCTION: wma_ProcessAddPeriodicTxPtrnInd
* WMI command sent to firmware to add patterns
* for the corresponding vdev id
*/
VOS_STATUS wma_ProcessAddPeriodicTxPtrnInd(WMA_HANDLE handle,
tSirAddPeriodicTxPtrn *pAddPeriodicTxPtrnParams)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param* cmd;
wmi_buf_t wmi_buf;
uint32_t len;
uint8_t vdev_id;
u_int8_t *buf_ptr;
u_int32_t ptrn_len, ptrn_len_aligned;
int j;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue fw add pattern cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
ptrn_len = pAddPeriodicTxPtrnParams->ucPtrnSize;
ptrn_len_aligned = roundup(ptrn_len, sizeof(uint32_t));
len = sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param) +
WMI_TLV_HDR_SIZE + ptrn_len_aligned;
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;
}
if (!wma_find_vdev_by_addr(wma_handle,
pAddPeriodicTxPtrnParams->macAddress, &vdev_id)) {
WMA_LOGE("%s: Failed to find vdev id for %pM",__func__,
pAddPeriodicTxPtrnParams->macAddress);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_INVAL;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param));
/* Pass the pattern id to delete for the corresponding vdev id */
cmd->vdev_id = vdev_id;
cmd->pattern_id = pAddPeriodicTxPtrnParams->ucPtrnId;
cmd->timeout = pAddPeriodicTxPtrnParams->usPtrnIntervalMs;
cmd->length = pAddPeriodicTxPtrnParams->ucPtrnSize;
/* Pattern info */
buf_ptr += sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ptrn_len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, pAddPeriodicTxPtrnParams->ucPattern,
ptrn_len);
for (j = 0; j < pAddPeriodicTxPtrnParams->ucPtrnSize; j++) {
WMA_LOGD("%s: Add Ptrn: %02x", __func__, buf_ptr[j] & 0xff);
}
WMA_LOGD("%s: Add ptrn id: %d vdev_id: %d",
__func__, cmd->pattern_id, cmd->vdev_id);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID)) {
WMA_LOGE("%s: failed to add pattern set state command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/*
* FUNCTION: wma_ProcessDelPeriodicTxPtrnInd
* WMI command sent to firmware to del patterns
* for the corresponding vdev id
*/
VOS_STATUS wma_ProcessDelPeriodicTxPtrnInd(WMA_HANDLE handle,
tSirDelPeriodicTxPtrn *pDelPeriodicTxPtrnParams)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param* cmd;
wmi_buf_t wmi_buf;
uint8_t vdev_id;
u_int32_t len = sizeof(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param);
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue Del Pattern cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
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;
}
if (!wma_find_vdev_by_addr(wma_handle,
pDelPeriodicTxPtrnParams->macAddress, &vdev_id)) {
WMA_LOGE("%s: Failed to find vdev id for %pM",__func__,
pDelPeriodicTxPtrnParams->macAddress);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_INVAL;
}
cmd = (WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *)wmi_buf_data(wmi_buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param));
/* Pass the pattern id to delete for the corresponding vdev id */
cmd->vdev_id = vdev_id;
cmd->pattern_id = pDelPeriodicTxPtrnParams->ucPtrnId;
WMA_LOGD("%s: Del ptrn id: %d vdev_id: %d",
__func__, cmd->pattern_id, cmd->vdev_id);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID)) {
WMA_LOGE("%s: failed to send del pattern command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
static void wma_set_p2pgo_noa_Req(tp_wma_handle wma,
tP2pPsParams *noa)
{
wmi_p2p_set_noa_cmd_fixed_param *cmd;
wmi_p2p_noa_descriptor *noa_discriptor;
wmi_buf_t buf;
u_int8_t *buf_ptr;
u_int16_t len;
int32_t status;
u_int32_t duration;
WMA_LOGD("%s: Enter", __func__);
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + sizeof(*noa_discriptor);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate memory");
goto end;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_p2p_set_noa_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_p2p_set_noa_cmd_fixed_param));
duration = (noa->count == 1)? noa->single_noa_duration : noa->duration;
cmd->vdev_id = noa->sessionId;
cmd->enable = (duration)? true : false;
cmd->num_noa = 1;
WMITLV_SET_HDR((buf_ptr + sizeof(wmi_p2p_set_noa_cmd_fixed_param)),
WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_p2p_noa_descriptor));
noa_discriptor = (wmi_p2p_noa_descriptor *) (buf_ptr +
sizeof(wmi_p2p_set_noa_cmd_fixed_param) +
WMI_TLV_HDR_SIZE);
WMITLV_SET_HDR(&noa_discriptor->tlv_header,
WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor,
WMITLV_GET_STRUCT_TLVLEN(wmi_p2p_noa_descriptor));
noa_discriptor->type_count = noa->count;
noa_discriptor->duration = duration;
noa_discriptor->interval = noa->interval;
/* Set the NOA start time as 25% of the NOA Interval as an offset */
noa_discriptor->start_time = noa_discriptor->interval/4;
WMA_LOGI("SET P2P GO NOA:vdev_id:%d count:%d duration:%d interval:%d",
cmd->vdev_id, noa->count, noa_discriptor->duration,
noa->interval);
status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID);
if (status != EOK) {
WMA_LOGE("Failed to send WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID");
wmi_buf_free(buf);
}
end:
WMA_LOGD("%s: Exit", __func__);
}
static void wma_set_p2pgo_oppps_req(tp_wma_handle wma,
tP2pPsParams *oppps)
{
wmi_p2p_set_oppps_cmd_fixed_param *cmd;
wmi_buf_t buf;
int32_t status;
WMA_LOGD("%s: Enter", __func__);
buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate memory");
goto end;
}
cmd = (wmi_p2p_set_oppps_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_p2p_set_oppps_cmd_fixed_param));
cmd->vdev_id = oppps->sessionId;
if (oppps->ctWindow)
WMI_UNIFIED_OPPPS_ATTR_ENABLED_SET(cmd);
WMI_UNIFIED_OPPPS_ATTR_CTWIN_SET(cmd, oppps->ctWindow);
WMA_LOGI("SET P2P GO OPPPS:vdev_id:%d ctwindow:%d",
cmd->vdev_id, oppps->ctWindow);
status = wmi_unified_cmd_send(wma->wmi_handle, buf, sizeof(*cmd),
WMI_P2P_SET_OPPPS_PARAM_CMDID);
if (status != EOK) {
WMA_LOGE("Failed to send WMI_P2P_SET_OPPPS_PARAM_CMDID");
wmi_buf_free(buf);
}
end:
WMA_LOGD("%s: Exit", __func__);
}
static void wma_process_set_p2pgo_noa_Req(tp_wma_handle wma,
tP2pPsParams *ps_params)
{
WMA_LOGD("%s: Enter", __func__);
if (ps_params->opp_ps) {
wma_set_p2pgo_oppps_req(wma, ps_params);
} else {
wma_set_p2pgo_noa_Req(wma, ps_params);
}
WMA_LOGD("%s: Exit", __func__);
}
/* function : wma_process_set_mimops_req
* Description : Set the received MiMo PS state to firmware.
* Args :
wma_handle : Pointer to WMA handle
* tSetMIMOPS : Pointer to MiMo PS struct
* Returns :
*/
static void wma_process_set_mimops_req(tp_wma_handle wma_handle,
tSetMIMOPS *mimops)
{
/* Translate to what firmware understands */
if ( mimops->htMIMOPSState == eSIR_HT_MIMO_PS_DYNAMIC)
mimops->htMIMOPSState = WMI_PEER_MIMO_PS_DYNAMIC;
else if ( mimops->htMIMOPSState == eSIR_HT_MIMO_PS_STATIC)
mimops->htMIMOPSState = WMI_PEER_MIMO_PS_STATIC;
else if ( mimops->htMIMOPSState == eSIR_HT_MIMO_PS_NO_LIMIT)
mimops->htMIMOPSState = WMI_PEER_MIMO_PS_NONE;
WMA_LOGD("%s: htMIMOPSState = %d, sessionId = %d peerMac <%02x:%02x:%02x:%02x:%02x:%02x>",
__func__,
mimops->htMIMOPSState, mimops->sessionId, mimops->peerMac[0],
mimops->peerMac[1], mimops->peerMac[2], mimops->peerMac[3],
mimops->peerMac[4], mimops->peerMac[5]);
wma_set_peer_param(wma_handle, mimops->peerMac,
WMI_PEER_MIMO_PS_STATE, mimops->htMIMOPSState,
mimops->sessionId);
}
/* function : wma_set_vdev_intrabss_fwd
* Description : Set intra_fwd value to wni_in.
* Args :
* wma_handle : Pointer to WMA handle
* pdis_intra_fwd : Pointer to DisableIntraBssFwd struct
* Returns :
*/
static void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle,
tpDisableIntraBssFwd pdis_intra_fwd)
{
ol_txrx_vdev_handle txrx_vdev;
WMA_LOGD("%s:intra_fwd:vdev(%d) intrabss_dis=%s",
__func__, pdis_intra_fwd->sessionId,
(pdis_intra_fwd->disableintrabssfwd ? "true" : "false"));
txrx_vdev = wma_handle->interfaces[pdis_intra_fwd->sessionId].handle;
wdi_in_vdev_rx_fwd_disabled(txrx_vdev, pdis_intra_fwd->disableintrabssfwd);
}
VOS_STATUS wma_notify_modem_power_state(void *wda_handle,
tSirModemPowerStateInd *pReq)
{
int32_t ret;
tp_wma_handle wma = (tp_wma_handle)wda_handle;
WMA_LOGD("%s: WMA Notify Modem Power State %d", __func__, pReq->param);
ret = wmi_unified_modem_power_state(wma->wmi_handle, pReq->param);
if (ret) {
WMA_LOGE("%s: Fail to notify Modem Power State %d",
__func__, pReq->param);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Successfully notify Modem Power State %d", pReq->param);
return VOS_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_TSF
/**
* wma_set_tsf_gpio_pin() - send wmi cmd to configure gpio pin
*
* @handle: wma handler
* @pin: GPIO pin id
*
* Return: VOS_STATUS
*/
static VOS_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle,
uint32_t pin)
{
tp_wma_handle wma = (tp_wma_handle)handle;
int32_t ret;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not set gpio",
__func__);
return VOS_STATUS_E_INVAL;
}
WMA_LOGD("%s: set tsf gpio pin: %d",
__func__, pin);
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_WNTS_CONFIG, pin);
if (ret) {
WMA_LOGE("%s: Failed to set tsf gpio pin (%d)",
__func__, ret);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#else
static inline VOS_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle,
uint32_t pin)
{
return VOS_STATUS_E_INVAL;
}
#endif
#ifdef WLAN_FEATURE_STATS_EXT
VOS_STATUS wma_stats_ext_req(void *wda_handle,
tpStatsExtRequest preq)
{
int32_t ret;
tp_wma_handle wma = (tp_wma_handle)wda_handle;
wmi_req_stats_ext_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int16_t len;
u_int8_t *buf_ptr;
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
preq->request_data_len;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_req_stats_ext_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_req_stats_ext_cmd_fixed_param));
cmd->vdev_id = preq->vdev_id;
cmd->data_len = preq->request_data_len;
WMA_LOGD("%s: The data len value is %u and vdev id set is %u ",
__func__, preq->request_data_len, preq->vdev_id);
buf_ptr += sizeof(wmi_req_stats_ext_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, cmd->data_len);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, preq->request_data,
cmd->data_len);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_REQUEST_STATS_EXT_CMDID);
if (ret != EOK) {
WMA_LOGE("%s: Failed to send notify cmd ret = %d", __func__, ret);
wmi_buf_free(buf);
}
return ret;
}
#endif
void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle,
tHalHiddenSsidVdevRestart *pReq)
{
struct wma_txrx_node *intr = wma_handle->interfaces;
struct wma_target_req *msg;
if ((pReq->sessionId != intr[pReq->sessionId].vdev_restart_params.vdev_id) ||
!((intr[pReq->sessionId].type == WMI_VDEV_TYPE_AP) &&
(intr[pReq->sessionId].sub_type == 0)))
{
WMA_LOGE("%s : invalid session id", __func__);
return;
}
intr[pReq->sessionId].vdev_restart_params.ssidHidden = pReq->ssidHidden;
adf_os_atomic_set(&intr[pReq->sessionId].vdev_restart_params.hidden_ssid_restart_in_progress,1);
msg = wma_fill_vdev_req(wma_handle, pReq->sessionId,
WDA_HIDDEN_SSID_VDEV_RESTART,
WMA_TARGET_REQ_TYPE_VDEV_STOP, pReq,
WMA_VDEV_STOP_REQUEST_TIMEOUT);
if (!msg) {
WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d",
__func__, pReq->sessionId);
return;
}
/* vdev stop -> vdev restart -> vdev up */
WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP",
__func__, pReq->sessionId);
wdi_in_vdev_pause(wma_handle->interfaces[pReq->sessionId].handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
wma_handle->interfaces[pReq->sessionId].pause_bitmap |=
(1 << PAUSE_TYPE_HOST);
if (wmi_unified_vdev_stop_send(wma_handle->wmi_handle, pReq->sessionId)) {
WMA_LOGE("%s: %d Failed to send vdev stop",
__func__, __LINE__);
adf_os_atomic_set(&intr[pReq->sessionId].vdev_restart_params.hidden_ssid_restart_in_progress,0);
wma_remove_vdev_req(wma_handle, pReq->sessionId,
WMA_TARGET_REQ_TYPE_VDEV_STOP);
return;
}
}
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
static VOS_STATUS wma_process_ll_stats_clearReq
(
tp_wma_handle wma,
const tpSirLLStatsClearReq clearReq
)
{
wmi_clear_link_stats_cmd_fixed_param *cmd;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int ret;
if (!clearReq || !wma) {
WMA_LOGE("%s: input pointer is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
vos_mem_zero(buf_ptr, len);
cmd = (wmi_clear_link_stats_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_clear_link_stats_cmd_fixed_param));
cmd->stop_stats_collection_req = clearReq->stopReq;
cmd->vdev_id = clearReq->staId;
cmd->stats_clear_req_mask = clearReq->statsClearReqMask;
WMI_CHAR_ARRAY_TO_MAC_ADDR(wma->interfaces[clearReq->staId].addr,
&cmd->peer_macaddr);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_CLEAR_LINK_STATS_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send clear link stats req", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_process_ll_stats_setReq
(
tp_wma_handle wma,
const tpSirLLStatsSetReq setReq
)
{
wmi_start_link_stats_cmd_fixed_param *cmd;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int ret;
if (!setReq || !wma) {
WMA_LOGE("%s: input pointer is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
vos_mem_zero(buf_ptr, len);
cmd = (wmi_start_link_stats_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_start_link_stats_cmd_fixed_param));
cmd->mpdu_size_threshold = setReq->mpduSizeThreshold;
cmd->aggressive_statistics_gathering = setReq->aggressiveStatisticsGathering;
WMA_LOGD("LINK_LAYER_STATS - Start/Set Request Params");
WMA_LOGD("MPDU Size Thresh : %d", cmd->mpdu_size_threshold);
WMA_LOGD("Aggressive Gather: %d", cmd->aggressive_statistics_gathering);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_START_LINK_STATS_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send set link stats request", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Set Link Layer Stats request sent successfully");
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_process_ll_stats_getReq
(
tp_wma_handle wma,
const tpSirLLStatsGetReq getReq
)
{
wmi_request_link_stats_cmd_fixed_param *cmd;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int ret;
if (!getReq || !wma) {
WMA_LOGE("%s: input pointer is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
if (!wma->interfaces[getReq->staId].vdev_active) {
WMA_LOGE("%s: vdev not created yet", __func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
vos_mem_zero(buf_ptr, len);
cmd = (wmi_request_link_stats_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_request_link_stats_cmd_fixed_param));
cmd->request_id = getReq->reqId;
cmd->stats_type = getReq->paramIdMask;
cmd->vdev_id = getReq->staId;
WMI_CHAR_ARRAY_TO_MAC_ADDR(wma->interfaces[getReq->staId].addr,
&cmd->peer_macaddr);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_REQUEST_LINK_STATS_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send get link stats request", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
#ifdef FEATURE_WLAN_EXTSCAN
VOS_STATUS wma_get_buf_extscan_start_cmd(tp_wma_handle wma_handle,
tSirWifiScanCmdReqParams *pstart,
wmi_buf_t *buf,
int *buf_len)
{
wmi_extscan_start_cmd_fixed_param *cmd;
wmi_extscan_bucket *dest_blist;
wmi_extscan_bucket_channel *dest_clist;
tSirWifiScanBucketSpec *src_bucket = pstart->buckets;
tSirWifiScanChannelSpec *src_channel = src_bucket->channels;
tSirWifiScanChannelSpec save_channel[WLAN_EXTSCAN_MAX_CHANNELS];
u_int8_t *buf_ptr;
int i, k, count = 0;
int len = sizeof(*cmd);
int nbuckets = pstart->numBuckets;
int nchannels = 0;
/* These TLV's are are NULL by default */
u_int32_t ie_len_with_pad = 0;
int num_ssid = 0;
int num_bssid = 0;
int ie_len = 0;
uint32_t base_period = pstart->basePeriod;
/* TLV placeholder for ssid_list (NULL) */
len += WMI_TLV_HDR_SIZE;
len += num_ssid * sizeof(wmi_ssid);
/* TLV placeholder for bssid_list (NULL) */
len += WMI_TLV_HDR_SIZE;
len += num_bssid * sizeof(wmi_mac_addr);
/* TLV placeholder for ie_data (NULL) */
len += WMI_TLV_HDR_SIZE;
len += ie_len * sizeof(u_int32_t);
/* TLV placeholder for bucket */
len += WMI_TLV_HDR_SIZE;
len += nbuckets * sizeof(wmi_extscan_bucket);
/* TLV channel placeholder */
len += WMI_TLV_HDR_SIZE;
for (i = 0; i < nbuckets; i++) {
nchannels += src_bucket->numChannels;
src_bucket++;
}
len += nchannels * sizeof(wmi_extscan_bucket_channel);
/* Allocate the memory */
*buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!*buf) {
WMA_LOGP("%s: failed to allocate memory"
" for start extscan cmd",
__func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *)wmi_buf_data(*buf);
cmd = (wmi_extscan_start_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_start_cmd_fixed_param));
cmd->request_id = pstart->requestId;
cmd->vdev_id = pstart->sessionId;
cmd->base_period = pstart->basePeriod;
cmd->num_buckets = nbuckets;
cmd->configuration_flags = 0;
if (pstart->configuration_flags & EXTSCAN_LP_EXTENDED_BATCHING)
cmd->configuration_flags |= WMI_EXTSCAN_EXTENDED_BATCHING_EN;
WMA_LOGD("%s: Total buckets: %d total #of channels: %d cfgn_flags: 0x%x",
__func__, nbuckets, nchannels, cmd->configuration_flags);
cmd->min_rest_time = WMA_EXTSCAN_REST_TIME;
cmd->max_rest_time = WMA_EXTSCAN_REST_TIME;
cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan;
/* The max dwell time is retrieved from the first channel
* of the first bucket and kept common for all channels.
*/
cmd->min_dwell_time_active = pstart->min_dwell_time_active;
cmd->max_dwell_time_active = pstart->max_dwell_time_active;
cmd->min_dwell_time_passive = pstart->min_dwell_time_passive;
cmd->max_dwell_time_passive = pstart->max_dwell_time_passive;
cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan;
cmd->max_table_usage = pstart->report_threshold_percent;
cmd->report_threshold_num_scans = pstart->report_threshold_num_scans;
cmd->repeat_probe_time = cmd->max_dwell_time_active /
WMA_SCAN_NPROBES_DEFAULT;
cmd->max_scan_time = WMA_EXTSCAN_MAX_SCAN_TIME;
cmd->probe_delay = 0;
cmd->probe_spacing_time = 0;
cmd->idle_time = 0;
cmd->burst_duration = WMA_EXTSCAN_BURST_DURATION;
cmd->scan_ctrl_flags = WMI_SCAN_ADD_BCAST_PROBE_REQ |
WMI_SCAN_ADD_CCK_RATES |
WMI_SCAN_ADD_OFDM_RATES |
WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ;
cmd->scan_priority = WMI_SCAN_PRIORITY_VERY_LOW;
cmd->num_ssids = 0;
cmd->num_bssid = 0;
cmd->ie_len = 0;
cmd->n_probes = (cmd->repeat_probe_time > 0) ?
cmd->max_dwell_time_active / cmd->repeat_probe_time : 0;
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_FIXED_STRUC,
num_ssid * sizeof(wmi_ssid));
buf_ptr += WMI_TLV_HDR_SIZE + (num_ssid * sizeof(wmi_ssid));
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_FIXED_STRUC,
num_bssid * sizeof(wmi_mac_addr));
buf_ptr += WMI_TLV_HDR_SIZE + (num_bssid * sizeof(wmi_mac_addr));
ie_len_with_pad = 0;
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_BYTE,
ie_len_with_pad);
buf_ptr += WMI_TLV_HDR_SIZE + ie_len_with_pad;
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
nbuckets * sizeof(wmi_extscan_bucket));
dest_blist = (wmi_extscan_bucket *)
(buf_ptr + WMI_TLV_HDR_SIZE);
src_bucket = pstart->buckets;
/* Retrieve scanning information from each bucket and
* channels and send it to the target
*/
for (i = 0; i < nbuckets; i++) {
WMITLV_SET_HDR(dest_blist,
WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_extscan_bucket));
dest_blist->bucket_id = src_bucket->bucket;
dest_blist->base_period_multiplier =
src_bucket->period / base_period;
dest_blist->min_period = src_bucket->period;
dest_blist->max_period = src_bucket->max_period;
dest_blist->exp_backoff = src_bucket->exponent;
dest_blist->exp_max_step_count = src_bucket->step_count;
dest_blist->channel_band = src_bucket->band;
dest_blist->num_channels = src_bucket->numChannels;
dest_blist->notify_extscan_events = 0;
if (src_bucket->reportEvents & EXTSCAN_REPORT_EVENTS_EACH_SCAN)
dest_blist->notify_extscan_events =
WMI_EXTSCAN_CYCLE_COMPLETED_EVENT |
WMI_EXTSCAN_CYCLE_STARTED_EVENT;
if (src_bucket->reportEvents &
EXTSCAN_REPORT_EVENTS_FULL_RESULTS) {
dest_blist->forwarding_flags =
WMI_EXTSCAN_FORWARD_FRAME_TO_HOST;
dest_blist->notify_extscan_events |=
WMI_EXTSCAN_CYCLE_STARTED_EVENT |
WMI_EXTSCAN_CYCLE_COMPLETED_EVENT;
} else {
dest_blist->forwarding_flags =
WMI_EXTSCAN_NO_FORWARDING;
}
if (src_bucket->reportEvents & EXTSCAN_REPORT_EVENTS_NO_BATCH)
dest_blist->configuration_flags = 0;
else
dest_blist->configuration_flags =
WMI_EXTSCAN_BUCKET_CACHE_RESULTS;
if (src_bucket->reportEvents &
EXTSCAN_REPORT_EVENTS_CONTEXT_HUB)
dest_blist->configuration_flags |=
WMI_EXTSCAN_REPORT_EVENT_CONTEXT_HUB;
WMA_LOGI("%s: ntfy_extscan_events:%u cfg_flags:%u fwd_flags:%u",
__func__, dest_blist->notify_extscan_events,
dest_blist->configuration_flags,
dest_blist->forwarding_flags);
dest_blist->min_dwell_time_active = src_bucket->min_dwell_time_active;
dest_blist->max_dwell_time_active = src_bucket->max_dwell_time_active;
dest_blist->min_dwell_time_passive = src_bucket->min_dwell_time_passive;
dest_blist->max_dwell_time_passive = src_bucket->max_dwell_time_passive;
src_channel = src_bucket->channels;
/* save the channel info to later populate
* the channel TLV
*/
for (k = 0; k < src_bucket->numChannels; k++) {
save_channel[count++].channel =
src_channel->channel;
src_channel++;
}
dest_blist++;
src_bucket++;
}
buf_ptr += WMI_TLV_HDR_SIZE +
(nbuckets * sizeof(wmi_extscan_bucket));
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
nchannels * sizeof(wmi_extscan_bucket_channel));
dest_clist = (wmi_extscan_bucket_channel *)
(buf_ptr + WMI_TLV_HDR_SIZE);
/* Active or passive scan is based on the bucket dwell time
* and channel specific active,passive scans are not
* supported yet
*/
for (i = 0; i < nchannels; i++) {
WMITLV_SET_HDR(dest_clist,
WMITLV_TAG_STRUC_wmi_extscan_bucket_channel_event_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_bucket_channel));
dest_clist->channel = save_channel[i].channel;
dest_clist++;
}
buf_ptr += WMI_TLV_HDR_SIZE +
(nchannels * sizeof(wmi_extscan_bucket_channel));
*buf_len = len;
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_start_extscan(tp_wma_handle wma,
tSirWifiScanCmdReqParams *pstart)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf;
int len;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed,can not issue extscan cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan feature bit not enabled",
__func__);
return VOS_STATUS_E_FAILURE;
}
/* Fill individual elements of extscan request and
* TLV for buckets, channel list.
*/
vos_status = wma_get_buf_extscan_start_cmd(wma, pstart,
&buf, &len);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to get buffer for ext scan cmd",
__func__);
return VOS_STATUS_E_FAILURE;
}
if (!buf) {
WMA_LOGE("%s:Failed to get buffer"
"for current extscan info", __func__);
return VOS_STATUS_E_FAILURE;
}
if (wmi_unified_cmd_send(wma->wmi_handle, buf,
len, WMI_EXTSCAN_START_CMDID)) {
WMA_LOGE("%s: failed to send command", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Extscan start request sent successfully for vdev %d",
pstart->sessionId);
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_stop_extscan(tp_wma_handle wma,
tSirExtScanStopReqParams *pstopcmd)
{
wmi_extscan_stop_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, cannot issue cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan not enabled",
__func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_extscan_stop_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_stop_cmd_fixed_param));
cmd->request_id = pstopcmd->requestId;
cmd->vdev_id = pstopcmd->sessionId;
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_EXTSCAN_STOP_CMDID)) {
WMA_LOGE("%s: failed to command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Extscan stop request sent successfully for vdev %d",
pstopcmd->sessionId);
return VOS_STATUS_SUCCESS;
}
/** wma_get_hotlist_entries_per_page() - hotlist entries per page
* @cmd: size of command structure.
* @per_entry_size: per entry size.
*
* This utility function calculates how many hotlist entries can
* fit in one page.
*
* Return: number of entries
*/
static inline int wma_get_hotlist_entries_per_page(wmi_unified_t wmi_handle,
size_t cmd_size,
size_t per_entry_size)
{
uint32_t avail_space = 0;
int num_entries = 0;
uint16_t max_msg_len = wmi_get_max_msg_len(wmi_handle);
/* Calculate number of hotlist entries that can
* be passed in wma message request.
*/
avail_space = max_msg_len - cmd_size;
num_entries = avail_space / per_entry_size;
return num_entries;
}
/** wma_get_buf_extscan_hotlist_cmd() - extscan hotlist command
* @wma_handle: pointer to WMA handle
* @photlist: pointer to input hotlist request message
* @buf_len: buffer len
*
* This function constructs the WMA set bssid hotlist command message
* and based on the maximum length of the WMA command buf, it issues
* multiple request.
*
* Return: VOS_STATUS enumeration.
*/
VOS_STATUS wma_get_buf_extscan_hotlist_cmd(tp_wma_handle wma_handle,
tSirExtScanSetBssidHotListReqParams *photlist,
int *buf_len)
{
wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd;
wmi_extscan_hotlist_entry *dest_hotlist;
tSirAPThresholdParam *src_ap = photlist->ap;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int j, index = 0;
int cmd_len = 0;
int num_entries = 0;
int min_entries = 0;
uint32_t numap = photlist->numAp;
int len = sizeof(*cmd);
len += WMI_TLV_HDR_SIZE;
cmd_len = len;
/* setbssid hotlist expects the bssid list
* to be non zero value
*/
if (!numap || (numap > WLAN_EXTSCAN_MAX_HOTLIST_APS)) {
WMA_LOGE("%s: Invalid number of APs: %d", __func__, numap);
return VOS_STATUS_E_INVAL;
}
num_entries = wma_get_hotlist_entries_per_page(wma_handle->wmi_handle,
cmd_len,
sizeof(*dest_hotlist));
/* Split the hot list entry pages and send multiple command
* requests if the buffer reaches the maximum request size
*/
while (index < numap) {
min_entries = VOS_MIN(num_entries, numap);
len += min_entries * sizeof(wmi_extscan_hotlist_entry);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *)wmi_buf_data(buf);
cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *)
buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_configure_hotlist_monitor_cmd_fixed_param));
/* Multiple requests are sent until the num_entries_in_page
* matches the total_entries
*/
cmd->request_id = photlist->requestId;
cmd->vdev_id = photlist->sessionId;
cmd->total_entries = numap;
cmd->mode = 1;
cmd->num_entries_in_page = min_entries;
cmd->lost_ap_scan_count = photlist->lost_ap_sample_size;
cmd->first_entry_index = index;
WMA_LOGD("%s: vdev id:%d total_entries: %d num_entries: %d lost_ap_sample_size: %d",
__func__, cmd->vdev_id, cmd->total_entries,
cmd->num_entries_in_page,
cmd->lost_ap_scan_count);
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
min_entries * sizeof(wmi_extscan_hotlist_entry));
dest_hotlist = (wmi_extscan_hotlist_entry *)
(buf_ptr + WMI_TLV_HDR_SIZE);
/* Populate bssid, channel info and rssi
* for the bssid's that are sent as hotlists.
*/
for (j = 0; j < min_entries; j++) {
WMITLV_SET_HDR(dest_hotlist,
WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_hotlist_entry));
dest_hotlist->min_rssi = src_ap->low;
WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid,
&dest_hotlist->bssid);
WMA_LOGD("%s: min_rssi %d", __func__,
dest_hotlist->min_rssi);
WMA_LOGD("%s: bssid mac_addr31to0: 0x%x, mac_addr47to32: 0x%x",
__func__, dest_hotlist->bssid.mac_addr31to0,
dest_hotlist->bssid.mac_addr47to32);
dest_hotlist++;
src_ap++;
}
buf_ptr += WMI_TLV_HDR_SIZE +
(min_entries * sizeof(wmi_extscan_hotlist_entry));
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) {
WMA_LOGE("%s: failed to send command", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
index = index + min_entries;
num_entries = numap - min_entries;
len = cmd_len;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma,
tSirExtScanSetBssidHotListReqParams *photlist)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int len;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue hotlist cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
/* Fill individual elements for hotlist request and
* TLV for bssid entries
*/
vos_status = wma_get_buf_extscan_hotlist_cmd(wma, photlist,
&len);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to get buffer for hotlist scan cmd",
__func__);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma,
tSirExtScanResetBssidHotlistReqParams *photlist_reset)
{
wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
int hotlist_entries = 0;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!photlist_reset) {
WMA_LOGE("%s: Invalid reset hotlist buffer",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan not enabled",
__func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
/* reset bssid hotlist with tlv set to 0 */
len += WMI_TLV_HDR_SIZE;
len += hotlist_entries * sizeof(wmi_extscan_hotlist_entry);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *)
buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_configure_hotlist_monitor_cmd_fixed_param));
cmd->request_id = photlist_reset->requestId;
cmd->vdev_id = photlist_reset->sessionId;
cmd->mode = 0;
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
hotlist_entries * sizeof(wmi_extscan_hotlist_entry));
buf_ptr += WMI_TLV_HDR_SIZE +
(hotlist_entries * sizeof(wmi_extscan_hotlist_entry));
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) {
WMA_LOGE("%s: failed to command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_get_buf_extscan_change_monitor_cmd(tp_wma_handle wma_handle,
tSirExtScanSetSigChangeReqParams *psigchange,
wmi_buf_t *buf, int *buf_len)
{
wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd;
wmi_extscan_wlan_change_bssid_param *dest_chglist;
u_int8_t *buf_ptr;
int j;
int len = sizeof(*cmd);
uint32_t numap = psigchange->numAp;
tSirAPThresholdParam *src_ap = psigchange->ap;
if (!numap || (numap > WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS)) {
WMA_LOGE("%s: Invalid number of APs: %d",
__func__, numap);
return VOS_STATUS_E_INVAL;
}
len += WMI_TLV_HDR_SIZE;
len += numap * sizeof(wmi_extscan_wlan_change_bssid_param);
*buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!*buf) {
WMA_LOGP("%s: failed to allocate memory for change monitor cmd",
__func__);
return VOS_STATUS_E_FAILURE;
}
buf_ptr = (u_int8_t *) wmi_buf_data(*buf);
cmd = (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param));
cmd->request_id = psigchange->requestId;
cmd->vdev_id = psigchange->sessionId;
cmd->total_entries = numap;
cmd->mode = 1;
cmd->num_entries_in_page = numap;
cmd->lost_ap_scan_count = psigchange->lostApSampleSize;
cmd->max_rssi_samples = psigchange->rssiSampleSize;
cmd->rssi_averaging_samples = psigchange->rssiSampleSize;
cmd->max_out_of_range_count = psigchange->minBreaching;
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
numap * sizeof(wmi_extscan_wlan_change_bssid_param));
dest_chglist = (wmi_extscan_wlan_change_bssid_param *)
(buf_ptr + WMI_TLV_HDR_SIZE);
for (j = 0; j < numap; j++) {
WMITLV_SET_HDR(dest_chglist,
WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_wlan_change_bssid_param));
dest_chglist->lower_rssi_limit = src_ap->low;
dest_chglist->upper_rssi_limit = src_ap->high;
WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid,
&dest_chglist->bssid);
WMA_LOGD("%s:min_rssi %d", __func__,
dest_chglist->lower_rssi_limit);
dest_chglist++;
src_ap++;
}
buf_ptr += WMI_TLV_HDR_SIZE +
(numap * sizeof(wmi_extscan_wlan_change_bssid_param));
*buf_len = len;
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_extscan_start_change_monitor(tp_wma_handle wma,
tSirExtScanSetSigChangeReqParams *psigchange)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf;
int len;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed,can not issue extscan cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
/* Fill individual elements of change monitor and
* TLV info ... */
vos_status = wma_get_buf_extscan_change_monitor_cmd(wma,
psigchange, &buf, &len);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("%s: Failed to get buffer for change monitor cmd",
__func__);
return VOS_STATUS_E_FAILURE;
}
if (!buf) {
WMA_LOGE("%s: Failed to get buffer", __func__);
return VOS_STATUS_E_FAILURE;
}
if (wmi_unified_cmd_send(wma->wmi_handle, buf,
len, WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) {
WMA_LOGE("%s: failed to send command", __func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma,
tSirExtScanResetSignificantChangeReqParams *pResetReq)
{
wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
int change_list = 0;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: ext scan not enabled",
__func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
/* reset significant change tlv is set to 0 */
len += WMI_TLV_HDR_SIZE;
len += change_list *
sizeof(wmi_extscan_wlan_change_bssid_param);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param));
cmd->request_id = pResetReq->requestId;
cmd->vdev_id = pResetReq->sessionId;
cmd->mode = 0;
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
change_list *
sizeof(wmi_extscan_wlan_change_bssid_param));
buf_ptr += WMI_TLV_HDR_SIZE + (change_list *
sizeof(wmi_extscan_wlan_change_bssid_param));
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) {
WMA_LOGE("%s: failed to command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_extscan_get_cached_results(tp_wma_handle wma,
tSirExtScanGetCachedResultsReqParams *pcached_results)
{
wmi_extscan_get_cached_results_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, cannot issue cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan not enabled",
__func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf);
cmd = (wmi_extscan_get_cached_results_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_get_cached_results_cmd_fixed_param));
cmd->request_id = pcached_results->requestId;
cmd->vdev_id = pcached_results->sessionId;
cmd->control_flags = pcached_results->flush;
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID)) {
WMA_LOGE("%s: failed to command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wma_extscan_get_capabilities(tp_wma_handle wma,
tSirGetExtScanCapabilitiesReqParams *pgetcapab)
{
wmi_extscan_get_capabilities_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan not enabled",
__func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf);
cmd = (wmi_extscan_get_capabilities_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_extscan_get_capabilities_cmd_fixed_param));
cmd->request_id = pgetcapab->requestId;
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_EXTSCAN_GET_CAPABILITIES_CMDID)) {
WMA_LOGE("%s: failed to command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/** wma_set_epno_network_list() - set epno network list
* @wma: WMA handle
* @req: epno config params request structure
*
* This function reads the incoming epno config request structure
* and constructs the WMI message to the firmware.
*
* Returns: 0 on success, error number otherwise
*/
static int wma_set_epno_network_list(tp_wma_handle wma,
struct wifi_epno_params *req)
{
wmi_nlo_config_cmd_fixed_param *cmd;
nlo_configured_parameters *nlo_list;
enlo_candidate_score_params *cand_score_params;
u_int8_t i, *buf_ptr;
wmi_buf_t buf;
uint32_t len;
int ret;
WMA_LOGD("wma_set_epno_network_list");
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__);
return -EINVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan not enabled", __func__);
return -EINVAL;
}
/* Fixed Params */
len = sizeof(*cmd);
if (req->num_networks) {
/* TLV place holder for array of structures
* then each nlo_configured_parameters(nlo_list) TLV.
*/
len += WMI_TLV_HDR_SIZE;
len += (sizeof(nlo_configured_parameters)
* VOS_MIN(req->num_networks, WMI_NLO_MAX_SSIDS));
/* TLV for array of uint32 channel_list */
len += WMI_TLV_HDR_SIZE;
/* TLV for nlo_channel_prediction_cfg */
len += WMI_TLV_HDR_SIZE;
/* TLV for candidate score params */
len += sizeof(enlo_candidate_score_params);
}
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return -ENOMEM;
}
cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_nlo_config_cmd_fixed_param));
cmd->vdev_id = req->session_id;
/* set flag to reset if num of networks are 0 */
cmd->flags = (req->num_networks == 0 ?
WMI_NLO_CONFIG_ENLO_RESET : WMI_NLO_CONFIG_ENLO);
buf_ptr += sizeof(wmi_nlo_config_cmd_fixed_param);
cmd->no_of_ssids = MIN(req->num_networks, WMI_NLO_MAX_SSIDS);
WMA_LOGD(FL("SSID count: %d flags: %d"),
cmd->no_of_ssids, cmd->flags);
/* Fill nlo_config only when num_networks are non zero */
if (cmd->no_of_ssids) {
/* Fill networks */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
cmd->no_of_ssids * sizeof(nlo_configured_parameters));
buf_ptr += WMI_TLV_HDR_SIZE;
nlo_list = (nlo_configured_parameters *) buf_ptr;
for (i = 0; i < cmd->no_of_ssids; i++) {
WMITLV_SET_HDR(&nlo_list[i].tlv_header,
WMITLV_TAG_ARRAY_BYTE,
WMITLV_GET_STRUCT_TLVLEN
(nlo_configured_parameters));
/* Copy ssid and it's length */
nlo_list[i].ssid.valid = TRUE;
nlo_list[i].ssid.ssid.ssid_len =
req->networks[i].ssid.length;
vos_mem_copy(nlo_list[i].ssid.ssid.ssid,
req->networks[i].ssid.ssId,
nlo_list[i].ssid.ssid.ssid_len);
WMA_LOGD("index: %d ssid: %.*s len: %d", i,
nlo_list[i].ssid.ssid.ssid_len,
(char *) nlo_list[i].ssid.ssid.ssid,
nlo_list[i].ssid.ssid.ssid_len);
/* Copy pno flags */
nlo_list[i].bcast_nw_type.valid = TRUE;
nlo_list[i].bcast_nw_type.bcast_nw_type =
req->networks[i].flags;
WMA_LOGD("PNO flags (%u)",
nlo_list[i].bcast_nw_type.bcast_nw_type);
/* Copy auth bit field */
nlo_list[i].auth_type.valid = TRUE;
nlo_list[i].auth_type.auth_type =
req->networks[i].auth_bit_field;
WMA_LOGD("Auth bit field (%u)",
nlo_list[i].auth_type.auth_type);
}
buf_ptr += cmd->no_of_ssids * sizeof(nlo_configured_parameters);
/* Fill the channel list */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill prediction_param */
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0);
buf_ptr += WMI_TLV_HDR_SIZE;
/* Fill epno candidate score params */
cand_score_params = (enlo_candidate_score_params *) buf_ptr;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_STRUC_enlo_candidate_score_param,
WMITLV_GET_STRUCT_TLVLEN(enlo_candidate_score_params));
cand_score_params->min5GHz_rssi =
req->min_5ghz_rssi;
cand_score_params->min24GHz_rssi =
req->min_24ghz_rssi;
cand_score_params->initial_score_max =
req->initial_score_max;
cand_score_params->current_connection_bonus =
req->current_connection_bonus;
cand_score_params->same_network_bonus =
req->same_network_bonus;
cand_score_params->secure_bonus =
req->secure_bonus;
cand_score_params->band5GHz_bonus =
req->band_5ghz_bonus;
buf_ptr += sizeof(enlo_candidate_score_params);
}
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send nlo wmi cmd", __func__);
wmi_buf_free(buf);
return -EINVAL;
}
WMA_LOGD("set ePNO list request sent successfully for vdev %d",
req->session_id);
return 0;
}
/**
* wma_set_passpoint_network_list() - set passpoint network list
* @handle: WMA handle
* @req: passpoint network request structure
*
* This function reads the incoming @req and fill in the destination
* WMI structure and send down the passpoint configs down to the firmware
*
* Return: 0 on success; error number otherwise
*/
static int wma_set_passpoint_network_list(tp_wma_handle wma,
struct wifi_passpoint_req *req)
{
wmi_passpoint_config_cmd_fixed_param *cmd;
u_int8_t i, j, *bytes;
wmi_buf_t buf;
uint32_t len;
int ret;
WMA_LOGD("wma_set_passpoint_network_list");
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__);
return -EINVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan not enabled", __func__);
return -EINVAL;
}
len = sizeof(*cmd);
for (i = 0; i < req->num_networks; i++) {
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return -ENOMEM;
}
cmd = (wmi_passpoint_config_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_passpoint_config_cmd_fixed_param));
cmd->id = req->networks[i].id;
WMA_LOGD("%s: network id: %u", __func__, cmd->id);
vos_mem_copy(cmd->realm, req->networks[i].realm,
strlen(req->networks[i].realm) + 1);
WMA_LOGD("%s: realm: %s", __func__, cmd->realm);
for (j = 0; j < PASSPOINT_ROAMING_CONSORTIUM_ID_NUM; j++) {
bytes = (uint8_t *) &req->networks[i].roaming_consortium_ids[j];
WMA_LOGD("index: %d rcids: %02x %02x %02x %02x %02x %02x %02x %02x",
j, bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5], bytes[6], bytes[7]);
vos_mem_copy(&cmd->roaming_consortium_ids[j],
&req->networks[i].roaming_consortium_ids[j],
PASSPOINT_ROAMING_CONSORTIUM_ID_LEN);
}
vos_mem_copy(cmd->plmn, req->networks[i].plmn,
PASSPOINT_PLMN_ID_LEN);
WMA_LOGD("%s: plmn: [%02x %02x %02x]", __func__,
cmd->plmn[0], cmd->plmn[1], cmd->plmn[2]);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PASSPOINT_LIST_CONFIG_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send set passpoint network list wmi cmd",
__func__);
wmi_buf_free(buf);
return -EINVAL;
}
}
WMA_LOGD("Set passpoint network list request is sent successfully for vdev %d",
req->session_id);
return 0;
}
/**
* wma_reset_passpoint_network_list() - reset passpoint network list
* @handle: WMA handle
* @req: passpoint network request structure
*
* This function sends down WMI command with network id set to wildcard id.
* firmware shall clear all the config entries
*
* Return: 0 on success; error number otherwise
*/
static int wma_reset_passpoint_network_list(tp_wma_handle wma,
struct wifi_passpoint_req *req)
{
wmi_passpoint_config_cmd_fixed_param *cmd;
wmi_buf_t buf;
uint32_t len;
int ret;
WMA_LOGD("wma_reset_passpoint_network_list");
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__);
return -EINVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
WMA_LOGE("%s: extscan not enabled", __func__);
return -EINVAL;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return -ENOMEM;
}
cmd = (wmi_passpoint_config_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_passpoint_config_cmd_fixed_param));
cmd->id = WMI_PASSPOINT_NETWORK_ID_WILDCARD;
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PASSPOINT_LIST_CONFIG_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send reset passpoint network list wmi cmd",
__func__);
wmi_buf_free(buf);
return -EINVAL;
}
WMA_LOGD("Reset passpoint network list request is sent successfully for vdev %d",
req->session_id);
return 0;
}
#endif
VOS_STATUS wma_ipa_offload_enable_disable(tp_wma_handle wma,
struct sir_ipa_offload_enable_disable *ipa_offload)
{
wmi_ipa_offload_enable_disable_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
#ifdef INTRA_BSS_FWD_OFFLOAD
ol_txrx_vdev_handle vdev;
struct txrx_pdev_cfg_t *cfg;
int32_t intra_bss_fwd = 0;
#endif
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
((ipa_offload->offload_type == AP_RX_DATA_OFFLOAD)?
WMI_SERVICE_HSOFFLOAD:
WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT))) {
WMA_LOGE("%s: %s not supported", __func__,
((ipa_offload->offload_type == AP_RX_DATA_OFFLOAD)?
"WMI_SERVICE_HSOFFLOAD":
"WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT"));
return VOS_STATUS_E_FAILURE;
}
if (ipa_offload->offload_type > STA_RX_DATA_OFFLOAD) {
return VOS_STATUS_E_INVAL;
}
if (vos_is_load_unload_in_progress(VOS_MODULE_ID_VOSS, NULL)) {
WMA_LOGE("%s: Driver load/unload in progress", __func__);
return VOS_STATUS_E_INVAL;
}
len = sizeof(*cmd);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed (len=%d)", __func__, len);
return VOS_STATUS_E_NOMEM;
}
WMA_LOGE("%s: offload_type=%d, enable=%d", __func__,
ipa_offload->offload_type, ipa_offload->enable);
buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf);
cmd = (wmi_ipa_offload_enable_disable_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUCT_wmi_ipa_offload_enable_disable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_ipa_offload_enable_disable_cmd_fixed_param));
cmd->offload_type = ipa_offload->offload_type;
cmd->vdev_id = ipa_offload->vdev_id;
cmd->enable = ipa_offload->enable;
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID)) {
WMA_LOGE("%s: failed to command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
#ifdef INTRA_BSS_FWD_OFFLOAD
/* Check if VDEV is already deleted. If deleted, don't
* send INTRA BSS FWD WMI command
*/
vdev = wma_find_vdev_by_id(wma, ipa_offload->vdev_id);
if (!vdev)
return VOS_STATUS_SUCCESS;
/* Disable Intra-BSS FWD offload when gDisableIntraBssFwd=1 in INI */
cfg = (struct txrx_pdev_cfg_t *)vdev->pdev->ctrl_pdev;
if (!ipa_offload->enable || cfg->rx_fwd_disabled) {
WMA_LOGE("%s: ipa_offload->enable=%d, rx_fwd_disabled=%d",
__func__, ipa_offload->enable, cfg->rx_fwd_disabled);
intra_bss_fwd = 1;
}
/* Disable/enable WMI_VDEV_PARAM_INTRA_BSS_FWD */
if (wmi_unified_vdev_set_param_send(wma->wmi_handle,
ipa_offload->vdev_id, WMI_VDEV_PARAM_INTRA_BSS_FWD,
intra_bss_fwd)) {
WMA_LOGE("Failed to disable WMI_VDEV_PARAM_INTRA_BSS_FWD");
return VOS_STATUS_E_FAILURE;
}
#endif
return VOS_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_NAN
/* function : wma_nan_req
* Descriptin : Function is used to send nan request down
* Args : wma_handle, request data which will be non-null
* Returns : SUCCESS or FAILURE
*/
static VOS_STATUS wma_nan_req(void *wda_handle, tpNanRequest nan_req)
{
int ret;
tp_wma_handle wma_handle = (tp_wma_handle)wda_handle;
wmi_nan_cmd_param *cmd;
wmi_buf_t buf;
u_int16_t len = sizeof(*cmd);
u_int16_t nan_data_len, nan_data_len_aligned;
u_int8_t *buf_ptr;
/*
* <----- cmd ------------><-- WMI_TLV_HDR_SIZE --><--- data ---->
* +------------+----------+-----------------------+--------------+
* | tlv_header | data_len | WMITLV_TAG_ARRAY_BYTE | nan_req_data |
* +------------+----------+-----------------------+--------------+
*/
if (!nan_req) {
WMA_LOGE("%s:nan req is not valid", __func__);
return VOS_STATUS_E_FAILURE;
}
nan_data_len = nan_req->request_data_len;
nan_data_len_aligned = roundup(nan_req->request_data_len,
sizeof(u_int32_t));
len += WMI_TLV_HDR_SIZE + nan_data_len_aligned;
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 = (wmi_nan_cmd_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_nan_cmd_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_nan_cmd_param));
cmd->data_len = nan_req->request_data_len;
WMA_LOGD("%s: The data len value is %u",
__func__, nan_req->request_data_len);
buf_ptr += sizeof(wmi_nan_cmd_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, nan_data_len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, nan_req->request_data,
cmd->data_len);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_NAN_CMDID);
if (ret != EOK) {
WMA_LOGE("%s Failed to send set param command ret = %d", __func__, ret);
wmi_buf_free(buf);
}
return ret;
}
#endif
static void wma_process_unit_test_cmd(WMA_HANDLE handle,
t_wma_unit_test_cmd *wma_utest)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_unit_test_cmd_fixed_param* cmd;
wmi_buf_t wmi_buf;
u_int8_t *buf_ptr;
int i;
u_int16_t len, args_tlv_len;
A_UINT32 *unit_test_cmd_args;
args_tlv_len = WMI_TLV_HDR_SIZE + wma_utest->num_args * sizeof(A_UINT32);
len = sizeof(wmi_unit_test_cmd_fixed_param) + args_tlv_len;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue fw unit test cmd",
__func__);
return;
}
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmai_buf_alloc failed", __func__);
return;
}
cmd = (wmi_unit_test_cmd_fixed_param *)wmi_buf_data(wmi_buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_unit_test_cmd_fixed_param));
cmd->vdev_id = wma_utest->vdev_id;
cmd->module_id = wma_utest->module_id;
cmd->num_args = wma_utest->num_args;
buf_ptr += sizeof(wmi_unit_test_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(wma_utest->num_args * sizeof(u_int32_t)));
unit_test_cmd_args = (A_UINT32 *)(buf_ptr + WMI_TLV_HDR_SIZE);
WMA_LOGI("%s: %d num of args = ", __func__, wma_utest->num_args);
for (i = 0; (i < wma_utest->num_args && i < WMA_MAX_NUM_ARGS); i++) {
unit_test_cmd_args[i] = wma_utest->args[i];
WMA_LOGI("%d,", wma_utest->args[i]);
}
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_UNIT_TEST_CMDID)) {
WMA_LOGP("%s: failed to send unit test command", __func__);
wmi_buf_free(wmi_buf);
return;
}
return;
}
VOS_STATUS wma_scan_probe_setoui(tp_wma_handle wma,
tSirScanMacOui *psetoui)
{
wmi_scan_prob_req_oui_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
u_int32_t *oui_buf;
uint32_t i = 0;
wmi_vendor_oui *voui = NULL;
struct vendor_oui *pvoui = NULL;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd",
__func__);
return VOS_STATUS_E_INVAL;
}
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
psetoui->num_vendor_oui * sizeof(wmi_vendor_oui);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf);
cmd = (wmi_scan_prob_req_oui_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_scan_prob_req_oui_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_scan_prob_req_oui_cmd_fixed_param));
oui_buf = &cmd->prob_req_oui;
vos_mem_zero(oui_buf, sizeof(cmd->prob_req_oui));
*oui_buf = psetoui->oui[0] << 16 | psetoui->oui[1] << 8
| psetoui->oui[2];
WMA_LOGD("%s: wma:oui received from hdd %08x", __func__,
cmd->prob_req_oui);
cmd->vdev_id = psetoui->vdev_id;
cmd->flags = WMI_SCAN_PROBE_OUI_SPOOFED_MAC_IN_PROBE_REQ;
if (psetoui->enb_probe_req_sno_randomization)
cmd->flags |= WMI_SCAN_PROBE_OUI_RANDOM_SEQ_NO_IN_PROBE_REQ;
if (psetoui->ie_whitelist)
cmd->flags |=
WMI_SCAN_PROBE_OUI_ENABLE_IE_WHITELIST_IN_PROBE_REQ;
WMA_LOGI(FL("vdev_id = %d, flags = %x"), cmd->vdev_id, cmd->flags);
cmd->num_vendor_oui = psetoui->num_vendor_oui;
if (psetoui->ie_whitelist) {
for (i = 0; i < PROBE_REQ_BITMAP_LEN; i++)
cmd->ie_bitmap[i] = psetoui->probe_req_ie_bitmap[i];
}
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
psetoui->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 *)psetoui +
sizeof(*psetoui));
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);
}
}
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_SCAN_PROB_REQ_OUI_CMDID)) {
WMA_LOGE("%s: failed to send command", __func__);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#ifdef DHCP_SERVER_OFFLOAD
static int wma_process_dhcpserver_offload(tp_wma_handle wma_handle,
tSirDhcpSrvOffloadInfo *pDhcpSrvOffloadInfo)
{
wmi_set_dhcp_server_offload_cmd_fixed_param *cmd;
wmi_buf_t buf;
int err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send "
"set_dhcp_server_offload cmd");
return -ENOMEM;
}
cmd = (wmi_set_dhcp_server_offload_cmd_fixed_param *)wmi_buf_data(buf);
vos_mem_zero(cmd, sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_set_dhcp_server_offload_cmd_fixed_param));
cmd->vdev_id = pDhcpSrvOffloadInfo->vdev_id;
cmd->enable = pDhcpSrvOffloadInfo->dhcpSrvOffloadEnabled;
cmd->num_client = pDhcpSrvOffloadInfo->dhcpClientNum;
cmd->srv_ipv4 = pDhcpSrvOffloadInfo->dhcpSrvIP;
cmd->start_lsb = pDhcpSrvOffloadInfo->dhcp_client_start_ip;
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_SET_DHCP_SERVER_OFFLOAD_CMDID);
if (err) {
WMA_LOGE("Failed to send set_dhcp_server_offload cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Set dhcp server offload to vdevId %d",
pDhcpSrvOffloadInfo->vdev_id);
return 0;
}
#endif /* DHCP_SERVER_OFFLOAD */
#ifdef WLAN_FEATURE_GPIO_LED_FLASHING
VOS_STATUS wma_set_led_flashing(tp_wma_handle wma_handle,
tSirLedFlashingReq *flashing)
{
wmi_set_led_flashing_cmd_fixed_param *cmd;
int status = 0;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int32_t len = sizeof(wmi_set_led_flashing_cmd_fixed_param);
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue cmd"));
return VOS_STATUS_E_INVAL;
}
if (!flashing) {
WMA_LOGE(FL("invalid parameter: flashing"));
return VOS_STATUS_E_INVAL;
}
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGP(FL("wmi_buf_alloc failed"));
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_set_led_flashing_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_set_led_flashing_cmd_fixed_param));
cmd->pattern_id = flashing->pattern_id;
cmd->led_x0 = flashing->led_x0;
cmd->led_x1 = flashing->led_x1;
cmd->gpio_num = flashing->gpio_num;
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PDEV_SET_LED_FLASHING_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;
}
#endif
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
static void wma_process_roam_invoke(WMA_HANDLE handle,
t_wma_roam_invoke_cmd *roaminvoke)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_roam_invoke_cmd_fixed_param* cmd;
wmi_buf_t wmi_buf;
u_int8_t *buf_ptr;
u_int16_t len, args_tlv_len;
A_UINT32 *channel_list;
wmi_mac_addr *bssid_list;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not send roam invoke",
__func__);
return;
}
/* Host sends only one channel and one bssid */
args_tlv_len = 2 * WMI_TLV_HDR_SIZE + sizeof(A_UINT32) +
sizeof(wmi_mac_addr);
len = sizeof(wmi_roam_invoke_cmd_fixed_param) + args_tlv_len;
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmai_buf_alloc failed", __func__);
return;
}
cmd = (wmi_roam_invoke_cmd_fixed_param *)wmi_buf_data(wmi_buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_roam_invoke_cmd_fixed_param));
cmd->vdev_id = roaminvoke->vdev_id;
cmd->flags = 0;
cmd->roam_scan_mode = 0;
cmd->roam_ap_sel_mode = 0;
cmd->roam_delay = 0;
cmd->num_chan = 1;
cmd->num_bssid = 1;
buf_ptr += sizeof(wmi_roam_invoke_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(sizeof(u_int32_t)));
channel_list = (A_UINT32 *)(buf_ptr + WMI_TLV_HDR_SIZE);
*channel_list = (A_UINT32)vos_chan_to_freq(roaminvoke->channel);
buf_ptr += sizeof(A_UINT32) + WMI_TLV_HDR_SIZE;
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC,
(sizeof(wmi_mac_addr)));
bssid_list = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE);
WMI_CHAR_ARRAY_TO_MAC_ADDR(roaminvoke->bssid, bssid_list);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_ROAM_INVOKE_CMDID)) {
WMA_LOGP("%s: failed to send roam invoke command", __func__);
wmi_buf_free(wmi_buf);
return;
}
return;
}
#endif
#ifdef MDNS_OFFLOAD
static int wma_set_mdns_offload(tp_wma_handle wma_handle,
tSirMDNSOffloadInfo *pMDNSInfo)
{
wmi_mdns_offload_cmd_fixed_param *cmd;
wmi_buf_t buf;
int err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send "
"set_mdns_offload cmd");
return -ENOMEM;
}
cmd = (wmi_mdns_offload_cmd_fixed_param *)wmi_buf_data(buf);
vos_mem_zero(cmd, sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_mdns_offload_cmd_fixed_param));
cmd->vdev_id = pMDNSInfo->vdev_id;
cmd->enable = pMDNSInfo->mDNSOffloadEnabled;
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_MDNS_OFFLOAD_ENABLE_CMDID);
if (err) {
WMA_LOGE("Failed to send set_mdns_offload cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Set mDNS offload to vdevId %d",
pMDNSInfo->vdev_id);
return 0;
}
static int wma_set_mdns_fqdn(tp_wma_handle wma_handle,
tSirMDNSFqdnInfo *pMDNSFqdnInfo)
{
wmi_mdns_set_fqdn_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int len, err;
int num;
int numPadding = 0;
/* mdns fqdn is a table of 2 TLV's */
len = WMI_TLV_HDR_SIZE + pMDNSFqdnInfo->fqdn_len;
len += sizeof(wmi_mdns_set_fqdn_cmd_fixed_param);
num = len % sizeof(A_UINT32);
if (num > 0) {
numPadding = sizeof(A_UINT32) - num;
len += numPadding;
}
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send "
"set_mdns_fqdn cmd");
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_mdns_set_fqdn_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_mdns_set_fqdn_cmd_fixed_param));
cmd->vdev_id = pMDNSFqdnInfo->vdev_id;
cmd->type = pMDNSFqdnInfo->fqdn_type;
cmd->fqdn_len = pMDNSFqdnInfo->fqdn_len;
buf_ptr += sizeof(wmi_mdns_set_fqdn_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, (numPadding+cmd->fqdn_len));
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, pMDNSFqdnInfo->fqdn_data, cmd->fqdn_len);
if (numPadding > 0) {
buf_ptr += cmd->fqdn_len;
vos_mem_zero(buf_ptr, numPadding);
}
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_MDNS_SET_FQDN_CMDID);
if (err) {
WMA_LOGE("Failed to send set_mdns_fqdn cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Set mDNS fqdn to vdevId %d",
pMDNSFqdnInfo->vdev_id);
return 0;
}
static int wma_set_mdns_response(tp_wma_handle wma_handle,
tSirMDNSResponseInfo *pMDNSRespInfo)
{
wmi_mdns_set_resp_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int len, err;
int num;
int numPadding = 0;
/* mdns response is a table of 2 TLV's */
len = WMI_TLV_HDR_SIZE + pMDNSRespInfo->resp_len;
len += sizeof(wmi_mdns_set_resp_cmd_fixed_param);
num = len % sizeof(A_UINT32);
if (num > 0) {
numPadding = sizeof(A_UINT32) - num;
len += numPadding;
}
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send "
"set_mdns_response cmd");
return -ENOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_mdns_set_resp_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_mdns_set_resp_cmd_fixed_param));
cmd->vdev_id = pMDNSRespInfo->vdev_id;
cmd->AR_count = pMDNSRespInfo->resourceRecord_count;
cmd->resp_len = pMDNSRespInfo->resp_len;
buf_ptr += sizeof(wmi_mdns_set_resp_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, (numPadding+cmd->resp_len));
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, pMDNSRespInfo->resp_data, cmd->resp_len);
if (numPadding > 0) {
buf_ptr += cmd->resp_len;
vos_mem_zero(buf_ptr, numPadding);
}
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_MDNS_SET_RESPONSE_CMDID);
if (err) {
WMA_LOGE("Failed to set_mdns_response cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Set mDNS response to vdevId %d",
pMDNSRespInfo->vdev_id);
return 0;
}
static int wma_get_mdns_status(tp_wma_handle wma_handle, A_UINT32 *pVdev_id)
{
wmi_mdns_get_stats_cmd_fixed_param *cmd;
wmi_buf_t buf;
int err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send "
"get_mdns_status cmd");
return -ENOMEM;
}
cmd = (wmi_mdns_get_stats_cmd_fixed_param *)wmi_buf_data(buf);
vos_mem_zero(cmd, sizeof(*cmd));
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_mdns_stats_event_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_mdns_get_stats_cmd_fixed_param));
cmd->vdev_id = *pVdev_id;
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(*cmd), WMI_MDNS_GET_STATS_CMDID);
if (err) {
WMA_LOGE("Failed to send get_mdns_status cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Get mDNS STATS for vdevId %d", *pVdev_id);
return 0;
}
#endif /* MDNS_OFFLOAD */
#ifdef SAP_AUTH_OFFLOAD
static int wma_process_sap_auth_offload(tp_wma_handle wma_handle,
struct tSirSapOffloadInfo *sap_auth_offload_info)
{
wmi_sap_ofl_enable_cmd_fixed_param *cmd = NULL;
wmi_buf_t buf;
u_int8_t *buf_ptr;
u_int16_t len, psk_len, psk_len_padded;
int err;
if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_SAP_AUTH_OFFLOAD)) {
WMA_LOGE("Firmware not support SAP auth offload feature");
return -EIO;
}
psk_len = sap_auth_offload_info->key_len;
psk_len_padded = roundup(psk_len, sizeof(uint32_t));
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + psk_len_padded;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send "
"sap_auth_offload_enable cmd");
return -ENOMEM;
}
vos_mem_zero(cmd, len);
buf_ptr = wmi_buf_data(buf);
cmd = (wmi_sap_ofl_enable_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_sap_ofl_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_sap_ofl_enable_cmd_fixed_param));
cmd->enable = sap_auth_offload_info->sap_auth_offload_enable;
cmd->vdev_id = sap_auth_offload_info->vdev_id;
cmd->psk_len = psk_len;
/* SSID didn't assign here, left for Supplicant Profile Assign
* This field just keep for extendable
*/
switch (sap_auth_offload_info->sap_auth_offload_sec_type) {
case eSIR_OFFLOAD_WPA2PSK_CCMP:
cmd->rsn_authmode = WMI_AUTH_RSNA_PSK;
cmd->rsn_mcastcipherset = WMI_CIPHER_AES_CCM;
cmd->rsn_ucastcipherset = WMI_CIPHER_AES_CCM;
break;
case eSIR_OFFLOAD_NONE:
default:
WMA_LOGE("Set software AP Auth offload "
"with none support security type\n");
break;
}
buf_ptr += sizeof(wmi_sap_ofl_enable_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, psk_len_padded);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, sap_auth_offload_info->key, psk_len);
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_SAP_OFL_ENABLE_CMDID);
if (err) {
WMA_LOGE("Failed to set software AP Auth offload enable cmd");
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGD("Set software AP Auth offload enable = %d to vdevId %d",
sap_auth_offload_info->sap_auth_offload_enable,
sap_auth_offload_info->vdev_id);
return 0;
}
/**
* wma_process_client_block_info send wmi cmd of block info to fw.
*
* @wma_handle: wma handler
* @client_block_info: client block info struct pointer
*
* Return: Return VOS_STATUS
*/
static VOS_STATUS wma_process_client_block_info(tp_wma_handle wma_handle,
struct sblock_info *client_block_info)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_sap_set_blacklist_param_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int16_t len = sizeof(*cmd);
int ret;
if (!client_block_info)
return VOS_STATUS_E_FAULT;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed to allocate buffer",__func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_sap_set_blacklist_param_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_sap_set_blacklist_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_sap_set_blacklist_param_cmd_fixed_param));
cmd->vdev_id = client_block_info->vdev_id;
cmd->num_retry = client_block_info->reconnect_cnt;
cmd->retry_allow_time_ms = client_block_info->con_fail_duration;
cmd->blackout_time_ms = client_block_info->block_duration;
WMA_LOGD("Set Sap client block info vdev id=%u, reconnect_cnt=%u"
"con_fail_duration=%u, block_duration=%u",
cmd->vdev_id, cmd->num_retry,
cmd->retry_allow_time_ms, cmd->blackout_time_ms);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_SAP_SET_BLACKLIST_PARAM_CMDID);
if (ret != EOK) {
WMA_LOGE("fail to semd WMI_SAP_SET_BLACKLIST_PARAM_CMDID");
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
}
return vos_status;
}
#endif /* SAP_AUTH_OFFLOAD */
/**
* wma_process_set_mas() - Function to enable/disable MAS
* @wma: Pointer to WMA handle
* @mas_val: 1-Enable MAS, 0-Disable MAS
*
* This function enables/disables the MAS value
*
* Return: VOS_STATUS_SUCCESS for success otherwise failure
*
*/
VOS_STATUS wma_process_set_mas(tp_wma_handle wma,
uint32_t *mas_val)
{
uint32_t val;
if (NULL == wma || NULL == mas_val) {
WMA_LOGE("%s: Invalid input to enable/disable MAS", __func__);
return VOS_STATUS_E_FAILURE;
}
val = (*mas_val);
if (VOS_STATUS_SUCCESS !=
wma_set_enable_disable_mcc_adaptive_scheduler(val)) {
WMA_LOGE("%s: Unable to enable/disable MAS", __func__);
return VOS_STATUS_E_FAILURE;
} else {
WMA_LOGE("%s: Value is %d", __func__, val);
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_process_set_miracast() - Function to set miracast value in WMA
* @wma: Pointer to WMA handle
* @miracast_val: 0-Disabled,1-Source,2-Sink
*
* This function stores the miracast value in WMA
*
* Return: VOS_STATUS_SUCCESS for success otherwise failure
*
*/
VOS_STATUS wma_process_set_miracast(tp_wma_handle wma, u_int32_t *miracast_val)
{
if (NULL == wma || NULL == miracast_val) {
WMA_LOGE("%s: Invalid input to store miracast value", __func__);
return VOS_STATUS_E_FAILURE;
}
wma->miracast_value = *miracast_val;
WMA_LOGE("%s: Miracast value is %d", __func__, wma->miracast_value);
return VOS_STATUS_SUCCESS;
}
/**
* wma_config_stats_factor() - Function to configure stats avg. factor
* @wma: pointer to WMA handle
* @avg_factor: stats. avg. factor passed down by userspace
*
* This function configures the avg. stats value in firmware
*
* Return: VOS_STATUS_SUCCESS for success otherwise failure
*
*/
VOS_STATUS wma_config_stats_factor(tp_wma_handle wma,
struct sir_stats_avg_factor *avg_factor)
{
int ret;
if (NULL == wma || NULL == avg_factor) {
WMA_LOGE("%s: Invalid input of stats avg factor", __func__);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
avg_factor->vdev_id,
WMI_VDEV_PARAM_STATS_AVG_FACTOR,
avg_factor->stats_avg_factor);
if (ret) {
WMA_LOGE(" failed to set avg_factor for vdev_id %d",
avg_factor->vdev_id);
}
WMA_LOGD("%s: Set stats_avg_factor %d for vdev_id %d", __func__,
avg_factor->stats_avg_factor, avg_factor->vdev_id);
return ret;
}
/**
* wma_config_guard_time() - Function to set guard time in firmware
* @wma: pointer to WMA handle
* @guard_time: guard time passed down by userspace
*
* This function configures the guard time in firmware
*
* Return: VOS_STATUS_SUCCESS for success otherwise failure
*
*/
VOS_STATUS wma_config_guard_time(tp_wma_handle wma,
struct sir_guard_time_request *guard_time)
{
int ret;
if (NULL == wma || NULL == guard_time) {
WMA_LOGE("%s: Invalid input of guard time", __func__);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle,
guard_time->vdev_id,
WMI_VDEV_PARAM_RX_LEAK_WINDOW,
guard_time->guard_time);
if (ret) {
WMA_LOGE(" failed to set guard time for vdev_id %d",
guard_time->vdev_id);
}
WMA_LOGD("Set guard time %d for vdev_id %d",
guard_time->guard_time, guard_time->vdev_id);
return ret;
}
/*
* wma_process_set_ie_info() - Function to send IE info to firmware
* @wma: Pointer to WMA handle
* @ie_data: Pointer for ie data
*
* This function sends IE information to firmware
*
* Return: VOS_STATUS_SUCCESS for success otherwise failure
*
*/
static VOS_STATUS wma_process_set_ie_info(tp_wma_handle wma,
struct vdev_ie_info* ie_info)
{
wmi_vdev_set_ie_cmd_fixed_param *cmd;
wmi_buf_t buf;
uint8_t *buf_ptr;
uint32_t len, ie_len_aligned;
int ret;
if (!ie_info || !wma) {
WMA_LOGE(FL("input pointer is NULL"));
return VOS_STATUS_E_FAILURE;
}
/* Validate the input */
if (ie_info->length <= 0) {
WMA_LOGE(FL("Invalid IE length"));
return -EINVAL;
}
ie_len_aligned = roundup(ie_info->length, sizeof(uint32_t));
/* Allocate memory for the WMI command */
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + ie_len_aligned;
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE(FL("wmi_buf_alloc failed"));
return VOS_STATUS_E_NOMEM;
}
buf_ptr = wmi_buf_data(buf);
vos_mem_zero(buf_ptr, len);
/* Populate the WMI command */
cmd = (wmi_vdev_set_ie_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_vdev_set_ie_cmd_fixed_param));
cmd->vdev_id = ie_info->vdev_id;
cmd->ie_id = ie_info->ie_id;
cmd->ie_len = ie_info->length;
WMA_LOGD(FL("IE:%d of size:%d sent for vdev:%d"), ie_info->ie_id,
ie_info->length, ie_info->vdev_id);
buf_ptr += sizeof(*cmd);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, ie_info->data, cmd->ie_len);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_VDEV_SET_IE_CMDID);
if (ret != EOK) {
WMA_LOGE(FL("Failed to send set IE command ret = %d"), ret);
wmi_buf_free(buf);
}
return ret;
}
/**
* wma_enable_specific_fw_logs() - Start/Stop logging of diag event/log id
* @wma_handle: WMA handle
* @start_log: Start logging related parameters
*
* Send the command to the FW based on which specific logging of diag
* event/log id can be started/stopped
*
* Return: None
*/
void wma_enable_specific_fw_logs(tp_wma_handle wma_handle,
struct sir_wifi_start_log *start_log)
{
wmi_diag_event_log_config_fixed_param *cmd;
wmi_buf_t buf;
uint8_t *buf_ptr;
uint32_t len, count, log_level, i;
uint32_t *cmd_args;
uint32_t total_len;
count = 0;
if (!start_log) {
WMA_LOGE("%s: start_log pointer is NULL", __func__);
return;
}
if (!wma_handle) {
WMA_LOGE("%s: Invalid wma handle", __func__);
return;
}
if (!((start_log->ring_id == RING_ID_CONNECTIVITY) ||
(start_log->ring_id == RING_ID_FIRMWARE_DEBUG))) {
WMA_LOGD("%s: Not connectivity or fw debug ring: %d",
__func__, start_log->ring_id);
return;
}
if (!wma_handle->events_logs_list) {
WMA_LOGE("%s: Not received event/log list from FW, yet",
__func__);
return;
}
/* total_len stores the number of events where BITS 17 and 18 are set.
* i.e., events of high frequency (17) and for extended debugging (18)
*/
total_len = 0;
for (i = 0; i < wma_handle->num_of_diag_events_logs; i++) {
if ((WMI_DIAG_FREQUENCY_GET(wma_handle->events_logs_list[i])) &&
(WMI_DIAG_EXT_FEATURE_GET(wma_handle->events_logs_list[i])))
total_len++;
}
len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
(total_len * sizeof(uint32_t));
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return;
}
cmd = (wmi_diag_event_log_config_fixed_param *) wmi_buf_data(buf);
buf_ptr = (uint8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_diag_event_log_config_fixed_param));
cmd->num_of_diag_events_logs = total_len;
buf_ptr += sizeof(wmi_diag_event_log_config_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32,
(total_len * sizeof(uint32_t)));
cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE);
if (start_log->verbose_level >= LOG_LEVEL_ACTIVE)
log_level = 1;
else
log_level = 0;
WMA_LOGD("%s: Length:%d, Log_level:%d", __func__, total_len, log_level);
for (i = 0; i < wma_handle->num_of_diag_events_logs; i++) {
uint32_t val = wma_handle->events_logs_list[i];
if ((WMI_DIAG_FREQUENCY_GET(val)) &&
(WMI_DIAG_EXT_FEATURE_GET(val))) {
WMI_DIAG_ID_SET(cmd_args[count],
WMI_DIAG_ID_GET(val));
WMI_DIAG_TYPE_SET(cmd_args[count],
WMI_DIAG_TYPE_GET(val));
WMI_DIAG_ID_ENABLED_DISABLED_SET(cmd_args[count],
log_level);
WMA_LOGD("%s: Idx:%d, val:%x", __func__, i, val);
count++;
}
}
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_DIAG_EVENT_LOG_CONFIG_CMDID)) {
WMA_LOGE("%s: WMI_DIAG_EVENT_LOG_CONFIG_CMDID failed",
__func__);
wmi_buf_free(buf);
}
return;
}
#if !defined(REMOVE_PKT_LOG)
/**
* wma_set_wifi_start_packet_stats() - Start/stop packet stats
* @wma_handle: WMA handle
* @start_log: Struture containing the start wifi logger params
*
* This function is used to send the WMA commands to start/stop logging
* of per packet statistics
*
* Return: None
*
*/
void wma_set_wifi_start_packet_stats(void *wma_handle,
struct sir_wifi_start_log *start_log)
{
void *vos_context;
struct ol_softc *scn;
uint32_t log_state;
if (!start_log) {
WMA_LOGE("%s: start_log pointer is NULL", __func__);
return;
}
if (!wma_handle) {
WMA_LOGE("%s: Invalid wma handle", __func__);
return;
}
/* No need to register for ring IDs other than packet stats */
if (start_log->ring_id != RING_ID_PER_PACKET_STATS) {
WMA_LOGI("%s: Ring id is not for per packet stats: %d",
__func__, start_log->ring_id);
return;
}
vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
scn = vos_get_context(VOS_MODULE_ID_HIF, vos_context);
if (!scn) {
WMA_LOGE("%s: ol_softc context is NULL\n", __func__);
return;
}
log_state = ATH_PKTLOG_ANI | ATH_PKTLOG_RCUPDATE | ATH_PKTLOG_RCFIND |
ATH_PKTLOG_RX | ATH_PKTLOG_TX | ATH_PKTLOG_TEXT;
if (start_log->verbose_level == WLAN_LOG_LEVEL_ACTIVE) {
pktlog_enable(scn, log_state);
WMA_LOGI("%s: Enabling per packet stats", __func__);
} else {
pktlog_enable(scn, 0);
WMA_LOGI("%s: Disabling per packet stats", __func__);
}
}
#endif
/**
* wma_send_flush_logs_to_fw() - Send log flush command to FW
* @wma_handle: WMI handle
*
* This function is used to send the flush command to the FW,
* that will flush the fw logs that are residue in the FW
*
* Return: None
*/
void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle)
{
VOS_STATUS status;
wmi_debug_mesg_flush_fixed_param *cmd;
wmi_buf_t buf;
int len = sizeof(*cmd);
int ret;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return;
}
cmd = (wmi_debug_mesg_flush_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_debug_mesg_flush_fixed_param));
cmd->reserved0 = 0;
ret = wmi_unified_cmd_send(wma_handle->wmi_handle,
buf,
len,
WMI_DEBUG_MESG_FLUSH_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send WMI_DEBUG_MESG_FLUSH_CMDID");
wmi_buf_free(buf);
return;
}
WMA_LOGI("Sent WMI_DEBUG_MESG_FLUSH_CMDID to FW");
status = vos_timer_start(&wma_handle->log_completion_timer,
WMA_LOG_COMPLETION_TIMER);
if (status != VOS_STATUS_SUCCESS)
WMA_LOGE("Failed to start the log completion timer");
}
/**
* wma_set_rssi_monitoring() - set rssi monitoring
* @handle: WMA handle
* @req: rssi monitoring request structure
*
* This function reads the incoming @req and fill in the destination
* WMI structure and send down the rssi monitoring configs down to the firmware
*
* Return: 0 on success; error number otherwise
*/
static VOS_STATUS wma_set_rssi_monitoring(tp_wma_handle wma,
struct rssi_monitor_req *req)
{
wmi_rssi_breach_monitor_config_fixed_param *cmd;
wmi_buf_t buf;
int ret, len = sizeof(*cmd);
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_rssi_breach_monitor_config_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_rssi_breach_monitor_config_fixed_param));
cmd->vdev_id = req->session_id;
cmd->request_id = req->request_id;
cmd->lo_rssi_reenable_hysteresis = 0;
cmd->hi_rssi_reenable_histeresis = 0;
cmd->min_report_interval = 0;
cmd->max_num_report = 1;
if (req->control) {
/* enable one threshold for each min/max */
cmd->enabled_bitmap = 0x09;
cmd->low_rssi_breach_threshold[0] = req->min_rssi;
cmd->hi_rssi_breach_threshold[0] = req->max_rssi;
} else {
cmd->enabled_bitmap = 0;
cmd->low_rssi_breach_threshold[0] = 0;
cmd->hi_rssi_breach_threshold[0] = 0;
}
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID");
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGI("Sent WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID to FW");
return VOS_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD
/**
* wma_send_udp_resp_offload_cmd() - send wmi cmd of udp response offload
* infomation to fw.
* @wma_handle: wma handler
* @udp_response: udp_resp_offload struct pointer
*
* Return: Return VOS_STATUS
*/
static VOS_STATUS wma_send_udp_resp_offload_cmd(tp_wma_handle wma_handle,
struct udp_resp_offload *udp_response)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf;
WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param *cmd;
u_int16_t len;
u_int16_t pattern_len = 0;
u_int16_t response_len = 0;
u_int16_t udp_len = 0;
u_int16_t resp_len = 0;
WMA_LOGD("%s: Enter", __func__);
if (1 == udp_response->enable) {
pattern_len = strlen(udp_response->udp_payload_filter);
response_len = strlen(udp_response->udp_response_payload);
}
udp_len = (pattern_len % 4) ?
(4 * ((pattern_len / 4) + 1)) : (pattern_len);
resp_len = (response_len % 4) ?
(4 * ((response_len / 4) + 1)) : (response_len);
len = sizeof(*cmd) + udp_len + resp_len + 2 * WMI_TLV_HDR_SIZE;
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("wmi_buf_alloc failed");
return VOS_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param *)wmi_buf_data(buf);
vos_mem_zero(cmd, len);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param));
cmd->vdev_id = udp_response->vdev_id;
cmd->enable = udp_response->enable;
cmd->dest_port = udp_response->dest_port;
cmd->pattern_len = pattern_len;
cmd->response_len = response_len;
WMITLV_SET_HDR((A_UINT32 *)(cmd + 1),
WMITLV_TAG_ARRAY_BYTE,
udp_len);
vos_mem_copy((void *)(cmd + 1) + WMI_TLV_HDR_SIZE,
(void *)udp_response->udp_payload_filter,
cmd->pattern_len);
WMITLV_SET_HDR((A_UINT32 *)((void *)(cmd + 1) +
WMI_TLV_HDR_SIZE + udp_len),
WMITLV_TAG_ARRAY_BYTE,
resp_len);
vos_mem_copy((void *)(cmd + 1) + WMI_TLV_HDR_SIZE +
udp_len + WMI_TLV_HDR_SIZE,
(void *)udp_response->udp_response_payload,
cmd->response_len);
WMA_LOGD("wma_set_udp_resp_cmd: enable:%d vdev_id:%d dest_port:%u",
cmd->enable,cmd->vdev_id, cmd->dest_port);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_WOW_UDP_SVC_OFLD_CMDID)) {
WMA_LOGE("Failed to send set udp resp offload");
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
}
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
#else
static inline VOS_STATUS wma_send_udp_resp_offload_cmd(tp_wma_handle wma_handle,
struct udp_resp_offload *udp_response)
{
return VOS_STATUS_E_FAILURE;
}
#endif
#ifdef WLAN_FEATURE_WOW_PULSE
#define WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM \
WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD_fixed_param
#define WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM \
WMITLV_TAG_STRUC_wmi_wow_hostwakeup_gpio_pin_pattern_config_cmd_fixed_param
/*
* the repeat_cnt is reserved by FW team, the current value
* is always 0xffffffff
*/
#define WMI_WOW_PULSE_REPEAT_CNT 0xffffffff
/**
* wma_send_wow_pulse_cmd() - send wmi cmd of wow pulse cmd
* infomation to fw.
* @wma_handle: wma handler
* @udp_response: wow_pulse_mode pointer
*
* Return: Return VOS_STATUS
*/
static VOS_STATUS wma_send_wow_pulse_cmd(tp_wma_handle wma_handle,
struct wow_pulse_mode *wow_pulse_cmd)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf;
WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM *cmd;
u_int16_t len;
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("wmi_buf_alloc failed");
return VOS_STATUS_E_NOMEM;
}
cmd = (WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM *)wmi_buf_data(buf);
vos_mem_zero(cmd, len);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM,
WMITLV_GET_STRUCT_TLVLEN(
WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM));
cmd->enable = wow_pulse_cmd->wow_pulse_enable;
cmd->pin = wow_pulse_cmd->wow_pulse_pin;
cmd->interval_low = wow_pulse_cmd->wow_pulse_interval_low;
cmd->interval_high = wow_pulse_cmd->wow_pulse_interval_high;
cmd->repeat_cnt = WMI_WOW_PULSE_REPEAT_CNT;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID)) {
WMA_LOGE("Failed to send send wow pulse");
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
}
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
#undef WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM
#undef WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM
#undef WMI_WOW_PULSE_REPEAT_CNT
#else
static inline VOS_STATUS wma_send_wow_pulse_cmd(tp_wma_handle wma_handle,
struct wow_pulse_mode *wow_pulse_cmd)
{
return VOS_STATUS_E_FAILURE;
}
#endif
/**
* wma_send_wakeup_gpio_cmd() - send wmi cmd of wakeup gpio cmd
* infomation to fw.
* @wma_handle: wma handler
* @wakeup_gpio_cmd: wakeup_gpio_mode pointer
*
* Return: Return VOS_STATUS
*/
static VOS_STATUS wma_send_wakeup_gpio_cmd(tp_wma_handle wma_handle,
struct wakeup_gpio_mode *wakeup_gpio_cmd)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_buf_t buf;
WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param *cmd;
u_int16_t len;
WMA_LOGD("%s: Enter", __func__);
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("wmi_buf_alloc failed");
return VOS_STATUS_E_NOMEM;
}
cmd = (WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param));
cmd->host_wakeup_gpio = wakeup_gpio_cmd->host_wakeup_gpio;
cmd->host_wakeup_type = wakeup_gpio_cmd->host_wakeup_type;
cmd->target_wakeup_gpio = wakeup_gpio_cmd->target_wakeup_gpio;
cmd->target_wakeup_type = wakeup_gpio_cmd->target_wakeup_type;
WMA_LOGD("%s:host gpio:%d host type:%d target gpio:%d target type:%d",
__func__, cmd->host_wakeup_gpio, cmd->host_wakeup_type,
cmd->target_wakeup_gpio, cmd->target_wakeup_type);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PDEV_SET_WAKEUP_CONFIG_CMDID)) {
WMA_LOGE("Failed to send wakeup gpio cmd");
wmi_buf_free(buf);
vos_status = VOS_STATUS_E_FAILURE;
}
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
/*
* wma_update_wep_default_key - function to update default key id
* @wma: pointer to wma handler
* @update_def_key: pointer to wep_update_default_key_idx
*
* function makes a copy of default key index to txrx node
*
* return: Success
*/
static VOS_STATUS wma_update_wep_default_key(tp_wma_handle wma,
struct wep_update_default_key_idx *update_def_key)
{
struct wma_txrx_node *iface =
&wma->interfaces[update_def_key->session_id];
iface->wep_default_key_idx = update_def_key->default_idx;
return VOS_STATUS_SUCCESS;
}
/**
* wma_update_tx_rate: Update max tx_rate to firmware
* @wma_handle: wma handle
* @req: Set max tx_rate parameters to firmware
* For the specific hardware mode validate the max tx_rate value specified
* by the user.
* WMA_RESET_MAX_RATE: Is specified to switch back to max rate index for the
* specified hardware mode.
* Return: VOS_STATUS enumeration.
*/
static VOS_STATUS wma_update_tx_rate(tp_wma_handle wma,
struct sir_txrate_update *req)
{
struct wma_txrx_node *intr = wma->interfaces;
wmi_peer_max_min_tx_rate peer_max_min_tx_rate;
uint16_t tx_rate = (req->txrate);
WMA_LOGI("%s: Enter", __func__);
peer_max_min_tx_rate.tx_rate = tx_rate;
switch (intr[req->session_id].chanmode) {
case MODE_11A:
case MODE_11G:
case MODE_11GONLY:
if ((tx_rate >= 0 && tx_rate <= WMI_MAX_OFDM_TX_RATE)) {
/* Do Nothing*/
} else if (tx_rate == WMA_RESET_MAX_RATE)
peer_max_min_tx_rate.tx_rate = WMI_MAX_OFDM_TX_RATE;
else {
WMA_LOGE("invalid rate for MODE_11A/MODE11_G");
return -EINVAL;
}
peer_max_min_tx_rate.mode = WMI_RATE_PREAMBLE_OFDM;
break;
case MODE_11B:
if ((tx_rate >= 0 && tx_rate <= WMI_MAX_CCK_TX_RATE)) {
/* Do nothing*/
} else if (tx_rate == WMA_RESET_MAX_RATE)
peer_max_min_tx_rate.tx_rate = WMI_MAX_CCK_TX_RATE;
else {
WMA_LOGE("invalid rate for Mode MODE_11B");
return -EINVAL;
}
peer_max_min_tx_rate.mode = WMI_RATE_PREAMBLE_CCK;
break;
case MODE_11NA_HT20:
case MODE_11NG_HT20:
case MODE_11NA_HT40:
case MODE_11NG_HT40:
if ((tx_rate >= 0 && tx_rate <= WMI_MAX_HT_TX_MCS)) {
/* Do nothing*/
} else if (tx_rate == WMA_RESET_MAX_RATE)
peer_max_min_tx_rate.tx_rate = WMI_MAX_HT_TX_MCS;
else {
WMA_LOGE("invalid rate for Mode MODE_11N");
return -EINVAL;
}
peer_max_min_tx_rate.mode = WMI_RATE_PREAMBLE_HT;
break;
case MODE_11AC_VHT20:
case MODE_11AC_VHT40:
case MODE_11AC_VHT80:
case MODE_11AC_VHT20_2G:
case MODE_11AC_VHT40_2G:
#if CONFIG_160MHZ_SUPPORT
case MODE_11AC_VHT80_80:
case MODE_11AC_VHT160:
#endif
if ((tx_rate >= 0 && tx_rate <= WMI_MAX_VHT_TX_MCS)) {
/* Do nothing*/
} else if (tx_rate == WMA_RESET_MAX_RATE)
peer_max_min_tx_rate.tx_rate = WMI_MAX_VHT_TX_MCS;
else {
WMA_LOGE("invalid rate for Mode MODE_11N");
return -EINVAL;
}
peer_max_min_tx_rate.mode = WMI_RATE_PREAMBLE_VHT;
break;
default:
WMA_LOGE("%s: Error not supported mode", __func__);
return -EINVAL;
}
WMA_LOGD(FL("tx_rate: %d hwmode: %d"), peer_max_min_tx_rate.tx_rate,
peer_max_min_tx_rate.mode);
wma_set_peer_param(wma, req->bssid,
WMI_PEER_SET_MAX_TX_RATE ,
(peer_max_min_tx_rate.mode |
(peer_max_min_tx_rate.tx_rate << 16)),
req->session_id);
WMA_LOGI("%s: Exit", __func__);
return VOS_STATUS_SUCCESS;
}
/**
* wma_get_bpf_capabilities - Send get bpf capability to firmware
* @wma_handle: wma handle
*
* Return: VOS_STATUS enumeration.
*/
static VOS_STATUS wma_get_bpf_capabilities(tp_wma_handle wma)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_bpf_get_capability_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
u_int8_t *buf_ptr;
if (!wma || !wma->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue get BPF capab"));
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_BPF_OFFLOAD)) {
WMA_LOGE(FL("BPF cababilities feature bit not enabled"));
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_bpf_get_capability_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_bpf_get_capability_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_bpf_get_capability_cmd_fixed_param));
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_BPF_GET_CAPABILITY_CMDID)) {
WMA_LOGE(FL("Failed to send BPF capability command"));
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return vos_status;
}
/**
* wma_set_beacon_filter() - Issue WMI command to set beacon filter
* @wma: wma handler
* @filter_params: beacon_filter_param to set
*
* Return: Return VOS_STATUS
*/
static VOS_STATUS wma_set_beacon_filter(tp_wma_handle wma,
struct beacon_filter_param *filter_params)
{
int i;
wmi_buf_t wmi_buf;
u_int8_t *buf;
A_UINT32 *ie_map;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_add_bcn_filter_cmd_fixed_param *cmd;
int len = sizeof(wmi_add_bcn_filter_cmd_fixed_param);
len += WMI_TLV_HDR_SIZE;
len += BCN_FLT_MAX_ELEMS_IE_LIST*sizeof(A_UINT32);
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue set beacon filter",
__func__);
return VOS_STATUS_E_INVAL;
}
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_add_bcn_filter_cmd_fixed_param *)wmi_buf_data(wmi_buf);
cmd->vdev_id = filter_params->vdev_id;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_add_bcn_filter_cmd_fixed_param));
buf += sizeof(wmi_add_bcn_filter_cmd_fixed_param);
WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_UINT32,
(BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(u_int32_t)));
ie_map = (A_UINT32 *)(buf + WMI_TLV_HDR_SIZE);
for (i = 0; i < BCN_FLT_MAX_ELEMS_IE_LIST; i++) {
ie_map[i] = filter_params->ie_map[i];
WMA_LOGD("beacon filter ie map = %u", ie_map[i]);
}
vos_status = wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_ADD_BCN_FILTER_CMDID);
if (vos_status < 0) {
WMA_LOGE("Failed to send wmi add beacon filter = %d",
vos_status);
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return vos_status;
}
/**
* wma_remove_beacon_filter() - Issue WMI command to remove beacon filter
* @wma: wma handler
* @filter_params: beacon_filter_params
*
* Return: Return VOS_STATUS
*/
static VOS_STATUS wma_remove_beacon_filter(tp_wma_handle wma,
struct beacon_filter_param *filter_params)
{
wmi_buf_t buf;
wmi_rmv_bcn_filter_cmd_fixed_param *cmd;
int len = sizeof(wmi_rmv_bcn_filter_cmd_fixed_param);
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, cannot issue remove beacon filter",
__func__);
return VOS_STATUS_E_INVAL;
}
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_rmv_bcn_filter_cmd_fixed_param *)wmi_buf_data(buf);
cmd->vdev_id = filter_params->vdev_id;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_rmv_bcn_filter_cmd_fixed_param));
vos_status = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_RMV_BCN_FILTER_CMDID);
if (vos_status < 0) {
WMA_LOGE("Failed to send wmi remove beacon filter = %d",
vos_status);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return vos_status;
}
/**
* wma_set_bpf_instructions - Set bpf instructions to firmware
* @wma: wma handle
* @bpf_set_offload: Bpf offload information to set to firmware
*
* Return: VOS_STATUS enumeration
*/
static VOS_STATUS wma_set_bpf_instructions(tp_wma_handle wma,
struct sir_bpf_set_offload *bpf_set_offload)
{
wmi_bpf_set_vdev_instructions_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len = 0, len_aligned = 0;
u_int8_t *buf_ptr;
if (!wma || !wma->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue set BPF capability",
__func__);
return VOS_STATUS_E_INVAL;
}
if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
WMI_SERVICE_BPF_OFFLOAD)) {
WMA_LOGE(FL("BPF offload feature Disabled"));
return VOS_STATUS_E_NOSUPPORT;
}
if (bpf_set_offload->total_length) {
len_aligned = roundup(bpf_set_offload->current_length,
sizeof(A_UINT32));
len = len_aligned + WMI_TLV_HDR_SIZE;
}
len += sizeof(*cmd);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_bpf_set_vdev_instructions_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_bpf_set_vdev_instructions_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_bpf_set_vdev_instructions_cmd_fixed_param));
cmd->vdev_id = bpf_set_offload->session_id;
cmd->filter_id = bpf_set_offload->filter_id;
cmd->total_length = bpf_set_offload->total_length;
cmd->current_offset = bpf_set_offload->current_offset;
cmd->current_length = bpf_set_offload->current_length;
if (bpf_set_offload->total_length) {
buf_ptr +=
sizeof(wmi_bpf_set_vdev_instructions_cmd_fixed_param);
WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, len_aligned);
buf_ptr += WMI_TLV_HDR_SIZE;
vos_mem_copy(buf_ptr, bpf_set_offload->program,
bpf_set_offload->current_length);
}
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID)) {
WMA_LOGE(FL("Failed to send config bpf instructions command"));
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_get_wakelock_stats() - Collects wake lock stats
* @wake_lock_stats: wakelock structure to be filled
*
* This function collects wake lock stats
*
* Return: VOS_STATUS_SUCCESS on success, error number otherwise
*/
VOS_STATUS wma_get_wakelock_stats(struct sir_wake_lock_stats *wake_lock_stats)
{
tp_wma_handle wma_handle;
wma_handle = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
if (!wake_lock_stats) {
WMA_LOGE("%s: invalid pointer", __func__);
return VOS_STATUS_E_INVAL;
}
if (!wma_handle) {
WMA_LOGE("%s: WMA context is invalid!", __func__);
return VOS_STATUS_E_INVAL;
}
wake_lock_stats->wow_ucast_wake_up_count =
wma_handle->wow_ucast_wake_up_count;
wake_lock_stats->wow_bcast_wake_up_count =
wma_handle->wow_bcast_wake_up_count;
wake_lock_stats->wow_ipv4_mcast_wake_up_count =
wma_handle->wow_ipv4_mcast_wake_up_count;
wake_lock_stats->wow_ipv6_mcast_wake_up_count =
wma_handle->wow_ipv6_mcast_wake_up_count;
wake_lock_stats->wow_ipv6_mcast_ra_stats =
wma_handle->wow_ipv6_mcast_ra_stats;
wake_lock_stats->wow_ipv6_mcast_ns_stats =
wma_handle->wow_ipv6_mcast_ns_stats;
wake_lock_stats->wow_ipv6_mcast_na_stats =
wma_handle->wow_ipv6_mcast_na_stats;
wake_lock_stats->wow_icmpv4_count = wma_handle->wow_icmpv4_count;
wake_lock_stats->wow_icmpv6_count =
wma_handle->wow_icmpv6_count;
wake_lock_stats->wow_rssi_breach_wake_up_count =
wma_handle->wow_rssi_breach_wake_up_count;
wake_lock_stats->wow_low_rssi_wake_up_count =
wma_handle->wow_low_rssi_wake_up_count;
wake_lock_stats->wow_gscan_wake_up_count =
wma_handle->wow_gscan_wake_up_count;
wake_lock_stats->wow_pno_complete_wake_up_count =
wma_handle->wow_pno_complete_wake_up_count;
wake_lock_stats->wow_pno_match_wake_up_count =
wma_handle->wow_pno_match_wake_up_count;
return VOS_STATUS_SUCCESS;
}
/**
* wma_enable_disable_caevent_ind() - Issue WMI command to enable or
* disable ca event indication
* @wma: wma handler
* @filter_params: boolean value true or false
*
* Return: Return VOS_STATUS
*/
VOS_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma,
uint8_t val)
{
WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param *cmd;
wmi_buf_t wmi_buf;
u_int8_t *buf_ptr;
uint32_t len;
if (!wma || !wma->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue set/clear CA"));
return VOS_STATUS_E_INVAL;
}
len = sizeof(*cmd);
wmi_buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param));
cmd->rpt_allow = val;
if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len,
WMI_CHAN_AVOID_RPT_ALLOW_CMDID)) {
WMA_LOGE(FL("Failed to send enable/disable CA event command"));
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_set_tx_rx_aggregation_size() - sets tx rx aggregation sizes
* @tx_rx_aggregation_size: aggregation size parameters
*
* This function sets tx rx aggregation sizes
*
* Return: VOS_STATUS_SUCCESS on success, error number otherwise
*/
VOS_STATUS wma_set_tx_rx_aggregation_size
(struct sir_set_tx_rx_aggregation_size *tx_rx_aggregation_size)
{
tp_wma_handle wma_handle;
wmi_vdev_set_custom_aggr_size_cmd_fixed_param *cmd;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int ret;
wma_handle = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
if (!tx_rx_aggregation_size) {
WMA_LOGE("%s: invalid pointer", __func__);
return VOS_STATUS_E_INVAL;
}
if (!wma_handle) {
WMA_LOGE("%s: WMA context is invald!", __func__);
return VOS_STATUS_E_INVAL;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_vdev_set_custom_aggr_size_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_set_custom_aggr_size_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_set_custom_aggr_size_cmd_fixed_param));
cmd->vdev_id = tx_rx_aggregation_size->vdev_id;
cmd->tx_aggr_size = tx_rx_aggregation_size->tx_aggregation_size;
cmd->rx_aggr_size = tx_rx_aggregation_size->rx_aggregation_size;
WMA_LOGI("tx aggr: %d rx aggr: %d vdev: %d",
cmd->tx_aggr_size, cmd->rx_aggr_size, cmd->vdev_id);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send aggregation size command",
__func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_set_powersave_config() - update power save config in wma
* @val: new power save value
* @vdev_id: vdev id
*
* This function update qpower value in wma layer
*
* Return: VOS_STATUS_SUCCESS on success, error number otherwise
*/
VOS_STATUS wma_set_powersave_config(uint8_t vdev_id, uint8_t val)
{
tp_wma_handle wma_handle;
wma_handle = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
WMA_LOGI("configuring qpower: %d vdev %d", val, vdev_id);
if (!wma_handle) {
WMA_LOGE("%s: WMA context is invald!", __func__);
return VOS_STATUS_E_INVAL;
}
wma_handle->powersave_mode = val;
return wmi_unified_set_sta_ps_param(wma_handle->wmi_handle,
vdev_id,
WMI_STA_PS_ENABLE_QPOWER,
wma_get_qpower_config(wma_handle));
}
/**
* wma_process_set_allowed_action_frames_ind() - Set bitmap to wma cache
* @wma_handle: WMI handle
* @allowed_action_frames: sir_allowed_action_frames parameter
*
* This function is used to set the allowed action frames to wma cache,
* that will allow the fw to wake up the host about the expected action frame.
*
* Return: None
*/
void wma_process_set_allowed_action_frames_ind(tp_wma_handle wma_handle,
struct sir_allowed_action_frames *allowed_action_frames)
{
uint32_t i;
wma_handle->allowed_action_frames.operation =
allowed_action_frames->operation;
WMA_LOGD("%s: action frames wow operation type = %d",
__func__, allowed_action_frames->operation);
for (i = 0; i < (SIR_MAC_ACTION_MAX / 32); i++) {
wma_handle->allowed_action_frames.action_category_map[i] =
allowed_action_frames->action_category_map[i];
WMA_LOGD("%s: action frames wow bitmap%d = 0x%x", __func__,
i, allowed_action_frames->action_category_map[i]);
}
for (i = 0; i < SIR_MAC_ACTION_MAX; i++) {
wma_handle->allowed_action_frames.action_per_category[i] =
allowed_action_frames->action_per_category[i];
}
WMA_LOGD("Spectrum mgmt action frames drop pattern 0x%x",
wma_handle->allowed_action_frames.
action_per_category[SIR_MAC_ACTION_SPECTRUM_MGMT]);
return;
}
static VOS_STATUS wma_get_chain_rssi(tp_wma_handle wma_handle,
struct get_chain_rssi_req_params *req_params)
{
wmi_pdev_div_get_rssi_antid_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len = sizeof(wmi_pdev_div_get_rssi_antid_fixed_param);
u_int8_t *buf_ptr;
if (!wma_handle) {
WMA_LOGE(FL("WMA is closed, can not issue cmd"));
return VOS_STATUS_E_INVAL;
}
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE(FL("wmi_buf_alloc failed"));
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf);
cmd = (wmi_pdev_div_get_rssi_antid_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_div_get_rssi_antid_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_pdev_div_get_rssi_antid_fixed_param));
cmd->pdev_id = 0;
WMI_CHAR_ARRAY_TO_MAC_ADDR(req_params->peer_macaddr.bytes,
&cmd->macaddr);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_PDEV_DIV_GET_RSSI_ANTID_CMDID)) {
WMA_LOGE(FL("failed to send get chain rssi command"));
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_update_tx_fail_cnt_th() - Set threshold for TX pkt fail
* @wma_handle: WMA handle
* @tx_fail_cnt_th: sme_tx_fail_cnt_threshold parameter
*
* This function is used to set Tx pkt fail count threshold,
* FW will do disconnect with station once this threshold is reached.
*
* Return: VOS_STATUS_SUCCESS on success, error number otherwise
*/
static VOS_STATUS wma_update_tx_fail_cnt_th(tp_wma_handle wma,
struct sme_tx_fail_cnt_threshold *tx_fail_cnt_th)
{
u_int8_t vdev_id;
u_int32_t tx_fail_disconn_th;
int ret = -EIO;
if (!wma || !wma->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue Tx pkt fail count threshold"));
return VOS_STATUS_E_INVAL;
}
vdev_id = tx_fail_cnt_th->session_id;
tx_fail_disconn_th = tx_fail_cnt_th->tx_fail_cnt_threshold;
WMA_LOGD("Set TX pkt fail count threshold vdevId %d count %d",
vdev_id, tx_fail_disconn_th);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_DISCONNECT_TH,
tx_fail_disconn_th);
if (ret) {
WMA_LOGE(FL("Failed to send TX pkt fail count threshold command"));
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_update_short_retry_limit() - Set retry limit for short frames
* @wma_handle: WMA handle
* @short_retry_limit_th: retry limir count for Short frames.
*
* This function is used to configure the transmission retry limit at which
* short frames needs to be retry.
*
* Return: VOS_STATUS_SUCCESS on success, error number otherwise
*/
static VOS_STATUS wma_update_short_retry_limit(tp_wma_handle wma,
struct sme_short_retry_limit *short_retry_limit_th)
{
u_int8_t vdev_id;
u_int8_t short_retry_limit;
int ret = -EIO;
if (!wma || !wma->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue short retry limit threshold"));
return VOS_STATUS_E_INVAL;
}
vdev_id = short_retry_limit_th->session_id;
short_retry_limit = short_retry_limit_th->short_retry_limit;
WMA_LOGD("Set short retry limit threshold vdevId %d count %d",
vdev_id, short_retry_limit);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_NON_AGG_SW_RETRY_TH ,
short_retry_limit);
if (ret) {
WMA_LOGE(FL("Failed to send short limit threshold command"));
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_update_long_retry_limit() - Set retry limit for long frames
* @wma_handle: WMA handle
* @long_retry_limit_th: retry limir count for long frames
*
* This function is used to configure the transmission retry limit at which
* long frames needs to be retry
*
* Return: VOS_STATUS_SUCCESS on success, error number otherwise
*/
static VOS_STATUS wma_update_long_retry_limit(tp_wma_handle wma,
struct sme_long_retry_limit *long_retry_limit_th)
{
u_int8_t vdev_id;
u_int8_t long_retry_limit;
int ret = -EIO;
if (!wma || !wma->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue long retry limit threshold"));
return VOS_STATUS_E_INVAL;
}
vdev_id = long_retry_limit_th->session_id;
long_retry_limit = long_retry_limit_th->long_retry_limit;
WMA_LOGD("Set long retry limit threshold vdevId %d count %d",
vdev_id, long_retry_limit);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_AGG_SW_RETRY_TH,
long_retry_limit);
if (ret) {
WMA_LOGE(FL("Failed to send long limit threshold command"));
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/*
* wma_update_sta_inactivity_timeout() - Set sta_inactivity_timeout to fw
* @wma_handle: WMA handle
* @sta_inactivity_timer: sme_sta_inactivity_timeout
*
* This function is used to set sta_inactivity_timeout.
* If a station does not send anything in sta_inactivity_timeout seconds, an
* empty data frame is sent to it in order to verify whether it is
* still in range. If this frame is not ACKed, the station will be
* disassociated and then deauthenticated.
*
* Return: None
*/
static void wma_update_sta_inactivity_timeout(tp_wma_handle wma,
struct sme_sta_inactivity_timeout *sta_inactivity_timer)
{
u_int8_t vdev_id;
u_int32_t max_unresponsive_time;
u_int32_t min_inactive_time, max_inactive_time;
if (!wma || !wma->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue sta_inactivity_timeout"));
return;
}
vdev_id = sta_inactivity_timer->session_id;
max_unresponsive_time = sta_inactivity_timer->sta_inactivity_timeout;
max_inactive_time = max_unresponsive_time* 2/3;
min_inactive_time = max_unresponsive_time - max_inactive_time ;
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);
return;
}
/**
* wma_process_power_debug_stats_req() - Process the Chip Power stats collect
* request and pass the Power stats request to Fw
* @wma_handle: WMA handle
*
* Return: VOS_STATUS
*/
#ifdef WLAN_POWER_DEBUGFS
static VOS_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle)
{
wmi_pdev_get_chip_power_stats_cmd_fixed_param *cmd;
int32_t len;
wmi_buf_t buf;
uint8_t *buf_ptr;
int ret;
if (!wma_handle) {
WMA_LOGE("%s: input pointer is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s: Failed allocate wmi buffer", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_pdev_get_chip_power_stats_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_get_chip_power_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_get_chip_power_stats_cmd_fixed_param));
cmd->pdev_id = 0;
WMA_LOGD("POWER_DEBUG_STATS - Get Request Params; Pdev id - %d",
cmd->pdev_id);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PDEV_GET_CHIP_POWER_STATS_CMDID);
if (ret) {
WMA_LOGE("%s: Failed to send power debug stats request",
__func__);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#else
static VOS_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle)
{
return VOS_STATUS_SUCCESS;
}
#endif
/**
* wma_set_rx_reorder_timeout_val() - set rx recorder timeout value
* @wma_handle: pointer to wma handle
* @sir_set_rx_reorder_timeout_val: rx recorder timeout value
*
* Return: VOS_STATUS_SUCCESS for success or error code.
*/
static VOS_STATUS wma_set_rx_reorder_timeout_val(tp_wma_handle wma_handle,
struct sir_set_rx_reorder_timeout_val *reorder_timeout)
{
wmi_pdev_set_reorder_timeout_val_cmd_fixed_param *cmd;
uint32_t len;
wmi_buf_t buf;
int ret;
if (!reorder_timeout) {
WMA_LOGE(FL("invalid pointer"));
return VOS_STATUS_E_INVAL;
}
if (!wma_handle) {
WMA_LOGE(FL("WMA context is invald!"));
return VOS_STATUS_E_INVAL;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE(FL("Failed allocate wmi buffer"));
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_pdev_set_reorder_timeout_val_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_reorder_timeout_val_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_pdev_set_reorder_timeout_val_cmd_fixed_param));
memcpy(cmd->rx_timeout_pri, reorder_timeout->rx_timeout_pri,
sizeof(reorder_timeout->rx_timeout_pri));
WMA_LOGD("rx aggr record timeout: VO: %d, VI: %d, BE: %d, BK: %d",
cmd->rx_timeout_pri[0], cmd->rx_timeout_pri[1],
cmd->rx_timeout_pri[2], cmd->rx_timeout_pri[3]);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID);
if (ret) {
WMA_LOGE(FL("Failed to send aggregation timeout"));
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_set_rx_blocksize() - set rx blocksize
* @wma_handle: pointer to wma handle
* @sir_peer_set_rx_blocksize: rx blocksize for peer mac
*
* Return: VOS_STATUS_SUCCESS for success or error code.
*/
static VOS_STATUS wma_set_rx_blocksize(tp_wma_handle wma_handle,
struct sir_peer_set_rx_blocksize *peer_rx_blocksize)
{
wmi_peer_set_rx_blocksize_cmd_fixed_param *cmd;
int32_t len;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int ret;
if (!peer_rx_blocksize) {
WMA_LOGE(FL("invalid pointer"));
return VOS_STATUS_E_INVAL;
}
if (!wma_handle) {
WMA_LOGE(FL(" WMA context is invald!"));
return VOS_STATUS_E_INVAL;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE(FL("Failed allocate wmi buffer"));
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_peer_set_rx_blocksize_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_set_rx_blocksize_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_peer_set_rx_blocksize_cmd_fixed_param));
cmd->vdev_id = peer_rx_blocksize->vdev_id;
cmd->rx_block_ack_win_limit =
peer_rx_blocksize->rx_block_ack_win_limit;
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_rx_blocksize->peer_macaddr.bytes,
&cmd->peer_macaddr);
WMA_LOGD("rx aggr blocksize: %d", cmd->rx_block_ack_win_limit);
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_PEER_SET_RX_BLOCKSIZE_CMDID);
if (ret) {
WMA_LOGE(FL("Failed to send aggregation size command"));
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wma_process_action_frame_random_mac() - set/clear action frame random mac
* @wma_handle: pointer to wma handle
* @filter: pointer to buffer containing random mac, session_id and callback
*
* Return: VOS_STATUS_SUCCESS for success or error code.
*/
static VOS_STATUS
wma_process_action_frame_random_mac(tp_wma_handle wma_handle,
struct action_frame_random_filter *filter)
{
wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param *cmd;
uint32_t len;
wmi_buf_t buf;
int ret;
struct action_frame_random_filter *filter_bkup = NULL;
struct wma_txrx_node *intr = NULL;
if (!filter) {
WMA_LOGE(FL("invalid pointer"));
return VOS_STATUS_E_INVAL;
}
if (!wma_handle) {
WMA_LOGE(FL("WMA context is invald!"));
return VOS_STATUS_E_INVAL;
}
if (filter->filter_type == SME_ACTION_FRAME_RANDOM_MAC_SET) {
intr = &wma_handle->interfaces[filter->session_id];
/* command is in progess */
if(intr->action_frame_filter != NULL) {
WMA_LOGE(FL("previous action frame req is pending"));
return VOS_STATUS_SUCCESS;
}
filter_bkup = adf_os_mem_alloc(NULL, sizeof(*filter));
if (!filter_bkup) {
WMA_LOGE(
FL("action frame filter mem alloc failed"));
return VOS_STATUS_E_FAILURE;
}
adf_os_mem_set(filter_bkup, 0, sizeof(*filter));
filter_bkup->session_id = filter->session_id;
filter_bkup->callback = filter->callback;
filter_bkup->filter_type = filter->filter_type;
filter_bkup->context = filter->context;
vos_mem_copy(filter_bkup->mac_addr, filter->mac_addr,
VOS_MAC_ADDR_SIZE);
intr->action_frame_filter = (void *)filter_bkup;
}
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE(FL("Failed allocate wmi buffer"));
return VOS_STATUS_E_NOMEM;
}
cmd = (wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param));
cmd->vdev_id = filter->session_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(filter->mac_addr, &cmd->mac_addr);
if (filter->filter_type == SME_ACTION_FRAME_RANDOM_MAC_SET)
cmd->enable = 1;
else
cmd->enable = 0;
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID);
if (ret) {
WMA_LOGE(FL("Failed to send action frame random mac cmd"));
wmi_buf_free(buf);
if (filter->filter_type == SME_ACTION_FRAME_RANDOM_MAC_SET) {
adf_os_mem_free(filter_bkup);
intr->action_frame_filter = NULL;
}
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
static VOS_STATUS wma_get_isolation(tp_wma_handle wma)
{
tp_wma_handle wma_handle = (tp_wma_handle)wma;
wmi_coex_get_antenna_isolation_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
uint8_t *buf_ptr;
WMA_LOGE("%s: get isolation",
__func__);
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue get isolation",
__func__);
return VOS_STATUS_E_INVAL;
}
len = sizeof(wmi_coex_get_antenna_isolation_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_coex_get_antenna_isolation_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_coex_get_antenna_isolation_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_coex_get_antenna_isolation_cmd_fixed_param));
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_COEX_GET_ANTENNA_ISOLATION_CMDID)) {
WMA_LOGE("Failed to get isolation request from fw");
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/*
* wma_peer_flush_pending() - Flush peer data in fw
* @wma_handle: WMA handle
* @sta_inactivity_timer: sme_sta_inactivity_timeout
*
* This function is used to discard pending packets of tids in fw.
*
* Return: None
*/
static void wma_peer_flush_pending(tp_wma_handle wma,
struct sme_flush_pending *flush_pend)
{
u_int8_t ac_to_tid[4][2] = { {0, 3}, {1, 2}, {4, 5}, {6, 7} };
u_int8_t vdev_id, peer_id;
u_int32_t peer_tid_bitmap = 0;
struct wma_txrx_node *iface;
u_int8_t i;
struct ol_txrx_peer_t *peer;
ol_txrx_pdev_handle pdev;
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (!pdev) {
WMA_LOGE("%s: pdev is NULL", __func__);
return;
}
peer = ol_txrx_find_peer_by_addr(pdev, flush_pend->peer_addr.bytes,
&peer_id);
if (!peer) {
WMA_LOGE("PEER [%pM] not found", flush_pend->peer_addr.bytes);
return;
}
WMA_LOGI("PEER [%pM] found", flush_pend->peer_addr.bytes);
vdev_id = flush_pend->session_id;
iface = &wma->interfaces[vdev_id];
if (!iface->handle) {
WMA_LOGE("%s: Failed to get iface handle: %p",
__func__, iface->handle);
return;
}
if (flush_pend->flush_ac) {
for (i = 0; i < 4; ++i) {
if (((flush_pend->flush_ac & 0x0f) >> i) & 0x01) {
peer_tid_bitmap |= (1 << ac_to_tid[i][0]) |
(1 << ac_to_tid[i][1]);
}
}
} else {
return;
}
WMA_LOGI("%s: vdevid %d peer_tid_bitmap %08x", __func__,
vdev_id, peer_tid_bitmap);
wmi_unified_peer_flush_tids_send(wma->wmi_handle,
flush_pend->peer_addr.bytes,
peer_tid_bitmap, vdev_id);
}
/*
* function : wma_mc_process_msg
* Description :
* Args :
* Returns :
*/
VOS_STATUS wma_mc_process_msg(v_VOID_t *vos_context, vos_msg_t *msg)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
tp_wma_handle wma_handle;
ol_txrx_vdev_handle txrx_vdev_handle = NULL;
extern tANI_U8* macTraceGetWdaMsgString( tANI_U16 wdaMsg );
if(NULL == msg) {
WMA_LOGE("msg is NULL");
VOS_ASSERT(0);
vos_status = VOS_STATUS_E_INVAL;
goto end;
}
WMA_LOGD(FL(" msg->type = %x %s"),
msg->type, macTraceGetWdaMsgString(msg->type));
wma_handle = (tp_wma_handle) vos_get_context(VOS_MODULE_ID_WDA,
vos_context);
if (NULL == wma_handle) {
WMA_LOGP("%s: wma_handle is NULL", __func__);
VOS_ASSERT(0);
vos_mem_free(msg->bodyptr);
vos_status = VOS_STATUS_E_INVAL;
goto end;
}
switch (msg->type) {
#ifdef FEATURE_WLAN_ESE
case WDA_TSM_STATS_REQ:
WMA_LOGA("McThread: WDA_TSM_STATS_REQ");
wma_process_tsm_stats_req(wma_handle, (void*)msg->bodyptr);
break;
#endif
case WNI_CFG_DNLD_REQ:
WMA_LOGA("McThread: WNI_CFG_DNLD_REQ");
vos_status = wma_wni_cfg_dnld(wma_handle);
if (VOS_IS_STATUS_SUCCESS(vos_status)) {
vos_WDAComplete_cback(vos_context);
}
else {
WMA_LOGD("config download failure");
}
break ;
case WDA_ADD_STA_SELF_REQ:
txrx_vdev_handle = wma_vdev_attach(wma_handle,
(tAddStaSelfParams *)msg->bodyptr, 1);
if (!txrx_vdev_handle) {
WMA_LOGE("Failed to attach vdev");
} else {
WLANTL_RegisterVdev(vos_context,
txrx_vdev_handle);
/* Register with TxRx Module for Data Ack Complete Cb */
wdi_in_data_tx_cb_set(txrx_vdev_handle,
wma_data_tx_ack_comp_hdlr, wma_handle);
}
break;
case WDA_DEL_STA_SELF_REQ:
wma_vdev_detach(wma_handle,
(tDelStaSelfParams *)msg->bodyptr, 1);
break;
case WDA_START_SCAN_OFFLOAD_REQ:
wma_start_scan(wma_handle, msg->bodyptr, msg->type);
vos_mem_free(msg->bodyptr);
break;
case WDA_STOP_SCAN_OFFLOAD_REQ:
wma_stop_scan(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_UPDATE_CHAN_LIST_REQ:
wma_update_channel_list(wma_handle,
(tSirUpdateChanList *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_LINK_STATE:
wma_set_linkstate(wma_handle,
(tpLinkStateParams)msg->bodyptr);
break;
case WDA_CHNL_SWITCH_REQ:
wma_set_channel(wma_handle,
(tpSwitchChannelParams)msg->bodyptr);
break;
case WDA_ADD_BSS_REQ:
wma_add_bss(wma_handle, (tpAddBssParams)msg->bodyptr);
break;
case WDA_ADD_STA_REQ:
wma_add_sta(wma_handle, (tpAddStaParams)msg->bodyptr);
break;
case WDA_SET_BSSKEY_REQ:
wma_set_bsskey(wma_handle,
(tpSetBssKeyParams)msg->bodyptr);
break;
case WDA_SET_STAKEY_REQ:
wma_set_stakey(wma_handle,
(tpSetStaKeyParams)msg->bodyptr);
break;
case WDA_DELETE_STA_REQ:
wma_delete_sta(wma_handle,
(tpDeleteStaParams)msg->bodyptr);
break;
case WDA_DELETE_BSS_REQ:
wma_delete_bss(wma_handle,
(tpDeleteBssParams)msg->bodyptr);
break;
case WDA_UPDATE_EDCA_PROFILE_IND:
wma_process_update_edca_param_req(
wma_handle,
(tEdcaParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SEND_BEACON_REQ:
wma_send_beacon(wma_handle,
(tpSendbeaconParams)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SEND_PROBE_RSP_TMPL:
wma_send_probe_rsp_tmpl(wma_handle,
(tpSendProbeRespParams)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_CLI_SET_CMD:
wma_process_cli_set_cmd(wma_handle,
(wda_cli_set_cmd_t *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_PDEV_IE_REQ:
wma_process_set_pdev_ie_req(wma_handle,
(struct set_ie_param *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#if !defined(REMOVE_PKT_LOG)
case WDA_PKTLOG_ENABLE_REQ:
wma_pktlog_wmi_send_cmd(wma_handle,
(struct ath_pktlog_wmi_params *)
msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
#if defined(QCA_WIFI_FTM)
case WDA_FTM_CMD_REQ:
wma_process_ftm_command(wma_handle,
(struct ar6k_testmode_cmd_data *)msg->bodyptr);
break;
#endif
case WDA_ENTER_BMPS_REQ:
wma_enable_sta_ps_mode(wma_handle,
(tpEnablePsParams)msg->bodyptr);
break;
case WDA_EXIT_BMPS_REQ:
wma_disable_sta_ps_mode(wma_handle,
(tpDisablePsParams)msg->bodyptr);
break;
case WDA_ENTER_UAPSD_REQ:
wma_enable_uapsd_mode(wma_handle,
(tpEnableUapsdParams)msg->bodyptr);
break;
case WDA_EXIT_UAPSD_REQ:
wma_disable_uapsd_mode(wma_handle,
(tpDisableUapsdParams)msg->bodyptr);
break;
case WDA_SET_TX_POWER_REQ:
wma_set_tx_power(wma_handle,
(tpMaxTxPowerParams)msg->bodyptr);
break;
case WDA_SET_MAX_TX_POWER_REQ:
wma_set_max_tx_power(wma_handle,
(tpMaxTxPowerParams)msg->bodyptr);
break;
case WDA_SET_KEEP_ALIVE:
wma_set_keepalive_req(wma_handle,
(tSirKeepAliveReq *)msg->bodyptr);
break;
#ifdef FEATURE_WLAN_SCAN_PNO
case WDA_SET_PNO_REQ:
wma_config_pno(wma_handle,
(tpSirPNOScanReq)msg->bodyptr);
break;
case WDA_SME_SCAN_CACHE_UPDATED:
wma_scan_cache_updated_ind(wma_handle, msg->bodyval);
break;
#endif
#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
case WDA_SET_PLM_REQ:
wma_config_plm(wma_handle,
(tpSirPlmReq)msg->bodyptr);
break;
#endif
case WDA_GET_STATISTICS_REQ:
wma_get_stats_req(wma_handle,
(tAniGetPEStatsReq *) msg->bodyptr);
break;
case WDA_MIB_STATS_REQ:
wma_process_mib_stats_req(wma_handle,
(struct get_mib_stats_req *)
msg->bodyptr);
break;
case WDA_CONFIG_PARAM_UPDATE_REQ:
wma_update_cfg_params(wma_handle,
(tSirMsgQ *)msg);
break;
case WDA_INIT_SCAN_REQ:
wma_init_scan_req(wma_handle,
(tInitScanParams *)msg->bodyptr);
break;
case WDA_FINISH_SCAN_REQ:
wma_finish_scan_req(wma_handle,
(tFinishScanParams *)msg->bodyptr);
break;
case WDA_UPDATE_OP_MODE:
wma_process_update_opmode(wma_handle,
(tUpdateVHTOpMode *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_UPDATE_RX_NSS:
wma_process_update_rx_nss(wma_handle,
(tUpdateRxNss *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef WLAN_FEATURE_11AC
case WDA_UPDATE_MEMBERSHIP:
wma_process_update_membership(wma_handle,
(tUpdateMembership *)msg->bodyptr);
break;
case WDA_UPDATE_USERPOS:
wma_process_update_userpos(wma_handle,
(tUpdateUserPos *)msg->bodyptr);
break;
#endif
case WDA_UPDATE_BEACON_IND:
wma_process_update_beacon_params(wma_handle,
(tUpdateBeaconParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_ADD_TS_REQ:
wma_add_ts_req(wma_handle, (tAddTsParams *)msg->bodyptr);
break;
case WDA_DEL_TS_REQ:
wma_del_ts_req(wma_handle, (tDelTsParams *)msg->bodyptr);
break;
case WDA_AGGR_QOS_REQ:
wma_aggr_qos_req(wma_handle, (tAggrAddTsParams *)msg->bodyptr);
break;
case WDA_RECEIVE_FILTER_SET_FILTER_REQ:
wma_process_receive_filter_set_filter_req(wma_handle,
(tSirRcvPktFilterCfgType *)msg->bodyptr);
break;
case WDA_RECEIVE_FILTER_CLEAR_FILTER_REQ:
wma_process_receive_filter_clear_filter_req(wma_handle,
(tSirRcvFltPktClearParam *)msg->bodyptr);
break;
case WDA_WOWL_ADD_BCAST_PTRN:
wma_wow_add_pattern(wma_handle,
(tpSirWowlAddBcastPtrn)msg->bodyptr);
break;
case WDA_WOWL_DEL_BCAST_PTRN:
wma_wow_del_pattern(wma_handle,
(tpSirWowlDelBcastPtrn)msg->bodyptr);
break;
case WDA_WOWL_ENTER_REQ:
wma_wow_enter(wma_handle,
(tpSirHalWowlEnterParams)msg->bodyptr);
break;
case WDA_WOWL_EXIT_REQ:
wma_wow_exit(wma_handle,
(tpSirHalWowlExitParams)msg->bodyptr);
break;
case WDA_WLAN_SUSPEND_IND:
wma_suspend_req(wma_handle,
(tpSirWlanSuspendParam)msg->bodyptr);
break;
case WDA_8023_MULTICAST_LIST_REQ:
wma_process_mcbc_set_filter_req(wma_handle,
(tpSirRcvFltMcAddrList)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef WLAN_FEATURE_GTK_OFFLOAD
case WDA_GTK_OFFLOAD_REQ:
wma_process_gtk_offload_req(
wma_handle,
(tpSirGtkOffloadParams)msg->bodyptr);
break;
case WDA_GTK_OFFLOAD_GETINFO_REQ:
wma_process_gtk_offload_getinfo_req(
wma_handle,
(tpSirGtkOffloadGetInfoRspParams)msg->bodyptr);
break;
#endif /* WLAN_FEATURE_GTK_OFFLOAD */
#ifdef FEATURE_OEM_DATA_SUPPORT
case WDA_START_OEM_DATA_REQ:
wma_start_oem_data_req(wma_handle,
(tStartOemDataReq *)msg->bodyptr);
break;
#endif /* FEATURE_OEM_DATA_SUPPORT */
case WDA_SET_HOST_OFFLOAD:
wma_enable_arp_ns_offload(wma_handle, (tpSirHostOffloadReq)msg->bodyptr, true);
break;
#ifdef WLAN_NS_OFFLOAD
case WDA_SET_NS_OFFLOAD:
wma_enable_arp_ns_offload(wma_handle, (tpSirHostOffloadReq)msg->bodyptr, false);
break;
#endif /*WLAN_NS_OFFLOAD */
case WDA_ROAM_SCAN_OFFLOAD_REQ:
/*
* Main entry point or roaming directives from CSR.
*/
wma_process_roam_scan_req(wma_handle,
(tSirRoamOffloadScanReq *)msg->bodyptr);
break;
case WDA_RATE_UPDATE_IND:
wma_process_rate_update_indicate(wma_handle, (tSirRateUpdateInd *)msg->bodyptr);
break;
#ifdef FEATURE_WLAN_TDLS
case WDA_UPDATE_FW_TDLS_STATE:
wma_update_fw_tdls_state(wma_handle,
(t_wma_tdls_params *)msg->bodyptr);
break;
case WDA_UPDATE_TDLS_PEER_STATE:
wma_update_tdls_peer_state(wma_handle,
(tTdlsPeerStateParams *)msg->bodyptr);
break;
case WDA_TDLS_SET_OFFCHAN_MODE:
wma_set_tdls_offchan_mode(wma_handle,
(tTdlsChanSwitchParams*)msg->bodyptr);
break;
#endif /* FEATURE_WLAN_TDLS */
case WDA_ADD_PERIODIC_TX_PTRN_IND:
wma_ProcessAddPeriodicTxPtrnInd(wma_handle,
(tSirAddPeriodicTxPtrn *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_DEL_PERIODIC_TX_PTRN_IND:
wma_ProcessDelPeriodicTxPtrnInd(wma_handle,
(tSirDelPeriodicTxPtrn *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_TX_POWER_LIMIT:
wma_ProcessTxPowerLimits(wma_handle,
(tSirTxPowerLimit *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef FEATURE_WLAN_LPHB
case WDA_LPHB_CONF_REQ:
wma_process_lphb_conf_req(wma_handle, (tSirLPHBReq *)msg->bodyptr);
break;
#endif
#ifdef FEATURE_WLAN_CH_AVOID
case WDA_CH_AVOID_UPDATE_REQ:
wma_process_ch_avoid_update_req(wma_handle,
(tSirChAvoidUpdateReq *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
case WDA_SET_AUTO_SHUTDOWN_TIMER_REQ:
wma_set_auto_shutdown_timer_req(wma_handle,
msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
case WDA_DHCP_START_IND:
case WDA_DHCP_STOP_IND:
wma_process_dhcp_ind(wma_handle,
(tAniDHCPInd *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_IBSS_CESIUM_ENABLE_IND:
wma_process_cesium_enable_ind(wma_handle);
break;
case WDA_GET_IBSS_PEER_INFO_REQ:
wma_process_get_peer_info_req(wma_handle,
(tSirIbssGetPeerInfoReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_TX_FAIL_MONITOR_IND:
wma_process_tx_fail_monitor_ind(wma_handle,
(tAniTXFailMonitorInd *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_RMC_ENABLE_IND:
wma_process_rmc_enable_ind(wma_handle);
break;
case WDA_RMC_DISABLE_IND:
wma_process_rmc_disable_ind(wma_handle);
break;
case WDA_RMC_ACTION_PERIOD_IND:
wma_process_rmc_action_period_ind(wma_handle);
break;
case WDA_INIT_THERMAL_INFO_CMD:
wma_process_init_thermal_info(wma_handle, (t_thermal_mgmt *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_THERMAL_LEVEL:
wma_process_set_thermal_level(wma_handle, msg->bodyval);
break;
case WDA_INIT_BAD_PEER_TX_CTL_INFO_CMD:
wma_process_init_bad_peer_tx_ctl_info(wma_handle,
(struct t_bad_peer_txtcl_config *) msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_P2P_GO_NOA_REQ:
wma_process_set_p2pgo_noa_Req(wma_handle,
(tP2pPsParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_MIMOPS_REQ:
wma_process_set_mimops_req(wma_handle, (tSetMIMOPS *) msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_SAP_INTRABSS_DIS:
wma_set_vdev_intrabss_fwd(wma_handle, (tDisableIntraBssFwd *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_FW_STATS_IND:
wma_fw_stats_ind(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_LINK_SPEED:
wma_get_link_speed(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_PEER_INFO:
wma_get_peer_info(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_PEER_INFO_EXT:
wma_get_peer_info_ext(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_MODEM_POWER_STATE_IND:
wma_notify_modem_power_state(wma_handle,
(tSirModemPowerStateInd *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_VDEV_STOP_IND:
wma_vdev_stop_ind(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_WLAN_RESUME_REQ:
wma_resume_req(wma_handle, false);
break;
#ifdef WLAN_FEATURE_STATS_EXT
case WDA_STATS_EXT_REQUEST:
wma_stats_ext_req(wma_handle,
(tpStatsExtRequest)(msg->bodyptr));
vos_mem_free(msg->bodyptr);
break;
#endif
case WDA_HIDDEN_SSID_VDEV_RESTART:
wma_hidden_ssid_vdev_restart(wma_handle,
(tHalHiddenSsidVdevRestart *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef WLAN_FEATURE_EXTWOW_SUPPORT
case WDA_WLAN_EXT_WOW:
wma_enable_ext_wow(wma_handle,
(tSirExtWoWParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_WLAN_SET_APP_TYPE1_PARAMS:
wma_set_app_type1_params_in_fw(wma_handle,
(tSirAppType1Params *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_WLAN_SET_APP_TYPE2_PARAMS:
wma_set_app_type2_params_in_fw(wma_handle,
(tSirAppType2Params *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
case WDA_VDEV_START_RSP_IND:
wma_vdev_start_rsp_ind(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_ROAM_PREAUTH_IND:
wma_roam_preauth_ind(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_TBTT_UPDATE_IND:
wma_tbtt_update_ind(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef FEATURE_WLAN_EXTSCAN
case WDA_EXTSCAN_START_REQ:
wma_start_extscan(wma_handle,
(tSirWifiScanCmdReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_STOP_REQ:
wma_stop_extscan(wma_handle,
(tSirExtScanStopReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_SET_BSSID_HOTLIST_REQ:
wma_extscan_start_hotlist_monitor(wma_handle,
(tSirExtScanSetBssidHotListReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_RESET_BSSID_HOTLIST_REQ:
wma_extscan_stop_hotlist_monitor(wma_handle,
(tSirExtScanResetBssidHotlistReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_SET_SIGNF_CHANGE_REQ:
wma_extscan_start_change_monitor(wma_handle,
(tSirExtScanSetSigChangeReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_RESET_SIGNF_CHANGE_REQ:
wma_extscan_stop_change_monitor(wma_handle,
(tSirExtScanResetSignificantChangeReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_GET_CACHED_RESULTS_REQ:
wma_extscan_get_cached_results(wma_handle,
(tSirExtScanGetCachedResultsReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_GET_CAPABILITIES_REQ:
wma_extscan_get_capabilities(wma_handle,
(tSirGetExtScanCapabilitiesReqParams *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_EPNO_LIST_REQ:
wma_set_epno_network_list(wma_handle,
(struct wifi_epno_params *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_PASSPOINT_LIST_REQ:
/* Issue reset passpoint network list first and clear
* the entries */
wma_reset_passpoint_network_list(wma_handle,
(struct wifi_passpoint_req *)msg->bodyptr);
wma_set_passpoint_network_list(wma_handle,
(struct wifi_passpoint_req *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_RESET_PASSPOINT_LIST_REQ:
wma_reset_passpoint_network_list(wma_handle,
(struct wifi_passpoint_req *)msg->bodyptr);
break;
case WDA_EXTSCAN_STATUS_IND:
wma_extscan_rsp_handler(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_EXTSCAN_OPERATION_IND:
wma_extscan_operations_ind_handler(wma_handle,
msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
case WDA_SET_SCAN_MAC_OUI_REQ:
wma_scan_probe_setoui(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
case WDA_LINK_LAYER_STATS_CLEAR_REQ:
wma_process_ll_stats_clearReq(wma_handle,
(tpSirLLStatsClearReq)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_LINK_LAYER_STATS_SET_REQ:
wma_process_ll_stats_setReq(wma_handle,
(tpSirLLStatsSetReq)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_LINK_LAYER_STATS_GET_REQ:
wma_process_ll_stats_getReq(wma_handle,
(tpSirLLStatsGetReq)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_LINK_LAYER_STATS_SET_THRESHOLD:
wma_config_stats_ext_threshold(wma_handle,
msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
case SIR_HAL_UNIT_TEST_CMD:
wma_process_unit_test_cmd(wma_handle,
(t_wma_unit_test_cmd *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
case WDA_ROAM_OFFLOAD_SYNCH_CNF:
wma_process_roam_synch_complete(wma_handle,
(tSirSmeRoamOffloadSynchCnf *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_ROAM_OFFLOAD_SYNCH_FAIL:
wma_process_roam_synch_fail(wma_handle,
(tSirRoamOffloadSynchFail *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_ROAM_INVOKE:
wma_process_roam_invoke(wma_handle,
(t_wma_roam_invoke_cmd *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
#ifdef WLAN_FEATURE_NAN
case WDA_NAN_REQUEST:
wma_nan_req(wma_handle,
(tNanRequest *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
case SIR_HAL_SET_BASE_MACADDR_IND:
wma_set_base_macaddr_indicate(wma_handle,
(tSirMacAddr *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_LINK_STATUS_GET_REQ:
wma_process_link_status_req(wma_handle,
(tAniGetLinkStatus *)msg->bodyptr);
break;
case WDA_GET_LINK_STATUS_RSP_IND:
wma_link_status_rsp(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_PEER_INFO_EXT_IND:
wma_peer_info_ext_rsp(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_TEMPERATURE_REQ:
wma_get_temperature(wma_handle);
vos_mem_free(msg->bodyptr);
break;
#ifdef DHCP_SERVER_OFFLOAD
case WDA_SET_DHCP_SERVER_OFFLOAD_CMD:
wma_process_dhcpserver_offload(wma_handle,
(tSirDhcpSrvOffloadInfo *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif /* DHCP_SERVER_OFFLOAD */
#ifdef WLAN_FEATURE_GPIO_LED_FLASHING
case WDA_LED_FLASHING_REQ:
wma_set_led_flashing(wma_handle,
(tSirLedFlashingReq *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif
case WDA_IPA_OFFLOAD_ENABLE_DISABLE:
wma_ipa_offload_enable_disable(wma_handle,
(struct sir_ipa_offload_enable_disable *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef MDNS_OFFLOAD
case WDA_SET_MDNS_OFFLOAD_CMD:
wma_set_mdns_offload(wma_handle,
(tSirMDNSOffloadInfo *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_MDNS_FQDN_CMD:
wma_set_mdns_fqdn(wma_handle,
(tSirMDNSFqdnInfo *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_MDNS_RESPONSE_CMD:
wma_set_mdns_response(wma_handle,
(tSirMDNSResponseInfo *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_MDNS_STATUS_CMD:
wma_get_mdns_status(wma_handle, (A_UINT32 *) msg->bodyptr);
break;
#endif /* MDNS_OFFLOAD */
#ifdef SAP_AUTH_OFFLOAD
case WDA_SET_SAP_AUTH_OFL:
wma_process_sap_auth_offload(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_CLIENT_BLOCK_INFO:
wma_process_client_block_info(wma_handle, msg->bodyptr);
if (msg->bodyptr)
vos_mem_free(msg->bodyptr);
break;
#endif /* SAP_AUTH_OFFLOAD */
#ifdef WLAN_FEATURE_APFIND
case WDA_APFIND_SET_CMD:
wma_apfind_set_cmd(wma_handle,
(struct hal_apfind_request *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#endif /* WLAN_FEATURE_APFIND */
case WDA_DSRC_RADIO_CHAN_STATS_REQ:
wma_process_radio_chan_stats_req(wma_handle,
(struct radio_chan_stats_req *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_OCB_SET_CONFIG_CMD:
wma_ocb_set_config_req(wma_handle,
(struct sir_ocb_config *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_OCB_SET_UTC_TIME_CMD:
wma_ocb_set_utc_time(wma_handle,
(struct sir_ocb_utc *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_OCB_START_TIMING_ADVERT_CMD:
wma_ocb_start_timing_advert(wma_handle,
(struct sir_ocb_timing_advert *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_OCB_STOP_TIMING_ADVERT_CMD:
wma_ocb_stop_timing_advert(wma_handle,
(struct sir_ocb_timing_advert *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_DCC_CLEAR_STATS_CMD:
wma_dcc_clear_stats(wma_handle,
(struct sir_dcc_clear_stats *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_OCB_GET_TSF_TIMER_CMD:
wma_ocb_get_tsf_timer(wma_handle,
(struct sir_ocb_get_tsf_timer *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_DCC_GET_STATS_CMD:
wma_dcc_get_stats(wma_handle,
(struct sir_dcc_get_stats *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_DCC_UPDATE_NDL_CMD:
wma_dcc_update_ndl(wma_handle,
(struct sir_dcc_update_ndl *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
#ifdef FEATURE_RUNTIME_PM
case WDA_RUNTIME_PM_SUSPEND_IND:
wma_suspend_req(wma_handle, NULL);
break;
case WDA_RUNTIME_PM_RESUME_IND:
wma_resume_req(wma_handle, true);
break;
#endif
case SIR_HAL_SET_MAS:
wma_process_set_mas(wma_handle,
(u_int32_t *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_SET_MIRACAST:
wma_process_set_miracast(wma_handle,
(u_int32_t *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_FW_STATUS_REQ:
wma_send_echo_request(wma_handle);
break;
case WDA_BTC_BT_WLAN_INTERVAL_CMD:
wma_btc_set_bt_wlan_interval(wma_handle,
(WMI_COEX_CONFIG_CMD_fixed_param *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_CONFIG_STATS_FACTOR:
wma_config_stats_factor(wma_handle,
(struct sir_stats_avg_factor *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_CONFIG_GUARD_TIME:
wma_config_guard_time(wma_handle,
(struct sir_guard_time_request *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_START_STOP_LOGGING:
wma_set_wifi_start_packet_stats(wma_handle,
(struct sir_wifi_start_log *)msg->bodyptr);
wma_enable_specific_fw_logs(wma_handle,
(struct sir_wifi_start_log *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_TSF_GPIO_PIN:
wma_set_tsf_gpio_pin(wma_handle, msg->bodyval);
break;
case SIR_HAL_FLUSH_LOG_TO_FW:
wma_send_flush_logs_to_fw(wma_handle);
/* Body ptr is NULL here */
break;
case WDA_SET_IE_INFO:
wma_process_set_ie_info(wma_handle,
(struct vdev_ie_info *) msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_RSSI_MONITOR_REQ:
wma_set_rssi_monitoring(wma_handle,
(struct rssi_monitor_req *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_UDP_RESP_OFFLOAD:
wma_send_udp_resp_offload_cmd(wma_handle,
(struct udp_resp_offload *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_WOW_PULSE_CMD:
wma_send_wow_pulse_cmd(wma_handle,
(struct wow_pulse_mode *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_WAKEUP_GPIO_CMD:
wma_send_wakeup_gpio_cmd(wma_handle,
(struct wakeup_gpio_mode *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_UPDATE_WEP_DEFAULT_KEY:
wma_update_wep_default_key(wma_handle,
(struct wep_update_default_key_idx *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_EGAP_CONF_PARAMS:
wma_send_egap_conf_params(wma_handle,
(struct egap_conf_params *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_CTS2SELF_FOR_STA:
wma_set_cts2self_for_p2p_go(wma_handle, true);
break;
case WDA_BPF_GET_CAPABILITIES_REQ:
wma_get_bpf_capabilities(wma_handle);
break;
case WDA_BPF_SET_INSTRUCTIONS_REQ:
wma_set_bpf_instructions(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_MIB_STATS_ENABLE:
wma_set_mib_stats_enable(wma_handle, true);
break;
case WDA_SET_MIB_STATS_DISABLE:
wma_set_mib_stats_enable(wma_handle, false);
break;
case WDA_UPDATE_TX_RATE:
wma_update_tx_rate(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_ADD_BCN_FILTER_CMDID:
wma_set_beacon_filter(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_REMOVE_BCN_FILTER_CMDID:
wma_remove_beacon_filter(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SEND_FREQ_RANGE_CONTROL_IND:
wma_enable_disable_caevent_ind(wma_handle,
msg->bodyval);
break;
case SIR_HAL_NDP_INITIATOR_REQ:
wma_handle_ndp_initiator_req(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_NDP_RESPONDER_REQ:
wma_handle_ndp_responder_req(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_NDP_END_REQ:
wma_handle_ndp_end_req(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_SET_ALLOWED_ACTION_FRAMES:
wma_process_set_allowed_action_frames_ind(wma_handle,
msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_UPDATE_TX_FAIL_CNT_TH:
wma_update_tx_fail_cnt_th(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_UPDATE_LONG_RETRY_LIMIT_CNT:
wma_update_long_retry_limit(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_UPDATE_SHORT_RETRY_LIMIT_CNT:
wma_update_short_retry_limit(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_UPDATE_STA_INACTIVITY_TIMEOUT:
wma_update_sta_inactivity_timeout(wma_handle,
msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_GET_CHAIN_RSSI_REQ:
wma_get_chain_rssi(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_SET_REORDER_TIMEOUT_CMDID:
wma_set_rx_reorder_timeout_val(wma_handle,
msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_SET_RX_BLOCKSIZE_CMDID:
wma_set_rx_blocksize(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case SIR_HAL_POWER_DEBUG_STATS_REQ:
wma_process_power_debug_stats_req(wma_handle);
break;
case WDA_ACTION_FRAME_RANDOM_MAC:
wma_process_action_frame_random_mac(wma_handle,
(struct action_frame_random_filter *)msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_ISOLATION:
wma_get_isolation(wma_handle);
break;
case WDA_PEER_FLUSH_PENDING:
wma_peer_flush_pending(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_SET_AC_TXQ_OPTIMIZE:
wma_set_ac_txq_optimize(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
default:
WMA_LOGD("unknow msg type %x", msg->type);
/* Do Nothing? MSG Body should be freed at here */
if(NULL != msg->bodyptr) {
vos_mem_free(msg->bodyptr);
}
}
end:
return vos_status ;
}
static int wma_scan_event_callback(WMA_HANDLE handle, u_int8_t *data,
u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_SCAN_EVENTID_param_tlvs *param_buf = NULL;
wmi_scan_event_fixed_param *wmi_event = NULL;
tSirScanOffloadEvent *scan_event;
u_int8_t vdev_id;
v_U32_t scan_id;
u_int8_t *buf;
vos_msg_t vos_msg = {0};
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
param_buf = (WMI_SCAN_EVENTID_param_tlvs *) data;
wmi_event = param_buf->fixed_param;
vdev_id = wmi_event->vdev_id;
if (wmi_event->vdev_id >= wma_handle->max_bssid) {
WMA_LOGE("Invalid vdev id from firmware");
return -EINVAL;
}
scan_id = wma_handle->interfaces[vdev_id].scan_info.scan_id;
adf_os_spin_lock_bh(&wma_handle->roam_preauth_lock);
if (wma_handle->roam_preauth_scan_id == wmi_event->scan_id) {
/* This is the scan requested by roam preauth set_channel operation */
adf_os_spin_unlock_bh(&wma_handle->roam_preauth_lock);
if (wmi_event->event & WMI_SCAN_FINISH_EVENTS) {
WMA_LOGD(" roam scan complete - scan_id %x, vdev_id %x",
wmi_event->scan_id, vdev_id);
wma_reset_scan_info(wma_handle, vdev_id);
}
buf = vos_mem_malloc(sizeof(wmi_scan_event_fixed_param));
if (!buf) {
WMA_LOGE("%s: Memory alloc failed for roam preauth ind",
__func__);
return -ENOMEM;
}
vos_mem_zero(buf, sizeof(wmi_scan_event_fixed_param));
vos_mem_copy(buf, (u_int8_t *)wmi_event,
sizeof(wmi_scan_event_fixed_param));
vos_msg.type = WDA_ROAM_PREAUTH_IND;
vos_msg.bodyptr = buf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_WDA, &vos_msg)) {
WMA_LOGE("%s: Failed to post WDA_ROAM_PREAUTH_IND msg",
__func__);
vos_mem_free(buf);
return -1;
}
WMA_LOGD("%s: WDA_ROAM_PREAUTH_IND posted", __func__);
return 0;
}
adf_os_spin_unlock_bh(&wma_handle->roam_preauth_lock);
scan_event = (tSirScanOffloadEvent *) vos_mem_malloc
(sizeof(tSirScanOffloadEvent));
if (!scan_event) {
WMA_LOGE("Memory allocation failed for tSirScanOffloadEvent");
return -ENOMEM;
}
scan_event->event = wmi_event->event;
WMA_LOGI("WMA <-- wmi_scan_event : event %u, scan_id %u, "
"freq %u, reason %u",
wmi_event->event, wmi_event->scan_id,
wmi_event->channel_freq, wmi_event->reason);
scan_event->scanId = wmi_event->scan_id;
scan_event->chanFreq = wmi_event->channel_freq;
scan_event->p2pScanType =
wma_handle->interfaces[vdev_id].scan_info.p2p_scan_type;
scan_event->sessionId = vdev_id;
if (wmi_event->reason == WMI_SCAN_REASON_COMPLETED ||
wmi_event->reason == WMI_SCAN_REASON_TIMEDOUT)
scan_event->reasonCode = eSIR_SME_SUCCESS;
else
scan_event->reasonCode = eSIR_SME_SCAN_FAILED;
switch (wmi_event->event) {
case WMI_SCAN_EVENT_COMPLETED:
case WMI_SCAN_EVENT_DEQUEUED:
/*
* return success always so that SME can pick whatever scan
* results is available in scan cache(due to partial or
* aborted scan)
*/
scan_event->event = WMI_SCAN_EVENT_COMPLETED;
scan_event->reasonCode = eSIR_SME_SUCCESS;
break;
case WMI_SCAN_EVENT_START_FAILED:
scan_event->event = WMI_SCAN_EVENT_COMPLETED;
scan_event->reasonCode = eSIR_SME_SCAN_FAILED;
break;
case WMI_SCAN_EVENT_PREEMPTED:
WMA_LOGW("%s: Unhandled Scan Event WMI_SCAN_EVENT_PREEMPTED", __func__);
break;
case WMI_SCAN_EVENT_RESTARTED:
WMA_LOGW("%s: Unhandled Scan Event WMI_SCAN_EVENT_RESTARTED", __func__);
break;
}
/* Stop the scan completion timeout if the event is WMI_SCAN_EVENT_COMPLETED */
if (scan_event->event ==
(enum sir_scan_event_type) WMI_SCAN_EVENT_COMPLETED) {
WMA_LOGD(" scan complete - scan_id %x, vdev_id %x",
wmi_event->scan_id, vdev_id);
/*
* first stop the timer then reset scan info, else there is a
* race condition between, timeout handler in host and reset
* operation here. because of that, sometime timeout handler
* triggers and scan ID mismatch messages is printed.
*/
vos_status = vos_timer_stop(&wma_handle->wma_scan_comp_timer);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to stop the scan completion timeout");
vos_mem_free(scan_event);
return -EPERM;
}
if (wmi_event->scan_id == scan_id)
wma_reset_scan_info(wma_handle, vdev_id);
else
WMA_LOGE("Scan id not matched for SCAN COMPLETE event");
}
wma_send_msg(wma_handle, WDA_RX_SCAN_EVENT, (void *) scan_event, 0) ;
return 0;
}
static void wma_mgmt_tx_ack_work_handler(struct work_struct *ack_work)
{
struct wma_tx_ack_work_ctx *work;
tp_wma_handle wma_handle;
pWDAAckFnTxComp ack_cb;
if (vos_is_load_unload_in_progress(VOS_MODULE_ID_WDA, NULL)) {
WMA_LOGE("%s: Driver load/unload in progress", __func__);
return;
}
work = container_of(ack_work, struct wma_tx_ack_work_ctx, ack_cmp_work);
wma_handle = work->wma_handle;
ack_cb = wma_handle->umac_ota_ack_cb[work->sub_type];
WMA_LOGD("Tx Ack Cb SubType %d Status %d",
work->sub_type, work->status);
/* Call the Ack Cb registered by UMAC */
ack_cb((tpAniSirGlobal)(wma_handle->mac_context),
work->status ? 0 : 1);
adf_os_mem_free(work);
wma_handle->ack_work_ctx = NULL;
}
/* function : wma_mgmt_tx_comp_conf_ind
* Description : Post mgmt tx complete indication to PE.
* Args :
wma_handle : Pointer to WMA handle
* sub_type : Tx mgmt frame sub type
* status : Mgmt frame tx status
* Returns :
*/
static void
wma_mgmt_tx_comp_conf_ind(tp_wma_handle wma_handle, u_int8_t sub_type,
int32_t status)
{
int32_t tx_comp_status;
tx_comp_status = status ? 0 : 1;
if(sub_type == SIR_MAC_MGMT_DISASSOC) {
wma_send_msg(wma_handle, WDA_DISASSOC_TX_COMP, NULL, tx_comp_status);
}
else if(sub_type == SIR_MAC_MGMT_DEAUTH) {
wma_send_msg(wma_handle, WDA_DEAUTH_TX_COMP, NULL, tx_comp_status);
}
}
/**
* wma_mgmt_tx_ack_comp_hdlr - handles tx ack mgmt completion
* @context: context with which the handler is registered
* @netbuf: tx mgmt nbuf
* @err: status of tx completion
*
* This is the cb registered with TxRx for
* Ack Complete
*/
static void
wma_mgmt_tx_ack_comp_hdlr(void *wma_context,
adf_nbuf_t netbuf, int32_t status)
{
tpSirMacFrameCtl pFc =
(tpSirMacFrameCtl)(adf_nbuf_data(netbuf));
tp_wma_handle wma_handle = (tp_wma_handle)wma_context;
if(wma_handle && wma_handle->umac_ota_ack_cb[pFc->subType]) {
if((pFc->subType == SIR_MAC_MGMT_DISASSOC) ||
(pFc->subType == SIR_MAC_MGMT_DEAUTH)) {
wma_mgmt_tx_comp_conf_ind(wma_handle, (u_int8_t)pFc->subType,
status);
}
else {
struct wma_tx_ack_work_ctx *ack_work;
ack_work =
adf_os_mem_alloc(NULL, sizeof(struct wma_tx_ack_work_ctx));
if(ack_work) {
vos_init_work(&ack_work->ack_cmp_work,
wma_mgmt_tx_ack_work_handler);
ack_work->wma_handle = wma_handle;
ack_work->sub_type = pFc->subType;
ack_work->status = status;
/* Schedue the Work */
schedule_work(&ack_work->ack_cmp_work);
}
}
}
}
/**
* wma_mgmt_tx_dload_comp_hldr - handles tx mgmt completion
* @context: context with which the handler is registered
* @netbuf: tx mgmt nbuf
* @err: status of tx completion
*/
static void
wma_mgmt_tx_dload_comp_hldr(void *wma_context, adf_nbuf_t netbuf,
int32_t status)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
tp_wma_handle wma_handle = (tp_wma_handle)wma_context;
void *mac_context = wma_handle->mac_context;
WMA_LOGD("Tx Complete Status %d", status);
if (!wma_handle->tx_frm_download_comp_cb) {
WMA_LOGE("Tx Complete Cb not registered by umac");
return;
}
/* Call Tx Mgmt Complete Callback registered by umac */
wma_handle->tx_frm_download_comp_cb(mac_context,
netbuf, 0);
/* Reset Callback */
wma_handle->tx_frm_download_comp_cb = NULL;
/* Set the Tx Mgmt Complete Event */
vos_status = vos_event_set(
&wma_handle->tx_frm_download_comp_event);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
WMA_LOGP("%s: Event Set failed - tx_frm_comp_event", __func__);
}
/**
* wma_tx_attach - attaches tx fn with underlying layer
* @pwmaCtx: wma context
*/
VOS_STATUS wma_tx_attach(tp_wma_handle wma_handle)
{
/* Get the Vos Context */
pVosContextType vos_handle =
(pVosContextType)(wma_handle->vos_context);
/* Get the txRx Pdev handle */
ol_txrx_pdev_handle txrx_pdev =
(ol_txrx_pdev_handle)(vos_handle->pdev_txrx_ctx);
/* Register for Tx Management Frames */
wdi_in_mgmt_tx_cb_set(txrx_pdev, GENERIC_NODOWLOAD_ACK_COMP_INDEX,
NULL, wma_mgmt_tx_ack_comp_hdlr,wma_handle);
wdi_in_mgmt_tx_cb_set(txrx_pdev, GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX,
wma_mgmt_tx_dload_comp_hldr, NULL, wma_handle);
wdi_in_mgmt_tx_cb_set(txrx_pdev, GENERIC_DOWNLD_COMP_ACK_COMP_INDEX,
wma_mgmt_tx_dload_comp_hldr,
wma_mgmt_tx_ack_comp_hdlr,wma_handle);
/* Store the Mac Context */
wma_handle->mac_context = vos_handle->pMACContext;
return VOS_STATUS_SUCCESS;
}
/**
* wma_tx_detach - detaches mgmt fn with underlying layer
* Deregister with TxRx for Tx Mgmt Download and Ack completion.
* @tp_wma_handle: wma context
*/
static VOS_STATUS wma_tx_detach(tp_wma_handle wma_handle)
{
u_int32_t frame_index = 0;
/* Get the Vos Context */
pVosContextType vos_handle =
(pVosContextType)(wma_handle->vos_context);
/* Get the txRx Pdev handle */
ol_txrx_pdev_handle txrx_pdev =
(ol_txrx_pdev_handle)(vos_handle->pdev_txrx_ctx);
if (txrx_pdev) {
/* Deregister with TxRx for Tx Mgmt completion call back */
for (frame_index = 0; frame_index < FRAME_INDEX_MAX;
frame_index++) {
wdi_in_mgmt_tx_cb_set(txrx_pdev, frame_index, NULL, NULL,
txrx_pdev);
}
}
/* Tx queue empty check event (dummy event) */
vos_event_destroy(&wma_handle->tx_queue_empty_event);
/* Reset Tx Frm Callbacks */
wma_handle->tx_frm_download_comp_cb = NULL;
/* Reset Tx Data Frame Ack Cb */
wma_handle->umac_data_ota_ack_cb = NULL;
/* Reset last Tx Data Frame nbuf ptr */
wma_handle->last_umac_data_nbuf = NULL;
return VOS_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
static void wma_roam_ho_fail_handler(tp_wma_handle wma, u_int32_t vdev_id)
{
tSirSmeHOFailureInd *ho_failure_ind;
vos_msg_t sme_msg = {0};
VOS_STATUS vos_status;
ho_failure_ind = vos_mem_malloc(sizeof(tSirSmeHOFailureInd));
if (NULL == ho_failure_ind) {
WMA_LOGE("%s: Memory allocation failure", __func__);
return;
}
ho_failure_ind->sessionId = vdev_id;
sme_msg.type = eWNI_SME_HO_FAIL_IND;
sme_msg.bodyptr = ho_failure_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("Fail to post eWNI_SME_HO_FAIL_IND msg to SME");
vos_mem_free(ho_failure_ind);
return;
}
return;
}
#endif
/* function : wma_roam_better_ap_handler
* Description : Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome.
* : This event means roam algorithm in Rome has found a better matching
* : candidate AP. The indication is sent through tl_shim as by repeating
* : the last beacon. Hence this routine calls a tlshim routine.
* Args :
* Returns :
*/
static void wma_roam_better_ap_handler(tp_wma_handle wma, u_int32_t vdev_id)
{
VOS_STATUS ret;
/* abort existing scans from GUI, but not roaming preauth scan */
if (wma->interfaces[vdev_id].scan_info.scan_id != 0 &&
(wma->interfaces[vdev_id].scan_info.scan_id &
WMA_HOST_ROAM_SCAN_REQID_PREFIX) !=
WMA_HOST_ROAM_SCAN_REQID_PREFIX) {
tAbortScanParams abortScan;
abortScan.SessionId = vdev_id;
wma_stop_scan(wma, &abortScan);
}
ret = tlshim_mgmt_roam_event_ind(wma->vos_context, vdev_id);
}
/* function : wma_roam_event_callback
* Description : Handler for all events from roam engine in firmware
* Args :
* Returns :
*/
static int wma_roam_event_callback(WMA_HANDLE handle, u_int8_t *event_buf,
u_int32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_ROAM_EVENTID_param_tlvs *param_buf;
wmi_roam_event_fixed_param *wmi_event;
param_buf = (WMI_ROAM_EVENTID_param_tlvs *) event_buf;
if (!param_buf) {
WMA_LOGE("Invalid roam event buffer");
return -EINVAL;
}
wmi_event = param_buf->fixed_param;
WMA_LOGD("%s: Reason %x for vdevid %x, rssi %d",
__func__, wmi_event->reason, wmi_event->vdev_id, wmi_event->rssi);
if (wmi_event->vdev_id >= wma_handle->max_bssid) {
WMA_LOGE("Invalid vdev id from firmware");
return -EINVAL;
}
DPTRACE(adf_dp_trace_record_event(ADF_DP_TRACE_EVENT_RECORD,
wmi_event->vdev_id, ADF_PROTO_TYPE_EVENT, ADF_ROAM_EVENTID));
switch(wmi_event->reason) {
case WMI_ROAM_REASON_BMISS:
WMA_LOGD("Beacon Miss for vdevid %x",
wmi_event->vdev_id);
wma_beacon_miss_handler(wma_handle, wmi_event->vdev_id,
wmi_event->rssi);
break;
case WMI_ROAM_REASON_BETTER_AP:
WMA_LOGD("%s:Better AP found for vdevid %x, rssi %d", __func__,
wmi_event->vdev_id, wmi_event->rssi);
wma_handle->suitable_ap_hb_failure = FALSE;
wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id);
break;
case WMI_ROAM_REASON_SUITABLE_AP:
wma_handle->suitable_ap_hb_failure = TRUE;
wma_handle->suitable_ap_hb_failure_rssi = wmi_event->rssi;
WMA_LOGD("%s:Bmiss scan AP found for vdevid %x, rssi %d", __func__,
wmi_event->vdev_id, wmi_event->rssi);
wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id);
break;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
case WMI_ROAM_REASON_HO_FAILED:
WMA_LOGE("LFR3:Hand-Off Failed for vdevid %x",
wmi_event->vdev_id);
wma_roam_ho_fail_handler(wma_handle, wmi_event->vdev_id);
break;
#endif
default:
WMA_LOGD("%s:Unhandled Roam Event %x for vdevid %x", __func__,
wmi_event->reason, wmi_event->vdev_id);
break;
}
return 0;
}
/**
* wma_smps_force_mode_callback() - SMPS force command event
* handler
* @handle: WMA handle
* @event_buf: event buffer
* @len: length of event data
*
* Return: 0 for success non-zero for failure
*/
static int wma_smps_force_mode_callback(WMA_HANDLE handle,
uint8_t *event_buf,
uint32_t len)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_STA_SMPS_FORCE_MODE_COMPLETE_EVENTID_param_tlvs *param_buf;
wmi_sta_smps_force_mode_complete_event_fixed_param *wmi_event;
struct sir_smps_force_mode_event *smps_ind;
param_buf =
(WMI_STA_SMPS_FORCE_MODE_COMPLETE_EVENTID_param_tlvs *)
event_buf;
if (!param_buf) {
WMA_LOGE("Invalid smps force mode event buffer");
return -EINVAL;
}
wmi_event = param_buf->fixed_param;
WMA_LOGD("%s: vdev id %x status %x",
__func__, wmi_event->vdev_id, wmi_event->status);
smps_ind = vos_mem_malloc(sizeof(*smps_ind));
if (NULL == smps_ind) {
WMA_LOGE("%s: memory alloc failed for SMPS force mode event",
__func__);
return -ENOMEM;
}
smps_ind->message_type = WDA_SMPS_FORCE_MODE_IND;
smps_ind->length = sizeof(struct sir_smps_force_mode_event);
smps_ind->vdev_id = wmi_event->vdev_id;
smps_ind->status = wmi_event->status;
wma_send_msg(wma_handle, WDA_SMPS_FORCE_MODE_IND, smps_ind, 0);
return 0;
}
#ifdef FEATURE_WLAN_SCAN_PNO
/* Record NLO match event comes from FW. It's a indication that
* one of the profile is matched.
*/
static int wma_nlo_match_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
wmi_nlo_event *nlo_event;
WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf =
(WMI_NLO_MATCH_EVENTID_param_tlvs *) event;
struct wma_txrx_node *node;
if (!param_buf) {
WMA_LOGE("Invalid NLO match event buffer");
return -EINVAL;
}
nlo_event = param_buf->fixed_param;
WMA_LOGD("PNO match event received for vdev %d",
nlo_event->vdev_id);
if (nlo_event->vdev_id >= wma->max_bssid) {
WMA_LOGE("Invalid vdev id in the NLO event %d",
nlo_event->vdev_id);
return -EINVAL;
}
node = &wma->interfaces[nlo_event->vdev_id];
if (node)
node->nlo_match_evt_received = TRUE;
vos_wake_lock_timeout_acquire(&wma->pno_wake_lock,
WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT,
WIFI_POWER_EVENT_WAKELOCK_PNO);
return 0;
}
/* Handles NLO scan completion event. */
static int wma_nlo_scan_cmp_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
wmi_nlo_event *nlo_event;
WMI_NLO_SCAN_COMPLETE_EVENTID_param_tlvs *param_buf =
(WMI_NLO_SCAN_COMPLETE_EVENTID_param_tlvs *) event;
tSirScanOffloadEvent *scan_event;
struct wma_txrx_node *node;
if (!param_buf) {
WMA_LOGE("Invalid NLO scan comp event buffer");
return -EINVAL;
}
nlo_event = param_buf->fixed_param;
WMA_LOGD("PNO scan completion event received for vdev %d",
nlo_event->vdev_id);
node = &wma->interfaces[nlo_event->vdev_id];
/* Handle scan completion event only after NLO match event. */
if (!node || !node->nlo_match_evt_received) {
WMA_LOGD("NLO match not received skipping PNO complete ind for vdev %d",
nlo_event->vdev_id);
goto skip_pno_cmp_ind;
}
vos_wake_lock_release(&wma->pno_wake_lock,
WIFI_POWER_EVENT_WAKELOCK_PNO);
scan_event = (tSirScanOffloadEvent *) vos_mem_malloc(
sizeof(tSirScanOffloadEvent));
if (scan_event) {
/* Posting scan completion msg would take scan cache result
* from LIM module and update in scan cache maintained in SME.*/
WMA_LOGD("Posting Scan completion to umac");
vos_wake_lock_timeout_acquire(&wma->pno_wake_lock,
WMA_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT,
WIFI_POWER_EVENT_WAKELOCK_PNO);
vos_mem_zero(scan_event, sizeof(tSirScanOffloadEvent));
scan_event->reasonCode = eSIR_SME_SUCCESS;
scan_event->event = SIR_SCAN_EVENT_COMPLETED;
scan_event->sessionId = nlo_event->vdev_id;
wma_send_msg(wma, WDA_RX_SCAN_EVENT,
(void *) scan_event, 0);
} else {
WMA_LOGE("Memory allocation failed for tSirScanOffloadEvent");
}
skip_pno_cmp_ind:
return 0;
}
#endif
#ifdef WLAN_FEATURE_APFIND
/* Record APFIND event comes from FW.
*/
static int wma_apfind_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
wmi_apfind_event_hdr *apfind_event_hdr;
WMI_APFIND_EVENTID_param_tlvs *param_buf =
(WMI_APFIND_EVENTID_param_tlvs *) event;
u_int8_t *buf;
u_int8_t ssid_tmp[WMI_MAX_SSID_LEN + 1];
u_int8_t *mac;
u_int32_t vdev_id;
if (!param_buf) {
WMA_LOGE("Invalid APFIND event buffer");
return -EINVAL;
}
apfind_event_hdr = param_buf->hdr;
WMA_LOGD("APFIND event received, id=%d, data_length=%d",
apfind_event_hdr->event_type, apfind_event_hdr->data_len);
buf = param_buf->data;
A_MEMZERO(ssid_tmp, sizeof(ssid_tmp));
A_MEMCPY(ssid_tmp, buf, WMI_MAX_SSID_LEN);
/* SSID param len is WMI_MAX_SSID_LEN, without '+1' */
WMA_LOGD("%s, APFIND match, dump ssid=%s", __func__, ssid_tmp);
buf = &param_buf->data[WMI_MAX_SSID_LEN];
mac = buf;
WMA_LOGD("%s, APFIND dump mac=0x%08X-0x%08X",
__func__, *(u_int32_t *)buf, *(u_int32_t *)(buf + sizeof(u_int32_t)));
if (apfind_event_hdr->data_len >=
(WMI_MAX_SSID_LEN + IEEE80211_ADDR_LEN + sizeof(vdev_id)
+ sizeof(apfind_event_hdr->tlv_header))) {
/* FW had the tlv_header len calculated into the data_len */
buf = &param_buf->data[WMI_MAX_SSID_LEN + IEEE80211_ADDR_LEN];
vdev_id = *(u_int32_t*) buf;
/* to trigger AP re-connection after QRF wakeup*/
WMA_LOGA("%s, trigger AP re-connection at QRF wakeup (APFIND_WAKEUP_EVENT), vdev_id=%d, SSID=%s",
__func__, vdev_id, ssid_tmp);
wma_beacon_miss_handler(wma, vdev_id, 0);
} else {
WMA_LOGD("%s, old version FW (no vdev_id).", __func__);
}
return 0;
}
#endif /* WLAN_FEATURE_APFIND */
#if defined(CONFIG_HL_SUPPORT) || defined(QCA_SUPPORT_TXRX_VDEV_PAUSE_LL)
/* Handle TX pause event from FW */
static int wma_mcc_vdev_tx_pause_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_TX_PAUSE_EVENTID_param_tlvs *param_buf;
wmi_tx_pause_event_fixed_param *wmi_event;
u_int8_t vdev_id;
A_UINT32 vdev_map;
param_buf = (WMI_TX_PAUSE_EVENTID_param_tlvs *) event;
if (!param_buf)
{
WMA_LOGE("Invalid roam event buffer");
return -EINVAL;
}
if (wma_get_wow_bus_suspend(wma)) {
WMA_LOGD(" Suspend is in progress: Pause/Unpause Tx is NoOp");
return 0;
}
wmi_event = param_buf->fixed_param;
vdev_map = wmi_event->vdev_map;
/* FW mapped vdev from ID
* vdev_map = (1 << vdev_id)
* So, host should unmap to ID */
for (vdev_id = 0; vdev_map != 0 && vdev_id < wma->max_bssid;
vdev_id++)
{
if (!(vdev_map & 0x1))
{
/* No Vdev */
}
else
{
if (!wma->interfaces[vdev_id].handle)
{
WMA_LOGE("%s: invalid vdev ID %d", __func__, vdev_id);
/* Test Next VDEV */
vdev_map >>= 1;
continue;
}
/* PAUSE action, add bitmap */
if (ACTION_PAUSE == wmi_event->action)
{
/*
* Now only support per-dev pause so it is not necessary
* to pause a paused queue again.
*/
if (!wma->interfaces[vdev_id].pause_bitmap)
wdi_in_vdev_pause(wma->interfaces[vdev_id].handle,
OL_TXQ_PAUSE_REASON_FW);
wma->interfaces[vdev_id].pause_bitmap |= (1 << wmi_event->pause_type);
}
/* UNPAUSE action, clean bitmap */
else if (ACTION_UNPAUSE == wmi_event->action)
{
/* Handle unpause only if already paused*/
if(wma->interfaces[vdev_id].pause_bitmap)
{
wma->interfaces[vdev_id].pause_bitmap &= ~(1 << wmi_event->pause_type);
if (!wma->interfaces[vdev_id].pause_bitmap)
{
/* PAUSE BIT MAP is cleared
* UNPAUSE VDEV */
wdi_in_vdev_unpause(wma->interfaces[vdev_id].handle,
OL_TXQ_PAUSE_REASON_FW);
}
}
}
else
{
WMA_LOGE("Not Valid Action Type %d", wmi_event->action);
}
WMA_LOGD("vdev_id %d, pause_map 0x%x, pause type %d, action %d",
vdev_id, wma->interfaces[vdev_id].pause_bitmap,
wmi_event->pause_type, wmi_event->action);
}
/* Test Next VDEV */
vdev_map >>= 1;
}
return 0;
}
#endif /* QCA_SUPPORT_TXRX_VDEV_PAUSE_LL */
/* function : wma_set_thermal_mgmt
* Description : This function sends the thermal management command to the firmware
* Args :
wma_handle : Pointer to WMA handle
* thermal_info : Thermal command information
* Returns :
* VOS_STATUS_SUCCESS for success otherwise failure
*/
static VOS_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle,
t_thermal_cmd_params thermal_info)
{
wmi_thermal_mgmt_cmd_fixed_param *cmd = NULL;
wmi_buf_t buf = NULL;
int status = 0;
u_int32_t len = 0;
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set key cmd");
return eHAL_STATUS_FAILURE;
}
cmd = (wmi_thermal_mgmt_cmd_fixed_param *) wmi_buf_data (buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_thermal_mgmt_cmd_fixed_param));
cmd->lower_thresh_degreeC = thermal_info.minTemp;
cmd->upper_thresh_degreeC = thermal_info.maxTemp;
cmd->enable = thermal_info.thermalEnable;
WMA_LOGE("TM Sending thermal mgmt cmd: low temp %d, upper temp %d, enabled %d",
cmd->lower_thresh_degreeC, cmd->upper_thresh_degreeC, cmd->enable);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_THERMAL_MGMT_CMDID);
if (status) {
wmi_buf_free(buf);
WMA_LOGE("%s:Failed to send thermal mgmt command", __func__);
return eHAL_STATUS_FAILURE;
}
return eHAL_STATUS_SUCCESS;
}
/* function : wma_thermal_mgmt_get_level
* Description : This function returns the thermal(throttle) level given the temperature
* Args :
handle : Pointer to WMA handle
* temp : temperature
* Returns :
* thermal (throttle) level
*/
u_int8_t wma_thermal_mgmt_get_level(void *handle, u_int32_t temp)
{
tp_wma_handle wma = (tp_wma_handle) handle;
int i;
u_int8_t level;
level = i = wma->thermal_mgmt_info.thermalCurrLevel;
while (temp < wma->thermal_mgmt_info.thermalLevels[i].minTempThreshold &&
i > 0) {
i--;
level = i;
}
i = wma->thermal_mgmt_info.thermalCurrLevel;
while (temp > wma->thermal_mgmt_info.thermalLevels[i].maxTempThreshold &&
i < (WLAN_WMA_MAX_THERMAL_LEVELS - 1)) {
i++;
level = i;
}
WMA_LOGW("Change thermal level from %d -> %d\n",
wma->thermal_mgmt_info.thermalCurrLevel, level);
return level;
}
static int wma_thermal_throttle_handler(void *handle, u_int32_t degree_c)
{
tp_wma_handle wma = (tp_wma_handle)handle;
u_int8_t thermal_level;
t_thermal_cmd_params thermal_params;
ol_txrx_pdev_handle curr_pdev;
tp_thermal_mgmt info;
/* Check if thermal mitigation is enabled */
if (!wma->thermal_mgmt_info.thermalMgmtEnabled){
WMA_LOGD("Thermal mgmt is not enabled, ignoring event");
return 0;
}
curr_pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == curr_pdev) {
WMA_LOGE("%s: Failed to get pdev", __func__);
return -EINVAL;
}
/* Get the thermal mitigation level for the reported temperature*/
thermal_level = wma_thermal_mgmt_get_level(handle, degree_c);
WMA_LOGD("Thermal mgmt level %d", thermal_level);
info = &wma->thermal_mgmt_info;
if (thermal_level == info->thermalCurrLevel) {
WMA_LOGD("Current level %d is same as the set level, ignoring",
info->thermalCurrLevel);
return 0;
}
info->thermalCurrLevel = thermal_level;
/* Inform txrx */
ol_tx_throttle_set_level(curr_pdev, thermal_level);
/* Send SME SET_THERMAL_LEVEL_IND message */
wma_set_thermal_level_ind(thermal_level);
/* Get the temperature thresholds to set in firmware */
thermal_params.minTemp =
info->thermalLevels[thermal_level].minTempThreshold;
thermal_params.maxTemp =
info->thermalLevels[thermal_level].maxTempThreshold;
thermal_params.thermalEnable = info->thermalMgmtEnabled;
if (VOS_STATUS_SUCCESS != wma_set_thermal_mgmt(wma, thermal_params)) {
WMA_LOGE("Could not send thermal mgmt cmd to the firmware!");
return -EINVAL;
}
return 0;
}
/* function : wma_thermal_mgmt_evt_handler
* Description : This function handles the thermal mgmt event from the firmware
* Args :
wma_handle : Pointer to WMA handle
* event : Thermal event information
* len :
* Returns :
* 0 for success otherwise failure
*/
static int wma_thermal_mgmt_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
tp_wma_handle wma;
wmi_thermal_mgmt_event_fixed_param *tm_event;
WMI_THERMAL_MGMT_EVENTID_param_tlvs *param_buf;
int ret;
if (NULL == event || NULL == handle) {
WMA_LOGE("Invalid thermal mitigation event buffer");
return -EINVAL;
}
wma = (tp_wma_handle) handle;
if (NULL == wma) {
WMA_LOGE("%s: Failed to get wma handle", __func__);
return -EINVAL;
}
param_buf = (WMI_THERMAL_MGMT_EVENTID_param_tlvs *) event;
tm_event = param_buf->fixed_param;
WMA_LOGD("Thermal mgmt event received with temperature %d",
tm_event->temperature_degreeC);
ret = wma_thermal_throttle_handler(handle,
tm_event->temperature_degreeC);
wma_thermal_shutdown_evt_handler(&wma->thermal_mgmt_info,
tm_event->temperature_degreeC);
return ret;
}
#ifdef FEATURE_WLAN_CH_AVOID
/* Process channel to avoid event comes from FW.
*/
static int wma_channel_avoid_evt_handler(void *handle, u_int8_t *event,
u_int32_t len)
{
wmi_avoid_freq_ranges_event_fixed_param *afr_fixed_param;
wmi_avoid_freq_range_desc *afr_desc;
u_int32_t num_freq_ranges, freq_range_idx;
tSirChAvoidIndType *sca_indication;
VOS_STATUS vos_status;
vos_msg_t sme_msg = {0} ;
WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *param_buf =
(WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *) event;
if (!param_buf) {
WMA_LOGE("Invalid channel avoid event buffer");
return -EINVAL;
}
afr_fixed_param = param_buf->fixed_param;
if (!afr_fixed_param) {
WMA_LOGE("Invalid channel avoid event fixed param buffer");
return -EINVAL;
}
num_freq_ranges = (afr_fixed_param->num_freq_ranges > SIR_CH_AVOID_MAX_RANGE)?
SIR_CH_AVOID_MAX_RANGE:afr_fixed_param->num_freq_ranges;
WMA_LOGD("Channel avoid event received with %d ranges", num_freq_ranges);
for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; freq_range_idx++) {
afr_desc = (wmi_avoid_freq_range_desc *) ((void *)param_buf->avd_freq_range
+ freq_range_idx * sizeof(wmi_avoid_freq_range_desc));
WMA_LOGD("range %d: tlv id = %u, start freq = %u, end freq = %u",
freq_range_idx,
afr_desc->tlv_header,
afr_desc->start_freq,
afr_desc->end_freq);
}
sca_indication = (tSirChAvoidIndType *)
vos_mem_malloc(sizeof(tSirChAvoidIndType));
if (!sca_indication) {
WMA_LOGE("Invalid channel avoid indication buffer");
return -EINVAL;
}
sca_indication->avoid_range_count = num_freq_ranges;
for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; freq_range_idx++) {
afr_desc = (wmi_avoid_freq_range_desc *) ((void *)param_buf->avd_freq_range
+ freq_range_idx * sizeof(wmi_avoid_freq_range_desc));
sca_indication->avoid_freq_range[freq_range_idx].start_freq =
afr_desc->start_freq;
sca_indication->avoid_freq_range[freq_range_idx].end_freq =
afr_desc->end_freq;
}
sme_msg.type = eWNI_SME_CH_AVOID_IND;
sme_msg.bodyptr = sca_indication;
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_CH_AVOID_IND msg to SME");
vos_mem_free(sca_indication);
return -EINVAL;
}
return 0;
}
/* function : wma_process_ch_avoid_update_req
* Description : handles channel avoid update request
* Args :
* Returns :
*/
VOS_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle,
tSirChAvoidUpdateReq *ch_avoid_update_req)
{
int status = 0;
wmi_buf_t buf = NULL;
u_int8_t *buf_ptr;
wmi_chan_avoid_update_cmd_param *ch_avoid_update_fp;
int len = sizeof(wmi_chan_avoid_update_cmd_param);
if (ch_avoid_update_req == NULL)
{
WMA_LOGE("%s : ch_avoid_update_req is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE",
__func__);
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);
ch_avoid_update_fp = (wmi_chan_avoid_update_cmd_param *) buf_ptr;
WMITLV_SET_HDR(&ch_avoid_update_fp->tlv_header,
WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_chan_avoid_update_cmd_param));
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_CHAN_AVOID_UPDATE_CMDID);
if (status != EOK) {
WMA_LOGE("wmi_unified_cmd_send"
" WMITLV_TABLE_WMI_CHAN_AVOID_UPDATE"
" returned Error %d",
status);
wmi_buf_free(buf);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE sent through WMI",
__func__);
return VOS_STATUS_SUCCESS;
}
#endif /* FEATURE_WLAN_CH_AVOID */
/* Handle IBSS peer info event from FW */
static int wma_ibss_peer_info_event_handler(void *handle, u_int8_t *data,
u_int32_t len)
{
vos_msg_t vosMsg;
wmi_peer_info *peer_info;
ol_txrx_pdev_handle pdev;
tSirIbssPeerInfoParams *pSmeRsp;
u_int32_t count, num_peers, status;
tSirIbssGetPeerInfoRspParams *pRsp;
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_PEER_INFO_EVENTID_param_tlvs *param_tlvs;
wmi_peer_info_event_fixed_param *fix_param;
u_int8_t peer_mac[IEEE80211_ADDR_LEN];
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma->vos_context);
if (NULL == pdev) {
WMA_LOGE("%s: could not get pdev context", __func__);
return 0;
}
param_tlvs = (WMI_PEER_INFO_EVENTID_param_tlvs *)data;
fix_param = param_tlvs->fixed_param;
peer_info = param_tlvs->peer_info;
num_peers = fix_param->num_peers;
status = 0;
WMA_LOGE("%s: num_peers %d", __func__, num_peers);
pRsp = vos_mem_malloc(sizeof(tSirIbssGetPeerInfoRspParams));
if (NULL == pRsp )
{
WMA_LOGE("%s: could not allocate memory for ibss peer info rsp len %zu",
__func__, sizeof(tSirIbssGetPeerInfoRspParams));
return 0;
}
/*sanity check*/
if ((num_peers > 32) || (num_peers > param_tlvs->num_peer_info) ||
(!peer_info))
{
WMA_LOGE("%s: Invalid event data from target num_peers %d peer_info %pK",
__func__, num_peers, peer_info);
status = 1;
goto send_response;
}
for (count = 0; count < num_peers; count++)
{
pSmeRsp = &pRsp->ibssPeerInfoRspParams.peerInfoParams[count];
WMI_MAC_ADDR_TO_CHAR_ARRAY (&peer_info->peer_mac_address, peer_mac);
vos_mem_copy(pSmeRsp->mac_addr, peer_mac,
sizeof(pSmeRsp->mac_addr));
pSmeRsp->mcsIndex = 0;
pSmeRsp->rssi = peer_info->rssi + WMA_TGT_NOISE_FLOOR_DBM;
pSmeRsp->txRate = peer_info->data_rate;
pSmeRsp->txRateFlags = 0;
WMA_LOGE("%s: peer " MAC_ADDRESS_STR "rssi %d txRate %d", __func__,
MAC_ADDR_ARRAY(peer_mac), pSmeRsp->rssi, pSmeRsp->txRate);
peer_info++;
}
send_response:
/* message header */
pRsp->mesgType = eWNI_SME_IBSS_PEER_INFO_RSP;
pRsp->mesgLen = sizeof(tSirIbssGetPeerInfoRspParams);
pRsp->ibssPeerInfoRspParams.status = status;
pRsp->ibssPeerInfoRspParams.numPeers = num_peers;
/* vos message wrapper */
vosMsg.type = eWNI_SME_IBSS_PEER_INFO_RSP;
vosMsg.bodyptr = (void *)pRsp;
vosMsg.bodyval = 0;
if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME, (vos_msg_t*)&vosMsg))
{
WMA_LOGE("%s: could not post peer info rsp msg to SME", __func__);
/* free the mem and return */
vos_mem_free((v_VOID_t *) pRsp);
}
return 0;
}
/* Handle fast tx failure indication event from FW */
static int wma_fast_tx_fail_event_handler(void *handle, u_int8_t *data,
u_int32_t len)
{
u_int8_t tx_fail_cnt;
u_int8_t peer_mac[IEEE80211_ADDR_LEN];
tp_wma_handle wma = (tp_wma_handle) handle;
WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *param_tlvs;
wmi_peer_tx_fail_cnt_thr_event_fixed_param *fix_param;
param_tlvs = (WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *)data;
fix_param = param_tlvs->fixed_param;
WMI_MAC_ADDR_TO_CHAR_ARRAY (&fix_param->peer_mac_address, peer_mac);
WMA_LOGE("%s: received fast tx failure event for peer"
" 0x:%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x seq No %d", __func__,
peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3],
peer_mac[4], peer_mac[5], fix_param->seq_no);
tx_fail_cnt = fix_param->seq_no;
/*call HDD callback*/
if (NULL != wma->hddTxFailCb)
{
wma->hddTxFailCb(peer_mac, tx_fail_cnt);
}
else
{
WMA_LOGE("%s: HDD callback is %pK", __func__, wma->hddTxFailCb);
}
return 0;
}
/* function : wma_scan_completion_timeout
* Description :
* Args :
* Returns :
*/
void wma_scan_completion_timeout(void *data)
{
tp_wma_handle wma_handle;
u_int8_t vdev_id;
WMA_LOGE("%s: Timeout occured for scan command", __func__);
wma_handle = (tp_wma_handle) data;
vdev_id = wma_handle->wma_scan_timer_info.vdev_id;
if (wma_handle->wma_scan_timer_info.scan_id !=
wma_handle->interfaces[vdev_id].scan_info.scan_id) {
WMA_LOGE("%s: Scan ID mismatch", __func__);
return;
}
/*
* To avoid race condition between scan timeout in host and in firmware
* here we should just send abort scan to firmware and do cleanup after
* receiving event from firmware. Since at this moment there will be no
* outstanding scans, aborting should not cause any problem in firmware.
*/
if (wma_handle->interfaces[vdev_id].scan_info.scan_id != 0) {
tAbortScanParams abortScan;
abortScan.SessionId = vdev_id;
WMA_LOGW("%s: Sending abort for timed out scan", __func__);
wma_stop_scan(wma_handle, &abortScan);
}
return;
}
/**
* wma_log_completion_timeout() - Log completion timeout
* @data: Timeout handler data
*
* This function is called when log completion timer expires
*
* Return: None
*/
void wma_log_completion_timeout(void *data)
{
tp_wma_handle wma_handle;
WMA_LOGE("%s: Timeout occured for log completion command", __func__);
wma_handle = (tp_wma_handle) data;
if (!wma_handle)
WMA_LOGE("%s: Invalid WMA handle", __func__);
/* Though we did not receive any event from FW,
* we can flush whatever logs we have with us */
vos_logging_set_fw_flush_complete();
return;
}
#ifdef SAP_AUTH_OFFLOAD
static int wma_sap_ofl_add_sta_handler(void *handle, u_int8_t *data,
u_int32_t data_len)
{
tp_wma_handle wma = handle;
WMI_SAP_OFL_ADD_STA_EVENTID_param_tlvs *param_buf = NULL;
wmi_sap_ofl_add_sta_event_fixed_param *sta_add_event = NULL;
struct sap_offload_add_sta_req *add_sta_req = NULL;
u_int8_t *buf_ptr;
param_buf = (WMI_SAP_OFL_ADD_STA_EVENTID_param_tlvs *)data;
sta_add_event = param_buf->fixed_param;
buf_ptr = (u_int8_t *)param_buf->bufp;
if (sta_add_event->data_len > MAX_CONNECT_REQ_LENGTH) {
WMA_LOGE("%s: Received data_len %d greater than max",
__func__, sta_add_event->data_len);
return 0;
}
add_sta_req = vos_mem_malloc(sizeof(*add_sta_req));
if (!add_sta_req) {
WMA_LOGE("%s: Failed to alloc memory for sap_ofl_add_sta_event",
__func__);
return 0;
}
vos_mem_set(add_sta_req, sizeof(*add_sta_req), 0);
add_sta_req->assoc_id = sta_add_event->assoc_id;
add_sta_req->conn_req_len = sta_add_event->data_len;
vos_mem_copy(add_sta_req->conn_req, buf_ptr,
sta_add_event->data_len);
wma_send_msg(wma, WDA_SAP_OFL_ADD_STA, add_sta_req, 0);
return 1;
}
static int wma_sap_ofl_del_sta_handler(void *handle, u_int8_t *data,
u_int32_t data_len)
{
tp_wma_handle wma = handle;
WMI_SAP_OFL_DEL_STA_EVENTID_param_tlvs *param_buf = NULL;
wmi_sap_ofl_del_sta_event_fixed_param *sta_del_event = NULL;
struct sap_offload_del_sta_req *del_sta_req = NULL;
param_buf = (WMI_SAP_OFL_DEL_STA_EVENTID_param_tlvs *)data;
sta_del_event = param_buf->fixed_param;
del_sta_req = vos_mem_malloc(sizeof(*del_sta_req));
if (!del_sta_req) {
WMA_LOGE("%s: Failed to alloc memory for sap_ofl_del_sta_event",
__func__);
return 0;
}
vos_mem_set(del_sta_req, sizeof(*del_sta_req), 0);
WMI_MAC_ADDR_TO_CHAR_ARRAY(&sta_del_event->peer_macaddr,
del_sta_req->sta_mac);
del_sta_req->assoc_id = sta_del_event->assoc_id;
del_sta_req->reason_code = sta_del_event->reason;
del_sta_req->flags = sta_del_event->flags;
wma_send_msg(wma, WDA_SAP_OFL_DEL_STA, del_sta_req, 0);
return 1;
}
#endif /* SAP_AUTH_OFFLOAD */
/**
* wma_vdev_tsf_handler() - handle tsf event indicated by FW
*
* @handle: wma context
* @data: event buffer
* @data len: length of event buffer
*
* Return: 0 on success
*/
static int wma_vdev_tsf_handler(void *handle, uint8_t *data,
uint32_t data_len)
{
vos_msg_t vos_msg = {0};
WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *param_buf;
wmi_vdev_tsf_report_event_fixed_param *tsf_event;
struct stsf *ptsf;
if (data == NULL) {
WMA_LOGE("%s: invalid pointer", __func__);
return -EINVAL;
}
ptsf = vos_mem_malloc(sizeof(*ptsf));
if (NULL == ptsf) {
WMA_LOGE("%s: failed to allocate sSirtsf memory", __func__);
return -ENOMEM;
}
param_buf = (WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *)data;
tsf_event = param_buf->fixed_param;
ptsf->vdev_id = tsf_event->vdev_id;
ptsf->tsf_low = tsf_event->tsf_low;
ptsf->tsf_high = tsf_event->tsf_high;
WMA_LOGD("%s: receive WMI_VDEV_TSF_REPORT_EVENTID ", __func__);
WMA_LOGD("%s: vdev_id = %u,tsf_low =%u, tsf_high = %u", __func__,
ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high);
vos_msg.type = eWNI_SME_TSF_EVENT;
vos_msg.bodyptr = ptsf;
vos_msg.bodyval = 0;
if (VOS_STATUS_SUCCESS !=
vos_mq_post_message(VOS_MQ_ID_SME, &vos_msg)) {
WMA_LOGP("%s: Failed to post eWNI_SME_TSF_EVENT", __func__);
vos_mem_free(ptsf);
return -EINVAL;
}
return 0;
}
/**
* wma_echo_event_handler() - received echo response event from firmware
* @handle: wma context
* @event_buf: event buffer
* @len: length of event buffer
*
* Return: 0 on success
*/
static int wma_echo_event_handler(void *handle, u_int8_t *event_buf,
u_int32_t len)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
vos_msg_t sme_msg = {0};
WMA_LOGD("Received Echo reply from firmware!");
sme_msg.type = eWNI_SME_FW_STATUS_IND;
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 firmware status ind msg", __func__);
}
return 0;
}
#if defined(QCA_WIFI_FTM) && defined(WLAN_SCPC_FEATURE)
/**
* wma_scpc_event_handler() - handler for scpc event from firmware
* @handle: wma context
* @event_buf: pointer to the event buffer
* @len: length of the event buffer
*
* Once SCPC feature is enabled in FTM mode, firmware will do calibration
* and indicates calibrated data in an SCPC message.
*
* This function is used to parse SCPC message. Calibrated data in an SCPC
* message is formated like this:
* patch1 offset(byte3~0), patch1 length(byte7~4), patch1 data
* ......
* patchn offset(byte3~0), patchn length(byte7~4), patchn data
* All data patches are 4bytes aligned. But the length indicated here is
* not multiple of 4.
*
* Return: 0 on success.
*/
int wma_scpc_event_handler(void *handle, u_int8_t *event_buf, u_int32_t len)
{
u_int8_t *buf;
u_int32_t length;
u_int32_t i;
u_int32_t n;
WMI_PDEV_UTF_SCPC_EVENTID_param_tlvs *param_buf;
wmi_scpc_event_fixed_param *scpc_event;
struct _bd {
u_int32_t offset;
u_int32_t length;
u_int8_t data[0];
} *bd_data;
WMA_LOGD("WMA event <---- SCPC\n");
if ((event_buf == NULL) || (len < sizeof(wmi_scpc_event_fixed_param))) {
WMA_LOGE("%s: invalid pointer", __func__);
return -EINVAL;
}
param_buf = (WMI_PDEV_UTF_SCPC_EVENTID_param_tlvs *)event_buf;
scpc_event = param_buf->fixed_param;
length = len - sizeof(wmi_scpc_event_fixed_param);
buf = (u_int8_t *)scpc_event + sizeof(wmi_scpc_event_fixed_param);
WMA_LOGD("%s: section count is %d, data length is %d, tag is 0x%x.\n",
__func__, scpc_event->num_patch, length, *(u_int32_t *)buf);
/* skip the tag */
buf += sizeof(u_int32_t);
i = n = 0;
bd_data = (struct _bd *)&buf[n];
n += roundup((sizeof(struct _bd) + bd_data->length), 4);
while ((n < length) && (i < scpc_event->num_patch)) {
bd_data = (struct _bd *)&buf[n];
WMA_LOGD("%s: board data patch%i, offset= %d, length= %d.\n",
__func__, i, bd_data->offset, bd_data->length);
/* cache the data section */
vos_cache_boarddata(bd_data->offset,
bd_data->length, bd_data->data);
n += roundup((sizeof(struct _bd) + bd_data->length), 4);
i++;
}
WMA_LOGD("%s: %d patches in message, %d cached.\n",
__func__, scpc_event->num_patch, i);
return 0;
}
#else
int wma_scpc_event_handler(void *handle, u_int8_t *event_buf, u_int32_t len)
{
return 0;
}
#endif
/* function : wma_start
* Description :
* Args :
* Returns :
*/
VOS_STATUS wma_start(v_VOID_t *vos_ctx)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
tp_wma_handle wma_handle;
int status;
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 handle", __func__);
vos_status = VOS_STATUS_E_INVAL;
goto end;
}
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_SCAN_EVENTID,
wma_scan_event_callback);
if (0 != status) {
WMA_LOGP("%s: Failed to register scan callback", __func__);
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_ROAM_EVENTID,
wma_roam_event_callback);
if (0 != status) {
WMA_LOGP("%s: Failed to register Roam callback", __func__);
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_WOW_WAKEUP_HOST_EVENTID,
wma_wow_wakeup_host_event);
if (status) {
WMA_LOGP("%s: Failed to register wow wakeup host event handler",
__func__);
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
#ifdef FEATURE_WLAN_D0WOW
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_D0_WOW_DISABLE_ACK_EVENTID,
wma_d0_wow_disable_ack_event);
if (status) {
WMA_LOGE("%s: Failed to register D0-WOW disable event handler!",
__func__);
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
#endif
#ifdef FEATURE_WLAN_SCAN_PNO
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_NLO)) {
WMA_LOGD("FW supports pno offload, registering nlo match handler");
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_NLO_MATCH_EVENTID,
wma_nlo_match_evt_handler);
if (status) {
WMA_LOGE("Failed to register nlo match event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_NLO_SCAN_COMPLETE_EVENTID,
wma_nlo_scan_cmp_evt_handler);
if (status) {
WMA_LOGE("Failed to register nlo scan comp event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
}
#endif
#ifdef WLAN_FEATURE_APFIND
WMA_LOGD("APFIND event handler register");
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_APFIND_EVENTID,
wma_apfind_evt_handler);
if (status) {
WMA_LOGE("Failed to register APFIND event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
#endif /* WLAN_FEATURE_APFIND*/
#if defined(CONFIG_HL_SUPPORT) || defined(QCA_SUPPORT_TXRX_VDEV_PAUSE_LL)
WMA_LOGE("MCC TX Pause Event Handler register");
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_TX_PAUSE_EVENTID,
wma_mcc_vdev_tx_pause_evt_handler);
#endif /* QCA_SUPPORT_TXRX_VDEV_PAUSE_LL */
#ifdef FEATURE_WLAN_CH_AVOID
WMA_LOGD("Registering channel to avoid handler");
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_WLAN_FREQ_AVOID_EVENTID,
wma_channel_avoid_evt_handler);
if (status) {
WMA_LOGE("Failed to register channel to avoid event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
#endif /* FEATURE_WLAN_CH_AVOID */
#ifdef FEATURE_WLAN_AUTO_SHUTDOWN
WMA_LOGD("Registering auto shutdown handler");
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_HOST_AUTO_SHUTDOWN_EVENTID, wma_auto_shutdown_event_handler);
if (status) {
WMA_LOGE("Failed to register WMI Auto shutdown event handler");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
#endif
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_THERMAL_MGMT_EVENTID,
wma_thermal_mgmt_evt_handler);
if (status) {
WMA_LOGE("Failed to register thermal mitigation event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
status = wma_ocb_register_event_handlers(wma_handle);
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_ECHO_EVENTID,
wma_echo_event_handler);
if (status) {
WMA_LOGE("Failed to register echo event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
vos_status = VOS_STATUS_SUCCESS;
#ifdef QCA_WIFI_FTM
/*
* Tx mgmt attach requires TXRX context which is not created
* in FTM mode as WLANTL_Open will not be called in this mode.
* So skip the TX mgmt attach.
*/
if (vos_get_conparam() == VOS_FTM_MODE)
goto end;
#endif
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_RMC))
{
WMA_LOGD("FW supports cesium network, registering event handlers");
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_INFO_EVENTID,
wma_ibss_peer_info_event_handler);
if (status)
{
WMA_LOGE("Failed to register ibss peer info event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PEER_TX_FAIL_CNT_THR_EVENTID,
wma_fast_tx_fail_event_handler);
if (status)
{
WMA_LOGE("Failed to register peer fast tx failure event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
}
else
{
WMA_LOGE("Target does not support cesium network");
}
vos_status = wma_tx_attach(wma_handle);
if(vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: Failed to register tx management", __func__);
goto end;
}
if (VOS_FTM_MODE != vos_get_conparam()) {
/* Initialize firmware time stamp sync timer */
vos_status = vos_timer_init(&wma_handle->wma_fw_time_sync_timer,
VOS_TIMER_TYPE_SW,
wma_send_time_stamp_sync_cmd,
wma_handle);
if (vos_status != VOS_STATUS_SUCCESS)
WMA_LOGE(FL("Failed to initialize firmware time stamp sync timer"));
/* Start firmware time stamp sync timer */
wma_send_time_stamp_sync_cmd(wma_handle);
}
/* Initialize scan completion timeout */
vos_status = vos_timer_init(&wma_handle->wma_scan_comp_timer,
VOS_TIMER_TYPE_SW,
wma_scan_completion_timeout,
wma_handle);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to initialize scan completion timeout");
goto end;
}
/* Initialize log completion timeout */
vos_status = vos_timer_init(&wma_handle->log_completion_timer,
VOS_TIMER_TYPE_SW,
wma_log_completion_timeout,
wma_handle);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to initialize log completion timeout");
goto end;
}
/* Initialize the get temperature event handler */
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PDEV_TEMPERATURE_EVENTID,
wma_pdev_temperature_evt_handler);
if (status != VOS_STATUS_SUCCESS)
{
WMA_LOGE("Failed to register get_temperature event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
#ifdef SAP_AUTH_OFFLOAD
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_SAP_AUTH_OFFLOAD)) {
/* Initialize the station connect event handler for
* software AP authentication offload feature.
*/
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_SAP_OFL_ADD_STA_EVENTID,
wma_sap_ofl_add_sta_handler);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to register sap offload add_sta event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
/* Initialize the station disconnect event handler for
* software AP authentication offload feature.
*/
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_SAP_OFL_DEL_STA_EVENTID,
wma_sap_ofl_del_sta_handler);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to register sap offload del_sta event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
}
#endif /* SAP_AUTH_OFFLOAD */
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_VDEV_TSF_REPORT_EVENTID,
wma_vdev_tsf_handler);
if (0 != status) {
WMA_LOGP("%s: Failed to register tsf callback", __func__);
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
/* Initialize the log flush complete event handler */
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID,
wma_flush_complete_evt_handler);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to register log flush complete event cb");
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
/* Initialize the SMPS force mode command event handler */
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_STA_SMPS_FORCE_MODE_COMPLETE_EVENTID,
wma_smps_force_mode_callback);
if (VOS_STATUS_SUCCESS != status) {
WMA_LOGP("%s: SMPS force mode event registration failed",
__func__);
vos_status = VOS_STATUS_E_FAILURE;
goto end;
}
end:
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
/* function : wma_stop
* Description :
* Args :
* Returns :
*/
VOS_STATUS wma_stop(v_VOID_t *vos_ctx, tANI_U8 reason)
{
tp_wma_handle wma_handle;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int i;
wma_handle = vos_get_context(VOS_MODULE_ID_WDA, vos_ctx);
WMA_LOGD("%s: Enter", __func__);
/* validate the wma_handle */
if (NULL == wma_handle) {
WMA_LOGP("%s: Invalid handle", __func__);
vos_status = VOS_STATUS_E_INVAL;
goto end;
}
#ifdef QCA_WIFI_FTM
/*
* Tx mgmt detach requires TXRX context which is not created
* in FTM mode as WLANTL_Open will not be called in this mode.
* So skip the TX mgmt detach.
*/
if (vos_get_conparam() == VOS_FTM_MODE) {
vos_status = VOS_STATUS_SUCCESS;
goto end;
}
#endif
if (wma_handle->ack_work_ctx) {
vos_flush_work(&wma_handle->ack_work_ctx->ack_cmp_work);
adf_os_mem_free(wma_handle->ack_work_ctx);
wma_handle->ack_work_ctx = NULL;
}
/* Destroy the timer for scan completion */
vos_status = vos_timer_destroy(&wma_handle->wma_scan_comp_timer);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to destroy the scan completion timer");
}
/* Destroy the timer for log completion */
vos_status = vos_timer_destroy(&wma_handle->log_completion_timer);
if (vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to destroy the log completion timer");
}
if (VOS_FTM_MODE != vos_get_conparam()) {
/* Destroy firmware time stamp sync timer */
vos_status = vos_timer_destroy(&wma_handle->wma_fw_time_sync_timer);
if (vos_status != VOS_STATUS_SUCCESS)
WMA_LOGE(FL("Failed to destroy the fw time sync timer"));
}
/* There's no need suspend target which is already down during SSR. */
if (!vos_is_logp_in_progress(VOS_MODULE_ID_HIF, NULL)) {
#ifdef HIF_USB
/* Suspend the target and enable interrupt */
if (wma_suspend_target(wma_handle, 0))
WMA_LOGE("Failed to suspend target");
#else
/* Suspend the target and disable interrupt */
if (wma_suspend_target(wma_handle, 1))
WMA_LOGE("Failed to suspend target");
#endif
}
/* clean up ll-queue for all vdev */
for (i = 0; i < wma_handle->max_bssid; i++) {
if (wma_handle->interfaces[i].handle &&
wma_handle->interfaces[i].vdev_up) {
ol_txrx_vdev_flush(wma_handle->interfaces[i].handle);
}
}
vos_status = wma_tx_detach(wma_handle);
if(vos_status != VOS_STATUS_SUCCESS) {
WMA_LOGP("%s: Failed to deregister tx management", __func__);
goto end;
}
end:
WMA_LOGD("%s: Exit", __func__);
return vos_status;
}
static void wma_cleanup_vdev_resp(tp_wma_handle wma)
{
struct wma_target_req *msg, *tmp;
adf_os_spin_lock_bh(&wma->vdev_respq_lock);
list_for_each_entry_safe(msg, tmp,
&wma->vdev_resp_queue, node) {
list_del(&msg->node);
vos_timer_destroy(&msg->event_timeout);
adf_os_mem_free(msg);
}
adf_os_spin_unlock_bh(&wma->vdev_respq_lock);
}
VOS_STATUS wma_wmi_service_close(v_VOID_t *vos_ctx)
{
tp_wma_handle wma_handle;
struct beacon_info *bcn;
int i;
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_LOGE("%s: Invalid wma handle", __func__);
return VOS_STATUS_E_INVAL;
}
/* validate the wmi handle */
if (NULL == wma_handle->wmi_handle) {
WMA_LOGE("%s: Invalid wmi handle", __func__);
return VOS_STATUS_E_INVAL;
}
/* dettach the wmi serice */
WMA_LOGD("calling wmi_unified_detach");
wmi_unified_detach(wma_handle->wmi_handle);
wma_handle->wmi_handle = NULL;
for (i = 0; i < wma_handle->max_bssid; i++) {
bcn = wma_handle->interfaces[i].beacon;
if (bcn) {
if (bcn->dma_mapped)
adf_nbuf_unmap_single(wma_handle->adf_dev,
bcn->buf, ADF_OS_DMA_TO_DEVICE);
adf_nbuf_free(bcn->buf);
vos_mem_free(bcn);
wma_handle->interfaces[i].beacon = NULL;
}
if (wma_handle->interfaces[i].handle) {
adf_os_mem_free(wma_handle->interfaces[i].handle);
wma_handle->interfaces[i].handle = NULL;
}
if (wma_handle->interfaces[i].addBssStaContext) {
adf_os_mem_free(wma_handle->
interfaces[i].addBssStaContext);
wma_handle->interfaces[i].addBssStaContext = NULL;
}
if (wma_handle->interfaces[i].del_staself_req) {
vos_mem_free(wma_handle->interfaces[i].del_staself_req);
wma_handle->interfaces[i].del_staself_req = NULL;
}
}
vos_mem_free(wma_handle->interfaces);
/* free the wma_handle */
vos_free_context(wma_handle->vos_context, VOS_MODULE_ID_WDA, wma_handle);
adf_os_mem_free(((pVosContextType) vos_ctx)->cfg_ctx);
WMA_LOGD("%s: Exit", __func__);
return VOS_STATUS_SUCCESS;
}
/**
* wma_wmi_work_close() - close the work queue items associated with WMI
* @vos_ctx: Pointer to vos context
*
* This function closes work queue items associated with WMI, but not fully
* closes WMI service.
*
* Return: VOS_STATUS_SUCCESS if work close is successful. Otherwise
* proper error codes.
*/
VOS_STATUS wma_wmi_work_close(v_VOID_t *vos_ctx)
{
tp_wma_handle wma_handle;
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_LOGE("%s: Invalid wma handle", __func__);
return VOS_STATUS_E_INVAL;
}
/* validate the wmi handle */
if (NULL == wma_handle->wmi_handle) {
WMA_LOGE("%s: Invalid wmi handle", __func__);
return VOS_STATUS_E_INVAL;
}
/* remove the wmi work */
WMA_LOGD("calling wmi_unified_remove_work");
wmi_unified_remove_work(wma_handle->wmi_handle);
return VOS_STATUS_SUCCESS;
}
/*
* Detach DFS methods
*/
static void wma_dfs_detach(struct ieee80211com *dfs_ic)
{
dfs_detach(dfs_ic);
adf_os_spinlock_destroy(&dfs_ic->chan_lock);
if (NULL != dfs_ic->ic_curchan) {
OS_FREE(dfs_ic->ic_curchan);
dfs_ic->ic_curchan = NULL;
}
OS_FREE(dfs_ic);
}
/* function : wma_close
* Description :
* Args :
* Returns :
*/
VOS_STATUS wma_close(v_VOID_t *vos_ctx)
{
tp_wma_handle wma_handle;
u_int32_t idx;
u_int8_t ptrn_id;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
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_LOGE("%s: Invalid wma handle", __func__);
return VOS_STATUS_E_INVAL;
}
/* validate the wmi handle */
if (NULL == wma_handle->wmi_handle) {
WMA_LOGP("%s: Invalid wmi handle", __func__);
return VOS_STATUS_E_INVAL;
}
if (wma_handle->events_logs_list) {
vos_mem_free(wma_handle->events_logs_list);
wma_handle->events_logs_list = NULL;
WMA_LOGD("%s: Event log list freed", __func__);
}
if (wma_handle->link_stats_results) {
vos_mem_free(wma_handle->link_stats_results);
wma_handle->link_stats_results = NULL;
}
/* Free wow pattern cache */
for (ptrn_id = 0; ptrn_id < wma_handle->wlan_resource_config.num_wow_filters;
ptrn_id++)
wma_free_wow_ptrn(wma_handle, ptrn_id);
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);
}
vos_mem_zero(&wma_handle->wow, sizeof(struct wma_wow));
wma_runtime_context_deinit(wma_handle);
/* unregister Firmware debug log */
vos_status = dbglog_deinit(wma_handle->wmi_handle);
if(vos_status != VOS_STATUS_SUCCESS)
WMA_LOGP("%s: dbglog_deinit failed", __func__);
/* close the vos events */
vos_event_destroy(&wma_handle->wma_ready_event);
vos_event_destroy(&wma_handle->target_suspend);
vos_event_destroy(&wma_handle->wma_resume_event);
vos_event_destroy(&wma_handle->wow_tx_complete);
vos_event_destroy(&wma_handle->runtime_suspend);
vos_event_destroy(&wma_handle->recovery_event);
/* Destroy Tx Frame Complete event */
vos_event_destroy(&wma_handle->tx_frm_download_comp_event);
wma_cleanup_vdev_resp(wma_handle);
for(idx = 0; idx < wma_handle->num_mem_chunks; ++idx) {
adf_os_mem_free_consistent(
wma_handle->adf_dev,
wma_handle->mem_chunks[idx].len,
wma_handle->mem_chunks[idx].vaddr,
wma_handle->mem_chunks[idx].paddr,
adf_os_get_dma_mem_context(
(&(wma_handle->mem_chunks[idx])),
memctx));
}
#if defined(QCA_WIFI_FTM)
/* Detach UTF and unregister the handler */
if (vos_get_conparam() == VOS_FTM_MODE)
wma_utf_detach(wma_handle);
#endif
if (NULL != wma_handle->dfs_ic){
wma_dfs_detach(wma_handle->dfs_ic);
wma_handle->dfs_ic = NULL;
}
if (NULL != wma_handle->pGetRssiReq) {
adf_os_mem_free(wma_handle->pGetRssiReq);
wma_handle->pGetRssiReq = NULL;
}
wma_ndp_unregister_all_event_handlers(wma_handle);
WMA_LOGD("%s: Exit", __func__);
return VOS_STATUS_SUCCESS;
}
static v_VOID_t wma_update_fw_config(tp_wma_handle wma_handle,
struct wma_target_cap *tgt_cap)
{
/*
* tgt_cap contains default target resource configuration
* which can be modified here, if required
*/
/* Override the no. of max fragments as per platform configuration */
tgt_cap->wlan_resource_config.max_frag_entries =
MIN(QCA_OL_11AC_TX_MAX_FRAGS, wma_handle->max_frag_entry);
wma_handle->max_frag_entry = tgt_cap->wlan_resource_config.max_frag_entries;
/* Update no. of maxWoWFilters depending on BPF service */
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_BPF_OFFLOAD))
tgt_cap->wlan_resource_config.num_wow_filters =
WMA_STA_WOW_DEFAULT_PTRN_MAX;
}
/**
* allocate a chunk of memory at the index indicated and
* if allocation fail allocate smallest size possiblr and
* return number of units allocated.
*/
static u_int32_t wma_alloc_host_mem_chunk(tp_wma_handle wma_handle,
u_int32_t req_id, u_int32_t idx,
u_int32_t num_units,
u_int32_t unit_len)
{
adf_os_dma_addr_t paddr;
if (!num_units || !unit_len) {
return 0;
}
wma_handle->mem_chunks[idx].vaddr = NULL ;
/** reduce the requested allocation by half until allocation succeeds */
while(wma_handle->mem_chunks[idx].vaddr == NULL && num_units ) {
wma_handle->mem_chunks[idx].vaddr = adf_os_mem_alloc_consistent(
wma_handle->adf_dev, num_units*unit_len, &paddr,
adf_os_get_dma_mem_context(
(&(wma_handle->mem_chunks[idx])),
memctx));
if(wma_handle->mem_chunks[idx].vaddr == NULL) {
num_units = (num_units >> 1) ; /* reduce length by half */
} else {
wma_handle->mem_chunks[idx].paddr = paddr;
wma_handle->mem_chunks[idx].len = num_units*unit_len;
wma_handle->mem_chunks[idx].req_id = req_id;
}
}
return num_units;
}
#define HOST_MEM_SIZE_UNIT 4
/*
* allocate amount of memory requested by FW.
*/
static void wma_alloc_host_mem(tp_wma_handle wma_handle, u_int32_t req_id,
u_int32_t num_units, u_int32_t unit_len)
{
u_int32_t remaining_units,allocated_units, idx;
/* adjust the length to nearest multiple of unit size */
unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) &
(~(HOST_MEM_SIZE_UNIT - 1));
idx = wma_handle->num_mem_chunks ;
remaining_units = num_units;
while(remaining_units) {
allocated_units = wma_alloc_host_mem_chunk(wma_handle, req_id,
idx, remaining_units,
unit_len);
if (allocated_units == 0) {
WMA_LOGE("FAILED TO ALLOCATED memory unit len %d"
" units requested %d units allocated %d ",
unit_len, num_units,
(num_units - remaining_units));
wma_handle->num_mem_chunks = idx;
break;
}
remaining_units -= allocated_units;
++idx;
if (idx == MAX_MEM_CHUNKS ) {
WMA_LOGE("RWACHED MAX CHUNK LIMIT for memory units %d"
" unit len %d requested by FW,"
" only allocated %d ",
num_units,unit_len,
(num_units - remaining_units));
wma_handle->num_mem_chunks = idx;
break;
}
}
wma_handle->num_mem_chunks = idx;
}
static inline void wma_update_target_services(tp_wma_handle wh,
struct hdd_tgt_services *cfg)
{
/* STA power save */
cfg->sta_power_save = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_STA_PWRSAVE);
/* Enable UAPSD */
cfg->uapsd = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_AP_UAPSD);
/* Update AP DFS service */
cfg->ap_dfs = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_AP_DFS);
/* Enable 11AC */
cfg->en_11ac = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_11AC);
if (cfg->en_11ac)
gFwWlanFeatCaps |= (1 << DOT11AC);
/* Proactive ARP response */
gFwWlanFeatCaps |= (1 << WLAN_PERIODIC_TX_PTRN);
/* Enable WOW */
gFwWlanFeatCaps |= (1 << WOW);
/* ARP offload */
cfg->arp_offload = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_ARPNS_OFFLOAD);
/* Adaptive early-rx */
cfg->early_rx = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_EARLY_RX);
#ifdef FEATURE_WLAN_SCAN_PNO
/* PNO offload */
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_NLO))
cfg->pno_offload = TRUE;
#endif
#ifdef FEATURE_WLAN_EXTSCAN
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_EXTSCAN)) {
gFwWlanFeatCaps |= (1 << EXTENDED_SCAN);
}
#endif
cfg->lte_coex_ant_share = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_LTE_ANT_SHARE_SUPPORT);
cfg->per_band_chainmask_supp = WMI_SERVICE_IS_ENABLED(
wh->wmi_service_bitmap,
WMI_SERVICE_PER_BAND_CHAINMASK_SUPPORT);
wh->per_band_chainmask_supp = cfg->per_band_chainmask_supp;
#ifdef FEATURE_WLAN_TDLS
/* Enable TDLS */
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_TDLS)) {
cfg->en_tdls = 1;
gFwWlanFeatCaps |= (1 << TDLS);
}
/* Enable advanced TDLS features */
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_TDLS_OFFCHAN)) {
cfg->en_tdls_offchan = 1;
gFwWlanFeatCaps |= (1 << TDLS_OFF_CHANNEL);
}
cfg->en_tdls_uapsd_buf_sta = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_TDLS_UAPSD_BUFFER_STA);
cfg->en_tdls_uapsd_sleep_sta = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_TDLS_UAPSD_SLEEP_STA);
#endif
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_BEACON_OFFLOAD))
cfg->beacon_offload = TRUE;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
/* Enable Roam Offload */
cfg->en_roam_offload = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_ROAM_HO_OFFLOAD);
#endif
#ifdef WLAN_FEATURE_NAN
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_NAN))
gFwWlanFeatCaps |= (1 << NAN);
#endif
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_RTT))
gFwWlanFeatCaps |= (1 << RTT);
#ifdef SAP_AUTH_OFFLOAD
cfg->sap_auth_offload_service =
WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_SAP_AUTH_OFFLOAD);
#endif
cfg->chain_mask_2g = wh->txrx_chainmask & 0xFF;
cfg->chain_mask_5g = (wh->txrx_chainmask >> 16 ) & 0xFF;
if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap,
WMI_SERVICE_PEER_STATS_INFO))
cfg->get_peer_info_enabled = 1;
}
static inline void wma_update_target_ht_cap(tp_wma_handle wh,
struct hdd_tgt_ht_cap *cfg)
{
/* RX STBC */
cfg->ht_rx_stbc = !!(wh->ht_cap_info & WMI_HT_CAP_RX_STBC);
/* TX STBC */
cfg->ht_tx_stbc = !!(wh->ht_cap_info & WMI_HT_CAP_TX_STBC);
/* MPDU density */
cfg->mpdu_density = wh->ht_cap_info & WMI_HT_CAP_MPDU_DENSITY;
/* HT RX LDPC */
cfg->ht_rx_ldpc = !!(wh->ht_cap_info & WMI_HT_CAP_LDPC);
/* HT SGI */
cfg->ht_sgi_20 = !!(wh->ht_cap_info & WMI_HT_CAP_HT20_SGI);
cfg->ht_sgi_40 = !!(wh->ht_cap_info & WMI_HT_CAP_HT40_SGI);
/* RF chains */
cfg->num_rf_chains = wh->num_rf_chains;
WMA_LOGD("%s: ht_cap_info - %x ht_rx_stbc - %d, ht_tx_stbc - %d, mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d, ht_sgi_40 - %d num_rf_chains - %d ",
__func__,
wh->ht_cap_info, cfg->ht_rx_stbc, cfg->ht_tx_stbc,
cfg->mpdu_density, cfg->ht_rx_ldpc, cfg->ht_sgi_20,
cfg->ht_sgi_40, cfg->num_rf_chains);
}
#ifdef WLAN_FEATURE_11AC
static inline void wma_update_target_vht_cap(tp_wma_handle wh,
struct hdd_tgt_vht_cap *cfg)
{
/* Max MPDU length */
if (wh->vht_cap_info & IEEE80211_VHTCAP_MAX_MPDU_LEN_3839)
cfg->vht_max_mpdu = 0;
else if (wh->vht_cap_info & IEEE80211_VHTCAP_MAX_MPDU_LEN_7935)
cfg->vht_max_mpdu = 1;
else if (wh->vht_cap_info & IEEE80211_VHTCAP_MAX_MPDU_LEN_11454)
cfg->vht_max_mpdu = 2;
else
cfg->vht_max_mpdu = 0;
/* supported channel width */
if (wh->vht_cap_info & IEEE80211_VHTCAP_SUP_CHAN_WIDTH_80)
cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ;
else if (wh->vht_cap_info & IEEE80211_VHTCAP_SUP_CHAN_WIDTH_160)
cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_160MHZ;
else if (wh->vht_cap_info & IEEE80211_VHTCAP_SUP_CHAN_WIDTH_80_160) {
cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ;
cfg->supp_chan_width |= 1 << eHT_CHANNEL_WIDTH_160MHZ;
}
else
cfg->supp_chan_width = 0;
/* LDPC capability */
cfg->vht_rx_ldpc = wh->vht_cap_info & IEEE80211_VHTCAP_RX_LDPC;
/* Guard interval */
cfg->vht_short_gi_80 = wh->vht_cap_info & IEEE80211_VHTCAP_SHORTGI_80;
cfg->vht_short_gi_160 = wh->vht_cap_info & IEEE80211_VHTCAP_SHORTGI_160;
/* TX STBC capability */
cfg->vht_tx_stbc = wh->vht_cap_info & IEEE80211_VHTCAP_TX_STBC;
/* RX STBC capability */
cfg->vht_rx_stbc = wh->vht_cap_info & IEEE80211_VHTCAP_RX_STBC;
cfg->vht_max_ampdu_len_exp = (wh->vht_cap_info &
IEEE80211_VHTCAP_MAX_AMPDU_LEN_EXP)
>> IEEE80211_VHTCAP_MAX_AMPDU_LEN_EXP_S;
/* SU beamformer cap */
cfg->vht_su_bformer = wh->vht_cap_info & IEEE80211_VHTCAP_SU_BFORMER;
/* SU beamformee cap */
cfg->vht_su_bformee = wh->vht_cap_info & IEEE80211_VHTCAP_SU_BFORMEE;
/* MU beamformer cap */
cfg->vht_mu_bformer = wh->vht_cap_info & IEEE80211_VHTCAP_MU_BFORMER;
/* MU beamformee cap */
cfg->vht_mu_bformee = wh->vht_cap_info & IEEE80211_VHTCAP_MU_BFORMEE;
/* VHT Max AMPDU Len exp */
cfg->vht_max_ampdu_len_exp = wh->vht_cap_info &
IEEE80211_VHTCAP_MAX_AMPDU_LEN_EXP;
/* VHT TXOP PS cap */
cfg->vht_txop_ps = wh->vht_cap_info & IEEE80211_VHTCAP_TXOP_PS;
WMA_LOGD("%s: max_mpdu %d supp_chan_width %x rx_ldpc %x short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x su_bformee %x mu_bformee %x max_ampdu_len_exp %d",
__func__, cfg->vht_max_mpdu, cfg->supp_chan_width,
cfg->vht_rx_ldpc, cfg->vht_short_gi_80, cfg->vht_tx_stbc,
cfg->vht_rx_stbc, cfg->vht_txop_ps, cfg->vht_su_bformee,
cfg->vht_mu_bformee, cfg->vht_max_ampdu_len_exp);
}
#endif /* #ifdef WLAN_FEATURE_11AC */
#ifdef FEATURE_WLAN_RA_FILTERING
static void wma_update_ra_rate_limit(tp_wma_handle wma_handle,
struct hdd_tgt_cfg *cfg)
{
cfg->is_ra_rate_limit_enabled = wma_handle->IsRArateLimitEnabled;
}
#else
static void wma_update_ra_rate_limit(tp_wma_handle wma_handle,
struct hdd_tgt_cfg *cfg)
{
}
#endif
static void wma_update_hdd_cfg(tp_wma_handle wma_handle)
{
struct hdd_tgt_cfg hdd_tgt_cfg;
void *hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD,
wma_handle->vos_context);
hdd_tgt_cfg.reg_domain = wma_handle->reg_cap.eeprom_rd;
hdd_tgt_cfg.eeprom_rd_ext = wma_handle->reg_cap.eeprom_rd_ext;
hdd_tgt_cfg.sub_20_support = wma_handle->sub_20_support;
switch (wma_handle->phy_capability) {
case WMI_11G_CAPABILITY:
case WMI_11NG_CAPABILITY:
hdd_tgt_cfg.band_cap = eCSR_BAND_24;
break;
case WMI_11A_CAPABILITY:
case WMI_11NA_CAPABILITY:
case WMI_11AC_CAPABILITY:
hdd_tgt_cfg.band_cap = eCSR_BAND_5G;
break;
case WMI_11AG_CAPABILITY:
case WMI_11NAG_CAPABILITY:
default:
hdd_tgt_cfg.band_cap = eCSR_BAND_ALL;
}
hdd_tgt_cfg.max_intf_count = wma_handle->wlan_resource_config.num_vdevs;
adf_os_mem_copy(hdd_tgt_cfg.hw_macaddr.bytes, wma_handle->hwaddr,
ATH_MAC_LEN);
wma_update_target_services(wma_handle, &hdd_tgt_cfg.services);
wma_update_target_ht_cap(wma_handle, &hdd_tgt_cfg.ht_cap);
#ifdef WLAN_FEATURE_11AC
wma_update_target_vht_cap(wma_handle, &hdd_tgt_cfg.vht_cap);
#endif /* #ifdef WLAN_FEATURE_11AC */
hdd_tgt_cfg.target_fw_version = wma_handle->target_fw_version;
#ifdef WLAN_FEATURE_LPSS
hdd_tgt_cfg.lpss_support = wma_handle->lpss_support;
#endif
hdd_tgt_cfg.ap_arpns_support = wma_handle->ap_arpns_support;
hdd_tgt_cfg.fine_time_measurement_cap =
wma_handle->fine_time_measurement_cap;
hdd_tgt_cfg.wmi_max_len = wmi_get_max_msg_len(wma_handle->wmi_handle)
- WMI_TLV_HEADROOM;
hdd_tgt_cfg.bpf_enabled = wma_handle->bpf_enabled;
wma_update_ra_rate_limit(wma_handle, &hdd_tgt_cfg);
wma_update_hdd_cfg_ndp(wma_handle, &hdd_tgt_cfg);
wma_setup_egap_support(&hdd_tgt_cfg, wma_handle);
hdd_tgt_cfg.max_mc_addr_list =
wma_handle->wlan_resource_config.num_multicast_filter_entries;
wma_handle->tgt_cfg_update_cb(hdd_ctx, &hdd_tgt_cfg);
}
static wmi_buf_t wma_setup_wmi_init_msg(tp_wma_handle wma_handle,
wmi_service_ready_event_fixed_param *ev,
WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf,
v_SIZE_t *len)
{
wmi_buf_t buf;
wmi_init_cmd_fixed_param *cmd;
wlan_host_mem_req *ev_mem_reqs;
wmi_abi_version my_vers;
int num_whitelist;
u_int8_t *buf_ptr;
wmi_resource_config *resource_cfg;
wlan_host_memory_chunk *host_mem_chunks;
u_int32_t mem_chunk_len = 0;
u_int16_t idx;
u_int32_t num_units;
*len = sizeof(*cmd) + sizeof(wmi_resource_config) + WMI_TLV_HDR_SIZE;
mem_chunk_len = (sizeof(wlan_host_memory_chunk) * MAX_MEM_CHUNKS);
buf = wmi_buf_alloc(wma_handle->wmi_handle, *len + mem_chunk_len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return NULL;
}
ev_mem_reqs = param_buf->mem_reqs;
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_init_cmd_fixed_param *) buf_ptr;
resource_cfg = (wmi_resource_config *) (buf_ptr + sizeof(*cmd));
host_mem_chunks = (wlan_host_memory_chunk*)
(buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config)
+ WMI_TLV_HDR_SIZE);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_init_cmd_fixed_param));
*resource_cfg = wma_handle->wlan_resource_config;
WMITLV_SET_HDR(&resource_cfg->tlv_header,
WMITLV_TAG_STRUC_wmi_resource_config,
WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config));
/* allocate memory requested by FW */
if (ev->num_mem_reqs > WMI_MAX_MEM_REQS) {
VOS_ASSERT(0);
wmi_buf_free(buf);
return NULL;
}
cmd->num_host_mem_chunks = 0;
for(idx = 0; idx < ev->num_mem_reqs; ++idx) {
num_units = ev_mem_reqs[idx].num_units;
if (ev_mem_reqs[idx].num_unit_info & NUM_UNITS_IS_NUM_PEERS) {
/*
* number of units to allocate is number
* of peers, 1 extra for self peer on
* target. this needs to be fied, host
* and target can get out of sync
*/
num_units = resource_cfg->num_peers + 1;
}
WMA_LOGD("idx %d req %d num_units %d num_unit_info %d unit size %d actual units %d ",
idx, ev_mem_reqs[idx].req_id,
ev_mem_reqs[idx].num_units,
ev_mem_reqs[idx].num_unit_info,
ev_mem_reqs[idx].unit_size,
num_units);
wma_alloc_host_mem(wma_handle, ev_mem_reqs[idx].req_id,
num_units, ev_mem_reqs[idx].unit_size);
}
for(idx = 0; idx < wma_handle->num_mem_chunks; ++idx) {
WMITLV_SET_HDR(&(host_mem_chunks[idx].tlv_header),
WMITLV_TAG_STRUC_wlan_host_memory_chunk,
WMITLV_GET_STRUCT_TLVLEN(wlan_host_memory_chunk));
host_mem_chunks[idx].ptr = wma_handle->mem_chunks[idx].paddr;
host_mem_chunks[idx].size = wma_handle->mem_chunks[idx].len;
host_mem_chunks[idx].req_id =
wma_handle->mem_chunks[idx].req_id;
WMA_LOGD("chunk %d len %d requested ,ptr 0x%x ",
idx, host_mem_chunks[idx].size,
host_mem_chunks[idx].ptr) ;
}
cmd->num_host_mem_chunks = wma_handle->num_mem_chunks;
*len += (wma_handle->num_mem_chunks * sizeof(wlan_host_memory_chunk));
WMITLV_SET_HDR((buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config)),
WMITLV_TAG_ARRAY_STRUC,
(sizeof(wlan_host_memory_chunk) *
wma_handle->num_mem_chunks));
vos_mem_copy(&wma_handle->target_abi_vers,
&param_buf->fixed_param->fw_abi_vers,
sizeof(wmi_abi_version));
num_whitelist = sizeof(version_whitelist) /
sizeof(wmi_whitelist_version_info);
my_vers.abi_version_0 = WMI_ABI_VERSION_0;
my_vers.abi_version_1 = WMI_ABI_VERSION_1;
my_vers.abi_version_ns_0 = WMI_ABI_VERSION_NS_0;
my_vers.abi_version_ns_1 = WMI_ABI_VERSION_NS_1;
my_vers.abi_version_ns_2 = WMI_ABI_VERSION_NS_2;
my_vers.abi_version_ns_3 = WMI_ABI_VERSION_NS_3;
wmi_cmp_and_set_abi_version(num_whitelist, version_whitelist,
&my_vers, &param_buf->fixed_param->fw_abi_vers,
&cmd->host_abi_vers);
WMA_LOGD("%s: INIT_CMD version: %d, %d, 0x%x, 0x%x, 0x%x, 0x%x",
__func__, WMI_VER_GET_MAJOR(cmd->host_abi_vers.abi_version_0),
WMI_VER_GET_MINOR(cmd->host_abi_vers.abi_version_0),
cmd->host_abi_vers.abi_version_ns_0,
cmd->host_abi_vers.abi_version_ns_1,
cmd->host_abi_vers.abi_version_ns_2,
cmd->host_abi_vers.abi_version_ns_3);
vos_mem_copy(&wma_handle->final_abi_vers, &cmd->host_abi_vers,
sizeof(wmi_abi_version));
return buf;
}
/**
* wma_send_time_stamp_sync_cmd() - timer callback send timestamp to
* firmware to sync with host.
* @wma_handle: wma handle
*
* Return: void
*/
static void wma_send_time_stamp_sync_cmd(void *data)
{
tp_wma_handle wma_handle;
wmi_buf_t buf;
WMI_DBGLOG_TIME_STAMP_SYNC_CMD_fixed_param *time_stamp;
A_STATUS status = A_OK;
int len;
VOS_STATUS vos_status;
unsigned long time_ms;
wma_handle = (tp_wma_handle) data;
len = sizeof(*time_stamp);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGP(FL("wmi_buf_alloc failed"));
return;
}
time_stamp =
(WMI_DBGLOG_TIME_STAMP_SYNC_CMD_fixed_param *)
(wmi_buf_data(buf));
WMITLV_SET_HDR(&time_stamp->tlv_header,
WMITLV_TAG_STRUC_wmi_dbglog_time_stamp_sync_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
WMI_DBGLOG_TIME_STAMP_SYNC_CMD_fixed_param));
time_ms = vos_get_time_of_the_day_ms();
time_stamp->mode = WMI_TIME_STAMP_SYNC_MODE_MS;
time_stamp->time_stamp_low = time_ms &
WMA_FW_TIME_STAMP_LOW_MASK;
/*
* Send time_stamp_high 0 as the time converted from HR:MIN:SEC:MS to ms
* wont exceed 27 bit
*/
time_stamp->time_stamp_high = 0;
WMA_LOGD(FL("WMA --> DBGLOG_TIME_STAMP_SYNC_CMDID mode %d time_stamp low %d high %d"),
time_stamp->mode, time_stamp->time_stamp_low,
time_stamp->time_stamp_high);
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
len, WMI_DBGLOG_TIME_STAMP_SYNC_CMDID);
if (status != EOK) {
WMA_LOGE("Failed to send WMI_DBGLOG_TIME_STAMP_SYNC_CMDID command");
wmi_buf_free(buf);
}
/* Start/Restart the timer */
vos_status = vos_timer_start(&wma_handle->wma_fw_time_sync_timer,
WMA_FW_TIME_SYNC_TIMER);
if (vos_status != VOS_STATUS_SUCCESS)
WMA_LOGE("Failed to start the firmware time sync timer");
}
#ifdef FEATURE_WLAN_RA_FILTERING
static void wma_update_ra_limit(tp_wma_handle wma_handle)
{
if (wma_handle->bpf_enabled)
wma_handle->IsRArateLimitEnabled = false;
}
#else
static void wma_update_ra__limit(tp_wma_handle handle)
{
}
#endif
/* Process service ready event and send wmi_init command */
v_VOID_t wma_rx_service_ready_event(WMA_HANDLE handle, void *cmd_param_info)
{
wmi_buf_t buf;
v_SIZE_t len;
tp_wma_handle wma_handle = (tp_wma_handle) handle;
struct wma_target_cap target_cap;
WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf;
wmi_service_ready_event_fixed_param *ev;
int status;
WMA_LOGD("%s: Enter", __func__);
param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) cmd_param_info;
if (!(handle && param_buf)) {
WMA_LOGP("%s: Invalid arguments", __func__);
return;
}
ev = param_buf->fixed_param;
if (!ev) {
WMA_LOGP("%s: Invalid buffer", __func__);
return;
}
WMA_LOGA("WMA <-- WMI_SERVICE_READY_EVENTID");
if (ev->num_dbs_hw_modes > param_buf->num_wlan_dbs_hw_mode_list) {
WMA_LOGE("FW dbs_hw_mode entry %d more than value %d in TLV hdr",
ev->num_dbs_hw_modes,
param_buf->num_wlan_dbs_hw_mode_list);
return;
}
wma_handle->phy_capability = ev->phy_capability;
wma_handle->max_frag_entry = ev->max_frag_entry;
wma_handle->num_rf_chains = ev->num_rf_chains;
vos_mem_copy(&wma_handle->reg_cap, param_buf->hal_reg_capabilities,
sizeof(HAL_REG_CAPABILITIES));
wma_handle->ht_cap_info = ev->ht_cap_info;
#ifdef WLAN_FEATURE_11AC
wma_handle->vht_cap_info = ev->vht_cap_info;
wma_handle->vht_supp_mcs = ev->vht_supp_mcs;
#endif
wma_handle->txrx_chainmask = ev->txrx_chainmask;
wma_handle->target_fw_version = ev->fw_build_vers;
wma_handle->fine_time_measurement_cap = ev->wmi_fw_sub_feat_caps;
WMA_LOGD(FL("FW fine time meas cap: 0x%x"), ev->wmi_fw_sub_feat_caps);
WMA_LOGE("%s: Firmware build version : %08x",
__func__, ev->fw_build_vers);
if (ev->hw_bd_id) {
wma_handle->hw_bd_id = ev->hw_bd_id;
vos_mem_copy(wma_handle->hw_bd_info,
ev->hw_bd_info, sizeof(ev->hw_bd_info));
WMA_LOGE("%s: Board version: %x.%x",
__func__,
wma_handle->hw_bd_info[0],
wma_handle->hw_bd_info[1]);
} else {
wma_handle->hw_bd_id = 0;
vos_mem_zero(wma_handle->hw_bd_info,
sizeof(wma_handle->hw_bd_info));
WMA_LOGE("%s: Board version is unknown!", __func__);
}
/* TODO: Recheck below line to dump service ready event */
/* dbg_print_wmi_service_11ac(ev); */
/* wmi service is ready */
vos_mem_copy(wma_handle->wmi_service_bitmap,
param_buf->wmi_service_bitmap,
sizeof(wma_handle->wmi_service_bitmap));
/* SWBA event handler for beacon transmission */
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_HOST_SWBA_EVENTID,
wma_beacon_swba_handler);
if (status) {
WMA_LOGE("Failed to register swba beacon event cb");
return;
}
#ifdef WLAN_FEATURE_LPSS
wma_handle->lpss_support =
WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_LPASS);
#endif
/*
* This Service bit is added to check for ARP/NS offload
* support for LL or HL targets
*/
wma_handle->ap_arpns_support =
WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_AP_ARPNS_OFFLOAD);
wma_handle->bpf_enabled = (wma_handle->bpf_packet_filter_enable &&
WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_BPF_OFFLOAD));
wma_update_ra_limit(wma_handle);
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_CSA_OFFLOAD)) {
WMA_LOGD("%s: FW support CSA offload capability", __func__);
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_CSA_HANDLING_EVENTID,
wma_csa_offload_handler);
if (status) {
WMA_LOGE("Failed to register CSA offload event cb");
return;
}
}
#ifdef WLAN_FEATURE_GTK_OFFLOAD
if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_GTK_OFFLOAD)) {
status = wmi_unified_register_event_handler(
wma_handle->wmi_handle,
WMI_GTK_OFFLOAD_STATUS_EVENTID,
wma_gtk_offload_status_event);
if (status) {
WMA_LOGE("Failed to register GTK offload event cb");
return;
}
}
#endif
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_P2P_NOA_EVENTID,
wma_p2p_noa_event_handler);
if (status) {
WMA_LOGE("Failed to register WMI_P2P_NOA_EVENTID callback");
return;
}
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_TBTTOFFSET_UPDATE_EVENTID,
wma_tbttoffset_update_event_handler);
if (status) {
WMA_LOGE("Failed to register WMI_TBTTOFFSET_UPDATE_EVENTID callback");
return;
}
/* register the Enhanced Green AP event handler */
wma_register_egap_event_handle(wma_handle);
/* Initialize the log supported event handler */
status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID,
wma_log_supported_evt_handler);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to register log supported event cb");
return;
}
ol_tx_mark_first_wakeup_packet(
WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_MARK_FIRST_WAKEUP_PACKET));
wma_handle->nan_datapath_enabled =
WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_NAN_DATA);
vos_mem_copy(target_cap.wmi_service_bitmap,
param_buf->wmi_service_bitmap,
sizeof(wma_handle->wmi_service_bitmap));
target_cap.wlan_resource_config = wma_handle->wlan_resource_config;
wma_update_fw_config(wma_handle, &target_cap);
vos_mem_copy(wma_handle->wmi_service_bitmap, target_cap.wmi_service_bitmap,
sizeof(wma_handle->wmi_service_bitmap));
wma_handle->wlan_resource_config = target_cap.wlan_resource_config;
buf = wma_setup_wmi_init_msg(wma_handle, ev, param_buf, &len);
if (!buf) {
WMA_LOGE("Failed to setup buffer for wma init command");
return;
}
WMA_LOGA("WMA --> WMI_INIT_CMDID");
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, WMI_INIT_CMDID);
if (status != EOK) {
WMA_LOGE("Failed to send WMI_INIT_CMDID command");
wmi_buf_free(buf);
return;
}
}
/* function : wma_rx_ready_event
* Description :
* Args :
* Retruns :
*/
v_VOID_t wma_rx_ready_event(WMA_HANDLE handle, void *cmd_param_info)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
WMI_READY_EVENTID_param_tlvs *param_buf = NULL;
wmi_ready_event_fixed_param *ev = NULL;
WMA_LOGD("%s: Enter", __func__);
param_buf = (WMI_READY_EVENTID_param_tlvs *) cmd_param_info;
if (!(wma_handle && param_buf)) {
WMA_LOGP("%s: Invalid arguments", __func__);
VOS_ASSERT(0);
return;
}
WMA_LOGA("WMA <-- WMI_READY_EVENTID");
ev = param_buf->fixed_param;
wma_handle->sub_20_support =
WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
WMI_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT);
/* Indicate to the waiting thread that the ready
* event was received */
wma_handle->wmi_ready = TRUE;
wma_handle->wlan_init_status = ev->status;
/*
* We need to check the WMI versions and make sure both
* host and fw are compatible.
*/
if (!wmi_versions_are_compatible(&wma_handle->final_abi_vers,
&ev->fw_abi_vers)) {
/*
* Error: Our host version and the given firmware version
* are incompatible.
*/
WMA_LOGE("%s: Error: Incompatible WMI version."
"Host: %d,%d,0x%x 0x%x 0x%x 0x%x, FW: %d,%d,0x%x 0x%x 0x%x 0x%x",
__func__,
WMI_VER_GET_MAJOR(
wma_handle->final_abi_vers.abi_version_0),
WMI_VER_GET_MINOR(
wma_handle->final_abi_vers.abi_version_0),
wma_handle->final_abi_vers.abi_version_ns_0,
wma_handle->final_abi_vers.abi_version_ns_1,
wma_handle->final_abi_vers.abi_version_ns_2,
wma_handle->final_abi_vers.abi_version_ns_3,
WMI_VER_GET_MAJOR(ev->fw_abi_vers.abi_version_0),
WMI_VER_GET_MINOR(ev->fw_abi_vers.abi_version_0),
ev->fw_abi_vers.abi_version_ns_0,
ev->fw_abi_vers.abi_version_ns_1,
ev->fw_abi_vers.abi_version_ns_2,
ev->fw_abi_vers.abi_version_ns_3);
if (wma_handle->wlan_init_status == WLAN_INIT_STATUS_SUCCESS) {
/* Failed this connection to FW */
wma_handle->wlan_init_status =
WLAN_INIT_STATUS_GEN_FAILED;
}
}
vos_mem_copy(&wma_handle->final_abi_vers, &ev->fw_abi_vers,
sizeof(wmi_abi_version));
vos_mem_copy(&wma_handle->target_abi_vers, &ev->fw_abi_vers,
sizeof(wmi_abi_version));
/* copy the mac addr */
WMI_MAC_ADDR_TO_CHAR_ARRAY (&ev->mac_addr, wma_handle->myaddr);
WMI_MAC_ADDR_TO_CHAR_ARRAY (&ev->mac_addr, wma_handle->hwaddr);
wma_update_hdd_cfg(wma_handle);
vos_event_set(&wma_handle->wma_ready_event);
WMA_LOGD("Exit");
}
int wma_set_peer_param(void *wma_ctx, u_int8_t *peer_addr, u_int32_t param_id,
u_int32_t param_value, u_int32_t vdev_id)
{
tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx;
wmi_peer_set_param_cmd_fixed_param *cmd;
wmi_buf_t buf;
int err;
buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (!buf) {
WMA_LOGE("Failed to allocate buffer to send set_param cmd");
return -ENOMEM;
}
cmd = (wmi_peer_set_param_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_peer_set_param_cmd_fixed_param));
cmd->vdev_id = vdev_id;
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr);
cmd->param_id = param_id;
cmd->param_value = param_value;
err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf,
sizeof(wmi_peer_set_param_cmd_fixed_param),
WMI_PEER_SET_PARAM_CMDID);
if (err) {
WMA_LOGE("Failed to send set_param cmd");
wmi_buf_free(buf);
return -EIO;
}
return 0;
}
static void
wma_decap_to_8023 (adf_nbuf_t msdu, struct wma_decap_info_t *info)
{
struct llc_snap_hdr_t *llc_hdr;
u_int16_t ether_type;
u_int16_t l2_hdr_space;
struct ieee80211_qosframe_addr4 *wh;
u_int8_t local_buf[ETHERNET_HDR_LEN];
u_int8_t *buf;
struct ethernet_hdr_t *ethr_hdr;
buf = (u_int8_t *)adf_nbuf_data(msdu);
llc_hdr = (struct llc_snap_hdr_t *)buf;
ether_type = (llc_hdr->ethertype[0] << 8)|llc_hdr->ethertype[1];
/* do llc remove if needed */
l2_hdr_space = 0;
if (IS_SNAP(llc_hdr)) {
if (IS_BTEP(llc_hdr)) {
/* remove llc*/
l2_hdr_space += sizeof(struct llc_snap_hdr_t);
llc_hdr = NULL;
} else if (IS_RFC1042(llc_hdr)) {
if (!(ether_type == ETHERTYPE_AARP ||
ether_type == ETHERTYPE_IPX)) {
/* remove llc*/
l2_hdr_space += sizeof(struct llc_snap_hdr_t);
llc_hdr = NULL;
}
}
}
if (l2_hdr_space > ETHERNET_HDR_LEN) {
buf = adf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN);
} else if (l2_hdr_space < ETHERNET_HDR_LEN) {
buf = adf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space);
}
/* mpdu hdr should be present in info,re-create ethr_hdr based on mpdu hdr*/
wh = (struct ieee80211_qosframe_addr4 *)info->hdr;
ethr_hdr = (struct ethernet_hdr_t *)local_buf;
switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
case IEEE80211_FC1_DIR_NODS:
adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr1,
ETHERNET_ADDR_LEN);
adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr2,
ETHERNET_ADDR_LEN);
break;
case IEEE80211_FC1_DIR_TODS:
adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr3,
ETHERNET_ADDR_LEN);
adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr2,
ETHERNET_ADDR_LEN);
break;
case IEEE80211_FC1_DIR_FROMDS:
adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr1,
ETHERNET_ADDR_LEN);
adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr3,
ETHERNET_ADDR_LEN);
break;
case IEEE80211_FC1_DIR_DSTODS:
adf_os_mem_copy(ethr_hdr->dest_addr, wh->i_addr3,
ETHERNET_ADDR_LEN);
adf_os_mem_copy(ethr_hdr->src_addr, wh->i_addr4,
ETHERNET_ADDR_LEN);
break;
}
if (llc_hdr == NULL) {
ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff;
ethr_hdr->ethertype[1] = (ether_type) & 0xff;
} else {
u_int32_t pktlen = adf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype);
ether_type = (u_int16_t)pktlen;
ether_type = adf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t);
ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff;
ethr_hdr->ethertype[1] = (ether_type) & 0xff;
}
adf_os_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN);
}
static int32_t
wma_ieee80211_hdrsize(const void *data)
{
const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data;
int32_t size = sizeof(struct ieee80211_frame);
if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
size += IEEE80211_ADDR_LEN;
if (IEEE80211_QOS_HAS_SEQ(wh))
size += sizeof(u_int16_t);
return size;
}
/**
* WDA_TxPacket - Sends Tx Frame to TxRx
* This function sends the frame corresponding to the
* given vdev id.
* This is blocking call till the downloading of frame is complete.
*/
VOS_STATUS WDA_TxPacket(void *wma_context, void *tx_frame, u_int16_t frmLen,
eFrameType frmType, eFrameTxDir txDir, u_int8_t tid,
pWDATxRxCompFunc tx_frm_download_comp_cb, void *pData,
pWDAAckFnTxComp tx_frm_ota_comp_cb, u_int8_t tx_flag,
u_int8_t vdev_id, bool tdlsFlag)
{
tp_wma_handle wma_handle = (tp_wma_handle)(wma_context);
int32_t status;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
int32_t is_high_latency;
ol_txrx_vdev_handle txrx_vdev;
ol_txrx_pdev_handle txrx_pdev;
pVosContextType vos_handle;
enum frame_index tx_frm_index =
GENERIC_NODOWNLD_NOACK_COMP_INDEX;
tpSirMacFrameCtl pFc = (tpSirMacFrameCtl)(adf_nbuf_data(tx_frame));
u_int8_t use_6mbps = 0;
u_int8_t downld_comp_required = 0;
u_int16_t chanfreq;
#ifdef WLAN_FEATURE_11W
tANI_U8 *pFrame = NULL;
void *pPacket = NULL;
u_int16_t newFrmLen = 0;
#endif /* WLAN_FEATURE_11W */
struct wma_txrx_node *iface;
tpAniSirGlobal pMac;
#ifdef QCA_PKT_PROTO_TRACE
v_U8_t proto_type = 0;
#endif
if (NULL == wma_handle)
{
WMA_LOGE("wma_handle is NULL");
return VOS_STATUS_E_FAILURE;
}
iface = &wma_handle->interfaces[vdev_id];
pMac = (tpAniSirGlobal)vos_get_context(VOS_MODULE_ID_PE,
wma_handle->vos_context);
/* Get the vdev handle from vdev id */
txrx_vdev = wma_handle->interfaces[vdev_id].handle;
vos_handle = (pVosContextType)(wma_handle->vos_context);
/* Get the txRx Pdev handle */
txrx_pdev = (ol_txrx_pdev_handle)(vos_handle->pdev_txrx_ctx);
if(!txrx_vdev) {
WMA_LOGE("TxRx Vdev Handle is NULL");
return VOS_STATUS_E_FAILURE;
}
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
txrx_vdev->hlTdlsFlag = false;
#endif
if (frmType >= HAL_TXRX_FRM_MAX) {
WMA_LOGE("Invalid Frame Type Fail to send Frame");
return VOS_STATUS_E_FAILURE;
}
if(!pMac) {
WMA_LOGE("pMac Handle is NULL");
return VOS_STATUS_E_FAILURE;
}
/*
* Currently only support to
* send 80211 Mgmt and 80211 Data are added.
*/
if (!((frmType == HAL_TXRX_FRM_802_11_MGMT) ||
(frmType == HAL_TXRX_FRM_802_11_DATA))) {
WMA_LOGE("No Support to send other frames except 802.11 Mgmt/Data");
return VOS_STATUS_E_FAILURE;
}
#ifdef WLAN_FEATURE_11W
if ((iface && iface->rmfEnabled) &&
(frmType == HAL_TXRX_FRM_802_11_MGMT) &&
(pFc->subType == SIR_MAC_MGMT_DISASSOC ||
pFc->subType == SIR_MAC_MGMT_DEAUTH ||
pFc->subType == SIR_MAC_MGMT_ACTION)) {
struct ieee80211_frame *wh =
(struct ieee80211_frame *)adf_nbuf_data(tx_frame);
if(!IEEE80211_IS_BROADCAST(wh->i_addr1) &&
!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
if (pFc->wep) {
/* Allocate extra bytes for privacy header and trailer */
newFrmLen = frmLen + IEEE80211_CCMP_HEADERLEN +
IEEE80211_CCMP_MICLEN;
vos_status = palPktAlloc( pMac->hHdd,
HAL_TXRX_FRM_802_11_MGMT,
( tANI_U16 )newFrmLen,
( void** ) &pFrame,
( void** ) &pPacket );
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGP("%s: Failed to allocate %d bytes for RMF status "
"code (%x)", __func__, newFrmLen, vos_status);
/* Free the original packet memory */
palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
( void* ) pData, ( void* ) tx_frame );
goto error;
}
/*
* Initialize the frame with 0's and only fill
* MAC header and data, Keep the CCMP header and
* trailer as 0's, firmware shall fill this
*/
vos_mem_set( pFrame, newFrmLen , 0 );
vos_mem_copy( pFrame, wh, sizeof(*wh));
vos_mem_copy( pFrame + sizeof(*wh) + IEEE80211_CCMP_HEADERLEN,
pData + sizeof(*wh), frmLen - sizeof(*wh));
palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
( void* ) pData, ( void* ) tx_frame );
tx_frame = pPacket;
frmLen = newFrmLen;
}
} else {
/* Allocate extra bytes for MMIE */
newFrmLen = frmLen + IEEE80211_MMIE_LEN;
vos_status = palPktAlloc( pMac->hHdd,
HAL_TXRX_FRM_802_11_MGMT,
( tANI_U16 )newFrmLen,
( void** ) &pFrame,
( void** ) &pPacket );
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGP("%s: Failed to allocate %d bytes for RMF status "
"code (%x)", __func__, newFrmLen, vos_status);
/* Free the original packet memory */
palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
( void* ) pData, ( void* ) tx_frame );
goto error;
}
/*
* Initialize the frame with 0's and only fill
* MAC header and data. MMIE field will be
* filled by vos_attach_mmie API
*/
vos_mem_set( pFrame, newFrmLen , 0 );
vos_mem_copy( pFrame, wh, sizeof(*wh));
vos_mem_copy( pFrame + sizeof(*wh),
pData + sizeof(*wh), frmLen - sizeof(*wh));
if (!vos_attach_mmie(iface->key.key,
iface->key.key_id[0].ipn,
WMA_IGTK_KEY_INDEX_4,
pFrame,
pFrame+newFrmLen, newFrmLen)) {
WMA_LOGP("%s: Failed to attach MMIE at the end of "
"frame", __func__);
/* Free the original packet memory */
palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
( void* ) pData, ( void* ) tx_frame );
goto error;
}
palPktFree( pMac->hHdd, HAL_TXRX_FRM_802_11_MGMT,
( void* ) pData, ( void* ) tx_frame );
tx_frame = pPacket;
frmLen = newFrmLen;
}
}
#endif /* WLAN_FEATURE_11W */
if ((frmType == HAL_TXRX_FRM_802_11_MGMT) &&
(pFc->subType == SIR_MAC_MGMT_PROBE_RSP)) {
u_int64_t adjusted_tsf_le;
struct ieee80211_frame *wh =
(struct ieee80211_frame *)adf_nbuf_data(tx_frame);
/* Make the TSF offset negative to match TSF in beacons */
adjusted_tsf_le = cpu_to_le64(0ULL -
wma_handle->interfaces[vdev_id].tsfadjust);
A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le));
}
if (frmType == HAL_TXRX_FRM_802_11_DATA) {
adf_nbuf_t ret;
adf_nbuf_t skb = (adf_nbuf_t)tx_frame;
ol_txrx_pdev_handle pdev =
vos_get_context(VOS_MODULE_ID_TXRX, wma_handle->vos_context);
struct wma_decap_info_t decap_info;
struct ieee80211_frame *wh =
(struct ieee80211_frame *)adf_nbuf_data(skb);
v_TIME_t curr_timestamp = vos_timer_get_system_ticks();
if (pdev == NULL) {
WMA_LOGE("%s: pdev pointer is not available", __func__);
return VOS_STATUS_E_FAULT;
}
/*
* 1) TxRx Module expects data input to be 802.3 format
* So Decapsulation has to be done.
* 2) Only one Outstanding Data pending for Ack is allowed
*/
if (tx_frm_ota_comp_cb) {
if (wma_handle->umac_data_ota_ack_cb) {
/*
* If last data frame was sent more than 5 seconds
* ago and still we did not receive ack/nack from
* fw then allow Tx of this data frame
*/
if (curr_timestamp >=
wma_handle->last_umac_data_ota_timestamp + 500) {
WMA_LOGE("%s: No Tx Ack for last data frame for more than 5 secs, allow Tx of current data frame",
__func__);
} else {
WMA_LOGE("%s: Already one Data pending for Ack, reject Tx of data frame",
__func__);
return VOS_STATUS_E_FAILURE;
}
}
} else {
/*
* Data Frames are sent through TxRx Non Standard Data Path
* so Ack Complete Cb is must
*/
WMA_LOGE("No Ack Complete Cb. Don't Allow");
return VOS_STATUS_E_FAILURE;
}
/* Take out 802.11 header from skb */
decap_info.hdr_len = wma_ieee80211_hdrsize(wh);
adf_os_mem_copy(decap_info.hdr, wh, decap_info.hdr_len);
adf_nbuf_pull_head(skb, decap_info.hdr_len);
/* Decapsulate to 802.3 format */
wma_decap_to_8023(skb, &decap_info);
/* Zero out skb's context buffer for the driver to use */
adf_os_mem_set(skb->cb, 0, sizeof(skb->cb));
/* Do the DMA Mapping */
adf_nbuf_map_single(pdev->osdev, skb, ADF_OS_DMA_TO_DEVICE);
/* Terminate the (single-element) list of tx frames */
skb->next = NULL;
/* Store the Ack Complete Cb */
wma_handle->umac_data_ota_ack_cb = tx_frm_ota_comp_cb;
/* Store the timestamp and nbuf for this data Tx */
wma_handle->last_umac_data_ota_timestamp = curr_timestamp;
wma_handle->last_umac_data_nbuf = skb;
/* Send the Data frame to TxRx in Non Standard Path */
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
txrx_vdev->hlTdlsFlag = tdlsFlag;
#endif
ret = ol_tx_non_std(txrx_vdev, ol_tx_spec_no_free, skb);
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
txrx_vdev->hlTdlsFlag = false;
#endif
if (ret) {
WMA_LOGE("TxRx Rejected. Fail to do Tx");
adf_nbuf_unmap_single(pdev->osdev, skb, ADF_OS_DMA_TO_DEVICE);
/* Call Download Cb so that umac can free the buffer */
if (tx_frm_download_comp_cb)
tx_frm_download_comp_cb(wma_handle->mac_context,
tx_frame,
WMA_TX_FRAME_BUFFER_FREE);
wma_handle->umac_data_ota_ack_cb = NULL;
wma_handle->last_umac_data_nbuf = NULL;
return VOS_STATUS_E_FAILURE;
}
/* Call Download Callback if passed */
if (tx_frm_download_comp_cb)
tx_frm_download_comp_cb(wma_handle->mac_context,
tx_frame,
WMA_TX_FRAME_BUFFER_NO_FREE);
return VOS_STATUS_SUCCESS;
}
is_high_latency = wdi_out_cfg_is_high_latency(
txrx_vdev->pdev->ctrl_pdev);
downld_comp_required = tx_frm_download_comp_cb && is_high_latency &&
tx_frm_ota_comp_cb;
/* Fill the frame index to send */
if(pFc->type == SIR_MAC_MGMT_FRAME) {
if(tx_frm_ota_comp_cb) {
if(downld_comp_required)
tx_frm_index =
GENERIC_DOWNLD_COMP_ACK_COMP_INDEX;
else
tx_frm_index =
GENERIC_NODOWLOAD_ACK_COMP_INDEX;
/* Store the Ack Cb sent by UMAC */
if(pFc->subType < SIR_MAC_MGMT_RESERVED15) {
wma_handle->umac_ota_ack_cb[pFc->subType] =
tx_frm_ota_comp_cb;
}
#ifdef QCA_PKT_PROTO_TRACE
if (pFc->subType == SIR_MAC_MGMT_ACTION)
proto_type = vos_pkt_get_proto_type(tx_frame,
pMac->fEnableDebugLog,
NBUF_PKT_TRAC_TYPE_MGMT_ACTION);
if (proto_type & NBUF_PKT_TRAC_TYPE_MGMT_ACTION)
vos_pkt_trace_buf_update("WM:T:MACT");
adf_nbuf_trace_set_proto_type(tx_frame, proto_type);
#endif /* QCA_PKT_PROTO_TRACE */
} else {
if(downld_comp_required)
tx_frm_index =
GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX;
else
tx_frm_index =
GENERIC_NODOWNLD_NOACK_COMP_INDEX;
}
}
/*
* If Dowload Complete is required
* Wait for download complete
*/
if(downld_comp_required) {
/* Store Tx Comp Cb */
wma_handle->tx_frm_download_comp_cb = tx_frm_download_comp_cb;
/* Reset the Tx Frame Complete Event */
vos_status = vos_event_reset(
&wma_handle->tx_frm_download_comp_event);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
WMA_LOGP("%s: Event Reset failed tx comp event %x",
__func__, vos_status);
goto error;
}
}
/* If the frame has to be sent at BD Rate2 inform TxRx */
if(tx_flag & HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME)
use_6mbps = 1;
if (wma_handle->roam_preauth_scan_state == WMA_ROAM_PREAUTH_ON_CHAN) {
chanfreq = wma_handle->roam_preauth_chanfreq;
WMA_LOGI("%s: Preauth frame on channel %d", __func__, chanfreq);
} else if(pFc->subType == SIR_MAC_MGMT_PROBE_RSP){
chanfreq = wma_handle->interfaces[vdev_id].mhz;
WMA_LOGI("%s: Probe response frame on channel %d", __func__, chanfreq);
WMA_LOGI("%s: Probe response frame on vdev id %d", __func__, vdev_id);
} else {
chanfreq = 0;
}
if (pMac->fEnableDebugLog & 0x1) {
if ((pFc->type == SIR_MAC_MGMT_FRAME) &&
(pFc->subType != SIR_MAC_MGMT_PROBE_REQ) &&
(pFc->subType != SIR_MAC_MGMT_PROBE_RSP)) {
WMA_LOGE("TX MGMT - Type %hu, SubType %hu",
pFc->type, pFc->subType);
}
}
/* Hand over the Tx Mgmt frame to TxRx */
status = wdi_in_mgmt_send(txrx_vdev, tx_frame, tx_frm_index, use_6mbps, chanfreq);
/*
* Failed to send Tx Mgmt Frame
*/
if (status) {
/* Call Download Cb so that umac can free the buffer */
if (tx_frm_download_comp_cb)
tx_frm_download_comp_cb(wma_handle->mac_context,
tx_frame,
WMA_TX_FRAME_BUFFER_FREE);
WMA_LOGP("%s: Failed to send Mgmt Frame", __func__);
goto error;
}
if (!tx_frm_download_comp_cb)
return VOS_STATUS_SUCCESS;
/*
* Wait for Download Complete
* if required
*/
if (downld_comp_required) {
static uint8_t mgmt_downld_fail_count = 0;
unsigned long time_snapshot;
time_snapshot = vos_timer_get_system_time();
/*
* Wait for Download Complete
* @ Integrated : Dxe Complete
* @ Discrete : Target Download Complete
*/
vos_status = vos_wait_single_event(
&wma_handle->tx_frm_download_comp_event,
WMA_TX_FRAME_COMPLETE_TIMEOUT);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
mgmt_downld_fail_count++;
WMA_LOGP("Wait Event failed txfrm_comp_event");
/*
* @Integrated: Something Wrong with Dxe
* TODO: Some Debug Code
* Here We need to trigger SSR since
* since system went into a bad state where
* we didn't get Download Complete for almost
* WMA_TX_FRAME_COMPLETE_TIMEOUT (1 sec)
*/
#ifdef CONFIG_HL_SUPPORT
/* display scheduler stats
* when count is max or modulus of
* OL_TXSTATS_DUMP_MOD_FREQ
*/
if ((mgmt_downld_fail_count ==
wma_handle->max_mgmt_tx_fail_count) ||
(mgmt_downld_fail_count %
OL_TXSTATS_DUMP_MOD_FREQ == 0)) {
wdi_in_display_stats(txrx_pdev,
WLAN_SCHEDULER_STATS);
}
#endif
WMA_LOGE("%s: download complete failure count:%d",
__func__, mgmt_downld_fail_count);
/*
* Inject crash only if max_mgmt_tx_fail_count is non
* zero value.
*/
if (wma_handle->max_mgmt_tx_fail_count &&
mgmt_downld_fail_count ==
wma_handle->max_mgmt_tx_fail_count) {
vos_flush_logs(WLAN_LOG_TYPE_FATAL,
WLAN_LOG_INDICATOR_HOST_DRIVER,
WLAN_LOG_REASON_MGMT_FRAME_TIMEOUT,
DUMP_VOS_TRACE);
wmi_crash_inject(wma_handle->wmi_handle,
RECOVERY_SIM_ASSERT, 0);
}
} else {
mgmt_downld_fail_count = 0;
if ((vos_timer_get_system_time() - time_snapshot) >=
WDA_TX_TIME_THRESHOLD)
WMA_LOGE("%s Tx Complete took %lu ms",__func__,
vos_timer_get_system_time() - time_snapshot);
}
}
return VOS_STATUS_SUCCESS;
error:
wma_handle->tx_frm_download_comp_cb = NULL;
wma_handle->umac_data_ota_ack_cb = NULL;
return VOS_STATUS_E_FAILURE;
}
/* function :wma_setneedshutdown
* Description :
* Args :
* Returns :
*/
v_VOID_t wma_setneedshutdown(v_VOID_t *vos_ctx)
{
tp_wma_handle wma_handle;
WMA_LOGD("%s: Enter", __func__);
wma_handle = vos_get_context(VOS_MODULE_ID_WDA, vos_ctx);
if (NULL == wma_handle) {
WMA_LOGP("%s: Invalid arguments", __func__);
VOS_ASSERT(0);
return;
}
wma_handle->needShutdown = TRUE;
WMA_LOGD("%s: Exit", __func__);
}
/* function : wma_rx_ready_event
* Description :
* Args :
* Returns :
*/
v_BOOL_t wma_needshutdown(v_VOID_t *vos_ctx)
{
tp_wma_handle wma_handle;
WMA_LOGD("%s: Enter", __func__);
wma_handle = vos_get_context(VOS_MODULE_ID_WDA, vos_ctx);
if (NULL == wma_handle) {
WMA_LOGP("%s: Invalid arguments", __func__);
VOS_ASSERT(0);
return 0;
}
WMA_LOGD("%s: Exit", __func__);
return wma_handle->needShutdown;
}
VOS_STATUS wma_wait_for_ready_event(WMA_HANDLE handle)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
VOS_STATUS vos_status;
/* wait until WMI_READY_EVENTID received from FW */
vos_status = vos_wait_single_event( &(wma_handle->wma_ready_event),
WMA_READY_EVENTID_TIMEOUT );
if (VOS_STATUS_SUCCESS != vos_status) {
WMA_LOGP("%s: Timeout waiting for ready event from FW", __func__);
vos_status = VOS_STATUS_E_FAILURE;
}
return vos_status;
}
int wma_suspend_target(WMA_HANDLE handle, int disable_target_intr)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_pdev_suspend_cmd_fixed_param* cmd;
wmi_buf_t wmibuf;
u_int32_t len = sizeof(*cmd);
struct ol_softc *scn;
#ifdef CONFIG_CNSS
tpAniSirGlobal pmac;
#endif
v_U32_t timeout = WMA_TGT_SUSPEND_COMPLETE_TIMEOUT;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("WMA is closed. can not issue suspend cmd");
return -EINVAL;
}
#ifdef CONFIG_CNSS
pmac = vos_get_context(VOS_MODULE_ID_PE, wma_handle->vos_context);
if (!pmac) {
WMA_LOGE("%s: Unable to get PE context!", __func__);
return -EINVAL;
}
#endif
/*
* send the comand to Target to ignore the
* PCIE reset so as to ensure that Host and target
* states are in sync
*/
wmibuf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (wmibuf == NULL) {
return -1;
}
cmd = (wmi_pdev_suspend_cmd_fixed_param *) wmi_buf_data(wmibuf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_suspend_cmd_fixed_param));
if (disable_target_intr) {
cmd->suspend_opt = WMI_PDEV_SUSPEND_AND_DISABLE_INTR;
}
else {
cmd->suspend_opt = WMI_PDEV_SUSPEND;
}
vos_event_reset(&wma_handle->target_suspend);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmibuf, len,
WMI_PDEV_SUSPEND_CMDID)) {
wmi_buf_free(wmibuf);
return -1;
}
wmi_set_target_suspend(wma_handle->wmi_handle, TRUE);
/* overwrite the timeout value to shorten the SSR latency in HL
* solution.
*/
if (vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)) {
WMA_LOGP("%s: %d HL ssr in progress",
__func__, __LINE__);
timeout = WMA_SUSPEND_TIMEOUT_IN_SSR;
}
if (vos_wait_single_event(&wma_handle->target_suspend,
timeout)
!= VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to get ACK from firmware for pdev suspend");
if (wma_did_ssr_happen(wma_handle)) {
WMA_LOGE("%s: SSR happened while waiting for response",
__func__);
return VOS_STATUS_E_FAILURE;
}
wmi_set_target_suspend(wma_handle->wmi_handle, FALSE);
#ifdef CONFIG_CNSS
if (vos_is_load_unload_in_progress(VOS_MODULE_ID_WDA, NULL) ||
vos_is_logp_in_progress(VOS_MODULE_ID_VOSS, NULL)) {
WMA_LOGE("%s: Unloading/Loading/LOGP is in progress, Ignore!",
__func__);
} else {
if (pmac->sme.enableSelfRecovery) {
vos_trigger_recovery(false);
} else {
VOS_BUG(0);
}
}
#endif
return -1;
}
scn = vos_get_context(VOS_MODULE_ID_HIF,wma_handle->vos_context);
if (scn == NULL) {
WMA_LOGE("%s: Failed to get HIF context", __func__);
VOS_ASSERT(0);
return -1;
}
return 0;
}
void wma_target_suspend_acknowledge(void *context)
{
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA, vos_context);
int wow_nack = *((int *)context);
if (NULL == wma) {
WMA_LOGE("%s: wma is NULL", __func__);
return;
}
wma->wow_nack = wow_nack;
vos_event_set(&wma->target_suspend);
if (wow_nack && !wmi_get_runtime_pm_inprogress(wma->wmi_handle))
vos_wake_lock_timeout_acquire(&wma->wow_wake_lock,
WMA_WAKE_LOCK_TIMEOUT,
WIFI_POWER_EVENT_WAKELOCK_WOW);
}
int wma_resume_target(WMA_HANDLE handle, int runtime_pm)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_buf_t wmibuf;
wmi_pdev_resume_cmd_fixed_param *cmd;
int ret;
int timeout = 0;
int wmi_pending_cmds;
wmibuf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd));
if (wmibuf == NULL) {
return -1;
}
cmd = (wmi_pdev_resume_cmd_fixed_param *) wmi_buf_data(wmibuf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_pdev_resume_cmd_fixed_param));
cmd->pdev_id = 0;
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, wmibuf, sizeof(*cmd),
WMI_PDEV_RESUME_CMDID);
if(ret != EOK) {
WMA_LOGE("Failed to send WMI_PDEV_RESUME_CMDID command");
wmi_buf_free(wmibuf);
}
if (runtime_pm)
goto end;
wmi_pending_cmds = wmi_get_pending_cmds(wma_handle->wmi_handle);
while (wmi_pending_cmds && timeout++ < WMA_MAX_RESUME_RETRY) {
msleep(10);
wmi_pending_cmds = wmi_get_pending_cmds(wma_handle->wmi_handle);
}
if (wmi_pending_cmds) {
WMA_LOGE("Failed to deliver WMI_PDEV_RESUME_CMDID command %d\n", timeout);
ret = -1;
}
end:
if (EOK == ret)
wmi_set_target_suspend(wma_handle->wmi_handle, FALSE);
return ret;
}
void WDA_TimerTrafficStatsInd(tWDA_CbContext *pWDA)
{
}
/* TODO: Below is stub should be removed later */
void WDI_DS_ActivateTrafficStats(void)
{
}
/*
* Function fills the rx packet meta info from the the vos packet
*/
VOS_STATUS WDA_DS_PeekRxPacketInfo(vos_pkt_t *pkt, v_PVOID_t *pkt_meta,
v_BOOL_t bSwap)
{
/* Sanity Check */
if(pkt == NULL) {
WMA_LOGE("wma:Invalid parameter sent on wma_peek_rx_pkt_info");
return VOS_STATUS_E_FAULT;
}
*pkt_meta = &(pkt->pkt_meta);
return VOS_STATUS_SUCCESS;
}
/*
* Function to lookup MAC address from vdev ID
*/
u_int8_t *wma_get_vdev_address_by_vdev_id(u_int8_t vdev_id)
{
tp_wma_handle wma;
wma = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
if (!wma) {
WMA_LOGE("%s: Invalid WMA handle", __func__);
return NULL;
}
if (vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
return NULL;
}
return wma->interfaces[vdev_id].addr;
}
/*
* Function to get the beacon buffer from vdev ID
* Note: The buffer returned must be freed explicitly by caller
*/
void *wma_get_beacon_buffer_by_vdev_id(u_int8_t vdev_id, u_int32_t *buffer_size)
{
tp_wma_handle wma;
struct beacon_info *beacon;
u_int8_t *buf;
u_int32_t buf_size;
wma = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
if (!wma) {
WMA_LOGE("%s: Invalid WMA handle", __func__);
return NULL;
}
if (vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
return NULL;
}
if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) {
WMA_LOGE("%s: vdevid %d is not in AP mode",
__func__, vdev_id);
return NULL;
}
beacon = wma->interfaces[vdev_id].beacon;
if (!beacon) {
WMA_LOGE("%s: beacon invalid", __func__);
return NULL;
}
adf_os_spin_lock_bh(&beacon->lock);
buf_size = adf_nbuf_len(beacon->buf);
buf = adf_os_mem_alloc(NULL, buf_size);
if (!buf) {
adf_os_spin_unlock_bh(&beacon->lock);
WMA_LOGE("%s: alloc failed for beacon buf", __func__);
return NULL;
}
adf_os_mem_copy(buf, adf_nbuf_data(beacon->buf), buf_size);
adf_os_spin_unlock_bh(&beacon->lock);
if (buffer_size)
*buffer_size = buf_size;
return buf;
}
#if defined(QCA_WIFI_FTM)
int wma_utf_rsp(tp_wma_handle wma_handle, u_int8_t **payload, u_int32_t *len)
{
int ret = -1;
u_int32_t payload_len;
payload_len = wma_handle->utf_event_info.length;
if (payload_len) {
ret = 0;
/*
* The first 4 bytes holds the payload size
* and the actual payload sits next to it
*/
*payload = (u_int8_t *)vos_mem_malloc((v_SIZE_t)payload_len
+ sizeof(A_UINT32));
*(A_UINT32*)&(*payload[0]) = wma_handle->utf_event_info.length;
memcpy(*payload + sizeof(A_UINT32),
wma_handle->utf_event_info.data,
payload_len);
wma_handle->utf_event_info.length = 0;
*len = payload_len;
}
return ret;
}
static void wma_post_ftm_response(tp_wma_handle wma_handle)
{
int ret;
u_int8_t *payload;
u_int32_t data_len;
vos_msg_t msg = {0};
VOS_STATUS status;
ret = wma_utf_rsp(wma_handle, &payload, &data_len);
if (ret) {
return;
}
msg.type = SYS_MSG_ID_FTM_RSP;
msg.bodyptr = payload;
msg.bodyval = 0;
msg.reserved = SYS_MSG_COOKIE;
status = vos_mq_post_message(VOS_MQ_ID_SYS, &msg);
if (status != VOS_STATUS_SUCCESS) {
WMA_LOGE("failed to post ftm response to SYS");
vos_mem_free(payload);
}
}
static int
wma_process_utf_event(WMA_HANDLE handle,
u_int8_t *datap, u_int32_t dataplen)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
SEG_HDR_INFO_STRUCT segHdrInfo;
u_int8_t totalNumOfSegments,currentSeq;
WMI_PDEV_UTF_EVENTID_param_tlvs *param_buf;
u_int8_t *data;
u_int32_t datalen;
param_buf = (WMI_PDEV_UTF_EVENTID_param_tlvs *) datap;
if (!param_buf) {
WMA_LOGE("Get NULL point message from FW");
return -EINVAL;
}
data = param_buf->data;
datalen = param_buf->num_data;
if (datalen < sizeof(segHdrInfo)) {
WMA_LOGE("message size %d is smaller than struct seg_hdr_info",
datalen);
return -EINVAL;
}
segHdrInfo = *(SEG_HDR_INFO_STRUCT *)&(data[0]);
wma_handle->utf_event_info.currentSeq = (segHdrInfo.segmentInfo & 0xF);
currentSeq = (segHdrInfo.segmentInfo & 0xF);
totalNumOfSegments = (segHdrInfo.segmentInfo >> 4) & 0xF;
datalen = datalen - sizeof(segHdrInfo);
if (currentSeq == 0) {
wma_handle->utf_event_info.expectedSeq = 0;
wma_handle->utf_event_info.offset = 0;
} else {
if (wma_handle->utf_event_info.expectedSeq != currentSeq)
WMA_LOGE("Mismatch in expecting seq expected"
" Seq %d got seq %d",
wma_handle->utf_event_info.expectedSeq,
currentSeq);
}
if ((datalen > MAX_UTF_EVENT_LENGTH) ||
(wma_handle->utf_event_info.offset >
(MAX_UTF_EVENT_LENGTH - datalen))) {
WMA_LOGE("Excess data from firmware, offset:%zu, len:%d",
wma_handle->utf_event_info.offset, datalen);
return -EINVAL;
}
memcpy(&wma_handle->utf_event_info.data[wma_handle->utf_event_info.offset],
&data[sizeof(segHdrInfo)],
datalen);
wma_handle->utf_event_info.offset = wma_handle->utf_event_info.offset + datalen;
wma_handle->utf_event_info.expectedSeq++;
if (wma_handle->utf_event_info.expectedSeq == totalNumOfSegments) {
if (wma_handle->utf_event_info.offset != segHdrInfo.len)
WMA_LOGE("All segs received total len mismatch.."
" len %zu total len %d",
wma_handle->utf_event_info.offset,
segHdrInfo.len);
wma_handle->utf_event_info.length = wma_handle->utf_event_info.offset;
}
wma_post_ftm_response(wma_handle);
return 0;
}
void wma_utf_detach(tp_wma_handle wma_handle)
{
if (wma_handle->utf_event_info.data) {
vos_mem_free(wma_handle->utf_event_info.data);
wma_handle->utf_event_info.data = NULL;
wma_handle->utf_event_info.length = 0;
wmi_unified_unregister_event_handler(wma_handle->wmi_handle,
WMI_PDEV_UTF_EVENTID);
}
}
void wma_utf_attach(tp_wma_handle wma_handle)
{
int ret;
wma_handle->utf_event_info.data = (unsigned char *)
vos_mem_malloc(MAX_UTF_EVENT_LENGTH);
wma_handle->utf_event_info.length = 0;
ret = wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_PDEV_UTF_EVENTID,
wma_process_utf_event);
if (ret)
WMA_LOGP("%s: Failed to register UTF event callback", __func__);
}
static int
wmi_unified_pdev_utf_cmd(wmi_unified_t wmi_handle, u_int8_t *utf_payload,
u_int16_t len)
{
wmi_buf_t buf;
u_int8_t *cmd;
int ret = 0;
static u_int8_t msgref = 1;
u_int8_t segNumber = 0, segInfo, numSegments;
u_int16_t chunk_len, total_bytes;
u_int8_t *bufpos;
SEG_HDR_INFO_STRUCT segHdrInfo;
bufpos = utf_payload;
total_bytes = len;
ASSERT(total_bytes / MAX_WMI_UTF_LEN ==
(u_int8_t)(total_bytes / MAX_WMI_UTF_LEN));
numSegments = (u_int8_t)(total_bytes / MAX_WMI_UTF_LEN);
if (len - (numSegments * MAX_WMI_UTF_LEN))
numSegments++;
while (len) {
if (len > MAX_WMI_UTF_LEN)
chunk_len = MAX_WMI_UTF_LEN; /* MAX messsage */
else
chunk_len = len;
buf = wmi_buf_alloc(wmi_handle,
(chunk_len + sizeof(segHdrInfo) +
WMI_TLV_HDR_SIZE));
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return -1;
}
cmd = (u_int8_t *)wmi_buf_data(buf);
segHdrInfo.len = total_bytes;
segHdrInfo.msgref = msgref;
segInfo = ((numSegments << 4 ) & 0xF0) | (segNumber & 0xF);
segHdrInfo.segmentInfo = segInfo;
segHdrInfo.pad = 0;
WMA_LOGD("%s:segHdrInfo.len = %d, segHdrInfo.msgref = %d,"
" segHdrInfo.segmentInfo = %d",
__func__, segHdrInfo.len, segHdrInfo.msgref,
segHdrInfo.segmentInfo);
WMA_LOGD("%s:total_bytes %d segNumber %d totalSegments %d"
"chunk len %d", __func__, total_bytes, segNumber,
numSegments, chunk_len);
segNumber++;
WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE,
(chunk_len + sizeof(segHdrInfo)));
cmd += WMI_TLV_HDR_SIZE;
memcpy(cmd, &segHdrInfo, sizeof(segHdrInfo)); /* 4 bytes */
memcpy(&cmd[sizeof(segHdrInfo)], bufpos, chunk_len);
ret = wmi_unified_cmd_send(wmi_handle, buf,
(chunk_len + sizeof(segHdrInfo) +
WMI_TLV_HDR_SIZE),
WMI_PDEV_UTF_CMDID);
if (ret != EOK) {
WMA_LOGE("Failed to send WMI_PDEV_UTF_CMDID command");
wmi_buf_free(buf);
break;
}
len -= chunk_len;
bufpos += chunk_len;
}
msgref++;
return ret;
}
int wma_utf_cmd(tp_wma_handle wma_handle, u_int8_t *data, u_int16_t len)
{
wma_handle->utf_event_info.length = 0;
return wmi_unified_pdev_utf_cmd(wma_handle->wmi_handle, data, len);
}
static VOS_STATUS
wma_process_ftm_command(tp_wma_handle wma_handle,
struct ar6k_testmode_cmd_data *msg_buffer)
{
u_int8_t *data = NULL;
u_int16_t len = 0;
int ret;
if (!msg_buffer)
return VOS_STATUS_E_INVAL;
if (vos_get_conparam() != VOS_FTM_MODE) {
WMA_LOGE("FTM command issued in non-FTM mode");
vos_mem_free(msg_buffer->data);
vos_mem_free(msg_buffer);
return VOS_STATUS_E_NOSUPPORT;
}
data = msg_buffer->data;
len = msg_buffer->len;
ret = wma_utf_cmd(wma_handle, data, len);
vos_mem_free(msg_buffer->data);
vos_mem_free(msg_buffer);
if (ret)
return VOS_STATUS_E_FAILURE;
return VOS_STATUS_SUCCESS;
}
#endif
/* Function to enable/disble Low Power Support(Pdev Specific) */
VOS_STATUS WDA_SetIdlePsConfig(void *wda_handle, tANI_U32 idle_ps)
{
int32_t ret;
tp_wma_handle wma = (tp_wma_handle)wda_handle;
WMA_LOGD("WMA Set Idle Ps Config [1:set 0:clear] val %d", idle_ps);
/* only use vdev 0 for imps tracking */
wma->interfaces[0].in_imps = idle_ps;
/* Set Idle Mode Power Save Config */
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_IDLE_PS_CONFIG, idle_ps);
if(ret) {
WMA_LOGE("Fail to Set Idle Ps Config %d", idle_ps);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Successfully Set Idle Ps Config %d", idle_ps);
return VOS_STATUS_SUCCESS;
}
/**
* wma_set_cts2self_for_p2p_go() - set CTS2SELF command for P2P GO.
* @wda_handle: pointer to wma handle.
* @cts2self_for_p2p_go: value needs to set to firmware.
*
* At the time of driver startup, inform about ini parma to FW that
* if legacy client connects to P2P GO, stop using NOA for P2P GO.
*
* Return: VOS_STATUS.
*/
VOS_STATUS wma_set_cts2self_for_p2p_go(void *wda_handle,
uint32_t cts2self_for_p2p_go)
{
int32_t ret;
tp_wma_handle wma = (tp_wma_handle)wda_handle;
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_CTS2SELF_FOR_P2P_GO_CONFIG,
cts2self_for_p2p_go);
if (ret) {
WMA_LOGE("Fail to Set CTS2SELF for p2p GO %d",
cts2self_for_p2p_go);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGD("Successfully Set CTS2SELF for p2p GO %d",
cts2self_for_p2p_go);
return VOS_STATUS_SUCCESS;
}
/**
* wmi_unified_ac_txq_optimize_send() - set command to firmware.
* @wmi: wmi_unified_t
* @ac_txq_optimize: value needs to set to firmware.
*
* Return: VOS_STATUS.
*/
static int32_t
wmi_unified_ac_txq_optimize_send(wmi_unified_t wmi, uint8_t *ac_txq_optimize)
{
wmi_pdev_set_ac_tx_queue_optimized_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_pdev_set_ac_tx_queue_optimized_cmd_fixed_param *)
wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_ac_tx_queue_optimized_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_ac_tx_queue_optimized_cmd_fixed_param));
cmd->pdev_id = 0;
if ((*ac_txq_optimize & 0x0f) < NUM_AC)
cmd->ac = *ac_txq_optimize & 0x0f;
else
return -EINVAL;
cmd->ac_tx_queue_optimize_enable = 1;
if (wmi_unified_cmd_send(wmi, buf, len,
WMI_PDEV_SET_AC_TX_QUEUE_OPTIMIZED_CMDID)) {
WMA_LOGP("%s: Failed to send AC queue optimize command",
__func__);
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGI("%s: ac %d pdev_id %d", __func__, cmd->ac, cmd->pdev_id);
return 0;
}
/**
* wma_set_ac_txq_optimize() - set one AC Tx queue optimize command.
* @wda_handle: pointer to wma handle.
* @value: value needs to set to firmware.
*
* Return: VOS_STATUS.
*/
VOS_STATUS wma_set_ac_txq_optimize(void *wda_handle, uint8_t *value)
{
int32_t ret;
tp_wma_handle wma = (tp_wma_handle)wda_handle;
ret = wmi_unified_ac_txq_optimize_send(wma->wmi_handle, value);
if (ret) {
WMA_LOGE("Fail to Set AC queue, input 0x%02x", *value);
return VOS_STATUS_E_FAILURE;
}
WMA_LOGI("Successfully Set AC queue, input 0x%02x", *value);
return VOS_STATUS_SUCCESS;
}
/**
* wma_set_mib_stats_enable() - enable mib stats in FW.
* @wda_handle: pointer to wma handle.
* @enable: value needs to set to firmware.
*
* At the time of driver startup, inform about ini parma to FW that
* if mibs stats needs to be collected
*
* Return: VOS_STATUS.
*/
VOS_STATUS wma_set_mib_stats_enable(void *handle,
uint32_t enable)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
wmi_mib_stats_enable_cmd_fixed_param *cmd;
int status = 0;
wmi_buf_t buf;
u_int8_t *buf_ptr;
int32_t len = sizeof(wmi_mib_stats_enable_cmd_fixed_param);
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE(FL("WMA is closed, can not issue cmd"));
return VOS_STATUS_E_INVAL;
}
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGP(FL("wmi_buf_alloc failed"));
return -ENOMEM;
}
/* reset previous data for ccmp replays */
wma_handle->ccmp_replays_attack_cnt = 0;
buf_ptr = (u_int8_t *) wmi_buf_data(buf);
cmd = (wmi_mib_stats_enable_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_mib_stats_enable_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_mib_stats_enable_cmd_fixed_param));
cmd->enable_Mib = enable;
status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_MIB_STATS_ENABLE_CMDID);
if (status != EOK) {
WMA_LOGE("%s: wmi_unified_cmd_send WMI_MIB_STATS_ENABLE_CMDID"
" returned Error %d",
__func__, status);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
eHalStatus wma_set_htconfig(tANI_U8 vdev_id, tANI_U16 ht_capab, int value)
{
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA, vos_context);
int ret = -EIO;
if (NULL == wma) {
WMA_LOGE("%s: Failed to get wma", __func__);
return eHAL_STATUS_INVALID_PARAMETER;
}
switch (ht_capab) {
case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING:
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_LDPC, value);
break;
case WNI_CFG_HT_CAP_INFO_TX_STBC:
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_TX_STBC, value);
break;
case WNI_CFG_HT_CAP_INFO_RX_STBC:
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_RX_STBC, value);
break;
case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ:
case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ:
WMA_LOGE("%s: ht_capab = %d, value = %d", __func__, ht_capab, value);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_SGI, value);
if (ret == 0)
wma->interfaces[vdev_id].config.shortgi = value;
break;
default:
WMA_LOGE("%s:INVALID HT CONFIG", __func__);
}
return (ret)? eHAL_STATUS_FAILURE : eHAL_STATUS_SUCCESS;
}
eHalStatus WMA_SetRegDomain(void * clientCtxt, v_REGDOMAIN_t regId,
tAniBool sendRegHint)
{
if(VOS_STATUS_SUCCESS != vos_nv_setRegDomain(clientCtxt, regId, sendRegHint))
return eHAL_STATUS_INVALID_PARAMETER;
return eHAL_STATUS_SUCCESS;
}
tANI_U8 wma_getFwWlanFeatCaps(tANI_U8 featEnumValue)
{
return ((gFwWlanFeatCaps & (1 << featEnumValue)) ? TRUE : FALSE);
}
void wma_send_regdomain_info(u_int32_t reg_dmn, u_int16_t regdmn2G,
u_int16_t regdmn5G, int8_t ctl2G, int8_t ctl5G)
{
wmi_buf_t buf;
wmi_pdev_set_regdomain_cmd_fixed_param *cmd;
int32_t len = sizeof(*cmd);
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA, vos_context);
int32_t cck_mask_val = 0;
int ret = 0;
if (NULL == wma) {
WMA_LOGE("%s: wma context is NULL", __func__);
return;
}
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGP("%s: wmi_buf_alloc failed", __func__);
return;
}
cmd = (wmi_pdev_set_regdomain_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_pdev_set_regdomain_cmd_fixed_param));
cmd->reg_domain = reg_dmn;
cmd->reg_domain_2G = regdmn2G;
cmd->reg_domain_5G = regdmn5G;
cmd->conformance_test_limit_2G = ctl2G;
cmd->conformance_test_limit_5G = ctl5G;
if (wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_PDEV_SET_REGDOMAIN_CMDID)) {
WMA_LOGP("%s: Failed to send pdev set regdomain command",
__func__);
wmi_buf_free(buf);
}
if ((((reg_dmn & ~COUNTRY_ERD_FLAG) == CTRY_JAPAN) ||
((reg_dmn & ~COUNTRY_ERD_FLAG) == CTRY_KOREA_ROC)) &&
(true == wma->tx_chain_mask_cck))
cck_mask_val = 1;
cck_mask_val |= (wma->self_gen_frm_pwr << 16);
ret = wmi_unified_pdev_set_param(wma->wmi_handle,
WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK,
cck_mask_val);
if (ret) {
WMA_LOGE("failed to set PDEV tx_chain_mask_cck %d",
ret);
}
return;
}
void wma_get_modeselect(tp_wma_handle wma, u_int32_t *modeSelect)
{
switch (wma->phy_capability) {
case WMI_11G_CAPABILITY:
case WMI_11NG_CAPABILITY:
*modeSelect &= ~(REGDMN_MODE_11A | REGDMN_MODE_TURBO |
REGDMN_MODE_108A | REGDMN_MODE_11A_HALF_RATE |
REGDMN_MODE_11A_QUARTER_RATE | REGDMN_MODE_11NA_HT20 |
REGDMN_MODE_11NA_HT40PLUS | REGDMN_MODE_11NA_HT40MINUS |
REGDMN_MODE_11AC_VHT20 | REGDMN_MODE_11AC_VHT40PLUS |
REGDMN_MODE_11AC_VHT40MINUS | REGDMN_MODE_11AC_VHT80);
break;
case WMI_11A_CAPABILITY:
case WMI_11NA_CAPABILITY:
case WMI_11AC_CAPABILITY:
*modeSelect &= ~(REGDMN_MODE_11B | REGDMN_MODE_11G |
REGDMN_MODE_108G | REGDMN_MODE_11NG_HT20 |
REGDMN_MODE_11NG_HT40PLUS | REGDMN_MODE_11NG_HT40MINUS |
REGDMN_MODE_11AC_VHT20_2G | REGDMN_MODE_11AC_VHT40_2G |
REGDMN_MODE_11AC_VHT80_2G);
break;
}
}
tANI_U8 wma_map_channel(tANI_U8 mapChannel)
{
return mapChannel;
}
static eHalStatus wma_set_mimops(tp_wma_handle wma, tANI_U8 vdev_id, int value)
{
int ret = eHAL_STATUS_SUCCESS;
wmi_sta_smps_force_mode_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int16_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_sta_smps_force_mode_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_sta_smps_force_mode_cmd_fixed_param));
cmd->vdev_id = vdev_id;
/* WMI_SMPS_FORCED_MODE values do not directly map
* to SM power save values defined in the specification.
* Make sure to send the right mapping.
*/
switch(value)
{
case 0:
cmd->forced_mode = WMI_SMPS_FORCED_MODE_NONE;
break;
case 1:
cmd->forced_mode = WMI_SMPS_FORCED_MODE_DISABLED;
break;
case 2:
cmd->forced_mode = WMI_SMPS_FORCED_MODE_STATIC;
break;
case 3:
cmd->forced_mode = WMI_SMPS_FORCED_MODE_DYNAMIC;
break;
default:
WMA_LOGE("%s:INVALID Mimo PS CONFIG", __func__);
return eHAL_STATUS_FAILURE;
}
WMA_LOGD("Setting vdev %d value = %u", vdev_id, value);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_STA_SMPS_FORCE_MODE_CMDID);
if (ret < 0) {
WMA_LOGE("Failed to send set Mimo PS ret = %d", ret);
wmi_buf_free(buf);
}
return ret;
}
static eHalStatus wma_set_ppsconfig(tANI_U8 vdev_id, tANI_U16 pps_param, int val)
{
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA, vos_context);
int ret = -EIO;
u_int32_t pps_val;
if (NULL == wma) {
WMA_LOGE("%s: Failed to get wma", __func__);
return eHAL_STATUS_INVALID_PARAMETER;
}
switch (pps_param) {
case WMA_VHT_PPS_PAID_MATCH:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_PAID_MATCH & 0xffff);
goto pkt_pwr_save_config;
case WMA_VHT_PPS_GID_MATCH:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_GID_MATCH & 0xffff);
goto pkt_pwr_save_config;
case WMA_VHT_PPS_DELIM_CRC_FAIL:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff);
goto pkt_pwr_save_config;
/* Enable the code below as and when the functionality
* is supported/added in host.
*/
#ifdef NOT_YET
case WMA_VHT_PPS_EARLY_TIM_CLEAR:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff);
goto pkt_pwr_save_config;
case WMA_VHT_PPS_EARLY_DTIM_CLEAR:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff);
goto pkt_pwr_save_config;
case WMA_VHT_PPS_EOF_PAD_DELIM:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff);
goto pkt_pwr_save_config;
case WMA_VHT_PPS_MACADDR_MISMATCH:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff);
goto pkt_pwr_save_config;
case WMA_VHT_PPS_GID_NSTS_ZERO:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff);
goto pkt_pwr_save_config;
case WMA_VHT_PPS_RSSI_CHECK:
pps_val = ((val << 31) & 0xffff0000) |
(PKT_PWR_SAVE_RSSI_CHECK & 0xffff);
goto pkt_pwr_save_config;
#endif
pkt_pwr_save_config:
WMA_LOGD("vdev_id:%d val:0x%x pps_val:0x%x", vdev_id,
val, pps_val);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_PACKET_POWERSAVE, pps_val);
break;
default:
WMA_LOGE("%s:INVALID PPS CONFIG", __func__);
}
return (ret)? eHAL_STATUS_FAILURE : eHAL_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_TDLS
static int wma_set_tdls_offchan_mode(WMA_HANDLE handle,
tTdlsChanSwitchParams* pChanSwitchParams)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_tdls_set_offchan_mode_cmd_fixed_param* cmd;
wmi_buf_t wmi_buf;
u_int16_t len = sizeof(wmi_tdls_set_offchan_mode_cmd_fixed_param);
int ret = 0;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue tdls off channel cmd",
__func__);
ret = -EINVAL;
goto end;
}
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmai_buf_alloc failed", __func__);
ret = -ENOMEM;
goto end;
}
cmd = (wmi_tdls_set_offchan_mode_cmd_fixed_param*)wmi_buf_data(wmi_buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_tdls_set_offchan_mode_cmd_fixed_param));
WMI_CHAR_ARRAY_TO_MAC_ADDR(pChanSwitchParams->peerMacAddr,
&cmd->peer_macaddr);
cmd->vdev_id = pChanSwitchParams->vdevId;
cmd->offchan_mode = pChanSwitchParams->tdlsSwMode;
cmd->is_peer_responder = pChanSwitchParams->is_responder;
cmd->offchan_num = pChanSwitchParams->tdlsOffCh;
cmd->offchan_bw_bitmap = pChanSwitchParams->tdlsOffChBwOffset;
cmd->offchan_oper_class = pChanSwitchParams->operClass;
WMA_LOGD("%s: Peer MAC Addr mac_addr31to0: 0x%x, "
"mac_addr47to32: 0x%x",
__func__, cmd->peer_macaddr.mac_addr31to0,
cmd->peer_macaddr.mac_addr47to32);
WMA_LOGD("%s: vdev_id: %d, "
"off channel mode: %d, "
"off channel Num: %d, "
"off channel offset: 0x%x, "
"is_peer_responder: %d, "
"operating class: %d, ",
__func__, cmd->vdev_id,
cmd->offchan_mode,
cmd->offchan_num,
cmd->offchan_bw_bitmap,
cmd->is_peer_responder,
cmd->offchan_oper_class);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_TDLS_SET_OFFCHAN_MODE_CMDID)) {
WMA_LOGP("%s: failed to send tdls off chan command", __func__);
wmi_buf_free(wmi_buf);
ret = -EIO;
}
end:
if (pChanSwitchParams)
vos_mem_free(pChanSwitchParams);
return ret;
}
/* wmi tdls command sent to firmware to enable/disable tdls for a vdev */
static int wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_tdls_set_state_cmd_fixed_param* cmd;
wmi_buf_t wmi_buf;
t_wma_tdls_mode tdls_mode;
t_wma_tdls_params *wma_tdls = (t_wma_tdls_params *)pwmaTdlsparams;
u_int16_t len = sizeof(wmi_tdls_set_state_cmd_fixed_param);
int ret = 0;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue fw tdls state cmd",
__func__);
ret = -EINVAL;
goto end_fw_tdls_state;
}
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmai_buf_alloc failed", __func__);
ret = ENOMEM;
goto end_fw_tdls_state;
}
tdls_mode = wma_tdls->tdls_state;
cmd = (wmi_tdls_set_state_cmd_fixed_param *)wmi_buf_data(wmi_buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_tdls_set_state_cmd_fixed_param));
cmd->vdev_id = wma_tdls->vdev_id;
if (WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode) {
cmd->state = WMI_TDLS_ENABLE_PASSIVE;
} else if (WMA_TDLS_SUPPORT_ENABLED == tdls_mode) {
cmd->state = WMI_TDLS_ENABLE_ACTIVE;
} else if (WMA_TDLS_SUPPORT_ACTIVE_EXTERNAL_CONTROL == tdls_mode) {
cmd->state = WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL;
} else {
cmd->state = WMI_TDLS_DISABLE;
}
cmd->notification_interval_ms = wma_tdls->notification_interval_ms;
cmd->tx_discovery_threshold = wma_tdls->tx_discovery_threshold;
cmd->tx_teardown_threshold = wma_tdls->tx_teardown_threshold;
cmd->rssi_teardown_threshold = wma_tdls->rssi_teardown_threshold;
cmd->rssi_delta = wma_tdls->rssi_delta;
cmd->tdls_options = wma_tdls->tdls_options;
cmd->tdls_peer_traffic_ind_window =
wma_tdls->peer_traffic_ind_window;
cmd->tdls_peer_traffic_response_timeout_ms =
wma_tdls->peer_traffic_response_timeout;
cmd->tdls_puapsd_mask =
wma_tdls->puapsd_mask;
cmd->tdls_puapsd_inactivity_time_ms =
wma_tdls->puapsd_inactivity_time;
cmd->tdls_puapsd_rx_frame_threshold =
wma_tdls->puapsd_rx_frame_threshold;
cmd->teardown_notification_ms =
wma_tdls->teardown_notification_ms;
cmd->tdls_peer_kickout_threshold =
wma_tdls->tdls_peer_kickout_threshold;
WMA_LOGD("%s: tdls_mode: %d, state: %d, "
"notification_interval_ms: %d, "
"tx_discovery_threshold: %d, "
"tx_teardown_threshold: %d, "
"rssi_teardown_threshold: %d, "
"rssi_delta: %d, "
"tdls_options: 0x%x, "
"tdls_peer_traffic_ind_window: %d, "
"tdls_peer_traffic_response_timeout: %d, "
"tdls_puapsd_mask: 0x%x, "
"tdls_puapsd_inactivity_time: %d, "
"tdls_puapsd_rx_frame_threshold: %d, "
"teardown_notification_ms: %d, "
"tdls_peer_kickout_threshold: %d ",
__func__, tdls_mode, cmd->state,
cmd->notification_interval_ms,
cmd->tx_discovery_threshold,
cmd->tx_teardown_threshold,
cmd->rssi_teardown_threshold,
cmd->rssi_delta,
cmd->tdls_options,
cmd->tdls_peer_traffic_ind_window,
cmd->tdls_peer_traffic_response_timeout_ms,
cmd->tdls_puapsd_mask,
cmd->tdls_puapsd_inactivity_time_ms,
cmd->tdls_puapsd_rx_frame_threshold,
cmd->teardown_notification_ms,
cmd->tdls_peer_kickout_threshold);
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_TDLS_SET_STATE_CMDID)) {
WMA_LOGP("%s: failed to send tdls set state command", __func__);
wmi_buf_free(wmi_buf);
ret = -EIO;
goto end_fw_tdls_state;
}
WMA_LOGD("%s: vdev_id %d", __func__, wma_tdls->vdev_id);
end_fw_tdls_state:
if (pwmaTdlsparams)
vos_mem_free(pwmaTdlsparams);
return ret;
}
static int wma_update_tdls_peer_state(WMA_HANDLE handle,
tTdlsPeerStateParams *peerStateParams)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_tdls_peer_update_cmd_fixed_param* cmd;
wmi_tdls_peer_capabilities *peer_cap;
wmi_channel *chan_info;
wmi_buf_t wmi_buf;
u_int8_t *buf_ptr;
u_int32_t i;
ol_txrx_pdev_handle pdev;
u_int8_t peer_id;
struct ol_txrx_peer_t *peer;
int32_t len = sizeof(wmi_tdls_peer_update_cmd_fixed_param) +
sizeof(wmi_tdls_peer_capabilities);
int ret = 0;
#if defined(CONFIG_HL_SUPPORT)
struct ol_txrx_vdev_t *vdev;
bool restore_last_peer = false;
#endif
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__);
ret = -EINVAL;
goto end_tdls_peer_state;
}
/* peer capability info is valid only when peer state is connected */
if (WDA_TDLS_PEER_STATE_CONNECTED != peerStateParams->peerState) {
vos_mem_zero(&peerStateParams->peerCap, sizeof(tTdlsPeerCapParams));
}
len += WMI_TLV_HDR_SIZE +
sizeof(wmi_channel) * peerStateParams->peerCap.peerChanLen;
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
ret = ENOMEM;
goto end_tdls_peer_state;
}
buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf);
cmd = (wmi_tdls_peer_update_cmd_fixed_param *) buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_tdls_peer_update_cmd_fixed_param));
cmd->vdev_id = peerStateParams->vdevId;
WMI_CHAR_ARRAY_TO_MAC_ADDR(peerStateParams->peerMacAddr, &cmd->peer_macaddr);
switch (peerStateParams->peerState) {
case WDA_TDLS_PEER_STATE_PEERING:
cmd->peer_state = WMI_TDLS_PEER_STATE_PEERING;
break;
case WDA_TDLS_PEER_STATE_CONNECTED:
cmd->peer_state = WMI_TDLS_PEER_STATE_CONNECTED;
break;
case WDA_TDLS_PEER_STATE_TEARDOWN:
cmd->peer_state = WMI_TDLS_PEER_STATE_TEARDOWN;
break;
case WDA_TDLS_PEER_ADD_MAC_ADDR:
cmd->peer_state = WMI_TDLS_PEER_ADD_MAC_ADDR;
break;
case WDA_TDLS_PEER_REMOVE_MAC_ADDR:
cmd->peer_state = WMI_TDLS_PEER_REMOVE_MAC_ADDR;
break;
}
WMA_LOGD("%s: vdev_id: %d, peerStateParams->peerMacAddr: %pM, "
"peer_macaddr.mac_addr31to0: 0x%x, "
"peer_macaddr.mac_addr47to32: 0x%x, peer_state: %d",
__func__, cmd->vdev_id, peerStateParams->peerMacAddr,
cmd->peer_macaddr.mac_addr31to0,
cmd->peer_macaddr.mac_addr47to32, cmd->peer_state);
buf_ptr += sizeof(wmi_tdls_peer_update_cmd_fixed_param);
peer_cap = (wmi_tdls_peer_capabilities *) buf_ptr;
WMITLV_SET_HDR(&peer_cap->tlv_header,
WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities,
WMITLV_GET_STRUCT_TLVLEN(wmi_tdls_peer_capabilities));
if ((peerStateParams->peerCap.peerUapsdQueue & 0x08) >> 3)
WMI_SET_TDLS_PEER_VO_UAPSD(peer_cap);
if ((peerStateParams->peerCap.peerUapsdQueue & 0x04) >> 2)
WMI_SET_TDLS_PEER_VI_UAPSD(peer_cap);
if ((peerStateParams->peerCap.peerUapsdQueue & 0x02) >> 1)
WMI_SET_TDLS_PEER_BK_UAPSD(peer_cap);
if (peerStateParams->peerCap.peerUapsdQueue & 0x01)
WMI_SET_TDLS_PEER_BE_UAPSD(peer_cap);
/* Ack and More Data Ack are sent as 0, so no need to set
* but fill SP
*/
WMI_SET_TDLS_PEER_SP_UAPSD(peer_cap, peerStateParams->peerCap.peerMaxSp);
peer_cap->buff_sta_support =
peerStateParams->peerCap.peerBuffStaSupport;
peer_cap->off_chan_support =
peerStateParams->peerCap.peerOffChanSupport;
peer_cap->peer_curr_operclass =
peerStateParams->peerCap.peerCurrOperClass;
/* self curr operclass is not being used and so pass op class for
* preferred off chan in it.
*/
peer_cap->self_curr_operclass =
peerStateParams->peerCap.opClassForPrefOffChan;
peer_cap->peer_chan_len =
peerStateParams->peerCap.peerChanLen;
peer_cap->peer_operclass_len =
peerStateParams->peerCap.peerOperClassLen;
WMA_LOGD("%s: peer_operclass_len: %d",
__func__, peer_cap->peer_operclass_len);
for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++) {
peer_cap->peer_operclass[i] =
peerStateParams->peerCap.peerOperClass[i];
WMA_LOGD("%s: peer_operclass[%d]: %d",
__func__, i, peer_cap->peer_operclass[i]);
}
peer_cap->is_peer_responder =
peerStateParams->peerCap.isPeerResponder;
peer_cap->pref_offchan_num =
peerStateParams->peerCap.prefOffChanNum;
peer_cap->pref_offchan_bw =
peerStateParams->peerCap.prefOffChanBandwidth;
WMA_LOGD("%s: peer_qos: 0x%x, buff_sta_support: %d, off_chan_support: %d, peer_curr_operclass: %d, self_curr_operclass: %d, peer_chan_len: %d, peer_operclass_len: %d, is_peer_responder: %d, pref_offchan_num: %d, pref_offchan_bw: %d",
__func__, peer_cap->peer_qos, peer_cap->buff_sta_support,
peer_cap->off_chan_support, peer_cap->peer_curr_operclass,
peer_cap->self_curr_operclass, peer_cap->peer_chan_len,
peer_cap->peer_operclass_len, peer_cap->is_peer_responder,
peer_cap->pref_offchan_num, peer_cap->pref_offchan_bw);
/* next fill variable size array of peer chan info */
buf_ptr += sizeof(wmi_tdls_peer_capabilities);
WMITLV_SET_HDR(buf_ptr,
WMITLV_TAG_ARRAY_STRUC,
sizeof(wmi_channel) * peerStateParams->peerCap.peerChanLen);
chan_info = (wmi_channel *) (buf_ptr + WMI_TLV_HDR_SIZE);
for (i = 0; i < peerStateParams->peerCap.peerChanLen; ++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(peerStateParams->peerCap.peerChan[i].chanId);
chan_info->band_center_freq1 = chan_info->mhz;
chan_info->band_center_freq2 = 0;
if (peerStateParams->peerCap.peerChan[i].dfsSet) {
WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_PASSIVE);
}
if (chan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) {
WMI_SET_CHANNEL_MODE(chan_info, MODE_11G);
} else {
WMI_SET_CHANNEL_MODE(chan_info, MODE_11A);
}
WMI_SET_CHANNEL_MAX_TX_POWER(chan_info,
peerStateParams->peerCap.peerChan[i].pwr);
WMI_SET_CHANNEL_REG_POWER(chan_info,
peerStateParams->peerCap.peerChan[i].pwr);
WMA_LOGD(FL("Channel %u[%d] DFS[%d] TX power = %d"),
chan_info->mhz, i,
peerStateParams->peerCap.peerChan[i].dfsSet,
peerStateParams->peerCap.peerChan[i].pwr);
chan_info++;
}
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_TDLS_PEER_UPDATE_CMDID)) {
WMA_LOGE("%s: failed to send tdls peer update state command",
__func__);
wmi_buf_free(wmi_buf);
ret = -EIO;
goto end_tdls_peer_state;
}
/* in case of teardown, remove peer from fw */
if (WDA_TDLS_PEER_STATE_TEARDOWN == peerStateParams->peerState) {
pdev = vos_get_context(VOS_MODULE_ID_TXRX, wma_handle->vos_context);
if (!pdev) {
WMA_LOGE("%s: Failed to find pdev", __func__);
ret = -EIO;
goto end_tdls_peer_state;
}
peer = ol_txrx_find_peer_by_addr(pdev, peerStateParams->peerMacAddr,
&peer_id);
if (!peer) {
WMA_LOGE("%s: Failed to get peer handle using peer mac %pM",
__func__, peerStateParams->peerMacAddr);
ret = -EIO;
goto end_tdls_peer_state;
}
#if defined(CONFIG_HL_SUPPORT)
vdev = peer->vdev;
if (vdev->last_real_peer && (vdev->last_real_peer == peer))
restore_last_peer = true;
#endif
WMA_LOGD("%s: calling wma_remove_peer for peer " MAC_ADDRESS_STR
" vdevId: %d", __func__,
MAC_ADDR_ARRAY(peer->mac_addr.raw), peerStateParams->vdevId);
wma_remove_peer(wma_handle, peer->mac_addr.raw,
peerStateParams->vdevId, peer,
VOS_FALSE);
#if defined(CONFIG_HL_SUPPORT)
if (restore_last_peer && (vdev->last_real_peer == NULL)) {
peer = NULL;
peer = ol_txrx_find_peer_by_addr(pdev, vdev->hl_tdls_ap_mac_addr.raw, &peer_id);
if (peer && (peer->peer_ids[0] != HTT_INVALID_PEER_ID))
vdev->last_real_peer = peer;
}
#endif
}
end_tdls_peer_state:
if (peerStateParams)
vos_mem_free(peerStateParams);
return ret;
}
#endif /* FEATURE_WLAN_TDLS */
/*
* Attach DFS methods to the umac state.
*/
struct ieee80211com* wma_dfs_attach(struct ieee80211com *dfs_ic)
{
/*Allocate memory for dfs_ic before passing it up to dfs_attach()*/
dfs_ic = (struct ieee80211com *)
OS_MALLOC(NULL, sizeof(struct ieee80211com), GFP_ATOMIC);
if (dfs_ic == NULL)
{
WMA_LOGE("%s:Allocation of dfs_ic failed %zu",
__func__, sizeof(struct ieee80211com));
return NULL;
}
OS_MEMZERO(dfs_ic, sizeof (struct ieee80211com));
/* DFS pattern matching hooks */
dfs_ic->ic_dfs_attach = ol_if_dfs_attach;
dfs_ic->ic_dfs_disable = ol_if_dfs_disable;
dfs_ic->ic_find_channel = ieee80211_find_channel;
dfs_ic->ic_dfs_enable = ol_if_dfs_enable;
dfs_ic->ic_ieee2mhz = ieee80211_ieee2mhz;
/* Hardware facing hooks */
dfs_ic->ic_get_ext_busy = ol_if_dfs_get_ext_busy;
dfs_ic->ic_get_mib_cycle_counts_pct =
ol_if_dfs_get_mib_cycle_counts_pct;
dfs_ic->ic_get_TSF64 = ol_if_get_tsf64;
/* NOL related hooks */
dfs_ic->ic_dfs_usenol = ol_if_dfs_usenol;
/*
* Hooks from wma/dfs/ back
* into the PE/SME
* and shared DFS code
*/
dfs_ic->ic_dfs_notify_radar = ieee80211_mark_dfs;
dfs_ic->ic_update_dfs_cac_block_tx = ieee80211_update_dfs_cac_block_tx;
adf_os_spinlock_init(&dfs_ic->chan_lock);
/* Initializes DFS Data Structures and queues*/
dfs_attach(dfs_ic);
return dfs_ic;
}
#ifdef ATH_SUPPORT_DFS
/*
* Configures Radar Filters during
* vdev start/channel change/regulatory domain
* change.This Configuration enables to program
* the DFS pattern matching module.
*/
void wma_dfs_configure(struct ieee80211com *ic)
{
struct ath_dfs_radar_tab_info rinfo;
int dfsdomain;
int radar_enabled_status = 0;
if(ic == NULL) {
WMA_LOGE("%s: DFS ic is Invalid",__func__);
return;
}
dfsdomain = ic->current_dfs_regdomain;
/* Fetch current radar patterns from the lmac */
OS_MEMZERO(&rinfo, sizeof(rinfo));
/*
* Look up the current DFS
* regulatory domain and decide
* which radar pulses to use.
*/
switch (dfsdomain)
{
case DFS_FCC_DOMAIN:
WMA_LOGI("%s: DFS-FCC domain",__func__);
rinfo.dfsdomain = DFS_FCC_DOMAIN;
rinfo.dfs_radars = dfs_fcc_radars;
rinfo.numradars = ARRAY_LENGTH(dfs_fcc_radars);
rinfo.b5pulses = dfs_fcc_bin5pulses;
rinfo.numb5radars = ARRAY_LENGTH(dfs_fcc_bin5pulses);
break;
case DFS_ETSI_DOMAIN:
WMA_LOGI("%s: DFS-ETSI domain",__func__);
rinfo.dfsdomain = DFS_ETSI_DOMAIN;
rinfo.dfs_radars = dfs_etsi_radars;
rinfo.numradars = ARRAY_LENGTH(dfs_etsi_radars);
rinfo.b5pulses = NULL;
rinfo.numb5radars = 0;
break;
case DFS_MKK4_DOMAIN:
WMA_LOGI("%s: DFS-MKK4 domain",__func__);
rinfo.dfsdomain = DFS_MKK4_DOMAIN;
rinfo.dfs_radars = dfs_mkk4_radars;
rinfo.numradars = ARRAY_LENGTH(dfs_mkk4_radars);
rinfo.b5pulses = dfs_jpn_bin5pulses;
rinfo.numb5radars = ARRAY_LENGTH(dfs_jpn_bin5pulses);
break;
default:
WMA_LOGI("%s: DFS-UNINT domain",__func__);
rinfo.dfsdomain = DFS_UNINIT_DOMAIN;
rinfo.dfs_radars = NULL;
rinfo.numradars = 0;
rinfo.b5pulses = NULL;
rinfo.numb5radars = 0;
break;
}
rinfo.dfs_pri_multiplier = ic->dfs_pri_multiplier;
/*
* Set the regulatory domain,
* radar pulse table and enable
* radar events if required.
* dfs_radar_enable() returns
* 0 on success and non-zero
* failure.
*/
radar_enabled_status = dfs_radar_enable(ic, &rinfo);
if (radar_enabled_status != DFS_STATUS_SUCCESS) {
WMA_LOGE("%s[%d]: DFS- Radar Detection Enabling Failed",
__func__, __LINE__);
}
}
/*
* Set the Channel parameters in to DFS module
* Also,configure the DFS radar filters for
* matching the DFS phyerrors.
*/
struct ieee80211_channel *
wma_dfs_configure_channel(struct ieee80211com *dfs_ic,
wmi_channel *chan,
WLAN_PHY_MODE chanmode,
struct wma_vdev_start_req *req)
{
if(dfs_ic == NULL)
{
WMA_LOGE("%s: DFS ic is Invalid",__func__);
return NULL;
}
if (!dfs_ic->ic_curchan) {
dfs_ic->ic_curchan = (struct ieee80211_channel *) OS_MALLOC(NULL,
sizeof(struct ieee80211_channel),
GFP_ATOMIC);
if (dfs_ic->ic_curchan == NULL) {
WMA_LOGE("%s: allocation of dfs_ic->ic_curchan failed %zu",
__func__, sizeof(struct ieee80211_channel));
return NULL;
}
}
OS_MEMZERO(dfs_ic->ic_curchan, sizeof (struct ieee80211_channel));
dfs_ic->ic_curchan->ic_ieee = req->chan;
dfs_ic->ic_curchan->ic_freq = chan->mhz;
if (chan->band_center_freq1 != 0)
dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1 = chan->band_center_freq1;
else {
dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1 = chan->mhz;
if (chanmode == MODE_11AC_VHT80)
chan->band_center_freq1 = vos_chan_to_freq(
wma_getCenterChannel(
chan->mhz,
req->chan_offset));
if ((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;
}
if (chanmode == MODE_11NA_HT40) {
if (req->chan_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
chan->band_center_freq1 += 10;
else
chan->band_center_freq1 -= 10;
}
dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1 = chan->band_center_freq1;
}
dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg2 = chan->band_center_freq2;
dfs_ic->ic_curchan->ic_pri_freq_center_freq_mhz_separation =
dfs_ic->ic_curchan->ic_freq -
dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1;
if ( (dfs_ic->ic_curchan->ic_ieee >= WMA_11A_CHANNEL_BEGIN) &&
(dfs_ic->ic_curchan->ic_ieee <= WMA_11A_CHANNEL_END) )
{
dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_5GHZ;
}
if(chanmode == MODE_11AC_VHT80)
{
dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_VHT80;
}
if (req->chan_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
{
dfs_ic->ic_curchan->ic_flags |=
(req->vht_capable ?
IEEE80211_CHAN_VHT40PLUS : IEEE80211_CHAN_HT40PLUS);
}
else if (req->chan_offset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
{
dfs_ic->ic_curchan->ic_flags |=
(req->vht_capable ?
IEEE80211_CHAN_VHT40MINUS : IEEE80211_CHAN_HT40MINUS);
}
else if (req->chan_offset == PHY_SINGLE_CHANNEL_CENTERED)
{
dfs_ic->ic_curchan->ic_flags |=
(req->vht_capable ? IEEE80211_CHAN_VHT20 : IEEE80211_CHAN_HT20);
}
dfs_ic->ic_curchan->ic_flagext |= IEEE80211_CHAN_DFS;
if (req->oper_mode == BSS_OPERATIONAL_MODE_AP)
{
dfs_ic->ic_opmode = IEEE80211_M_HOSTAP;
dfs_ic->vdev_id = req->vdev_id;
}
dfs_ic->dfs_pri_multiplier = req->dfs_pri_multiplier;
/*
* Configuring the DFS with current channel and the radar filters
*/
wma_dfs_configure(dfs_ic);
WMA_LOGI("%s: DFS- CHANNEL CONFIGURED",__func__);
return dfs_ic->ic_curchan;
}
/*
* Configure the regulatory domain for DFS radar filter initialization
*/
void wma_set_dfs_regdomain(tp_wma_handle wma, uint8_t dfs_region)
{
/* dfs information is passed */
if (dfs_region > DFS_MKK4_DOMAIN || dfs_region == DFS_UNINIT_DOMAIN)
/* assign DFS_FCC_DOMAIN as default domain*/
wma->dfs_ic->current_dfs_regdomain = DFS_FCC_DOMAIN;
else
wma->dfs_ic->current_dfs_regdomain = dfs_region;
WMA_LOGI("%s: DFS Region Domain: %d", __func__,
wma->dfs_ic->current_dfs_regdomain);
}
#else
void wma_dfs_configure(struct ieee80211com *ic)
{
}
void wma_set_dfs_regdomain(tp_wma_handle wma, uint8_t dfs_region)
{
}
struct ieee80211_channel *
wma_dfs_configure_channel(struct ieee80211com *dfs_ic,
wmi_channel *chan,
WLAN_PHY_MODE chanmode,
struct wma_vdev_start_req *req)
{
return NULL;
}
#endif
int wma_get_channels(struct ieee80211_channel *ichan,
struct wma_dfs_radar_channel_list *chan_list)
{
uint8_t center_chan = vos_freq_to_chan(ichan->ic_vhtop_ch_freq_seg1);
chan_list->nchannels = 0;
if (IEEE80211_IS_CHAN_11AC_VHT80(ichan))
{
chan_list->nchannels= 4;
chan_list->channels[0] = center_chan - 6;
chan_list->channels[1] = center_chan - 2;
chan_list->channels[2] = center_chan + 2;
chan_list->channels[3] = center_chan + 6;
}
else if(IEEE80211_IS_CHAN_11N_HT40(ichan) ||
IEEE80211_IS_CHAN_11AC_VHT40(ichan))
{
chan_list->nchannels = 2;
chan_list->channels[0] = center_chan - 2;
chan_list->channels[1] = center_chan + 2;
}
else
{
chan_list->nchannels = 1;
chan_list->channels[0] = center_chan;
}
return chan_list->nchannels;
}
void wma_update_dfs_cac_block_tx(bool cac_block_tx)
{
tp_wma_handle wma;
void *hdd_ctx;
void *vos_context;
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 == NULL) {
WMA_LOGE("%s: DFS- Invalid wma", __func__);
return;
}
hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, wma->vos_context);
wma->dfs_block_tx_cb(hdd_ctx, cac_block_tx);
}
/*
* Indicate Radar to SAP/HDD
*/
int wma_dfs_indicate_radar(struct ieee80211com *ic,
struct ieee80211_channel *ichan)
{
tp_wma_handle wma;
void *hdd_ctx;
struct wma_dfs_radar_indication *radar_event;
struct hdd_dfs_radar_ind hdd_radar_event;
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tpAniSirGlobal pmac = NULL;
bool indication_status;
wma = (tp_wma_handle) vos_get_context(VOS_MODULE_ID_WDA, vos_context);
if (wma == NULL)
{
WMA_LOGE("%s: DFS- Invalid wma", __func__);
return -ENOENT;
}
hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD,wma->vos_context);
pmac = (tpAniSirGlobal)
vos_get_context(VOS_MODULE_ID_PE, wma->vos_context);
if (!pmac) {
WMA_LOGE("%s:Invalid MAC handle", __func__);
return -ENOENT;
}
if (wma->dfs_ic != ic)
{
WMA_LOGE("%s:DFS- Invalid WMA handle", __func__);
return -ENOENT;
}
/*
* Do not post multiple Radar events on the same channel.
* But, when DFS test mode is enabled, allow multiple dfs
* radar events to be posted on the same channel.
*/
adf_os_spin_lock_bh(&ic->chan_lock);
if (!pmac->sap.SapDfsInfo.disable_dfs_ch_switch)
wma->dfs_ic->disable_phy_err_processing = true;
if ((ichan->ic_ieee != (wma->dfs_ic->last_radar_found_chan)) ||
( pmac->sap.SapDfsInfo.disable_dfs_ch_switch == VOS_TRUE) )
{
radar_event = (struct wma_dfs_radar_indication *)
vos_mem_malloc(sizeof(*radar_event));
if (radar_event == NULL) {
WMA_LOGE(FL("Failed to allocate memory for radar_event"));
adf_os_spin_unlock_bh(&ic->chan_lock);
return -ENOMEM;
}
/* Indicate the radar event to HDD to stop the netif Tx queues*/
hdd_radar_event.ieee_chan_number = ichan->ic_ieee;
hdd_radar_event.chan_freq = ichan->ic_freq;
hdd_radar_event.dfs_radar_status = WMA_DFS_RADAR_FOUND;
indication_status =
wma->dfs_radar_indication_cb(hdd_ctx,&hdd_radar_event);
if (indication_status == false)
{
WMA_LOGE("%s:Application triggered channel switch in progress!.. drop radar event indiaction to SAP",
__func__);
vos_mem_free(radar_event);
adf_os_spin_unlock_bh(&ic->chan_lock);
return 0;
}
else
WMA_LOGE("%s:DFS- RADAR INDICATED TO HDD",__func__);
wma->dfs_ic->last_radar_found_chan = ichan->ic_ieee;
/*
* Indicate to the radar event to SAP to
* select a new channel and set CSA IE
*/
radar_event->vdev_id = ic->vdev_id;
wma_get_channels(ichan, &radar_event->chan_list);
radar_event->dfs_radar_status = WMA_DFS_RADAR_FOUND;
radar_event->use_nol = ic->ic_dfs_usenol(ic);
wma_send_msg(wma, WDA_DFS_RADAR_IND, (void *)radar_event, 0);
WMA_LOGE("%s:DFS- WDA_DFS_RADAR_IND Message Posted",__func__);
}
adf_os_spin_unlock_bh(&ic->chan_lock);
return 0;
}
static eHalStatus wma_set_smps_params(tp_wma_handle wma, tANI_U8 vdev_id, int value)
{
int ret = eHAL_STATUS_SUCCESS;
wmi_sta_smps_param_cmd_fixed_param *cmd;
wmi_buf_t buf;
u_int16_t len = sizeof(*cmd);
buf = wmi_buf_alloc(wma->wmi_handle, len);
if (!buf) {
WMA_LOGE("%s:wmi_buf_alloc failed", __func__);
return -ENOMEM;
}
cmd = (wmi_sta_smps_param_cmd_fixed_param *) wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(
wmi_sta_smps_param_cmd_fixed_param));
cmd->vdev_id = vdev_id;
cmd->value = value & WMA_SMPS_MASK_LOWER_16BITS;
cmd->param = (value >> WMA_SMPS_PARAM_VALUE_S) & WMA_SMPS_MASK_UPPER_3BITS;
WMA_LOGD("Setting vdev %d value = %x param %x", vdev_id, cmd->value, cmd->param);
ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len,
WMI_STA_SMPS_PARAM_CMDID);
if (ret < 0) {
WMA_LOGE("Failed to send set Mimo PS ret = %d", ret);
wmi_buf_free(buf);
}
return ret;
}
VOS_STATUS WMA_GetWcnssSoftwareVersion(v_PVOID_t pvosGCtx,
tANI_U8 *pVersion,
tANI_U32 versionBufferSize)
{
tp_wma_handle wma_handle;
wma_handle = vos_get_context(VOS_MODULE_ID_WDA, pvosGCtx);
if (NULL == wma_handle) {
WMA_LOGE("%s: Failed to get wma", __func__);
return VOS_STATUS_E_FAULT;
}
snprintf(pVersion, versionBufferSize, "%x", (unsigned int)wma_handle->target_fw_version);
return VOS_STATUS_SUCCESS;
}
#ifdef HL_RX_AGGREGATION_HOLE_DETCTION
/**
* ol_rx_aggregation_hole - ol rx aggregation hole report
* @hole_info: hole_info
*
* Return: void
*/
void ol_rx_aggregation_hole(uint32_t hole_info)
{
struct sir_sme_rx_aggr_hole_ind *rx_aggr_hole_event;
uint32_t alloc_len;
vos_msg_t vos_msg;
VOS_STATUS status;
alloc_len = sizeof(*rx_aggr_hole_event) +
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;
}
rx_aggr_hole_event->hole_cnt = 1;
rx_aggr_hole_event->hole_info_array[0] = 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 aggr event to SME", __func__);
vos_mem_free(rx_aggr_hole_event);
return;
}
}
#endif
void ol_rx_err(ol_pdev_handle pdev, u_int8_t vdev_id,
u_int8_t *peer_mac_addr, int tid, u_int32_t tsf32,
enum ol_rx_err_type err_type, adf_nbuf_t rx_frame,
u_int64_t *pn, u_int8_t key_id)
{
void *g_vos_ctx = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA, g_vos_ctx);
tpSirSmeMicFailureInd mic_err_ind;
struct ether_header *eth_hdr;
if (NULL == wma) {
WMA_LOGE("%s: Failed to get wma", __func__);
return;
}
if (err_type != OL_RX_ERR_TKIP_MIC)
return;
if (adf_nbuf_len(rx_frame) < sizeof(*eth_hdr))
return;
eth_hdr = (struct ether_header *) adf_nbuf_data(rx_frame);
mic_err_ind = vos_mem_malloc(sizeof(*mic_err_ind));
if (!mic_err_ind) {
WMA_LOGE("%s: Failed to allocate memory for MIC indication message", __func__);
return;
}
adf_os_mem_set((void *) mic_err_ind, 0, sizeof(*mic_err_ind));
mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND;
mic_err_ind->length = sizeof(*mic_err_ind);
adf_os_mem_copy(mic_err_ind->bssId,
(v_MACADDR_t *) wma->interfaces[vdev_id].bssid,
sizeof(tSirMacAddr));
adf_os_mem_copy(mic_err_ind->info.taMacAddr,
(v_MACADDR_t *) peer_mac_addr, sizeof(tSirMacAddr));
adf_os_mem_copy(mic_err_ind->info.srcMacAddr,
(v_MACADDR_t *) eth_hdr->ether_shost, sizeof(tSirMacAddr));
adf_os_mem_copy(mic_err_ind->info.dstMacAddr,
(v_MACADDR_t *) eth_hdr->ether_dhost, sizeof(tSirMacAddr));
mic_err_ind->info.keyId = key_id;
mic_err_ind->info.multicast = IEEE80211_IS_MULTICAST(eth_hdr->ether_dhost);
adf_os_mem_copy(mic_err_ind->info.TSC, pn, SIR_CIPHER_SEQ_CTR_SIZE);
wma_send_msg(wma, SIR_HAL_MIC_FAILURE_IND, (void *) mic_err_ind, 0);
}
void
ol_indicate_err(
enum ol_rx_err_type err_type,
struct ol_error_info * err_info)
{
switch (err_type) {
case OL_RX_ERR_TKIP_MIC:
{
void *g_vos_ctx = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA, g_vos_ctx);
tpSirSmeMicFailureInd mic_err_ind;
if (!wma) {
WMA_LOGE("%s: MIC error: Null wma handle",
__func__);
return;
}
mic_err_ind = vos_mem_malloc(sizeof(*mic_err_ind));
if (!mic_err_ind) {
WMA_LOGE("%s: Failed to allocate memory for MIC indication message", __func__);
return;
}
adf_os_mem_set((void *) mic_err_ind, 0, sizeof(*mic_err_ind));
mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND;
mic_err_ind->length = sizeof(*mic_err_ind);
adf_os_mem_copy(mic_err_ind->bssId,
(v_MACADDR_t *) wma->interfaces[err_info->u.mic_err.vdev_id].bssid,
sizeof(tSirMacAddr));
WMA_LOGE("MIC error: BSSID:%02x:%02x:%02x:%02x:%02x:%02x\n",
mic_err_ind->bssId[0], mic_err_ind->bssId[1],
mic_err_ind->bssId[2], mic_err_ind->bssId[3],
mic_err_ind->bssId[4], mic_err_ind->bssId[5]);
adf_os_mem_copy(mic_err_ind->info.taMacAddr,
(v_MACADDR_t *) err_info->u.mic_err.ta, sizeof(tSirMacAddr));
adf_os_mem_copy(mic_err_ind->info.srcMacAddr,
(v_MACADDR_t *) err_info->u.mic_err.sa, sizeof(tSirMacAddr));
adf_os_mem_copy(mic_err_ind->info.dstMacAddr,
(v_MACADDR_t *) err_info->u.mic_err.da, sizeof(tSirMacAddr));
mic_err_ind->info.keyId = err_info->u.mic_err.key_id;
mic_err_ind->info.multicast =
IEEE80211_IS_MULTICAST(err_info->u.mic_err.da);
adf_os_mem_copy(mic_err_ind->info.TSC, (void*)&err_info->
u.mic_err.pn, SIR_CIPHER_SEQ_CTR_SIZE);
wma_send_msg(wma, SIR_HAL_MIC_FAILURE_IND, (void *) mic_err_ind, 0);
break;
}
default:
{
WMA_LOGE("%s: unhandled ol error type %d", __func__, err_type);
break;
}
}
}
void WDA_TxAbort(v_U8_t vdev_id)
{
#define PEER_ALL_TID_BITMASK 0xffffffff
tp_wma_handle wma;
u_int32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK;
struct wma_txrx_node *iface;
wma = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_WDA, NULL));
if (NULL == wma) {
WMA_LOGE("%s: wma is NULL", __func__);
return;
}
iface = &wma->interfaces[vdev_id];
if (!iface->handle) {
WMA_LOGE("%s: Failed to get iface handle: %pK",
__func__, iface->handle);
return;
}
WMA_LOGI("%s: vdevid %d bssid %pM", __func__, vdev_id, iface->bssid);
iface->pause_bitmap |= (1 << PAUSE_TYPE_HOST);
wdi_in_vdev_pause(iface->handle, OL_TXQ_PAUSE_REASON_TX_ABORT);
/* 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, iface->bssid,
peer_tid_bitmap, vdev_id);
}
static void wma_set_vdev_suspend_dtim(tp_wma_handle wma, v_U8_t vdev_id)
{
struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
if ((iface->type == WMI_VDEV_TYPE_STA) &&
(iface->dtimPeriod != 0)) {
int32_t ret;
u_int32_t listen_interval;
u_int32_t max_mod_dtim;
u_int32_t beacon_interval_mod;
if (wma->staDynamicDtim) {
listen_interval = wma->staDynamicDtim;
} else if ((wma->staModDtim) &&
(wma->staMaxLIModDtim)) {
/*
* When the system is in suspend
* (maximum beacon will be at 1s == 10)
* If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM)
* equal or larger than MDTIM (configured in WCNSS_qcom_cfg.ini)
* Set LI to MDTIM * AP_DTIM
* If Dtim = 2 and Mdtim = 2 then LI is 4
* Else
* Set LI to maxModulatedDTIM * AP_DTIM
*/
beacon_interval_mod = iface->beaconInterval/100;
if (beacon_interval_mod == 0)
beacon_interval_mod = 1;
max_mod_dtim = wma->staMaxLIModDtim
/(iface->dtimPeriod*beacon_interval_mod);
if (max_mod_dtim <= 0)
max_mod_dtim = 1;
if (max_mod_dtim >= wma->staModDtim) {
listen_interval =
(wma->staModDtim * iface->dtimPeriod);
} else {
listen_interval =
(max_mod_dtim * iface->dtimPeriod);
}
} else {
return;
}
WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
vdev_id, listen_interval);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_LISTEN_INTERVAL,
listen_interval);
if (ret) {
/* Even it fails continue Fw will take default LI */
WMA_LOGE("Failed to Set Listen Interval vdevId %d",
vdev_id);
}
if (qpower_config) {
WMA_LOGD("disable Qpower in suspend mode!");
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
vdev_id,
WMI_STA_PS_ENABLE_QPOWER,
0);
if (ret)
WMA_LOGE("Failed to disable Qpower in suspend mode!");
}
/*
* Set inactivity time to 50ms when DUT is in WoW mode.
* It will be recovered to the cfg value when DUT resumes.
*
* The value 50ms inherits from Pronto. Pronto has different
* inactivity for broadcast frames (worst case inactivity
* is 50ms). 200ms Inactivity timer is applicable only to
* unicast data traffic.
*/
WMA_LOGD("%s: Set inactivity_time to 50.", __func__);
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_INACTIVITY_TIME, 50);
if (ret)
WMA_LOGE("%s: Setting InActivity time Failed.",
__func__);
WMA_LOGD("%s: Set the Tx Wake Threshold 0.", __func__);
ret = wmi_unified_set_sta_ps_param(
wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD,
WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER);
if (ret)
WMA_LOGE("%s: Setting TxWake Threshold Failed.",
__func__);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_DTIM_POLICY ,
NORMAL_DTIM);
if (ret) {
/* Set it to Normal DTIM */
WMA_LOGE("Failed to Set to Normal DTIM vdevId %d",
vdev_id);
}
iface->dtim_policy = NORMAL_DTIM;
WMA_LOGD("Set DTIM Policy to Normal Dtim vdevId %d", vdev_id);
}
}
static void wma_set_suspend_dtim(tp_wma_handle wma)
{
u_int8_t i;
if (NULL == wma) {
WMA_LOGE("%s: wma is NULL", __func__);
return;
}
for (i = 0; i < wma->max_bssid; i++) {
if ((wma->interfaces[i].handle) &&
(false == wma->interfaces[i].alt_modulated_dtim_enabled)) {
wma_set_vdev_suspend_dtim(wma, i);
}
}
}
static void wma_set_vdev_resume_dtim(tp_wma_handle wma, v_U8_t vdev_id)
{
struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma);
u_int32_t inactivity_time;
if ((iface->type == WMI_VDEV_TYPE_STA) &&
(iface->dtim_policy == NORMAL_DTIM)) {
int32_t ret;
tANI_U32 cfg_data_val = 0;
/* get mac to acess CFG data base */
struct sAniSirGlobal *mac =
(struct sAniSirGlobal*)vos_get_context(VOS_MODULE_ID_PE,
wma->vos_context);
if (!mac) {
WMA_LOGE(FL("Failed to get mac context"));
return;
}
/* Set Listen Interval */
if (wlan_cfgGetInt(mac, WNI_CFG_LISTEN_INTERVAL,
&cfg_data_val) != eSIR_SUCCESS) {
VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get value for listen interval");
cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL;
}
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_LISTEN_INTERVAL,
cfg_data_val);
if (ret) {
/* Even it fails continue Fw will take default LI */
WMA_LOGE("Failed to Set Listen Interval vdevId %d",
vdev_id);
}
WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d",
vdev_id, cfg_data_val);
ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id,
WMI_VDEV_PARAM_DTIM_POLICY ,
STICK_DTIM);
if (ret) {
/* Set it back to Stick DTIM */
WMA_LOGE("Failed to Set to Stick DTIM vdevId %d",
vdev_id);
}
iface->dtim_policy = STICK_DTIM;
WMA_LOGD("Set DTIM Policy to Stick Dtim vdevId %d", vdev_id);
if (qpower_config) {
WMA_LOGD("enable Qpower in resume mode!");
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle,
vdev_id,
WMI_STA_PS_ENABLE_QPOWER,
qpower_config);
if (ret)
WMA_LOGE("Failed to enable Qpower in resume mode!");
}
if (wlan_cfgGetInt(mac, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT");
cfg_data_val = POWERSAVE_DEFAULT_INACTIVITY_TIME;
}
inactivity_time = (u_int32_t)cfg_data_val;
WMA_LOGD("%s: Setting InActivity time %d.", __func__,
inactivity_time);
ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_INACTIVITY_TIME,
inactivity_time);
if (ret)
WMA_LOGE("%s: Setting InActivity time Failed.",
__func__);
if (wlan_cfgGetInt(mac, WNI_CFG_MAX_PS_POLL,
&cfg_data_val ) != eSIR_SUCCESS) {
VOS_TRACE(VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
"Failed to get value for WNI_CFG_MAX_PS_POLL");
cfg_data_val = 0;
}
/*
* Recover the Tx Wake Threshold
* 1, do not recover the value, because driver sets
* WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER before suspend,
* 2, recover the value, because driver sets
* WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS before suspend,
* 3, recover the value WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS,
* which is defined by fw as default and driver does
* not set it when psSetting is eSIR_ADDON_DISABLE_UAPSD.
*/
if ((eSIR_ADDON_DISABLE_UAPSD == wma->psSetting)
|| ((eSIR_ADDON_NOTHING == wma->psSetting)
&& (!cfg_data_val))) {
WMA_LOGD("%s: Set the Tx Wake Threshold.", __func__);
ret = wmi_unified_set_sta_ps_param(
wma->wmi_handle, vdev_id,
WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD,
WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS);
if (ret)
WMA_LOGE("Setting TxWake Threshold vdevId %d",
vdev_id);
}
}
}
static void wma_set_resume_dtim(tp_wma_handle wma)
{
u_int8_t i;
if (NULL == wma) {
WMA_LOGE("%s: wma is NULL", __func__);
return;
}
for (i = 0; i < wma->max_bssid; i++) {
if ((wma->interfaces[i].handle) &&
(false == wma->interfaces[i].alt_modulated_dtim_enabled)) {
wma_set_vdev_resume_dtim(wma, i);
}
}
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
void wma_process_roam_synch_complete(WMA_HANDLE handle,
tSirSmeRoamOffloadSynchCnf *synchcnf)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
wmi_roam_synch_complete_fixed_param* cmd;
wmi_buf_t wmi_buf;
u_int8_t *buf_ptr;
u_int16_t len;
v_BOOL_t roam_synch_in_progress;
len = sizeof(wmi_roam_synch_complete_fixed_param);
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue roam synch cnf",
__func__);
return;
}
roam_synch_in_progress =
wma_handle->interfaces[synchcnf->sessionId].roam_synch_in_progress;
if (roam_synch_in_progress == VOS_FALSE) {
WMA_LOGE("%s: Dont send the roam synch complete since Roam Synch"
"Propagation is not in Progress", __func__);
return;
} else {
adf_os_spin_lock_bh(&wma_handle->roam_synch_lock);
wma_handle->interfaces[synchcnf->sessionId].roam_synch_in_progress =
VOS_FALSE;
adf_os_spin_unlock_bh(&wma_handle->roam_synch_lock);
}
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return;
}
cmd = (wmi_roam_synch_complete_fixed_param *)wmi_buf_data(wmi_buf);
buf_ptr = (u_int8_t *) cmd;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_roam_synch_complete_fixed_param));
cmd->vdev_id = synchcnf->sessionId;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_ROAM_SYNCH_COMPLETE)) {
WMA_LOGP("%s: failed to send roam synch confirmation", __func__);
wmi_buf_free(wmi_buf);
return;
}
DPTRACE(adf_dp_trace_record_event(ADF_DP_TRACE_EVENT_RECORD,
synchcnf->sessionId, ADF_PROTO_TYPE_EVENT, ADF_ROAM_COMPLETE));
return;
}
void wma_process_roam_synch_fail(WMA_HANDLE handle,
tSirRoamOffloadSynchFail *synchfail)
{
tp_wma_handle wma_handle = (tp_wma_handle) handle;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not clean-up roam synch",
__func__);
return;
}
/* Hand Off Failure could happen as an exception, when a roam synch
* indication is posted to Host, but a roam synch complete is not
* posted to the firmware.So, clear the roam synch in progress
* flag before disconnecting the session through this event.*/
adf_os_spin_lock_bh(&wma_handle->roam_synch_lock);
wma_handle->interfaces[synchfail->sessionId].roam_synch_in_progress =
VOS_FALSE;
adf_os_spin_unlock_bh(&wma_handle->roam_synch_lock);
}
#endif
#ifdef FEATURE_RUNTIME_PM
int wma_runtime_suspend_req(WMA_HANDLE handle)
{
vos_msg_t vosMessage;
VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
int ret = 0;
tp_wma_handle wma = (tp_wma_handle) handle;
vos_event_reset(&wma->runtime_suspend);
vosMessage.bodyptr = NULL;
vosMessage.type = WDA_RUNTIME_PM_SUSPEND_IND;
vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage );
if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
ret = -EAGAIN;
return ret;
}
if (vos_wait_single_event(&wma->runtime_suspend,
WMA_TGT_SUSPEND_COMPLETE_TIMEOUT) !=
VOS_STATUS_SUCCESS) {
WMA_LOGE("Failed to get runtime suspend event");
ret = -EAGAIN;
goto out;
}
/* Check if suspend completed, if not return failure */
if (!wma_get_wow_bus_suspend(wma)) {
WMA_LOGE("Runtime Suspend Failed: %d",
wma_get_wow_bus_suspend(wma));
ret = -EAGAIN;
}
out:
if (ret)
wma_runtime_resume_req(wma);
return ret;
}
int wma_runtime_resume_req(WMA_HANDLE handle)
{
vos_msg_t vosMessage;
VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
int ret = 0;
tp_wma_handle wma = (tp_wma_handle) handle;
struct wma_runtime_pm_context *runtime_context = &wma->runtime_context;
vos_runtime_pm_prevent_suspend(runtime_context->resume);
vosMessage.bodyptr = NULL;
vosMessage.type = WDA_RUNTIME_PM_RESUME_IND;
vosStatus = vos_mq_post_message(VOS_MQ_ID_WDA, &vosMessage );
if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
WMA_LOGE("Failed to post Runtime PM Resume IND to VOS");
ret = -EAGAIN;
vos_runtime_pm_allow_suspend(runtime_context->resume);
}
return ret;
}
#endif
/**
* wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID
* @vdev_id: vdev id
*
* Return: entry from vdev table
*/
struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id)
{
tp_wma_handle wma;
void *vos_ctx;
vos_ctx = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
wma = vos_get_context(VOS_MODULE_ID_WDA, vos_ctx);
if (!wma) {
WMA_LOGE("%s: Invalid WMA handle", __func__);
return NULL;
}
if (vdev_id >= wma->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id);
return NULL;
}
return &wma->interfaces[vdev_id];
}
/**
* wma_is_vdev_up() - return whether a vdev is up
* @vdev_id: vdev id
*
* Return: true if the vdev is up, false otherwise
*/
bool wma_is_vdev_up(uint8_t vdev_id)
{
struct wma_txrx_node *vdev = wma_get_interface_by_vdev_id(vdev_id);
if (vdev)
return vdev->vdev_up;
else
return false;
}
/**
* wma_get_vht_ch_width - return vht channel width
*
* Return: return vht channel width
*/
uint32_t wma_get_vht_ch_width(void)
{
uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ;
v_CONTEXT_t v_ctx = vos_get_global_context(VOS_MODULE_ID_VOSS, NULL);
tp_wma_handle wm_hdl = (tp_wma_handle)vos_get_context(VOS_MODULE_ID_WDA,
v_ctx);
if (NULL == wm_hdl) {
WMA_LOGE("%s: Failed to get wm_hdl", __func__);
return -EINVAL;
}
if (wm_hdl->vht_cap_info & IEEE80211_VHTCAP_SUP_CHAN_WIDTH_160)
fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ;
else if (wm_hdl->vht_cap_info & IEEE80211_VHTCAP_SUP_CHAN_WIDTH_80_160)
fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
return fw_ch_wd;
}
/*
* wma_suspend_fw() - API to suspend FW
*
* The API will be called only for SDIO driver from HDD, for other drivers
* by default HIF return failure, FW suspend happens in bus suspend callbacks.
*
* Return : int
*/
int wma_suspend_fw(void)
{
int ret = 0;
int is_wow_enabled;
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_VOSS, NULL));
if (!wma)
return -EINVAL;
if (wma_check_scan_in_progress(wma)) {
WMA_LOGE("%s: Scan in progress, Aborting suspend", __func__);
return -EBUSY;
}
is_wow_enabled = wma_is_wow_mode_selected(wma);
if (is_wow_enabled)
ret = wma_enable_wow_in_fw(wma, 0);
else
ret = wma_suspend_target(wma, 0);
if (ret) {
pr_err("%s: %s suspend failed\n", __func__,
is_wow_enabled ? "wow" : "pdev");
return ret;
}
pr_debug("%s: %s suspend successful\n", __func__,
is_wow_enabled ? "wow" : "pdev");
return ret;
}
/*
* wma_resume_fw() - API to resume FW
*
* The API will be called only for SDIO driver from HDD, for other drivers
* by default HIF return failure, FW resume happens in bus resume callbacks.
*
* Return : int
*/
int wma_resume_fw(void)
{
int ret = 0;
int is_wow_enabled;
tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA,
vos_get_global_context(VOS_MODULE_ID_VOSS, NULL));
if (!wma)
return -EINVAL;
is_wow_enabled = wma_is_wow_mode_selected(wma);
if (is_wow_enabled)
ret = wma_disable_wow_in_fw(wma, 0);
else
ret = wma_resume_target(wma, 0);
if (ret) {
pr_err("%s: %s resume failed\n", __func__,
is_wow_enabled ? "wow" : "pdev");
return ret;
}
pr_debug("%s: %s resume successful\n", __func__,
is_wow_enabled ? "wow" : "pdev");
return ret;
}
/**
* wma_btc_set_bt_wlan_interval() - send btc bt/wlan interval page to FW
* common function to send btc bt/wlan interval page (p2p/sta/sap)
* to the firmware
* @wma_handle: pointer to the WMA handle
* @interval: pointer to the WMI_COEX_CONFIG_CMD_fixed_param struct
*
* Return: 0 - success
*/
int wma_btc_set_bt_wlan_interval(tp_wma_handle wma_handle,
WMI_COEX_CONFIG_CMD_fixed_param *interval)
{
int32_t ret;
WMI_COEX_CONFIG_CMD_fixed_param *cmd;
uint8_t *buf_ptr;
uint32_t len;
wmi_buf_t buf;
len = sizeof(*cmd);
buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!buf) {
WMA_LOGE(FL("wmi_buf_alloc failed"));
return -ENOMEM;
}
buf_ptr = (uint8_t *)wmi_buf_data(buf);
cmd = (WMI_COEX_CONFIG_CMD_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_WMI_COEX_CONFIG_CMD_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(WMI_COEX_CONFIG_CMD_fixed_param));
cmd->vdev_id = interval->vdev_id;
cmd->config_type= interval->config_type;
cmd->config_arg1 = interval->config_arg1;
cmd->config_arg2 = interval->config_arg2;
ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
WMI_COEX_CONFIG_CMDID);
if (ret != EOK) {
WMA_LOGE(FL("Failed to set btc bt/wlan interval"));
wmi_buf_free(buf);
return -EIO;
}
WMA_LOGI("[BTC]: config_type = %d, config_arg1 = %d, config_arg2 = %d",
interval->config_type,
interval->config_arg1,
interval->config_arg2);
return 0;
}
/**
* wma_set_tx_power_scale() - set tx power scale
* @vdev_id: vdev id
* @value: value
*
* Return: VOS_STATUS_SUCCESS for success or error code.
*/
VOS_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value)
{
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
VOS_STATUS ret;
tp_wma_handle wma_handle = (tp_wma_handle) vos_get_context(
VOS_MODULE_ID_WDA, vos_context);
if (NULL == wma_handle) {
WMA_LOGE("%s: wma_handle is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
if (!(wma_handle->interfaces[vdev_id].vdev_up)) {
WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id,
WMI_VDEV_PARAM_TXPOWER_SCALE, value);
if (ret != VOS_STATUS_SUCCESS)
WMA_LOGE("Set tx power value failed");
return ret;
}
/**
* wma_set_tx_power_scale_decr_db() - decrease power by DB value
* @vdev_id: vdev id
* @value: value
*
* Return: CDF_STATUS_SUCCESS for success or error code.
*/
VOS_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value)
{
void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL);
VOS_STATUS ret;
tp_wma_handle wma_handle = (tp_wma_handle) vos_get_context(
VOS_MODULE_ID_WDA, vos_context);
if (NULL == wma_handle) {
WMA_LOGE("%s: wma_handle is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
if (!(wma_handle->interfaces[vdev_id].vdev_up)) {
WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id);
return VOS_STATUS_E_FAILURE;
}
ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id,
WMI_VDEV_PARAM_TXPOWER_SCALE_DECR_DB, value);
if (ret != VOS_STATUS_SUCCESS)
WMA_LOGE("Decrease tx power value failed");
return ret;
}