M7350/wlan/host/wmi/wmi.c

8618 lines
231 KiB
C
Raw Normal View History

2024-09-09 08:52:07 +00:00
//------------------------------------------------------------------------------
// ISC License (ISC)
//
// Copyright (c) 2004-2012, The Linux Foundation
// All rights reserved.
// Software was previously licensed under 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 module implements the hardware independent layer of the
// Wireless Module Interface (WMI) protocol.
//
// Author(s): ="Atheros"
//==============================================================================
#include <a_config.h>
#include <athdefs.h>
#include <a_types.h>
#include <a_osapi.h>
#include "htc.h"
#include "htc_api.h"
#include "wmi.h"
#include <wlan_api.h>
#include <wmi_api.h>
#include <ieee80211.h>
#include <ieee80211_node.h>
#include "dset_api.h"
#include "gpio_api.h"
#include "wmi_host.h"
#include "a_drv.h"
#include "a_drv_api.h"
#define ATH_MODULE_NAME wmi
#include "a_debug.h"
#include "dbglog_api.h"
#include "roaming.h"
#include "wmi_parser.h"
#define RSSI_AVE(avg, rssi, weight) \
((!(avg)) ? (rssi) : \
((((avg) * (weight)) + ((16 - (weight)) * (rssi))) / 16))
#define ATH_DEBUG_WMI ATH_DEBUG_MAKE_MODULE_MASK(0)
#ifdef DEBUG
static ATH_DEBUG_MASK_DESCRIPTION wmi_debug_desc[] = {
{ ATH_DEBUG_WMI , "General WMI Tracing"},
};
ATH_DEBUG_INSTANTIATE_MODULE_VAR(wmi,
"wmi",
"Wireless Module Interface",
ATH_DEBUG_MASK_DEFAULTS,
ATH_DEBUG_DESCRIPTION_COUNT(wmi_debug_desc),
wmi_debug_desc);
#endif
#ifndef REXOS
#define DBGARG _A_FUNCNAME_
#define DBGFMT "%s() : "
#define DBG_WMI ATH_DEBUG_WMI
#define DBG_ERROR ATH_DEBUG_ERR
#define DBG_WMI2 ATH_DEBUG_WMI
#define A_DPRINTF AR_DEBUG_PRINTF
#endif
#ifdef CONFIG_WLAN_RFKILL
static A_STATUS wmi_rfkill_state_change_event(struct wmi_t *wmip, A_UINT8* datap,int len);
static A_STATUS wmi_rfkill_get_mode_cmd_event_rx(struct wmi_t *wmip, A_UINT8* datap,int len);
#endif /* CONFIG_WLAN_RFKILL */
static A_STATUS wmi_ready_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_connect_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_disconnect_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_tkip_micerr_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_bssInfo_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_opt_frame_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_pstream_timeout_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_sync_point(struct wmi_t *wmip);
static A_STATUS wmi_bitrate_reply_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_ratemask_reply_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_channelList_reply_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_regDomain_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_txPwr_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_neighborReport_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_dset_open_req_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
#ifdef CONFIG_HOST_DSET_SUPPORT
static A_STATUS wmi_dset_close_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_dset_data_req_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
#endif /* CONFIG_HOST_DSET_SUPPORT */
static A_STATUS wmi_scanComplete_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_errorEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_statsEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_rssiThresholdEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_hbChallengeResp_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_reportErrorEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_cac_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_channel_change_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_roam_tbl_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_roam_data_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_get_wow_list_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS
wmi_get_pmkid_list_event_rx(struct wmi_t *wmip, A_UINT8 *datap, A_UINT32 len);
static A_STATUS
wmi_set_params_event_rx(struct wmi_t *wmip, A_UINT8 *datap, A_UINT32 len);
static A_STATUS
wmi_wacGetInfoReply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
#ifdef CONFIG_HOST_GPIO_SUPPORT
static A_STATUS wmi_gpio_intr_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_gpio_data_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_gpio_ack_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
#endif /* CONFIG_HOST_GPIO_SUPPORT */
#ifdef CONFIG_HOST_TCMD_SUPPORT
static A_STATUS
wmi_tcmd_test_report_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
#endif
static A_STATUS
wmi_txRetryErrEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS
wmi_snrThresholdEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS
wmi_lqThresholdEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_BOOL
wmi_is_bitrate_index_valid(struct wmi_t *wmip, A_INT32 rateIndex);
static A_STATUS
wmi_aplistEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS
wmi_dbglog_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_keepalive_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
A_STATUS wmi_cmd_send_xtnd(struct wmi_t *wmip, void *osbuf, WMIX_COMMAND_ID cmdId,
WMI_SYNC_FLAG syncflag);
A_UINT8 ar6000_get_upper_threshold(A_INT16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh, A_UINT32 size);
A_UINT8 ar6000_get_lower_threshold(A_INT16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh, A_UINT32 size);
void wmi_cache_configure_rssithreshold(struct wmi_t *wmip, WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd);
void wmi_cache_configure_snrthreshold(struct wmi_t *wmip, WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd);
static A_STATUS wmi_send_rssi_threshold_params(struct wmi_t *wmip,
WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd);
static A_STATUS wmi_send_snr_threshold_params(struct wmi_t *wmip,
WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd);
#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
static A_STATUS
wmi_prof_count_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
static A_STATUS wmi_pspoll_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_dtimexpiry_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
static A_STATUS wmi_peer_node_event_rx (struct wmi_t *wmip, A_UINT8 *datap,
int len);
#ifdef ATH_AR6K_11N_SUPPORT
static A_STATUS wmi_addba_req_event_rx(struct wmi_t *, A_UINT8 *, int);
static A_STATUS wmi_addba_resp_event_rx(struct wmi_t *, A_UINT8 *, int);
static A_STATUS wmi_delba_req_event_rx(struct wmi_t *, A_UINT8 *, int);
static A_STATUS wmi_btcoex_config_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_btcoex_stats_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
#endif
static A_STATUS wmi_hci_event_rx(struct wmi_t *, A_UINT8 *, int);
#ifdef WAPI_ENABLE
static A_STATUS wmi_wapi_rekey_event_rx(struct wmi_t *wmip, A_UINT8 *datap,
int len);
#endif
static A_STATUS
wmi_report_assoc_req_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);
static A_STATUS wmi_set_host_sleep_mode_cmd_processed(struct wmi_t *wmip,
A_UINT8 *datap, A_UINT8 len);
#if defined(UNDER_CE) || defined(WIN_NWF)
#if defined(NDIS51_MINIPORT)
unsigned int processDot11Hdr = 0;
#else
unsigned int processDot11Hdr = 1;
#endif
#else
extern unsigned int processDot11Hdr;
#endif
int wps_enable;
static const A_INT32 wmi_rateTable[][2] = {
//{W/O SGI, with SGI}
{1000, 1000},
{2000, 2000},
{5500, 5500},
{11000, 11000},
{6000, 6000},
{9000, 9000},
{12000, 12000},
{18000, 18000},
{24000, 24000},
{36000, 36000},
{48000, 48000},
{54000, 54000},
{6500, 7200},
{13000, 14400},
{19500, 21700},
{26000, 28900},
{39000, 43300},
{52000, 57800},
{58500, 65000},
{65000, 72200},
{13500, 15000},
{27000, 30000},
{40500, 45000},
/* 54100 is just to differentiate between 54M with or without aggregation
User has to give 54.1M for HT40 but firmware is going to use 54M only*/
{54100, 60000},
{81000, 90000},
{108000, 120000},
{121500, 135000},
{135000, 150000},
{0, 0}};
#define MODE_A_SUPPORT_RATE_START ((A_INT32) 4)
#define MODE_A_SUPPORT_RATE_STOP ((A_INT32) 11)
#define MODE_GONLY_SUPPORT_RATE_START MODE_A_SUPPORT_RATE_START
#define MODE_GONLY_SUPPORT_RATE_STOP MODE_A_SUPPORT_RATE_STOP
#define MODE_B_SUPPORT_RATE_START ((A_INT32) 0)
#define MODE_B_SUPPORT_RATE_STOP ((A_INT32) 3)
#define MODE_G_SUPPORT_RATE_START ((A_INT32) 0)
#define MODE_G_SUPPORT_RATE_STOP ((A_INT32) 11)
#define MODE_HT20_SUPPORT_RATE_START ((A_INT32) 12)
#define MODE_HT20_SUPPORT_RATE_STOP ((A_INT32) 19)
#define MODE_HT40_SUPPORT_RATE_START ((A_INT32) 20)
#define MODE_HT40_SUPPORT_RATE_STOP ((A_INT32) 27)
#define MAX_NUMBER_OF_SUPPORT_RATES (MODE_HT40_SUPPORT_RATE_STOP + 1)
/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
const A_UINT8 up_to_ac[]= {
WMM_AC_BE,
WMM_AC_BK,
WMM_AC_BK,
WMM_AC_BE,
WMM_AC_VI,
WMM_AC_VI,
WMM_AC_VO,
WMM_AC_VO,
};
#include "athstartpack.h"
/* This stuff is used when we want a simple layer-3 visibility */
typedef PREPACK struct _iphdr {
A_UINT8 ip_ver_hdrlen; /* version and hdr length */
A_UINT8 ip_tos; /* type of service */
A_UINT16 ip_len; /* total length */
A_UINT16 ip_id; /* identification */
A_INT16 ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
A_UINT8 ip_ttl; /* time to live */
A_UINT8 ip_p; /* protocol */
A_UINT16 ip_sum; /* checksum */
A_UINT8 ip_src[4]; /* source and dest address */
A_UINT8 ip_dst[4];
} POSTPACK iphdr;
#include "athendpack.h"
A_INT16 rssi_event_value = 0;
A_INT16 snr_event_value = 0;
A_BOOL is_probe_ssid = FALSE;
struct wmi_t *wmi_list[NUM_DEV];
static struct wmi_priv_t *pWmiPriv = NULL;
/*
* EV94003 [Samsung P2] Kernel panic - 'Shutting down HTC ....' when wifi is turned off
*/
static A_MUTEX_T _wmi_lock;
static int _wmi_init = FALSE;
void *
wmi_init(void *devt, int devid)
{
struct wmi_t *wmip;
A_REGISTER_MODULE_DEBUG_INFO(wmi);
wmip = A_MALLOC(sizeof(struct wmi_t));
if (wmip == NULL) {
return (NULL);
}
A_MEMZERO(wmip, sizeof(*wmip));
wmip->wmi_devt = devt;
wlan_node_table_init(wmip, &wmip->wmi_scan_table);
wmip->wmi_powerMode = REC_POWER;
wmip->wmi_phyMode = WMI_11G_MODE;
wmip->wmi_pair_crypto_type = NONE_CRYPT;
wmip->wmi_grp_crypto_type = NONE_CRYPT;
A_MEMZERO(&wmip->wmi_ht_cap[A_BAND_24GHZ], sizeof(WMI_SET_HT_CAP_CMD));
A_MEMZERO(&wmip->wmi_ht_cap[A_BAND_5GHZ], sizeof(WMI_SET_HT_CAP_CMD));
wmip->wmi_ht_cap[A_BAND_24GHZ].enable = 1;
wmip->wmi_ht_cap[A_BAND_5GHZ].enable = 1;
wmip->wmi_ht_cap[A_BAND_24GHZ].short_GI_20MHz = 1;
wmip->wmi_ht_cap[A_BAND_5GHZ].short_GI_20MHz = 1;
wmip->wmi_ht_cap[A_BAND_24GHZ].max_ampdu_len_exp = 1;
wmip->wmi_ht_cap[A_BAND_5GHZ].max_ampdu_len_exp = 1;
wmip->wmi_ht_cap[A_BAND_5GHZ].short_GI_40MHz = 1;
wmip->wmi_ht_cap[A_BAND_5GHZ].chan_width_40M_supported = 1;
wmip->wmi_dev_index = devid;
wmip->wmi_user_ht[A_BAND_24GHZ] = 1;
wmip->wmi_user_ht[A_BAND_5GHZ] = 1;
wmip->wmi_user_phy = WMI_11G_MODE;
wmi_list[devid] = wmip;
/*One time memory allocation for wmi virtual device structure*/
if(pWmiPriv == NULL) {
pWmiPriv = A_MALLOC(sizeof(struct wmi_priv_t));
if (pWmiPriv == NULL) {
return (NULL);
}
A_MEMZERO(pWmiPriv, sizeof(*pWmiPriv));
A_MUTEX_INIT(&pWmiPriv->wmi_lock);
wmi_qos_state_init(NULL);
A_WMI_SET_NUMDATAENDPTS(wmip->wmi_devt, 1);
}
A_MUTEX_INIT(&_wmi_lock);
_wmi_init = TRUE;
return (wmip);
}
void
wmi_qos_state_init(struct wmi_t *wmip)
{
A_UINT8 i;
if (pWmiPriv == NULL) {
return;
}
LOCK_WMI(pWmiPriv);
/* Initialize QoS States */
pWmiPriv->wmi_numQoSStream = 0;
pWmiPriv->wmi_fatPipeExists = 0;
for (i=0; i < WMM_NUM_AC; i++) {
pWmiPriv->wmi_streamExistsForAC[i]=0;
}
UNLOCK_WMI(pWmiPriv);
}
void
wmi_set_control_ep(struct wmi_t * wmip, HTC_ENDPOINT_ID eid)
{
A_ASSERT( eid != ENDPOINT_UNUSED);
pWmiPriv->wmi_endpoint_id = eid;
}
HTC_ENDPOINT_ID
wmi_get_control_ep(struct wmi_t * wmip)
{
return(pWmiPriv->wmi_endpoint_id);
}
void
wmi_shutdown(struct wmi_t *wmip)
{
A_MUTEX_LOCK(&_wmi_lock);
_wmi_init = FALSE;
if (wmip != NULL) {
wlan_node_table_cleanup(&wmip->wmi_scan_table);
A_FREE(wmip);
wmip = NULL;
}
A_MUTEX_UNLOCK(&_wmi_lock);
if (pWmiPriv != NULL) {
if (A_IS_MUTEX_VALID(&pWmiPriv->wmi_lock)) {
A_MUTEX_DELETE(&pWmiPriv->wmi_lock);
}
A_FREE(pWmiPriv);
pWmiPriv = NULL;
}
}
/*
* Sets the function pointer of the function to be run when a
* WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENT is received. This
* is needed because we must wait for the HTC credit report to come
* in after we send the set host sleep mode command. Failure to do
* this can result in the HTC credit report arriving while the
* system is in suspend. This can cause a kernel assert in
* hifIRQHandler.
*/
void wmi_set_host_sleep_mode_event_fn_ptr(struct wmi_t *wmip,
void (*host_sleep_mode_event_fn)(void *), void *host_sleep_mode_event_fn_arg)
{
wmip->host_sleep_mode_event_fn = host_sleep_mode_event_fn;
wmip->host_sleep_mode_event_fn_arg = host_sleep_mode_event_fn_arg;
}
/*
* performs DIX to 802.3 encapsulation for transmit packets.
* uses passed in buffer. Returns buffer or NULL if failed.
* Assumes the entire DIX header is contigous and that there is
* enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
*/
A_STATUS
wmi_dix_2_dot3(struct wmi_t *wmip, void *osbuf)
{
A_UINT8 *datap;
A_UINT16 typeorlen;
ATH_MAC_HDR macHdr;
ATH_LLC_SNAP_HDR *llcHdr;
#ifdef DIX_TX_OFFLOAD
/*Ethernet to DIX Conversion is offloaded to firmware */
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
if(A_NETBUF_HEADROOM(osbuf) < (sizeof(ATH_LLC_SNAP_HDR) + sizeof(WMI_DATA_HDR))) {
return A_NO_MEMORY;
}
datap = A_NETBUF_DATA(osbuf);
typeorlen = *(A_UINT16 *)(datap + ATH_MAC_LEN + ATH_MAC_LEN);
if(!IS_ETHERTYPE(A_BE2CPU16(typeorlen))) {
/*packet is already in 802.3 format - return success*/
A_DPRINTF(DBG_WMI,(DBGFMT"packet in 802.3 format\n",DBGARG));
return A_OK;
}
/*Save MAC fields and lenght to be inserted later*/
macHdr.typeOrLen = A_CPU2BE16(A_NETBUF_LEN(osbuf) - sizeof(ATH_MAC_HDR) +
sizeof(ATH_LLC_SNAP_HDR));
/*Make room for LLC+SNAP headers*/
if(A_NETBUF_PUSH(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != A_OK) {
return A_NO_MEMORY;
}
datap = A_NETBUF_DATA(osbuf);
llcHdr = (ATH_LLC_SNAP_HDR *)(datap);
llcHdr->etherType = macHdr.typeOrLen;
return (A_OK);
#else
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
if (A_NETBUF_HEADROOM(osbuf) <
(sizeof(ATH_LLC_SNAP_HDR) + sizeof(WMI_DATA_HDR)))
{
return A_NO_MEMORY;
}
datap = A_NETBUF_DATA(osbuf);
typeorlen = *(A_UINT16 *)(datap + ATH_MAC_LEN + ATH_MAC_LEN);
if (!IS_ETHERTYPE(A_BE2CPU16(typeorlen))) {
/*
* packet is already in 802.3 format - return success
*/
A_DPRINTF(DBG_WMI, (DBGFMT "packet already 802.3\n", DBGARG));
return (A_OK);
}
/*
* Save mac fields and length to be inserted later
*/
A_MEMCPY(macHdr.dstMac, datap, ATH_MAC_LEN);
A_MEMCPY(macHdr.srcMac, datap + ATH_MAC_LEN, ATH_MAC_LEN);
macHdr.typeOrLen = A_CPU2BE16(A_NETBUF_LEN(osbuf) - sizeof(ATH_MAC_HDR) +
sizeof(ATH_LLC_SNAP_HDR));
/*
* Make room for LLC+SNAP headers
*/
if (A_NETBUF_PUSH(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != A_OK) {
return A_NO_MEMORY;
}
datap = A_NETBUF_DATA(osbuf);
A_MEMCPY(datap, &macHdr, sizeof (ATH_MAC_HDR));
llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(ATH_MAC_HDR));
llcHdr->dsap = 0xAA;
llcHdr->ssap = 0xAA;
llcHdr->cntl = 0x03;
llcHdr->orgCode[0] = 0x0;
llcHdr->orgCode[1] = 0x0;
llcHdr->orgCode[2] = 0x0;
llcHdr->etherType = typeorlen;
return (A_OK);
#endif
}
A_STATUS wmi_meta_add(struct wmi_t *wmip, void *osbuf, A_UINT8 *pVersion,void *pTxMetaS)
{
A_ASSERT(pVersion != NULL);
if (pVersion == NULL)
return A_ERROR;
switch(*pVersion){
case 0:
return (A_OK);
case WMI_META_VERSION_1:
{
WMI_TX_META_V1 *pV1= NULL;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
if (A_NETBUF_PUSH(osbuf, WMI_MAX_TX_META_SZ) != A_OK) {
return A_NO_MEMORY;
}
pV1 = (WMI_TX_META_V1 *)A_NETBUF_DATA(osbuf);
/* the pktID is used in conjunction with txComplete messages
* allowing the target to notify which tx requests have been
* completed and how. */
pV1->pktID = 0;
/* the ratePolicyID allows the host to specify which rate policy
* to use for transmitting this packet. 0 means use default behavior. */
pV1->ratePolicyID = 0;
/* the version must be used to populate the meta field of the WMI_DATA_HDR */
*pVersion = WMI_META_VERSION_1;
return (A_OK);
}
#ifdef CONFIG_CHECKSUM_OFFLOAD
case WMI_META_VERSION_2:
{
WMI_TX_META_V2 *pV2 ;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
if (A_NETBUF_PUSH(osbuf, WMI_MAX_TX_META_SZ) != A_OK) {
return A_NO_MEMORY;
}
pV2 = (WMI_TX_META_V2 *)A_NETBUF_DATA(osbuf);
A_MEMCPY(pV2,(WMI_TX_META_V2 *)pTxMetaS,sizeof(WMI_TX_META_V2));
return (A_OK);
}
#endif
default:
return (A_OK);
}
}
/* Adds a WMI data header */
A_STATUS
wmi_data_hdr_add(struct wmi_t *wmip, void *osbuf, A_UINT8 msgType, A_UINT32 flags,
WMI_DATA_HDR_DATA_TYPE data_type,A_UINT8 metaVersion, void *pTxMetaS)
{
WMI_DATA_HDR *dtHdr;
// A_UINT8 metaVersion = 0;
A_STATUS status;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
/* adds the meta data field after the wmi data hdr. If metaVersion
* is returns 0 then no meta field was added. */
if ((status = wmi_meta_add(wmip, osbuf, &metaVersion,pTxMetaS)) != A_OK) {
return status;
}
if (A_NETBUF_PUSH(osbuf, sizeof(WMI_DATA_HDR)) != A_OK) {
return A_NO_MEMORY;
}
dtHdr = (WMI_DATA_HDR *)A_NETBUF_DATA(osbuf);
A_MEMZERO(dtHdr, sizeof(WMI_DATA_HDR));
WMI_DATA_HDR_SET_MSG_TYPE(dtHdr, msgType);
WMI_DATA_HDR_SET_DATA_TYPE(dtHdr, data_type);
if (flags & WMI_DATA_HDR_FLAGS_MORE) {
WMI_DATA_HDR_SET_MORE_BIT(dtHdr);
}
if (flags & WMI_DATA_HDR_FLAGS_EOSP) {
WMI_DATA_HDR_SET_EOSP_BIT(dtHdr);
}
WMI_DATA_HDR_SET_META(dtHdr, metaVersion);
//dtHdr->rssi = 0;
WMI_DATA_HDR_SET_DEVID(dtHdr, wmip->wmi_dev_index);
return (A_OK);
}
A_UINT8 wmi_implicit_create_pstream(struct wmi_t *wmip, void *osbuf, A_UINT32 layer2Priority, A_BOOL wmmEnabled)
{
A_UINT8 *datap;
A_UINT8 trafficClass = WMM_AC_BE;
A_UINT16 ipType = IP_ETHERTYPE;
WMI_DATA_HDR *dtHdr;
A_BOOL streamExists = FALSE;
A_UINT8 userPriority;
A_UINT32 hdrsize, metasize;
ATH_LLC_SNAP_HDR *llcHdr;
WMI_CREATE_PSTREAM_CMD cmd;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return -1;
//
// Initialize header size
//
hdrsize = 0;
datap = A_NETBUF_DATA(osbuf);
dtHdr = (WMI_DATA_HDR *)datap;
metasize = (WMI_DATA_HDR_GET_META(dtHdr))? WMI_MAX_TX_META_SZ : 0;
if (!wmmEnabled)
{
/* If WMM is disabled all traffic goes as BE traffic */
userPriority = 0;
}
else
{
if (processDot11Hdr)
{
hdrsize = A_ROUND_UP(sizeof(struct ieee80211_qosframe),sizeof(A_UINT32));
llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(WMI_DATA_HDR) + metasize +
hdrsize);
}
else
{
llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(WMI_DATA_HDR) + metasize +
sizeof(ATH_MAC_HDR));
}
if (llcHdr->etherType == A_CPU2BE16(ipType))
{
/* Extract the endpoint info from the TOS field in the IP header */
userPriority = wmi_determine_userPriority (((A_UINT8 *)llcHdr) + sizeof(ATH_LLC_SNAP_HDR),layer2Priority);
}
else
{
userPriority = layer2Priority & 0x7;
}
}
trafficClass = convert_userPriority_to_trafficClass(userPriority);
WMI_DATA_HDR_SET_UP(dtHdr, userPriority);
/* lower 3-bits are 802.1d priority */
//dtHdr->info |= (userPriority & WMI_DATA_HDR_UP_MASK) << WMI_DATA_HDR_UP_SHIFT;
LOCK_WMI(pWmiPriv);
streamExists = pWmiPriv->wmi_fatPipeExists;
UNLOCK_WMI(pWmiPriv);
if (!(streamExists & (1 << trafficClass)))
{
A_MEMZERO(&cmd, sizeof(cmd));
cmd.trafficClass = trafficClass;
cmd.userPriority = userPriority;
cmd.inactivityInt = WMI_IMPLICIT_PSTREAM_INACTIVITY_INT;
/* Implicit streams are created with TSID 0xFF */
cmd.tsid = WMI_IMPLICIT_PSTREAM;
wmi_create_pstream_cmd(wmip, &cmd);
}
return trafficClass;
}
A_STATUS
wmi_dot11_hdr_add (struct wmi_t *wmip, void *osbuf, NETWORK_TYPE mode)
{
A_UINT8 *datap;
A_UINT16 typeorlen;
ATH_MAC_HDR macHdr;
ATH_LLC_SNAP_HDR *llcHdr;
struct ieee80211_frame *wh;
A_UINT32 hdrsize;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
if (A_NETBUF_HEADROOM(osbuf) <
(sizeof(struct ieee80211_qosframe) + sizeof(ATH_LLC_SNAP_HDR) + sizeof(WMI_DATA_HDR)))
{
return A_NO_MEMORY;
}
datap = A_NETBUF_DATA(osbuf);
typeorlen = *(A_UINT16 *)(datap + ATH_MAC_LEN + ATH_MAC_LEN);
if (!IS_ETHERTYPE(A_BE2CPU16(typeorlen))) {
/*
* packet is already in 802.3 format - return success
*/
A_DPRINTF(DBG_WMI, (DBGFMT "packet already 802.3\n", DBGARG));
goto AddDot11Hdr;
}
/*
* Save mac fields and length to be inserted later
*/
A_MEMCPY(macHdr.dstMac, datap, ATH_MAC_LEN);
A_MEMCPY(macHdr.srcMac, datap + ATH_MAC_LEN, ATH_MAC_LEN);
macHdr.typeOrLen = A_CPU2BE16(A_NETBUF_LEN(osbuf) - sizeof(ATH_MAC_HDR) +
sizeof(ATH_LLC_SNAP_HDR));
// Remove the Ethernet hdr
A_NETBUF_PULL(osbuf, sizeof(ATH_MAC_HDR));
/*
* Make room for LLC+SNAP headers
*/
if (A_NETBUF_PUSH(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != A_OK) {
return A_NO_MEMORY;
}
datap = A_NETBUF_DATA(osbuf);
llcHdr = (ATH_LLC_SNAP_HDR *)(datap);
llcHdr->dsap = 0xAA;
llcHdr->ssap = 0xAA;
llcHdr->cntl = 0x03;
llcHdr->orgCode[0] = 0x0;
llcHdr->orgCode[1] = 0x0;
llcHdr->orgCode[2] = 0x0;
llcHdr->etherType = typeorlen;
AddDot11Hdr:
/* Make room for 802.11 hdr */
if (wmip->wmi_is_wmm_enabled)
{
hdrsize = A_ROUND_UP(sizeof(struct ieee80211_qosframe),sizeof(A_UINT32));
if (A_NETBUF_PUSH(osbuf, hdrsize) != A_OK)
{
return A_NO_MEMORY;
}
wh = (struct ieee80211_frame *) A_NETBUF_DATA(osbuf);
wh->i_fc[0] = IEEE80211_FC0_SUBTYPE_QOS;
}
else
{
hdrsize = A_ROUND_UP(sizeof(struct ieee80211_frame),sizeof(A_UINT32));
if (A_NETBUF_PUSH(osbuf, hdrsize) != A_OK)
{
return A_NO_MEMORY;
}
wh = (struct ieee80211_frame *) A_NETBUF_DATA(osbuf);
wh->i_fc[0] = IEEE80211_FC0_SUBTYPE_DATA;
}
/* Setup the SA & DA */
IEEE80211_ADDR_COPY(wh->i_addr2, macHdr.srcMac);
if (mode == INFRA_NETWORK) {
IEEE80211_ADDR_COPY(wh->i_addr3, macHdr.dstMac);
}
else if (mode == ADHOC_NETWORK) {
IEEE80211_ADDR_COPY(wh->i_addr1, macHdr.dstMac);
}
return (A_OK);
}
A_STATUS
wmi_dot11_hdr_remove(struct wmi_t *wmip, void *osbuf)
{
A_UINT8 *datap;
struct ieee80211_frame *pwh,wh;
A_UINT8 type,subtype;
ATH_LLC_SNAP_HDR *llcHdr;
ATH_MAC_HDR macHdr;
A_UINT32 hdrsize;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
datap = A_NETBUF_DATA(osbuf);
pwh = (struct ieee80211_frame *)datap;
type = pwh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
subtype = pwh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
A_MEMCPY((A_UINT8 *)&wh, datap, sizeof(struct ieee80211_frame));
/* strip off the 802.11 hdr*/
if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
hdrsize = A_ROUND_UP(sizeof(struct ieee80211_qosframe),sizeof(A_UINT32));
A_NETBUF_PULL(osbuf, hdrsize);
} else if (subtype == IEEE80211_FC0_SUBTYPE_DATA) {
A_NETBUF_PULL(osbuf, sizeof(struct ieee80211_frame));
}
datap = A_NETBUF_DATA(osbuf);
llcHdr = (ATH_LLC_SNAP_HDR *)(datap);
macHdr.typeOrLen = llcHdr->etherType;
A_MEMZERO(macHdr.dstMac, sizeof(macHdr.dstMac));
A_MEMZERO(macHdr.srcMac, sizeof(macHdr.srcMac));
switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
case IEEE80211_FC1_DIR_NODS:
IEEE80211_ADDR_COPY(macHdr.dstMac, wh.i_addr1);
IEEE80211_ADDR_COPY(macHdr.srcMac, wh.i_addr2);
break;
case IEEE80211_FC1_DIR_TODS:
IEEE80211_ADDR_COPY(macHdr.dstMac, wh.i_addr3);
IEEE80211_ADDR_COPY(macHdr.srcMac, wh.i_addr2);
break;
case IEEE80211_FC1_DIR_FROMDS:
IEEE80211_ADDR_COPY(macHdr.dstMac, wh.i_addr1);
IEEE80211_ADDR_COPY(macHdr.srcMac, wh.i_addr3);
break;
case IEEE80211_FC1_DIR_DSTODS:
break;
}
// Remove the LLC Hdr.
A_NETBUF_PULL(osbuf, sizeof(ATH_LLC_SNAP_HDR));
// Insert the ATH MAC hdr.
A_NETBUF_PUSH(osbuf, sizeof(ATH_MAC_HDR));
datap = A_NETBUF_DATA(osbuf);
A_MEMCPY (datap, &macHdr, sizeof(ATH_MAC_HDR));
return A_OK;
}
/*
* performs 802.3 to DIX encapsulation for received packets.
* Assumes the entire 802.3 header is contigous.
*/
A_STATUS
wmi_dot3_2_dix(void *osbuf)
{
A_UINT8 *datap;
ATH_MAC_HDR macHdr;
ATH_LLC_SNAP_HDR *llcHdr;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
datap = A_NETBUF_DATA(osbuf);
A_MEMCPY(&macHdr, datap, sizeof(ATH_MAC_HDR));
llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(ATH_MAC_HDR));
macHdr.typeOrLen = llcHdr->etherType;
if (A_NETBUF_PULL(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != A_OK) {
return A_NO_MEMORY;
}
datap = A_NETBUF_DATA(osbuf);
A_MEMCPY(datap, &macHdr, sizeof (ATH_MAC_HDR));
return (A_OK);
}
/*
* Removes a WMI data header
*/
A_STATUS
wmi_data_hdr_remove(struct wmi_t *wmip, void *osbuf)
{
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
return (A_NETBUF_PULL(osbuf, sizeof(WMI_DATA_HDR)));
}
void
wmi_iterate_nodes(struct wmi_t *wmip, wlan_node_iter_func *f, void *arg)
{
wlan_iterate_nodes(&wmip->wmi_scan_table, f, arg);
}
void
wmi_scan_report_lock(struct wmi_t *wmip)
{
if (wmip)
IEEE80211_SCAN_REPORT_LOCK(&wmip->wmi_scan_table);
}
void
wmi_scan_report_unlock(struct wmi_t *wmip)
{
if (wmip)
IEEE80211_SCAN_REPORT_UNLOCK(&wmip->wmi_scan_table);
}
static A_STATUS
wmi_report_wmm_params(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_REPORT_WMM_PARAMS_EVENT *ev;
A_UINT8 i;
if (len < sizeof(*ev)) {
return A_EINVAL;
}
ev = (WMI_REPORT_WMM_PARAMS_EVENT *)datap;
A_PRINTF("WMM params\n");
for (i = 0; i < 4; i++) {
A_PRINTF("AC %d, ACM %d, AIFSN %d, CWmin %d, CWmax %d, TXOPlimit %d\n", i,
ev->wmm_params[i].acm,
ev->wmm_params[i].aifsn,
ev->wmm_params[i].logcwmin,
ev->wmm_params[i].logcwmax,
ev->wmm_params[i].txopLimit);
}
return A_OK;
}
/*
* WMI Extended Event received from Target.
*/
A_STATUS
wmi_control_rx_xtnd(struct wmi_t *wmip, void *osbuf)
{
WMIX_CMD_HDR *cmd;
A_UINT16 id;
A_UINT8 *datap;
A_UINT32 len;
A_STATUS status = A_OK;
if (A_NETBUF_LEN(osbuf) < sizeof(WMIX_CMD_HDR)) {
A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 1\n", DBGARG));
wmip->wmi_stats.cmd_len_err++;
return A_ERROR;
}
cmd = (WMIX_CMD_HDR *)A_NETBUF_DATA(osbuf);
id = cmd->commandId;
if (A_NETBUF_PULL(osbuf, sizeof(WMIX_CMD_HDR)) != A_OK) {
A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 2\n", DBGARG));
wmip->wmi_stats.cmd_len_err++;
return A_ERROR;
}
datap = A_NETBUF_DATA(osbuf);
len = A_NETBUF_LEN(osbuf);
switch (id) {
case (WMIX_DSETOPENREQ_EVENTID):
status = wmi_dset_open_req_rx(wmip, datap, len);
break;
#ifdef CONFIG_HOST_DSET_SUPPORT
case (WMIX_DSETCLOSE_EVENTID):
status = wmi_dset_close_rx(wmip, datap, len);
break;
case (WMIX_DSETDATAREQ_EVENTID):
status = wmi_dset_data_req_rx(wmip, datap, len);
break;
#endif /* CONFIG_HOST_DSET_SUPPORT */
#ifdef CONFIG_HOST_GPIO_SUPPORT
case (WMIX_GPIO_INTR_EVENTID):
wmi_gpio_intr_rx(wmip, datap, len);
break;
case (WMIX_GPIO_DATA_EVENTID):
wmi_gpio_data_rx(wmip, datap, len);
break;
case (WMIX_GPIO_ACK_EVENTID):
wmi_gpio_ack_rx(wmip, datap, len);
break;
#endif /* CONFIG_HOST_GPIO_SUPPORT */
case (WMIX_HB_CHALLENGE_RESP_EVENTID):
wmi_hbChallengeResp_rx(wmip, datap, len);
break;
case (WMIX_DBGLOG_EVENTID):
wmi_dbglog_event_rx(wmip, datap, len);
break;
#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
case (WMIX_PROF_COUNT_EVENTID):
wmi_prof_count_rx(wmip, datap, len);
break;
#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
default:
A_DPRINTF(DBG_WMI|DBG_ERROR,
(DBGFMT "Unknown id 0x%x\n", DBGARG, id));
wmip->wmi_stats.cmd_id_err++;
status = A_ERROR;
break;
}
return status;
}
/*
* Control Path
*/
A_UINT32 cmdRecvNum;
A_STATUS
wmi_control_rx(struct wmi_t *wmip, void *osbuf)
{
WMI_CMD_HDR *cmd;
A_UINT16 id;
A_UINT8 *datap;
A_UINT32 len, i, loggingReq;
A_STATUS status = A_OK;
if(wmip == NULL || osbuf == NULL)
{
AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("AR6K: wmi_p is null or osbuf is null\n"));
return A_ERROR;
}
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
if (A_NETBUF_LEN(osbuf) < sizeof(WMI_CMD_HDR)) {
A_NETBUF_FREE(osbuf);
A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 1\n", DBGARG));
wmip->wmi_stats.cmd_len_err++;
return A_ERROR;
}
cmd = (WMI_CMD_HDR *)A_NETBUF_DATA(osbuf);
id = cmd->commandId;
if (A_NETBUF_PULL(osbuf, sizeof(WMI_CMD_HDR)) != A_OK) {
A_NETBUF_FREE(osbuf);
A_DPRINTF(DBG_WMI, (DBGFMT "bad packet 2\n", DBGARG));
wmip->wmi_stats.cmd_len_err++;
return A_ERROR;
}
datap = A_NETBUF_DATA(osbuf);
len = A_NETBUF_LEN(osbuf);
loggingReq = 0;
ar6000_get_driver_cfg(wmip->wmi_devt,
AR6000_DRIVER_CFG_LOG_RAW_WMI_MSGS,
&loggingReq);
if(loggingReq) {
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI %d \n",id));
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI devid %d \n",wmip->wmi_dev_index));
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI recv, MsgNo %d : ", cmdRecvNum));
for(i = 0; i < len; i++)
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("%x ", datap[i]));
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("\n"));
}
LOCK_WMI(pWmiPriv);
cmdRecvNum++;
UNLOCK_WMI(pWmiPriv);
switch (id) {
case (WMI_GET_BITRATE_CMDID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_BITRATE_CMDID\n", DBGARG));
status = wmi_bitrate_reply_rx(wmip, datap, len);
break;
case (WMI_GET_CHANNEL_LIST_CMDID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_CHANNEL_LIST_CMDID\n", DBGARG));
status = wmi_channelList_reply_rx(wmip, datap, len);
break;
case (WMI_GET_TX_PWR_CMDID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_TX_PWR_CMDID\n", DBGARG));
status = wmi_txPwr_reply_rx(wmip, datap, len);
break;
case (WMI_READY_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_READY_EVENTID\n", DBGARG));
status = wmi_ready_event_rx(wmip, datap, len);
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
A_WMI_DBGLOG_INIT_DONE(wmip->wmi_devt);
break;
case (WMI_CONNECT_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CONNECT_EVENTID\n", DBGARG));
status = wmi_connect_event_rx(wmip, datap, len);
A_WMI_SEND_GENERIC_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case (WMI_DISCONNECT_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_DISCONNECT_EVENTID\n", DBGARG));
A_MUTEX_LOCK(&_wmi_lock);
if(_wmi_init) {
status = wmi_disconnect_event_rx(wmip, datap, len);
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
}
A_MUTEX_UNLOCK(&_wmi_lock);
break;
case (WMI_PEER_NODE_EVENTID):
A_DPRINTF (DBG_WMI, (DBGFMT "WMI_PEER_NODE_EVENTID\n", DBGARG));
status = wmi_peer_node_event_rx(wmip, datap, len);
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case (WMI_TKIP_MICERR_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_TKIP_MICERR_EVENTID\n", DBGARG));
status = wmi_tkip_micerr_event_rx(wmip, datap, len);
break;
case (WMI_BSSINFO_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_BSSINFO_EVENTID\n", DBGARG));
{
/*
* convert WMI_BSS_INFO_HDR2 to WMI_BSS_INFO_HDR
* Take a local copy of the WMI_BSS_INFO_HDR2 from the wmi buffer
* and reconstruct the WMI_BSS_INFO_HDR in its place
*/
WMI_BSS_INFO_HDR2 bih2;
WMI_BSS_INFO_HDR *bih;
A_UINT16 devBitMap;
A_UINT16 dev_id = 0;
struct wmi_t *wmiptr;
A_MEMCPY(&bih2, datap, sizeof(WMI_BSS_INFO_HDR2));
A_NETBUF_PUSH(osbuf, 4);
datap = A_NETBUF_DATA(osbuf);
len = A_NETBUF_LEN(osbuf);
bih = (WMI_BSS_INFO_HDR *)datap;
bih->channel = bih2.channel;
bih->frameType = bih2.frameType;
bih->snr = bih2.snr;
bih->rssi = bih2.snr - 95;
bih->ieMask = bih2.ieMask;
A_MEMCPY(bih->bssid, bih2.bssid, ATH_MAC_LEN);
/* Deliever the BSS info event based on the device id set
* by target
*/
devBitMap = (bih2.ieMask >> 12);
do {
if(devBitMap & 1) {
wmiptr = wmi_list[dev_id];
status = wmi_bssInfo_event_rx(wmiptr, datap, len);
A_WMI_SEND_GENERIC_EVENT_TO_APP(wmiptr->wmi_devt, id, datap, len);
}
devBitMap = (devBitMap >> 1);
dev_id++;
}while(devBitMap);
}
break;
case (WMI_REGDOMAIN_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REGDOMAIN_EVENTID\n", DBGARG));
status = wmi_regDomain_event_rx(wmip, datap, len);
break;
case (WMI_PSTREAM_TIMEOUT_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_PSTREAM_TIMEOUT_EVENTID\n", DBGARG));
status = wmi_pstream_timeout_event_rx(wmip, datap, len);
/* pstreams are fatpipe abstractions that get implicitly created.
* User apps only deal with thinstreams. creation of a thinstream
* by the user or data traffic flow in an AC triggers implicit
* pstream creation. Do we need to send this event to App..?
* no harm in sending it.
*/
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case (WMI_NEIGHBOR_REPORT_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_NEIGHBOR_REPORT_EVENTID\n", DBGARG));
status = wmi_neighborReport_event_rx(wmip, datap, len);
break;
case (WMI_SCAN_COMPLETE_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_SCAN_COMPLETE_EVENTID\n", DBGARG));
status = wmi_scanComplete_rx(wmip, datap, len);
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case (WMI_CMDERROR_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CMDERROR_EVENTID\n", DBGARG));
status = wmi_errorEvent_rx(wmip, datap, len);
break;
case (WMI_REPORT_STATISTICS_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REPORT_STATISTICS_EVENTID\n", DBGARG));
status = wmi_statsEvent_rx(wmip, datap, len);
break;
case (WMI_RSSI_THRESHOLD_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_RSSI_THRESHOLD_EVENTID\n", DBGARG));
status = wmi_rssiThresholdEvent_rx(wmip, datap, len);
break;
case (WMI_ERROR_REPORT_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_ERROR_REPORT_EVENTID\n", DBGARG));
status = wmi_reportErrorEvent_rx(wmip, datap, len);
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case (WMI_OPT_RX_FRAME_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_OPT_RX_FRAME_EVENTID\n", DBGARG));
status = wmi_opt_frame_event_rx(wmip, datap, len);
break;
case (WMI_REPORT_ROAM_TBL_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REPORT_ROAM_TBL_EVENTID\n", DBGARG));
status = wmi_roam_tbl_event_rx(wmip, datap, len);
break;
case (WMI_EXTENSION_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_EXTENSION_EVENTID\n", DBGARG));
status = wmi_control_rx_xtnd(wmip, osbuf);
break;
case (WMI_CAC_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CAC_EVENTID\n", DBGARG));
status = wmi_cac_event_rx(wmip, datap, len);
break;
case (WMI_CHANNEL_CHANGE_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_CHANNEL_CHANGE_EVENTID\n", DBGARG));
status = wmi_channel_change_event_rx(wmip, datap, len);
break;
case (WMI_REPORT_ROAM_DATA_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_REPORT_ROAM_DATA_EVENTID\n", DBGARG));
status = wmi_roam_data_event_rx(wmip, datap, len);
break;
#ifdef CONFIG_HOST_TCMD_SUPPORT
case (WMI_TEST_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_TEST_EVENTID\n", DBGARG));
status = wmi_tcmd_test_report_rx(wmip, datap, len);
break;
#endif
case (WMI_GET_FIXRATES_CMDID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_FIXRATES_CMDID\n", DBGARG));
status = wmi_ratemask_reply_rx(wmip, datap, len);
break;
case (WMI_TX_RETRY_ERR_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_TX_RETRY_ERR_EVENTID\n", DBGARG));
status = wmi_txRetryErrEvent_rx(wmip, datap, len);
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case (WMI_SNR_THRESHOLD_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_SNR_THRESHOLD_EVENTID\n", DBGARG));
status = wmi_snrThresholdEvent_rx(wmip, datap, len);
break;
case (WMI_LQ_THRESHOLD_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_LQ_THRESHOLD_EVENTID\n", DBGARG));
status = wmi_lqThresholdEvent_rx(wmip, datap, len);
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case (WMI_APLIST_EVENTID):
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Received APLIST Event\n"));
status = wmi_aplistEvent_rx(wmip, datap, len);
break;
case (WMI_GET_KEEPALIVE_CMDID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_KEEPALIVE_CMDID\n", DBGARG));
status = wmi_keepalive_reply_rx(wmip, datap, len);
break;
case (WMI_GET_WOW_LIST_EVENTID):
status = wmi_get_wow_list_event_rx(wmip, datap, len);
break;
case (WMI_GET_PMKID_LIST_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_GET_PMKID_LIST Event\n", DBGARG));
status = wmi_get_pmkid_list_event_rx(wmip, datap, len);
break;
case (WMI_PSPOLL_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_PSPOLL_EVENT\n", DBGARG));
status = wmi_pspoll_event_rx(wmip, datap, len);
break;
case (WMI_DTIMEXPIRY_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_DTIMEXPIRY_EVENT\n", DBGARG));
status = wmi_dtimexpiry_event_rx(wmip, datap, len);
break;
case (WMI_SET_PARAMS_REPLY_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_SET_PARAMS_REPLY Event\n", DBGARG));
status = wmi_set_params_event_rx(wmip, datap, len);
break;
#ifdef ATH_AR6K_11N_SUPPORT
case (WMI_ADDBA_REQ_EVENTID):
status = wmi_addba_req_event_rx(wmip, datap, len);
break;
case (WMI_ADDBA_RESP_EVENTID):
status = wmi_addba_resp_event_rx(wmip, datap, len);
break;
case (WMI_DELBA_REQ_EVENTID):
status = wmi_delba_req_event_rx(wmip, datap, len);
break;
case (WMI_REPORT_BTCOEX_CONFIG_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_BTCOEX_CONFIG_EVENTID", DBGARG));
status = wmi_btcoex_config_event_rx(wmip, datap, len);
break;
case (WMI_REPORT_BTCOEX_STATS_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_BTCOEX_STATS_EVENTID", DBGARG));
status = wmi_btcoex_stats_event_rx(wmip, datap, len);
break;
#endif
case (WMI_TX_COMPLETE_EVENTID):
{
int index;
TX_COMPLETE_MSG_V1 *pV1;
WMI_TX_COMPLETE_EVENT *pEv = (WMI_TX_COMPLETE_EVENT *)datap;
A_PRINTF("comp: %d %d %d\n", pEv->numMessages, pEv->msgLen, pEv->msgType);
for(index = 0 ; index < pEv->numMessages ; index++) {
pV1 = (TX_COMPLETE_MSG_V1 *)(datap + sizeof(WMI_TX_COMPLETE_EVENT) + index*sizeof(TX_COMPLETE_MSG_V1));
A_PRINTF("msg: %d %d %d %d\n", pV1->status, pV1->pktID, pV1->rateIdx, pV1->ackFailures);
}
}
break;
case (WMI_HCI_EVENT_EVENTID):
status = wmi_hci_event_rx(wmip, datap, len);
break;
#ifdef WAPI_ENABLE
case (WMI_WAPI_REKEY_EVENTID):
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_WAPI_REKEY_EVENTID", DBGARG));
status = wmi_wapi_rekey_event_rx(wmip, datap, len);
break;
#endif
case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
A_DPRINTF(DBG_WMI, (DBGFMT "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID\n", DBGARG));
status = wmi_set_host_sleep_mode_cmd_processed(wmip, datap, len);
break;
case WMI_WAC_REPORT_BSS_EVENTID:
{
WMI_BSS_INFO_HDR2 *p = (WMI_BSS_INFO_HDR2 *)datap;
A_DPRINTF(ATH_DEBUG_ERR, (DBGFMT "WMI_WAC_REPORT_BSS: %x:%x:%x:%x:%x:%x\n", DBGARG,
p->bssid[0],
p->bssid[1],
p->bssid[2],
p->bssid[3],
p->bssid[4],
p->bssid[5]));
}
case WMI_WAC_SCAN_DONE_EVENTID:
case WMI_WAC_START_WPS_EVENTID:
A_WMI_SEND_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
case WMI_WAC_CTRL_REQ_REPLY_EVENTID:
{
status = wmi_wacGetInfoReply_rx(wmip, datap, len);
break;
}
case WMI_REPORT_WMM_PARAMS_EVENTID:
{
status = wmi_report_wmm_params(wmip, datap, len);
break;
}
#ifdef CONFIG_WLAN_RFKILL
case (WMI_RFKILL_STATE_CHANGE_EVENTID):
status = wmi_rfkill_state_change_event(wmip,datap,len);
break;
case (WMI_RFKILL_GET_MODE_CMD_EVENTID):
status = wmi_rfkill_get_mode_cmd_event_rx(wmip,datap,len);
break;
#endif /* CONFIG_WLAN_RFKILL */
case WMI_ASSOC_REQ_EVENTID:
status = wmi_report_assoc_req_rx(wmip, datap, len);
break;
case WMI_WLAN_VERSION_EVENTID:
{
A_UINT32 wlan_ver = *(A_UINT32*)datap;
A_DPRINTF(DBG_WMI, ("AR6K: wlan_ver %u.%u.%u.%u\n",
((wlan_ver)&0xf0000000)>>28, ((wlan_ver)&0x0f000000)>>24,
((wlan_ver)&0x00ff0000)>>16, ((wlan_ver)&0x0000ffff)));
}
break;
case WMI_AP_IDLE_CLOSE_TIMEOUT_EVENTID:
A_PRINTF("WMI_AP_IDLE_CLOSE_TIMEOUT_EVENTID\n");
break;
#ifdef HS20_ENABLE
case WMI_HS20_RX_EVENTID:
AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("Received HS2.0 RX Event, Len = %d", len));
A_WMI_SEND_GENERIC_EVENT_TO_APP(wmip->wmi_devt, id, datap, len);
break;
#endif
default:
A_DPRINTF(DBG_WMI|DBG_ERROR,
(DBGFMT "Unknown id 0x%x\n", DBGARG, id));
wmip->wmi_stats.cmd_id_err++;
status = A_ERROR;
break;
}
A_NETBUF_FREE(osbuf);
return status;
}
/* Send a "simple" wmi command -- one with no arguments */
static A_STATUS
wmi_simple_cmd(struct wmi_t *wmip, WMI_COMMAND_ID cmdid)
{
void *osbuf;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(0);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
status = wmi_cmd_send(wmip, osbuf, cmdid, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/* Send a "simple" extended wmi command -- one with no arguments.
Enabling this command only if GPIO or profiling support is enabled.
This is to suppress warnings on some platforms */
#if defined(CONFIG_HOST_GPIO_SUPPORT) || defined(CONFIG_TARGET_PROFILE_SUPPORT)
static A_STATUS
wmi_simple_cmd_xtnd(struct wmi_t *wmip, WMIX_COMMAND_ID cmdid)
{
void *osbuf;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(0);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
status = wmi_cmd_send_xtnd(wmip, osbuf, cmdid, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#endif
static A_STATUS
wmi_ready_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_READY_EVENT *ev = (WMI_READY_EVENT *)datap;
if (len < sizeof(WMI_READY_EVENT)) {
return A_EINVAL;
}
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
pWmiPriv->wmi_ready = TRUE;
A_WMI_READY_EVENT(wmip->wmi_devt, ev->macaddr, ev->phyCapability,
ev->sw_version, ev->abi_version);
return A_OK;
}
int
iswmmoui(const A_UINT8 *frm)
{
return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI);
}
int
iswmmparam(const A_UINT8 *frm)
{
return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
}
static A_STATUS
wmi_connect_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_CONNECT_EVENT *ev;
A_UINT8 *pie,*peie;
A_UINT32 phymode;
NETWORK_TYPE mode;
if (len < sizeof(WMI_CONNECT_EVENT))
{
return A_EINVAL;
}
ev = (WMI_CONNECT_EVENT *)datap;
A_MEMCPY(wmip->wmi_bssid, ev->u.infra_ibss_bss.bssid, ATH_MAC_LEN);
/* initialize pointer to start of assoc rsp IEs */
pie = ev->assocInfo + ev->beaconIeLen + ev->assocReqLen +
sizeof(A_UINT16) + /* capinfo*/
sizeof(A_UINT16) + /* status Code */
sizeof(A_UINT16) ; /* associd */
/* initialize pointer to end of assoc rsp IEs */
peie = ev->assocInfo + ev->beaconIeLen + ev->assocReqLen + ev->assocRespLen;
while (pie < peie)
{
switch (*pie)
{
case IEEE80211_ELEMID_VENDOR:
if (iswmmoui(pie))
{
if(iswmmparam (pie))
{
wmip->wmi_is_wmm_enabled = TRUE;
}
}
break;
}
if (wmip->wmi_is_wmm_enabled)
{
break;
}
pie += pie[1] + 2;
}
mode = A_WMI_GET_NETWORK_TYPE(wmip->wmi_devt);
if (mode == INFRA_NETWORK){
phymode = WMI_CONNECTED_PHYMODE(ev->u.infra_ibss_bss.networkType);
ev->u.infra_ibss_bss.networkType = INFRA_NETWORK;
switch(phymode)
{
case MODE_11G:
#ifdef SUPPORT_11N
case MODE_11NG_HT20:
case MODE_11NG_HT40:
#endif
wmip->wmi_user_phy = wmip->wmi_phyMode;
wmip->wmi_phyMode = WMI_11G_MODE;
break;
case MODE_11GONLY:
wmip->wmi_user_phy = wmip->wmi_phyMode;
wmip->wmi_phyMode = WMI_11GONLY_MODE;
break;
case MODE_11B:
wmip->wmi_user_phy = wmip->wmi_phyMode;
wmip->wmi_phyMode = WMI_11B_MODE;
break;
case MODE_11A:
#ifdef SUPPORT_11N
case MODE_11NA_HT20:
case MODE_11NA_HT40:
#endif
wmip->wmi_user_phy = wmip->wmi_phyMode;
wmip->wmi_phyMode = WMI_11A_MODE;
break;
}
if ((MODE_11A == phymode) || (MODE_11G == phymode) || (MODE_11B == phymode)) {
wmip->wmi_user_ht[A_BAND_24GHZ] = wmip->wmi_ht_cap[A_BAND_24GHZ].enable;
wmip->wmi_user_ht[A_BAND_5GHZ] = wmip->wmi_ht_cap[A_BAND_5GHZ].enable;
wmip->wmi_ht_cap[A_BAND_24GHZ].enable = 0;
wmip->wmi_ht_cap[A_BAND_5GHZ].enable = 0;
} else {
wmip->wmi_user_ht[A_BAND_24GHZ] = wmip->wmi_ht_cap[A_BAND_24GHZ].enable;
wmip->wmi_user_ht[A_BAND_5GHZ] = wmip->wmi_ht_cap[A_BAND_5GHZ].enable;
}
}
A_WMI_CONNECT_EVENT(wmip->wmi_devt, ev);
return A_OK;
}
static A_STATUS
wmi_regDomain_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_REG_DOMAIN_EVENT *ev;
if (len < sizeof(*ev)) {
return A_EINVAL;
}
ev = (WMI_REG_DOMAIN_EVENT *)datap;
A_WMI_REGDOMAIN_EVENT(wmip->wmi_devt, ev->regDomain);
return A_OK;
}
static A_STATUS
wmi_neighborReport_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_NEIGHBOR_REPORT_EVENT *ev;
int numAps;
if (len < sizeof(*ev)) {
return A_EINVAL;
}
ev = (WMI_NEIGHBOR_REPORT_EVENT *)datap;
numAps = ev->numberOfAps;
if (len < (int)(sizeof(*ev) + ((numAps - 1) * sizeof(WMI_NEIGHBOR_INFO)))) {
return A_EINVAL;
}
A_WMI_NEIGHBORREPORT_EVENT(wmip->wmi_devt, numAps, ev->neighbor);
return A_OK;
}
static A_STATUS
wmi_disconnect_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_DISCONNECT_EVENT *ev;
if (len < sizeof(WMI_DISCONNECT_EVENT)) {
return A_EINVAL;
}
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
ev = (WMI_DISCONNECT_EVENT *)datap;
A_MEMZERO(wmip->wmi_bssid, sizeof(wmip->wmi_bssid));
wmip->wmi_is_wmm_enabled = FALSE;
wmip->wmi_pair_crypto_type = NONE_CRYPT;
wmip->wmi_grp_crypto_type = NONE_CRYPT;
wmip->wmi_phyMode = wmip->wmi_user_phy;
wmip->wmi_ht_cap[A_BAND_24GHZ].enable = wmip->wmi_user_ht[A_BAND_24GHZ];
wmip->wmi_ht_cap[A_BAND_5GHZ].enable = wmip->wmi_user_ht[A_BAND_5GHZ];
A_WMI_DISCONNECT_EVENT(wmip->wmi_devt, ev->disconnectReason, ev->bssid,
ev->assocRespLen, ev->assocInfo, ev->protocolReasonStatus);
return A_OK;
}
static A_STATUS
wmi_peer_node_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_PEER_NODE_EVENT *ev;
if (len < sizeof(WMI_PEER_NODE_EVENT)) {
return A_EINVAL;
}
ev = (WMI_PEER_NODE_EVENT *)datap;
if (ev->eventCode == PEER_NODE_JOIN_EVENT) {
A_DPRINTF (DBG_WMI, (DBGFMT "Joined node with Macaddr: ", DBGARG));
} else if(ev->eventCode == PEER_NODE_LEAVE_EVENT) {
A_DPRINTF (DBG_WMI, (DBGFMT "left node with Macaddr: ", DBGARG));
}
A_WMI_PEER_EVENT (wmip->wmi_devt, ev->eventCode, ev->peerMacAddr);
return A_OK;
}
static A_STATUS
wmi_tkip_micerr_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_TKIP_MICERR_EVENT *ev;
if (len < sizeof(*ev)) {
return A_EINVAL;
}
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
ev = (WMI_TKIP_MICERR_EVENT *)datap;
A_WMI_TKIP_MICERR_EVENT(wmip->wmi_devt, ev->keyid, ev->ismcast);
return A_OK;
}
static A_STATUS
wmi_bssInfo_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
bss_t *bss = NULL;
WMI_BSS_INFO_HDR *bih;
A_UINT8 *buf;
A_UINT32 nodeCachingAllowed = 1;
A_UCHAR cached_ssid_len = 0;
A_UCHAR cached_ssid_buf[IEEE80211_NWID_LEN] = {0};
A_UINT8 beacon_ssid_len = 0;
A_UINT8 newNode=0;
A_STATUS status = A_OK;
if (len <= sizeof(WMI_BSS_INFO_HDR)) {
return A_EINVAL;
}
wmi_scan_report_lock(wmip);
bih = (WMI_BSS_INFO_HDR *)datap;
if(bih->frameType == PROBEREQ_FTYPE) {
if(A_WMI_AP_MODE_PROBE_RX(wmip->wmi_devt, datap, len) == A_OK) {
wmi_scan_report_unlock(wmip);
return A_OK;
}
}
bss = wlan_find_node(&wmip->wmi_scan_table, bih->bssid);
if (bih->rssi > 0) {
if (NULL == bss)
{
wmi_scan_report_unlock(wmip);
return A_OK; //no node found in the table, just drop the node with incorrect RSSI
}
else
bih->rssi = bss->ni_rssi; //Adjust RSSI in datap in case it is used in A_WMI_BSSINFO_EVENT_RX
}
A_WMI_BSSINFO_EVENT_RX(wmip->wmi_devt, datap, len);
/* What is driver config for wlan node caching? */
if(ar6000_get_driver_cfg(wmip->wmi_devt,
AR6000_DRIVER_CFG_GET_WLANNODECACHING,
&nodeCachingAllowed) != A_OK) {
wmi_node_return(wmip, bss);
wlan_node_reclaim(&wmip->wmi_scan_table, bss);
wmi_scan_report_unlock(wmip);
return A_EINVAL;
}
if(!nodeCachingAllowed) {
status = A_OK;
goto err_exit;
}
buf = datap + sizeof(WMI_BSS_INFO_HDR);
len -= sizeof(WMI_BSS_INFO_HDR);
#ifndef WM_NWF
if(bih->frameType == PROBERESP_FTYPE)
{
A_WMI_PROBERESP_RECV_EVENT(wmip->wmi_devt,buf,len,bih->bssid);
}
else if(bih->frameType == BEACON_FTYPE)
{
A_WMI_BEACON_RECV_EVENT(wmip->wmi_devt,buf,len,bih->bssid);
}
#endif
A_DPRINTF(DBG_WMI2, (DBGFMT "bssInfo event - ch %u, rssi %02x, "
"bssid \"%02x:%02x:%02x:%02x:%02x:%02x\"\n", DBGARG,
bih->channel, (unsigned char) bih->rssi, bih->bssid[0],
bih->bssid[1], bih->bssid[2], bih->bssid[3], bih->bssid[4],
bih->bssid[5]));
if(wps_enable && (bih->frameType == PROBERESP_FTYPE) ) {
status = A_OK;
goto err_exit;
}
if (bss != NULL) {
/* Legacy Way - This is no longer valid. Retaining the comment to know
* the history. Now we do not reclaim the entire node. We only update
* the ni_buf.
* Free up the node. Not the most efficient process given
* we are about to allocate a new node but it is simple and should be
* adequate.
*/
/* In case of hidden AP, beacon will not have ssid,
* but a directed probe response will have it,
* so cache the probe-resp-ssid if already present. */
if (((TRUE == is_probe_ssid) || IEEE80211_ADDR_EQ (wmip->wmi_bssid, bih->bssid)) &&
((BEACON_FTYPE == bih->frameType) || PROBERESP_FTYPE == bih->frameType))
{
A_UCHAR *ie_ssid;
ie_ssid = bss->ni_cie.ie_ssid;
if(ie_ssid && (ie_ssid[1] <= IEEE80211_NWID_LEN) && (ie_ssid[2] != 0))
{
cached_ssid_len = ie_ssid[1];
if (cached_ssid_len)
{
memcpy(cached_ssid_buf, ie_ssid + 2, cached_ssid_len);
}
}
}
/*
* Use the current average rssi of associated AP base on assumpiton
* 1. Most os with GUI will update RSSI by wmi_get_stats_cmd() periodically
* 2. wmi_get_stats_cmd(..) will be called when calling wmi_startscan_cmd(...)
* The average value of RSSI give end-user better feeling for instance value of scan result
* It also sync up RSSI info in GUI between scan result and RSSI signal icon
*/
if (bss && IEEE80211_ADDR_EQ (wmip->wmi_bssid, bih->bssid)) {
bih->rssi = bss->ni_rssi;
bih->snr = bss->ni_snr;
}
bih->rssi = RSSI_AVE(bss->ni_rssi, bih->rssi, 13);
bih->snr = RSSI_AVE(bss->ni_snr, bih->snr, 13);
/* beacon/probe response frame format
* [8] time stamp
* [2] beacon interval
* [2] capability information
* [tlv] ssid */
beacon_ssid_len = buf[SSID_IE_LEN_INDEX];
/* If ssid is cached for this hidden AP, then change buffer len accordingly. */
if (((TRUE == is_probe_ssid) || IEEE80211_ADDR_EQ (wmip->wmi_bssid, bih->bssid)) &&
((BEACON_FTYPE == bih->frameType) || (PROBERESP_FTYPE == bih->frameType)) &&
(0 != cached_ssid_len) &&
(0 == beacon_ssid_len || (cached_ssid_len > beacon_ssid_len && 0 == buf[SSID_IE_LEN_INDEX + 1])))
{
len += (cached_ssid_len - beacon_ssid_len);
}
/*
* Some APs, like TP-LINK, will report a RSN with zero unicast cipher suites in probe resp.
* Do not update the ni_buf if buf is invalid. It also handles other invalid IEs
*/
if (bih->frameType == PROBERESP_FTYPE) {
struct ieee80211_common_ie cie;
if (wlan_parse_beacon(buf, len, &cie)!=A_OK) {
wmi_node_update_timestamp(wmip, bss);
status = A_OK;
goto err_exit;
}
}
/* Free up just the ni_buf from the node. Not the entire Node as done
* before. The previous method of reclaiming the entire node even for
* updates leads to frequent node reclaims/allocs in the case of P2P.
*/
if (wlan_node_buf_update(&wmip->wmi_scan_table, bss, len) != A_OK) {
status = A_NO_MEMORY;
goto err_exit;
}
} else {
bss = wlan_node_alloc(&wmip->wmi_scan_table, len);
if (bss == NULL) {
wmi_scan_report_unlock(wmip);
return A_NO_MEMORY;
}
newNode = 1;
}
bss->ni_frametype = bih->frameType;
bss->ni_snr = bih->snr;
bss->ni_rssi = bih->rssi;
A_ASSERT(bss->ni_buf != NULL);
if (bss->ni_buf == NULL)
return A_ERROR;
/* In case of hidden AP, beacon will not have ssid,
* but a directed probe response will have it,
* so place the cached-ssid(probe-resp) in the bssinfo. */
if (((TRUE == is_probe_ssid) || IEEE80211_ADDR_EQ (wmip->wmi_bssid, bih->bssid)) &&
((BEACON_FTYPE == bih->frameType) || (PROBERESP_FTYPE == bih->frameType))&&
(0 != cached_ssid_len) &&
(0 == beacon_ssid_len || (beacon_ssid_len && 0 == buf[SSID_IE_LEN_INDEX + 1])))
{
A_UINT8 *ni_buf = bss->ni_buf;
int buf_len = len;
/* copy the first 14 bytes such as
* time-stamp(8), beacon-interval(2), cap-info(2), ssid-id(1), ssid-len(1). */
A_MEMCPY(ni_buf, buf, SSID_IE_LEN_INDEX + 1);
ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len;
ni_buf += (SSID_IE_LEN_INDEX + 1);
buf += (SSID_IE_LEN_INDEX + 1);
buf_len -= (SSID_IE_LEN_INDEX + 1);
/* copy the cached ssid */
A_MEMCPY(ni_buf, cached_ssid_buf, cached_ssid_len);
ni_buf += cached_ssid_len;
buf += beacon_ssid_len;
buf_len -= beacon_ssid_len;
if (cached_ssid_len > beacon_ssid_len)
buf_len -= (cached_ssid_len - beacon_ssid_len);
if (buf_len)
{
/* now copy the rest of bytes */
A_MEMCPY(ni_buf, buf, buf_len);
}
}
else
{
if (len)
{
A_MEMCPY(bss->ni_buf, buf, len);
}
}
bss->ni_framelen = len;
if ((bih->frameType == BEACON_FTYPE || bih->frameType == PROBERESP_FTYPE) &&
wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie) != A_OK)
{
status = A_EINVAL;
goto err_exit;
}
/*
* Update the frequency in ie_chan, overwriting of channel number
* which is done in wlan_parse_beacon
*/
bss->ni_cie.ie_chan = bih->channel;
/* If the Node was updated, release the ref. count acquired by wlan_find_node() in the
* beginning.
*/
err_exit:
if (newNode) {
if (status == A_OK) {
wlan_setup_node(&wmip->wmi_scan_table, bss, bih->bssid);
} else if (bss) {
wlan_node_free(bss);
}
} else {
wmi_node_return(wmip, bss);
}
wmi_scan_report_unlock(wmip);
return status;
}
static A_STATUS
wmi_opt_frame_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
bss_t *bss;
WMI_OPT_RX_INFO_HDR *bih;
A_UINT8 *buf;
if (len <= sizeof(WMI_OPT_RX_INFO_HDR)) {
return A_EINVAL;
}
bih = (WMI_OPT_RX_INFO_HDR *)datap;
buf = datap + sizeof(WMI_OPT_RX_INFO_HDR);
len -= sizeof(WMI_OPT_RX_INFO_HDR);
A_DPRINTF(DBG_WMI2, (DBGFMT "opt frame event %2.2x:%2.2x\n", DBGARG,
bih->bssid[4], bih->bssid[5]));
bss = wlan_find_node(&wmip->wmi_scan_table, bih->bssid);
if (bss != NULL) {
/*
* Free up the node. Not the most efficient process given
* we are about to allocate a new node but it is simple and should be
* adequate.
*/
wlan_node_return(&wmip->wmi_scan_table, bss);
wlan_node_reclaim(&wmip->wmi_scan_table, bss);
}
bss = wlan_node_alloc(&wmip->wmi_scan_table, len);
if (bss == NULL) {
return A_NO_MEMORY;
}
bss->ni_snr = bih->snr;
bss->ni_cie.ie_chan = bih->channel;
A_ASSERT(bss->ni_buf != NULL);
if (bss->ni_buf == NULL)
return A_ERROR;
if (len)
{
A_MEMCPY(bss->ni_buf, buf, len);
}
wlan_setup_node(&wmip->wmi_scan_table, bss, bih->bssid);
return A_OK;
}
/* This event indicates inactivity timeout of a fatpipe(pstream)
* at the target
*/
static A_STATUS
wmi_pstream_timeout_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_PSTREAM_TIMEOUT_EVENT *ev;
if (len < sizeof(WMI_PSTREAM_TIMEOUT_EVENT)) {
return A_EINVAL;
}
A_DPRINTF(DBG_WMI, (DBGFMT "wmi_pstream_timeout_event_rx\n", DBGARG));
ev = (WMI_PSTREAM_TIMEOUT_EVENT *)datap;
/* When the pstream (fat pipe == AC) timesout, it means there were no
* thinStreams within this pstream & it got implicitly created due to
* data flow on this AC. We start the inactivity timer only for
* implicitly created pstream. Just reset the host state.
*/
/* Set the activeTsids for this AC to 0 */
LOCK_WMI(pWmiPriv);
pWmiPriv->wmi_streamExistsForAC[ev->trafficClass]=0;
pWmiPriv->wmi_fatPipeExists &= ~(1 << ev->trafficClass);
UNLOCK_WMI(pWmiPriv);
/*Indicate inactivity to driver layer for this fatpipe (pstream)*/
A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt, ev->trafficClass);
return A_OK;
}
static A_STATUS
wmi_bitrate_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_BIT_RATE_REPLY *reply;
A_INT32 rate;
A_UINT32 sgi,index;
/* 54149:
* WMI_BIT_RATE_CMD structure is changed to WMI_BIT_RATE_REPLY.
* since there is difference in the length and to avoid returning
* error value.
*/
if (len < sizeof(WMI_BIT_RATE_REPLY)) {
return A_EINVAL;
}
reply = (WMI_BIT_RATE_REPLY *)datap;
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - rateindex %d\n", DBGARG, reply->rateIndex));
if (reply->rateIndex == (A_INT8) RATE_AUTO) {
rate = RATE_AUTO;
} else {
// the SGI state is stored as the MSb of the rateIndex
index = reply->rateIndex & 0x7f;
if (index >= ARRAY_SIZE(wmi_rateTable))
return A_EINVAL;
sgi = (reply->rateIndex & 0x80)? 1:0;
rate = wmi_rateTable[index][sgi];
}
A_WMI_BITRATE_RX(wmip->wmi_devt, rate);
return A_OK;
}
static A_STATUS
wmi_ratemask_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_FIX_RATES_REPLY *reply;
if (len < sizeof(WMI_FIX_RATES_REPLY)) {
return A_EINVAL;
}
reply = (WMI_FIX_RATES_REPLY *)datap;
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - fixed rate mask %04x%04x\n", DBGARG, reply->fixRateMask[0], reply->fixRateMask[1]));
A_WMI_RATEMASK_RX(wmip->wmi_devt, reply->fixRateMask);
return A_OK;
}
static A_STATUS
wmi_channelList_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_CHANNEL_LIST_REPLY *reply;
if (len < sizeof(WMI_CHANNEL_LIST_REPLY)) {
return A_EINVAL;
}
reply = (WMI_CHANNEL_LIST_REPLY *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_CHANNELLIST_RX(wmip->wmi_devt, reply->numChannels,
reply->channelList);
return A_OK;
}
static A_STATUS
wmi_txPwr_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_TX_PWR_REPLY *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_TX_PWR_REPLY *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_TXPWR_RX(wmip->wmi_devt, reply->dbM);
return A_OK;
}
static A_STATUS
wmi_keepalive_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_GET_KEEPALIVE_CMD *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_GET_KEEPALIVE_CMD *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_KEEPALIVE_RX(wmip->wmi_devt, reply->configured);
return A_OK;
}
static A_STATUS
wmi_dset_open_req_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMIX_DSETOPENREQ_EVENT *dsetopenreq;
if (len < sizeof(WMIX_DSETOPENREQ_EVENT)) {
return A_EINVAL;
}
dsetopenreq = (WMIX_DSETOPENREQ_EVENT *)datap;
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - dset_id=0x%x\n", DBGARG, dsetopenreq->dset_id));
A_WMI_DSET_OPEN_REQ(wmip->wmi_devt,
dsetopenreq->dset_id,
dsetopenreq->targ_dset_handle,
dsetopenreq->targ_reply_fn,
dsetopenreq->targ_reply_arg);
return A_OK;
}
#ifdef CONFIG_HOST_DSET_SUPPORT
static A_STATUS
wmi_dset_close_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMIX_DSETCLOSE_EVENT *dsetclose;
if (len < sizeof(WMIX_DSETCLOSE_EVENT)) {
return A_EINVAL;
}
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
dsetclose = (WMIX_DSETCLOSE_EVENT *)datap;
A_WMI_DSET_CLOSE(wmip->wmi_devt, dsetclose->access_cookie);
return A_OK;
}
static A_STATUS
wmi_dset_data_req_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMIX_DSETDATAREQ_EVENT *dsetdatareq;
if (len < sizeof(WMIX_DSETDATAREQ_EVENT)) {
return A_EINVAL;
}
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
dsetdatareq = (WMIX_DSETDATAREQ_EVENT *)datap;
A_WMI_DSET_DATA_REQ(wmip->wmi_devt,
dsetdatareq->access_cookie,
dsetdatareq->offset,
dsetdatareq->length,
dsetdatareq->targ_buf,
dsetdatareq->targ_reply_fn,
dsetdatareq->targ_reply_arg);
return A_OK;
}
#endif /* CONFIG_HOST_DSET_SUPPORT */
static A_STATUS
wmi_scanComplete_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_SCAN_COMPLETE_EVENT *ev;
ev = (WMI_SCAN_COMPLETE_EVENT *)datap;
if ((A_STATUS)ev->status == A_OK) {
wmi_scan_report_lock(wmip);
wlan_refresh_inactive_nodes(&wmip->wmi_scan_table);
wmi_scan_report_unlock(wmip);
}
A_WMI_SCANCOMPLETE_EVENT(wmip->wmi_devt, (A_STATUS) ev->status);
//is_probe_ssid = FALSE;
return A_OK;
}
/*
* Target is reporting a programming error. This is for
* developer aid only. Target only checks a few common violations
* and it is responsibility of host to do all error checking.
* Behavior of target after wmi error event is undefined.
* A reset is recommended.
*/
static A_STATUS
wmi_errorEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_CMD_ERROR_EVENT *ev;
ev = (WMI_CMD_ERROR_EVENT *)datap;
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Programming Error: cmd=%d Interface id: %d",
ev->commandId, wmip->wmi_dev_index));
switch (ev->errorCode) {
case (INVALID_PARAM):
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Illegal Parameter\n"));
break;
case (ILLEGAL_STATE):
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Illegal State\n"));
break;
case (INTERNAL_ERROR):
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Internal Error\n"));
break;
case (DFS_CHANNEL):
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("AP cannot start in DFS channel\n"));
break;
}
return A_OK;
}
static A_STATUS
wmi_statsEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_TARGETSTATS_EVENT(wmip->wmi_devt, datap, len);
return A_OK;
}
static A_STATUS
wmi_rssiThresholdEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_RSSI_THRESHOLD_EVENT *reply;
WMI_RSSI_THRESHOLD_VAL newThreshold;
WMI_RSSI_THRESHOLD_PARAMS_CMD cmd;
SQ_THRESHOLD_PARAMS *sq_thresh =
&wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_RSSI];
A_UINT8 upper_rssi_threshold, lower_rssi_threshold;
A_INT16 rssi;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_RSSI_THRESHOLD_EVENT *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
newThreshold = (WMI_RSSI_THRESHOLD_VAL) reply->range;
rssi = reply->rssi;
/*
* Identify the threshold breached and communicate that to the app. After
* that install a new set of thresholds based on the signal quality
* reported by the target
*/
if (newThreshold) {
/* Upper threshold breached */
if (rssi < sq_thresh->upper_threshold[0]) {
A_DPRINTF(DBG_WMI, (DBGFMT "Spurious upper RSSI threshold event: "
" %d\n", DBGARG, rssi));
} else if ((rssi < sq_thresh->upper_threshold[1]) &&
(rssi >= sq_thresh->upper_threshold[0]))
{
newThreshold = WMI_RSSI_THRESHOLD1_ABOVE;
} else if ((rssi < sq_thresh->upper_threshold[2]) &&
(rssi >= sq_thresh->upper_threshold[1]))
{
newThreshold = WMI_RSSI_THRESHOLD2_ABOVE;
} else if ((rssi < sq_thresh->upper_threshold[3]) &&
(rssi >= sq_thresh->upper_threshold[2]))
{
newThreshold = WMI_RSSI_THRESHOLD3_ABOVE;
} else if ((rssi < sq_thresh->upper_threshold[4]) &&
(rssi >= sq_thresh->upper_threshold[3]))
{
newThreshold = WMI_RSSI_THRESHOLD4_ABOVE;
} else if ((rssi < sq_thresh->upper_threshold[5]) &&
(rssi >= sq_thresh->upper_threshold[4]))
{
newThreshold = WMI_RSSI_THRESHOLD5_ABOVE;
} else if (rssi >= sq_thresh->upper_threshold[5]) {
newThreshold = WMI_RSSI_THRESHOLD6_ABOVE;
}
} else {
/* Lower threshold breached */
if (rssi > sq_thresh->lower_threshold[0]) {
A_DPRINTF(DBG_WMI, (DBGFMT "Spurious lower RSSI threshold event: "
"%d %d\n", DBGARG, rssi, sq_thresh->lower_threshold[0]));
} else if ((rssi > sq_thresh->lower_threshold[1]) &&
(rssi <= sq_thresh->lower_threshold[0]))
{
newThreshold = WMI_RSSI_THRESHOLD6_BELOW;
} else if ((rssi > sq_thresh->lower_threshold[2]) &&
(rssi <= sq_thresh->lower_threshold[1]))
{
newThreshold = WMI_RSSI_THRESHOLD5_BELOW;
} else if ((rssi > sq_thresh->lower_threshold[3]) &&
(rssi <= sq_thresh->lower_threshold[2]))
{
newThreshold = WMI_RSSI_THRESHOLD4_BELOW;
} else if ((rssi > sq_thresh->lower_threshold[4]) &&
(rssi <= sq_thresh->lower_threshold[3]))
{
newThreshold = WMI_RSSI_THRESHOLD3_BELOW;
} else if ((rssi > sq_thresh->lower_threshold[5]) &&
(rssi <= sq_thresh->lower_threshold[4]))
{
newThreshold = WMI_RSSI_THRESHOLD2_BELOW;
} else if (rssi <= sq_thresh->lower_threshold[5]) {
newThreshold = WMI_RSSI_THRESHOLD1_BELOW;
}
}
/* Calculate and install the next set of thresholds */
lower_rssi_threshold = ar6000_get_lower_threshold(rssi, sq_thresh,
sq_thresh->lower_threshold_valid_count);
upper_rssi_threshold = ar6000_get_upper_threshold(rssi, sq_thresh,
sq_thresh->upper_threshold_valid_count);
/* Issue a wmi command to install the thresholds */
cmd.thresholdAbove1_Val = upper_rssi_threshold;
cmd.thresholdBelow1_Val = lower_rssi_threshold;
cmd.weight = sq_thresh->weight;
cmd.pollTime = sq_thresh->polling_interval;
rssi_event_value = rssi;
if (wmi_send_rssi_threshold_params(wmip, &cmd) != A_OK) {
A_DPRINTF(DBG_WMI, (DBGFMT "Unable to configure the RSSI thresholds\n",
DBGARG));
}
A_WMI_RSSI_THRESHOLD_EVENT(wmip->wmi_devt, newThreshold, reply->rssi);
return A_OK;
}
static A_STATUS
wmi_reportErrorEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_TARGET_ERROR_REPORT_EVENT *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_TARGET_ERROR_REPORT_EVENT *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_REPORT_ERROR_EVENT(wmip->wmi_devt, (WMI_TARGET_ERROR_VAL) reply->errorVal);
return A_OK;
}
static A_STATUS
wmi_cac_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_CAC_EVENT *reply;
WMM_TSPEC_IE *tspec_ie;
A_UINT16 activeTsids;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_CAC_EVENT *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
(reply->statusCode != TSPEC_STATUS_CODE_ADMISSION_ACCEPTED)) {
tspec_ie = (WMM_TSPEC_IE *) &(reply->tspecSuggestion);
wmi_delete_pstream_cmd(wmip, reply->ac,
(tspec_ie->tsInfo_info >> TSPEC_TSID_S) & TSPEC_TSID_MASK);
}
else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
A_UINT16 activeTsids;
A_UINT8 i;
/* following assumes that there is only one outstanding ADDTS request
when this event is received */
LOCK_WMI(pWmiPriv);
activeTsids = pWmiPriv->wmi_streamExistsForAC[reply->ac];
UNLOCK_WMI(pWmiPriv);
for (i = 0; i < sizeof(activeTsids) * 8; i++) {
if ((activeTsids >> i) & 1) {
break;
}
}
if (i < (sizeof(activeTsids) * 8)) {
wmi_delete_pstream_cmd(wmip, reply->ac, i);
}
}
/*
* Ev#72990: Clear active tsids and Add missing handling
* for delete qos stream from AP
*/
else if (reply->cac_indication == CAC_INDICATION_DELETE) {
A_UINT8 tsid = 0;
A_UINT8 tsidActive;
tspec_ie = (WMM_TSPEC_IE *) &(reply->tspecSuggestion);
tsid= ((tspec_ie->tsInfo_info >> TSPEC_TSID_S) & TSPEC_TSID_MASK);
LOCK_WMI(pWmiPriv);
tsidActive = (pWmiPriv->wmi_streamExistsForAC[reply->ac] & (1<<tsid));
pWmiPriv->wmi_streamExistsForAC[reply->ac] &= ~(1<<tsid);
activeTsids = pWmiPriv->wmi_streamExistsForAC[reply->ac];
UNLOCK_WMI(pWmiPriv);
/* Indicate stream inactivity to driver layer only if all tsids
* within this AC are deleted.
*/
if ((!activeTsids) && (tsidActive)) {
A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt, reply->ac);
pWmiPriv->wmi_fatPipeExists &= ~(1 << reply->ac);
}
}
A_WMI_CAC_EVENT(wmip->wmi_devt, reply->ac,
reply->cac_indication, reply->statusCode,
reply->tspecSuggestion);
return A_OK;
}
static A_STATUS
wmi_channel_change_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_CHANNEL_CHANGE_EVENT *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_CHANNEL_CHANGE_EVENT *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_CHANNEL_CHANGE_EVENT(wmip->wmi_devt, reply->oldChannel,
reply->newChannel);
return A_OK;
}
static A_STATUS
wmi_hbChallengeResp_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMIX_HB_CHALLENGE_RESP_EVENT *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMIX_HB_CHALLENGE_RESP_EVENT *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "wmi: challenge response event\n", DBGARG));
A_WMI_HBCHALLENGERESP_EVENT(wmip->wmi_devt, reply->cookie, reply->source);
return A_OK;
}
static A_STATUS
wmi_roam_tbl_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_TARGET_ROAM_TBL *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_TARGET_ROAM_TBL *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_ROAM_TABLE_EVENT(wmip->wmi_devt, reply);
return A_OK;
}
static A_STATUS
wmi_roam_data_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_TARGET_ROAM_DATA *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_TARGET_ROAM_DATA *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_ROAM_DATA_EVENT(wmip->wmi_devt, reply);
return A_OK;
}
static A_STATUS
wmi_txRetryErrEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
if (len < sizeof(WMI_TX_RETRY_ERR_EVENT)) {
return A_EINVAL;
}
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_TX_RETRY_ERR_EVENT(wmip->wmi_devt);
return A_OK;
}
static A_STATUS
wmi_snrThresholdEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_SNR_THRESHOLD_EVENT *reply;
SQ_THRESHOLD_PARAMS *sq_thresh =
&wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_SNR];
WMI_SNR_THRESHOLD_VAL newThreshold;
WMI_SNR_THRESHOLD_PARAMS_CMD cmd;
A_UINT8 upper_snr_threshold, lower_snr_threshold;
A_INT16 snr;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_SNR_THRESHOLD_EVENT *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
newThreshold = (WMI_SNR_THRESHOLD_VAL) reply->range;
snr = reply->snr;
/*
* Identify the threshold breached and communicate that to the app. After
* that install a new set of thresholds based on the signal quality
* reported by the target
*/
if (newThreshold) {
/* Upper threshold breached */
if (snr < sq_thresh->upper_threshold[0]) {
A_DPRINTF(DBG_WMI, (DBGFMT "Spurious upper SNR threshold event: "
"%d\n", DBGARG, snr));
} else if ((snr < sq_thresh->upper_threshold[1]) &&
(snr >= sq_thresh->upper_threshold[0]))
{
newThreshold = WMI_SNR_THRESHOLD1_ABOVE;
} else if ((snr < sq_thresh->upper_threshold[2]) &&
(snr >= sq_thresh->upper_threshold[1]))
{
newThreshold = WMI_SNR_THRESHOLD2_ABOVE;
} else if ((snr < sq_thresh->upper_threshold[3]) &&
(snr >= sq_thresh->upper_threshold[2]))
{
newThreshold = WMI_SNR_THRESHOLD3_ABOVE;
} else if (snr >= sq_thresh->upper_threshold[3]) {
newThreshold = WMI_SNR_THRESHOLD4_ABOVE;
}
} else {
/* Lower threshold breached */
if (snr > sq_thresh->lower_threshold[0]) {
A_DPRINTF(DBG_WMI, (DBGFMT "Spurious lower SNR threshold event: "
"%d %d\n", DBGARG, snr, sq_thresh->lower_threshold[0]));
} else if ((snr > sq_thresh->lower_threshold[1]) &&
(snr <= sq_thresh->lower_threshold[0]))
{
newThreshold = WMI_SNR_THRESHOLD4_BELOW;
} else if ((snr > sq_thresh->lower_threshold[2]) &&
(snr <= sq_thresh->lower_threshold[1]))
{
newThreshold = WMI_SNR_THRESHOLD3_BELOW;
} else if ((snr > sq_thresh->lower_threshold[3]) &&
(snr <= sq_thresh->lower_threshold[2]))
{
newThreshold = WMI_SNR_THRESHOLD2_BELOW;
} else if (snr <= sq_thresh->lower_threshold[3]) {
newThreshold = WMI_SNR_THRESHOLD1_BELOW;
}
}
/* Calculate and install the next set of thresholds */
lower_snr_threshold = ar6000_get_lower_threshold(snr, sq_thresh,
sq_thresh->lower_threshold_valid_count);
upper_snr_threshold = ar6000_get_upper_threshold(snr, sq_thresh,
sq_thresh->upper_threshold_valid_count);
/* Issue a wmi command to install the thresholds */
cmd.thresholdAbove1_Val = upper_snr_threshold;
cmd.thresholdBelow1_Val = lower_snr_threshold;
cmd.weight = sq_thresh->weight;
cmd.pollTime = sq_thresh->polling_interval;
A_DPRINTF(DBG_WMI, (DBGFMT "snr: %d, threshold: %d, lower: %d, upper: %d\n"
,DBGARG, snr, newThreshold, lower_snr_threshold,
upper_snr_threshold));
snr_event_value = snr;
if (wmi_send_snr_threshold_params(wmip, &cmd) != A_OK) {
A_DPRINTF(DBG_WMI, (DBGFMT "Unable to configure the SNR thresholds\n",
DBGARG));
}
A_WMI_SNR_THRESHOLD_EVENT_RX(wmip->wmi_devt, newThreshold, reply->snr);
return A_OK;
}
static A_STATUS
wmi_lqThresholdEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_LQ_THRESHOLD_EVENT *reply;
if (len < sizeof(*reply)) {
return A_EINVAL;
}
reply = (WMI_LQ_THRESHOLD_EVENT *)datap;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_LQ_THRESHOLD_EVENT_RX(wmip->wmi_devt,
(WMI_LQ_THRESHOLD_VAL) reply->range,
reply->lq);
return A_OK;
}
static A_STATUS
wmi_aplistEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_UINT16 ap_info_entry_size;
WMI_APLIST_EVENT *ev = (WMI_APLIST_EVENT *)datap;
WMI_AP_INFO_V1 *ap_info_v1;
A_UINT8 i;
if (len < sizeof(WMI_APLIST_EVENT)) {
return A_EINVAL;
}
if (ev->apListVer == APLIST_VER1) {
ap_info_entry_size = sizeof(WMI_AP_INFO_V1);
ap_info_v1 = (WMI_AP_INFO_V1 *)ev->apList;
} else {
return A_EINVAL;
}
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("Number of APs in APLIST Event is %d\n", ev->numAP));
if (len < (int)(sizeof(WMI_APLIST_EVENT) +
(ev->numAP - 1) * ap_info_entry_size))
{
return A_EINVAL;
}
/*
* AP List Ver1 Contents
*/
for (i = 0; i < ev->numAP; i++) {
AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("AP#%d BSSID %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x "\
"Channel %d\n", i,
ap_info_v1->bssid[0], ap_info_v1->bssid[1],
ap_info_v1->bssid[2], ap_info_v1->bssid[3],
ap_info_v1->bssid[4], ap_info_v1->bssid[5],
ap_info_v1->channel));
ap_info_v1++;
}
return A_OK;
}
static A_STATUS
wmi_dbglog_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_UINT32 dropped;
dropped = *((A_UINT32 *)datap);
datap += sizeof(dropped);
len -= sizeof(dropped);
A_WMI_DBGLOG_EVENT(wmip->wmi_devt, dropped, (A_INT8*)datap, len);
return A_OK;
}
static A_STATUS
wmi_wacGetInfoReply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_WMI_WACINFO_EVENT(wmip->wmi_devt, datap, len);
return A_OK;
}
#ifdef CONFIG_HOST_GPIO_SUPPORT
static A_STATUS
wmi_gpio_intr_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMIX_GPIO_INTR_EVENT *gpio_intr = (WMIX_GPIO_INTR_EVENT *)datap;
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - intrmask=0x%x input=0x%x.\n", DBGARG,
gpio_intr->intr_mask, gpio_intr->input_values));
A_WMI_GPIO_INTR_RX(wmip->wmi_devt, gpio_intr->intr_mask, gpio_intr->input_values);
return A_OK;
}
static A_STATUS
wmi_gpio_data_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMIX_GPIO_DATA_EVENT *gpio_data = (WMIX_GPIO_DATA_EVENT *)datap;
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - reg=%d value=0x%x\n", DBGARG,
gpio_data->reg_id, gpio_data->value));
A_WMI_GPIO_DATA_RX(wmip->wmi_devt, gpio_data->reg_id, gpio_data->value);
return A_OK;
}
static A_STATUS
wmi_gpio_ack_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_GPIO_ACK_RX(wmip->wmi_devt);
return A_OK;
}
#endif /* CONFIG_HOST_GPIO_SUPPORT */
/*
* Called to send a wmi command. Command specific data is already built
* on osbuf and current osbuf->data points to it.
*/
A_STATUS
wmi_cmd_send(struct wmi_t *wmip, void *osbuf, WMI_COMMAND_ID cmdId,
WMI_SYNC_FLAG syncflag)
{
WMI_CMD_HDR *cHdr;
HTC_ENDPOINT_ID eid;
A_STATUS status;
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
A_ASSERT(pWmiPriv != NULL);
if (pWmiPriv == NULL)
return A_ERROR;
eid = pWmiPriv->wmi_endpoint_id;
if (eid < 0)
return A_EINVAL;
if (syncflag >= END_WMIFLAG) {
return A_EINVAL;
}
if ((syncflag == SYNC_BEFORE_WMIFLAG) || (syncflag == SYNC_BOTH_WMIFLAG)) {
/*
* We want to make sure all data currently queued is transmitted before
* the cmd execution. Establish a new sync point.
*/
status = wmi_sync_point(wmip);
if (status != A_OK) {
return status;
}
}
if (A_NETBUF_PUSH(osbuf, sizeof(WMI_CMD_HDR)) != A_OK) {
return A_NO_MEMORY;
}
cHdr = (WMI_CMD_HDR *)A_NETBUF_DATA(osbuf);
cHdr->commandId = (A_UINT16) cmdId;
WMI_CMD_HDR_SET_DEVID(cHdr, wmip->wmi_dev_index); // added for virtual interface
#ifdef WIN_NWF
wmi_cmd_decode(cmdId);
#endif
status = A_WMI_CONTROL_TX(wmip->wmi_devt, osbuf, eid);
if (status != A_OK) {
return status;
}
if ((syncflag == SYNC_AFTER_WMIFLAG) || (syncflag == SYNC_BOTH_WMIFLAG)) {
/*
* We want to make sure all new data queued waits for the command to
* execute. Establish a new sync point.
*/
status = wmi_sync_point(wmip);
if (status != A_OK) {
return status;
}
}
return status;
#undef IS_OPT_TX_CMD
}
A_STATUS
wmi_cmd_send_xtnd(struct wmi_t *wmip, void *osbuf, WMIX_COMMAND_ID cmdId,
WMI_SYNC_FLAG syncflag)
{
WMIX_CMD_HDR *cHdr;
if (A_NETBUF_PUSH(osbuf, sizeof(WMIX_CMD_HDR)) != A_OK) {
return A_NO_MEMORY;
}
cHdr = (WMIX_CMD_HDR *)A_NETBUF_DATA(osbuf);
cHdr->commandId = (A_UINT32) cmdId;
return wmi_cmd_send(wmip, osbuf, WMI_EXTENSION_CMDID, syncflag);
}
A_STATUS
wmi_connect_cmd(struct wmi_t *wmip, NETWORK_TYPE netType,
DOT11_AUTH_MODE dot11AuthMode, AUTH_MODE authMode,
CRYPTO_TYPE pairwiseCrypto, A_UINT8 pairwiseCryptoLen,
CRYPTO_TYPE groupCrypto, A_UINT8 groupCryptoLen,
int ssidLength, A_UCHAR *ssid,
A_UINT8 *bssid, A_UINT16 channel, A_UINT32 ctrl_flags)
{
void *osbuf;
WMI_CONNECT_CMD *cc;
A_STATUS status;
if ((pairwiseCrypto == NONE_CRYPT) && (groupCrypto != NONE_CRYPT)) {
return A_EINVAL;
}
if ((pairwiseCrypto != NONE_CRYPT) && (groupCrypto == NONE_CRYPT)) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(WMI_CONNECT_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_CONNECT_CMD));
cc = (WMI_CONNECT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cc, sizeof(*cc));
if (ssidLength)
{
A_MEMCPY(cc->ssid, ssid, ssidLength);
}
cc->ssidLength = ssidLength;
cc->networkType = netType;
cc->dot11AuthMode = dot11AuthMode;
cc->authMode = authMode;
cc->pairwiseCryptoType = pairwiseCrypto;
cc->pairwiseCryptoLen = pairwiseCryptoLen;
cc->groupCryptoType = groupCrypto;
cc->groupCryptoLen = groupCryptoLen;
cc->channel = channel;
cc->ctrl_flags = ctrl_flags;
if (bssid != NULL) {
A_MEMCPY(cc->bssid, bssid, ATH_MAC_LEN);
}
wmip->wmi_pair_crypto_type = pairwiseCrypto;
wmip->wmi_grp_crypto_type = groupCrypto;
status = wmi_cmd_send(wmip, osbuf, WMI_CONNECT_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_div_param_cmd(struct wmi_t *wmip, A_UINT32 divIdleTime,
A_UINT8 antRssiThresh, A_UINT8 divEnable, A_UINT16 active_treshold_rate)
{
void *osbuf;
WMI_DIV_PARAMS_CMD *dc;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_DIV_PARAMS_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_DIV_PARAMS_CMD));
dc = (WMI_DIV_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(dc, sizeof(*dc));
dc->divIdleTime = divIdleTime;
dc->antRssiThresh = antRssiThresh;
dc->divEnable = divEnable;
dc->active_treshold_rate = active_treshold_rate;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_DIV_PARAMS_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_reconnect_cmd(struct wmi_t *wmip, A_UINT8 *bssid, A_UINT16 channel)
{
void *osbuf;
WMI_RECONNECT_CMD *cc;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_RECONNECT_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_RECONNECT_CMD));
cc = (WMI_RECONNECT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cc, sizeof(*cc));
cc->channel = channel;
if (bssid != NULL) {
A_MEMCPY(cc->bssid, bssid, ATH_MAC_LEN);
}
status = wmi_cmd_send(wmip, osbuf, WMI_RECONNECT_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_disconnect_cmd(struct wmi_t *wmip)
{
A_STATUS status;
/* Bug fix for 24817(elevator bug) - the disconnect command does not
need to do a SYNC before.*/
status = wmi_simple_cmd(wmip, WMI_DISCONNECT_CMDID);
return status;
}
A_STATUS
wmi_startscan_cmd(struct wmi_t *wmip, WMI_SCAN_TYPE scanType,
A_BOOL forceFgScan, A_BOOL isLegacy,
A_UINT32 homeDwellTime, A_UINT32 forceScanInterval,
A_INT8 numChan, A_UINT16 *channelList)
{
void *osbuf;
WMI_START_SCAN_CMD *sc;
A_INT8 size;
A_STATUS status;
size = sizeof (*sc);
if ((scanType != WMI_LONG_SCAN) && (scanType != WMI_SHORT_SCAN)) {
return A_EINVAL;
}
if (numChan) {
if (numChan > WMI_MAX_CHANNELS) {
return A_EINVAL;
}
size += sizeof(A_UINT16) * (numChan - 1);
}
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
sc = (WMI_START_SCAN_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(sc, sizeof(*sc));
sc->scanType = scanType;
sc->forceFgScan = forceFgScan;
sc->isLegacy = isLegacy;
sc->homeDwellTime = homeDwellTime;
sc->forceScanInterval = forceScanInterval;
sc->numChannels = numChan;
if (numChan) {
A_MEMCPY(sc->channelList, channelList, numChan * sizeof(A_UINT16));
}
status = wmi_cmd_send(wmip, osbuf, WMI_START_SCAN_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_scanparams_cmd(struct wmi_t *wmip, A_UINT16 fg_start_sec,
A_UINT16 fg_end_sec, A_UINT16 bg_sec,
A_UINT16 minact_chdw_msec, A_UINT16 maxact_chdw_msec,
A_UINT16 pas_chdw_msec,
A_UINT8 shScanRatio, A_UINT8 scanCtrlFlags,
A_UINT32 max_dfsch_act_time, A_UINT16 maxact_scan_per_ssid)
{
void *osbuf;
WMI_SCAN_PARAMS_CMD *sc;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*sc));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*sc));
sc = (WMI_SCAN_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(sc, sizeof(*sc));
sc->fg_start_period = fg_start_sec;
sc->fg_end_period = fg_end_sec;
sc->bg_period = bg_sec;
sc->minact_chdwell_time = minact_chdw_msec;
sc->maxact_chdwell_time = maxact_chdw_msec;
sc->pas_chdwell_time = pas_chdw_msec;
sc->shortScanRatio = shScanRatio;
sc->scanCtrlFlags = scanCtrlFlags;
sc->max_dfsch_act_time = max_dfsch_act_time;
sc->maxact_scan_per_ssid = maxact_scan_per_ssid;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_SCAN_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_bssfilter_cmd(struct wmi_t *wmip, A_UINT8 filter, A_UINT32 ieMask)
{
void *osbuf;
WMI_BSS_FILTER_CMD *cmd;
A_STATUS status;
if (filter >= LAST_BSS_FILTER) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_BSS_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->bssFilter = filter;
cmd->ieMask = ieMask;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BSS_FILTER_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_probedSsid_cmd(struct wmi_t *wmip, A_UINT8 index, A_UINT8 flag,
A_UINT8 ssidLength, A_UCHAR *ssid)
{
void *osbuf;
WMI_PROBED_SSID_CMD *cmd;
A_STATUS status;
if (index > MAX_PROBED_SSID_INDEX) {
return A_EINVAL;
}
if (ssidLength > sizeof(cmd->ssid)) {
return A_EINVAL;
}
if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssidLength > 0)) {
is_probe_ssid = FALSE;
return A_EINVAL;
}
if ((flag & SPECIFIC_SSID_FLAG) && !ssidLength) {
return A_EINVAL;
}
if (flag & SPECIFIC_SSID_FLAG) {
is_probe_ssid = TRUE;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_PROBED_SSID_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->entryIndex = index;
cmd->flag = flag;
cmd->ssidLength = ssidLength;
if (ssidLength)
{
A_MEMCPY(cmd->ssid, ssid, ssidLength);
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_PROBED_SSID_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_listeninterval_cmd(struct wmi_t *wmip, A_UINT16 listenInterval, A_UINT16 listenBeacons)
{
void *osbuf;
WMI_LISTEN_INT_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_LISTEN_INT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->listenInterval = listenInterval;
cmd->numBeacons = listenBeacons;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_LISTEN_INT_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_bmisstime_cmd(struct wmi_t *wmip, A_UINT16 bmissTime, A_UINT16 bmissBeacons)
{
void *osbuf;
WMI_BMISS_TIME_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_BMISS_TIME_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->bmissTime = bmissTime;
cmd->numBeacons = bmissBeacons;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BMISS_TIME_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_associnfo_cmd(struct wmi_t *wmip, A_UINT8 ieType,
A_UINT8 ieLen, A_UINT8 *ieInfo)
{
void *osbuf;
WMI_SET_ASSOC_INFO_CMD *cmd;
A_UINT16 cmdLen;
A_STATUS status;
cmdLen = sizeof(*cmd) + ieLen - 1;
osbuf = A_NETBUF_ALLOC(cmdLen);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, cmdLen);
cmd = (WMI_SET_ASSOC_INFO_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, cmdLen);
cmd->ieType = ieType;
cmd->bufferSize = ieLen;
if (ieLen)
{
A_MEMCPY(cmd->assocInfo, ieInfo, ieLen);
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_ASSOC_INFO_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_powermode_cmd(struct wmi_t *wmip, A_UINT8 powerMode)
{
void *osbuf;
WMI_POWER_MODE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_POWER_MODE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->powerMode = powerMode;
wmip->wmi_powerMode = powerMode;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_POWER_MODE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_powermode_cmd_w_psminfo(struct wmi_t *wmip, A_UINT8 _psm_info,A_UINT8 _default)
{
A_STATUS status;
switch(_psm_info)
{
case 0: //MAX_PERF_POWER by _psm_info 0
status = wmi_powermode_cmd(wmip, MAX_PERF_POWER);
break;
case 1: //REC_POWER by _psm_info 1
status = wmi_powermode_cmd(wmip, REC_POWER);
break;
default:
switch(_default)
{
case MAX_PERF_POWER: //MAX_PERF_POWER by default
status = wmi_powermode_cmd(wmip, MAX_PERF_POWER);
break;
case REC_POWER: //REC_POWER by default
status = wmi_powermode_cmd(wmip, REC_POWER);
break;
default:
status = A_OK;
}
}
return status;
}
A_STATUS
wmi_ibsspmcaps_cmd(struct wmi_t *wmip, A_UINT8 pmEnable, A_UINT8 ttl,
A_UINT16 atim_windows, A_UINT16 timeout_value)
{
void *osbuf;
WMI_IBSS_PM_CAPS_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_IBSS_PM_CAPS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->power_saving = pmEnable;
cmd->ttl = ttl;
cmd->atim_windows = atim_windows;
cmd->timeout_value = timeout_value;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_IBSS_PM_CAPS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_apps_cmd(struct wmi_t *wmip, A_UINT8 psType, A_UINT32 idle_time,
A_UINT32 ps_period, A_UINT8 sleep_period)
{
void *osbuf;
WMI_AP_PS_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_AP_PS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->psType = psType;
cmd->idle_time = idle_time;
cmd->ps_period = ps_period;
cmd->sleep_period = sleep_period;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_AP_PS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_pmparams_cmd(struct wmi_t *wmip, A_UINT16 idlePeriod,
A_UINT16 psPollNum, A_UINT16 dtimPolicy,
A_UINT16 tx_wakeup_policy, A_UINT16 num_tx_to_wakeup,
A_UINT16 ps_fail_event_policy)
{
void *osbuf;
WMI_POWER_PARAMS_CMD *pm;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*pm));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*pm));
pm = (WMI_POWER_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(pm, sizeof(*pm));
pm->idle_period = idlePeriod;
pm->pspoll_number = psPollNum;
pm->dtim_policy = dtimPolicy;
pm->tx_wakeup_policy = tx_wakeup_policy;
pm->num_tx_to_wakeup = num_tx_to_wakeup;
pm->ps_fail_event_policy = ps_fail_event_policy;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_POWER_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_disctimeout_cmd(struct wmi_t *wmip, A_UINT8 timeout)
{
void *osbuf;
WMI_DISC_TIMEOUT_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_DISC_TIMEOUT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->disconnectTimeout = timeout;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_DISC_TIMEOUT_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_addKey_cmd(struct wmi_t *wmip, A_UINT8 keyIndex, CRYPTO_TYPE keyType,
A_UINT8 keyUsage, A_UINT8 keyLength, A_UINT8 *keyRSC,
A_UINT8 *keyMaterial, A_UINT8 key_op_ctrl, A_UINT8 *macAddr,
WMI_SYNC_FLAG sync_flag)
{
void *osbuf;
WMI_ADD_CIPHER_KEY_CMD *cmd;
A_STATUS status;
#ifdef CONFIG_ARCH_MSM9615
/*
* This change is to fix a data stall issue when FTP data transfers are
* done with 10 connected stations in WPA/WPA2 security mode for long
* hours like 30 hours. Data stall was happening during GTK rekey. As part
* of group key plumb, SYNC commands are sent to pause the transmit queues.
* In corner cases (After 10 to 15 hours may be because of low credits)
* paused queues are not resumed again causing data stall.
* Now this change is made not to send the SYNC command to pause the
* TX queues. With this change test ran for more than 45 hours.
*/
sync_flag = NO_SYNC_WMIFLAG;
#endif
if ((keyIndex > WMI_MAX_KEY_INDEX) || (keyLength > WMI_MAX_KEY_LEN) ||
(keyMaterial == NULL))
{
return A_EINVAL;
}
if ((WEP_CRYPT != keyType) && (NULL == keyRSC)) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_ADD_CIPHER_KEY_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->keyIndex = keyIndex;
cmd->keyType = keyType;
cmd->keyUsage = keyUsage;
cmd->keyLength = keyLength;
A_MEMCPY(cmd->key, keyMaterial, keyLength);
#ifdef WAPI_ENABLE
if (NULL != keyRSC && key_op_ctrl != KEY_OP_INIT_WAPIPN)
#else
if (NULL != keyRSC)
#endif // WAPI_ENABLE
{
A_MEMCPY(cmd->keyRSC, keyRSC, sizeof(cmd->keyRSC));
}
cmd->key_op_ctrl = key_op_ctrl;
if(macAddr) {
A_MEMCPY(cmd->key_macaddr,macAddr,IEEE80211_ADDR_LEN);
}
status = wmi_cmd_send(wmip, osbuf, WMI_ADD_CIPHER_KEY_CMDID, sync_flag);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_add_krk_cmd(struct wmi_t *wmip, A_UINT8 *krk)
{
void *osbuf;
WMI_ADD_KRK_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_ADD_KRK_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
A_MEMCPY(cmd->krk, krk, WMI_KRK_LEN);
status = wmi_cmd_send(wmip, osbuf, WMI_ADD_KRK_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_delete_krk_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_DELETE_KRK_CMDID);
}
A_STATUS
wmi_deleteKey_cmd(struct wmi_t *wmip, A_UINT8 keyIndex)
{
void *osbuf;
WMI_DELETE_CIPHER_KEY_CMD *cmd;
A_STATUS status;
if (keyIndex > WMI_MAX_KEY_INDEX) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_DELETE_CIPHER_KEY_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->keyIndex = keyIndex;
status = wmi_cmd_send(wmip, osbuf, WMI_DELETE_CIPHER_KEY_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_setPmkid_cmd(struct wmi_t *wmip, A_UINT8 *bssid, A_UINT8 *pmkId,
A_BOOL set)
{
void *osbuf;
WMI_SET_PMKID_CMD *cmd;
A_STATUS status;
if (bssid == NULL) {
return A_EINVAL;
}
if ((set == TRUE) && (pmkId == NULL)) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_PMKID_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMCPY(cmd->bssid, bssid, sizeof(cmd->bssid));
if (set == TRUE) {
A_MEMCPY(cmd->pmkid, pmkId, sizeof(cmd->pmkid));
cmd->enable = PMKID_ENABLE;
} else {
A_MEMZERO(cmd->pmkid, sizeof(cmd->pmkid));
cmd->enable = PMKID_DISABLE;
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_PMKID_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_tkip_countermeasures_cmd(struct wmi_t *wmip, A_BOOL en)
{
void *osbuf;
WMI_SET_TKIP_COUNTERMEASURES_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_TKIP_COUNTERMEASURES_CMD *)(A_NETBUF_DATA(osbuf));
cmd->cm_en = (en == TRUE)? WMI_TKIP_CM_ENABLE : WMI_TKIP_CM_DISABLE;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_TKIP_COUNTERMEASURES_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_akmp_params_cmd(struct wmi_t *wmip,
WMI_SET_AKMP_PARAMS_CMD *akmpParams)
{
void *osbuf;
WMI_SET_AKMP_PARAMS_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_AKMP_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
cmd->akmpInfo = akmpParams->akmpInfo;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_AKMP_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_pmkid_list_cmd(struct wmi_t *wmip,
WMI_SET_PMKID_LIST_CMD *pmkInfo)
{
void *osbuf;
WMI_SET_PMKID_LIST_CMD *cmd;
A_UINT16 cmdLen;
A_UINT8 i;
A_STATUS status;
cmdLen = sizeof(pmkInfo->numPMKID) +
pmkInfo->numPMKID * sizeof(WMI_PMKID);
osbuf = A_NETBUF_ALLOC(cmdLen);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, cmdLen);
cmd = (WMI_SET_PMKID_LIST_CMD *)(A_NETBUF_DATA(osbuf));
cmd->numPMKID = pmkInfo->numPMKID;
for (i = 0; i < cmd->numPMKID; i++) {
A_MEMCPY(&cmd->pmkidList[i], &pmkInfo->pmkidList[i],
WMI_PMKID_LEN);
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_PMKID_LIST_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_pmkid_list_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_PMKID_LIST_CMDID);
}
A_STATUS
wmi_dataSync_send(struct wmi_t *wmip, void *osbuf, HTC_ENDPOINT_ID eid)
{
WMI_DATA_HDR *dtHdr;
A_ASSERT( eid != pWmiPriv->wmi_endpoint_id);
A_ASSERT(osbuf != NULL);
if (osbuf == NULL)
return A_ERROR;
if (A_NETBUF_PUSH(osbuf, sizeof(WMI_DATA_HDR)) != A_OK) {
/* osbuf will be freed in A_WMI_CONTROL_TX if status is not A_OK,
* Free it here too
*/
A_NETBUF_FREE(osbuf);
return A_NO_MEMORY;
}
dtHdr = (WMI_DATA_HDR *)A_NETBUF_DATA(osbuf);
A_MEMZERO(dtHdr, sizeof(WMI_DATA_HDR));
dtHdr->info =
(SYNC_MSGTYPE & WMI_DATA_HDR_MSG_TYPE_MASK) << WMI_DATA_HDR_MSG_TYPE_SHIFT;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter - eid %d\n", DBGARG, eid));
return (A_WMI_CONTROL_TX(wmip->wmi_devt, osbuf, eid));
}
typedef struct _WMI_DATA_SYNC_BUFS {
A_UINT8 trafficClass;
void *osbuf;
}WMI_DATA_SYNC_BUFS;
static A_STATUS
wmi_sync_point(struct wmi_t *wmip)
{
void *cmd_osbuf;
WMI_SYNC_CMD *cmd;
WMI_DATA_SYNC_BUFS dataSyncBufs[WMM_NUM_AC];
A_UINT8 i,numPriStreams=0;
A_STATUS status = A_OK;
A_UINT8 wmi_fatPipeExists;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
memset(dataSyncBufs,0,sizeof(dataSyncBufs));
/* lock out while we walk through the priority list and assemble our local array */
LOCK_WMI(pWmiPriv);
/* Cache the data stream exists within the lock */
wmi_fatPipeExists =pWmiPriv->wmi_fatPipeExists;
for (i=0; i < WMM_NUM_AC ; i++) {
if (wmi_fatPipeExists & (1 << i)) {
numPriStreams++;
dataSyncBufs[numPriStreams-1].trafficClass = i;
}
}
UNLOCK_WMI(pWmiPriv);
/* dataSyncBufs is now filled with entries (starting at index 0) containing valid streamIDs */
do {
/*
* We allocate all network buffers needed so we will be able to
* send all required frames.
*/
cmd_osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (cmd_osbuf == NULL) {
status = A_NO_MEMORY;
break;
}
A_NETBUF_PUT(cmd_osbuf, sizeof(*cmd));
cmd = (WMI_SYNC_CMD *)(A_NETBUF_DATA(cmd_osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
/* In the SYNC cmd sent on the control Ep, send a bitmap of the data
* eps on which the Data Sync will be sent
*/
cmd->dataSyncMap = wmi_fatPipeExists;
for (i=0; i < numPriStreams ; i++) {
dataSyncBufs[i].osbuf = A_NETBUF_ALLOC(0);
if (dataSyncBufs[i].osbuf == NULL) {
status = A_NO_MEMORY;
break;
}
} //end for
/* if Buffer allocation for any of the dataSync fails, then do not
* send the Synchronize cmd on the control ep
*/
if (A_FAILED(status)) {
break;
}
/*
* Send sync cmd followed by sync data messages on all endpoints being
* used
*/
status = wmi_cmd_send(wmip, cmd_osbuf, WMI_SYNCHRONIZE_CMDID,
NO_SYNC_WMIFLAG);
if (A_FAILED(status)) {
/* cmd_osbuf had been freed if status is not A_OK,
* Make cmd_osbuf = NULL to avoid double free issue
*/
cmd_osbuf = NULL;
break;
}
/* cmd buffer sent, we no longer own it */
cmd_osbuf = NULL;
for(i=0; i < numPriStreams; i++) {
A_ASSERT(dataSyncBufs[i].osbuf != NULL);
status = wmi_dataSync_send(wmip,
dataSyncBufs[i].osbuf,
A_WMI_Ac2EndpointID(wmip->wmi_devt,
dataSyncBufs[i].
trafficClass)
);
if (A_FAILED(status)) {
/* dataSyncBufs[i].osbuf had been freed if status is not A_OK,
* Make dataSyncBufs[i].osbuf = NULL to avoid double free issue
*/
dataSyncBufs[i].osbuf = NULL;
break;
}
/* we don't own this buffer anymore, NULL it out of the array so it
* won't get cleaned up */
dataSyncBufs[i].osbuf = NULL;
} //end for
} while(FALSE);
/* free up any resources left over (possibly due to an error) */
if (cmd_osbuf != NULL) {
A_NETBUF_FREE(cmd_osbuf);
}
for (i = 0; i < numPriStreams; i++) {
if (dataSyncBufs[i].osbuf != NULL) {
A_NETBUF_FREE(dataSyncBufs[i].osbuf);
}
}
return (status);
}
A_STATUS
wmi_create_pstream_cmd(struct wmi_t *wmip, WMI_CREATE_PSTREAM_CMD *params)
{
void *osbuf;
WMI_CREATE_PSTREAM_CMD *cmd;
A_UINT8 fatPipeExistsForAC=0;
A_INT32 minimalPHY = 0;
A_INT32 nominalPHY = 0;
A_STATUS status;
/* Validate all the parameters. */
if( !((params->userPriority < 8) &&
(params->userPriority <= 0x7) &&
(convert_userPriority_to_trafficClass(params->userPriority) == params->trafficClass) &&
(params->trafficDirection == UPLINK_TRAFFIC ||
params->trafficDirection == DNLINK_TRAFFIC ||
params->trafficDirection == BIDIR_TRAFFIC) &&
(params->trafficType == TRAFFIC_TYPE_APERIODIC ||
params->trafficType == TRAFFIC_TYPE_PERIODIC ) &&
(params->voicePSCapability == DISABLE_FOR_THIS_AC ||
params->voicePSCapability == ENABLE_FOR_THIS_AC ||
params->voicePSCapability == ENABLE_FOR_ALL_AC) &&
(params->tsid == WMI_IMPLICIT_PSTREAM || params->tsid <= WMI_MAX_THINSTREAM)) )
{
return A_EINVAL;
}
//
// check nominal PHY rate is >= minimalPHY, so that DUT
// can allow TSRS IE
//
// get the physical rate
minimalPHY = ((params->minPhyRate / 1000)/1000); // unit of bps
// check minimal phy < nominal phy rate
//
if (params->nominalPHY >= minimalPHY)
{
nominalPHY = (params->nominalPHY * 1000)/500; // unit of 500 kbps
A_DPRINTF(DBG_WMI,
(DBGFMT "TSRS IE Enabled::MinPhy %x->NominalPhy ===> %x\n", DBGARG,
minimalPHY, nominalPHY));
params->nominalPHY = nominalPHY;
}
else
{
params->nominalPHY = 0;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
A_DPRINTF(DBG_WMI,
(DBGFMT "Sending create_pstream_cmd: ac=%d tsid:%d\n", DBGARG,
params->trafficClass, params->tsid));
cmd = (WMI_CREATE_PSTREAM_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
A_MEMCPY(cmd, params, sizeof(*cmd));
/* this is an implicitly created Fat pipe */
if ((A_UINT32)params->tsid == (A_UINT32)WMI_IMPLICIT_PSTREAM) {
LOCK_WMI(pWmiPriv);
fatPipeExistsForAC = (pWmiPriv->wmi_fatPipeExists & (1 << params->trafficClass));
/*
* EV#84204 target assert failure in _tx_aggr_drain_post_process()
* To prevent the driver from sending the back-to-back CREATE_PSTREAM cmd
*/
if (fatPipeExistsForAC) {
UNLOCK_WMI(pWmiPriv);
A_NETBUF_FREE(osbuf);
return A_OK;
}
pWmiPriv->wmi_fatPipeExists |= (1<<params->trafficClass);
UNLOCK_WMI(pWmiPriv);
} else {
/* this is an explicitly created thin stream within a fat pipe */
LOCK_WMI(pWmiPriv);
fatPipeExistsForAC = (pWmiPriv->wmi_fatPipeExists & (1 << params->trafficClass));
pWmiPriv->wmi_streamExistsForAC[params->trafficClass] |= (1<<params->tsid);
/* if a thinstream becomes active, the fat pipe automatically
* becomes active
*/
pWmiPriv->wmi_fatPipeExists |= (1<<params->trafficClass);
UNLOCK_WMI(pWmiPriv);
}
/* Indicate activty change to driver layer only if this is the
* first TSID to get created in this AC explicitly or an implicit
* fat pipe is getting created.
*/
if (!fatPipeExistsForAC) {
A_WMI_STREAM_TX_ACTIVE(wmip->wmi_devt, params->trafficClass);
}
/* mike: should be SYNC_BEFORE_WMIFLAG */
status = wmi_cmd_send(wmip, osbuf, WMI_CREATE_PSTREAM_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_delete_pstream_cmd(struct wmi_t *wmip, A_UINT8 trafficClass, A_UINT8 tsid)
{
void *osbuf;
WMI_DELETE_PSTREAM_CMD *cmd;
A_STATUS status;
A_UINT16 activeTsids=0;
/* validate the parameters */
if (trafficClass > 3) {
A_DPRINTF(DBG_WMI, (DBGFMT "Invalid trafficClass: %d\n", DBGARG, trafficClass));
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_DELETE_PSTREAM_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->trafficClass = trafficClass;
cmd->tsid = tsid;
LOCK_WMI(pWmiPriv);
activeTsids = pWmiPriv->wmi_streamExistsForAC[trafficClass];
UNLOCK_WMI(pWmiPriv);
/* Check if the tsid was created & exists */
if (!(activeTsids & (1<<tsid))) {
A_NETBUF_FREE(osbuf);
A_DPRINTF(DBG_WMI,
(DBGFMT "TSID %d does'nt exist for trafficClass: %d\n", DBGARG, tsid, trafficClass));
/* TODO: return a more appropriate err code */
return A_ERROR;
}
A_DPRINTF(DBG_WMI,
(DBGFMT "Sending delete_pstream_cmd: trafficClass: %d tsid=%d\n", DBGARG, trafficClass, tsid));
status = (wmi_cmd_send(wmip, osbuf, WMI_DELETE_PSTREAM_CMDID,
SYNC_BEFORE_WMIFLAG));
LOCK_WMI(pWmiPriv);
pWmiPriv->wmi_streamExistsForAC[trafficClass] &= ~(1<<tsid);
activeTsids = pWmiPriv->wmi_streamExistsForAC[trafficClass];
UNLOCK_WMI(pWmiPriv);
/* Indicate stream inactivity to driver layer only if all tsids
* within this AC are deleted.
*/
if(!activeTsids) {
A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt, trafficClass);
pWmiPriv->wmi_fatPipeExists &= ~(1<<trafficClass);
}
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_framerate_cmd(struct wmi_t *wmip, A_UINT8 bEnable, A_UINT8 type, A_UINT8 subType, A_UINT16 rateMask)
{
void *osbuf;
WMI_FRAME_RATES_CMD *cmd;
A_UINT8 frameType;
A_STATUS status;
A_DPRINTF(DBG_WMI,
(DBGFMT " type %02X, subType %02X, rateMask %04x\n", DBGARG, type, subType, rateMask));
if((type != IEEE80211_FRAME_TYPE_MGT && type != IEEE80211_FRAME_TYPE_CTL) ||
(subType > 15)){
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_FRAME_RATES_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
frameType = (A_UINT8)((subType << 4) | type);
cmd->bEnableMask = bEnable;
cmd->frameType = frameType;
cmd->frameRateMask[0] = rateMask;
cmd->frameRateMask[1] = 0;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_FRAMERATES_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/*
* used to set the bit rate. rate is in Kbps. If rate == -1
* then auto selection is used.
*/
A_STATUS
wmi_set_bitrate_cmd(struct wmi_t *wmip, A_INT32 dataRate, A_INT32 mgmtRate, A_INT32 ctlRate)
{
void *osbuf;
WMI_BIT_RATE_CMD *cmd;
A_INT8 drix, mrix, crix, ret_val;
A_STATUS status;
if (dataRate != -1) {
ret_val = wmi_validate_bitrate(wmip, dataRate, &drix);
if(ret_val == A_EINVAL){
return A_EINVAL;
}
} else {
drix = -1;
}
if (mgmtRate != -1) {
ret_val = wmi_validate_bitrate(wmip, mgmtRate, &mrix);
if(ret_val == A_EINVAL){
return A_EINVAL;
}
} else {
mrix = -1;
}
if (ctlRate != -1) {
ret_val = wmi_validate_bitrate(wmip, ctlRate, &crix);
if(ret_val == A_EINVAL){
return A_EINVAL;
}
} else {
crix = -1;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_BIT_RATE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->rateIndex = drix;
cmd->mgmtRateIndex = mrix;
cmd->ctlRateIndex = crix;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BITRATE_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_bitrate_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_BITRATE_CMDID);
}
/*
* Returns TRUE iff the given rate index is legal in the current PHY mode.
*/
A_BOOL
wmi_is_bitrate_index_valid(struct wmi_t *wmip, A_INT32 rateIndex)
{
WMI_PHY_MODE phyMode = (WMI_PHY_MODE) wmip->wmi_phyMode;
A_BOOL isValid = TRUE;
switch(phyMode) {
case WMI_11A_MODE:
if (wmip->wmi_ht_cap[A_BAND_5GHZ].enable){
if(wmip->wmi_ht_cap[A_BAND_5GHZ].chan_width_40M_supported) {
if ((rateIndex < MODE_A_SUPPORT_RATE_START) || (rateIndex > MODE_HT40_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
} else {
if ((rateIndex < MODE_A_SUPPORT_RATE_START) || (rateIndex > MODE_HT20_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
}
} else {
if ((rateIndex < MODE_A_SUPPORT_RATE_START) || (rateIndex > MODE_A_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
}
break;
case WMI_11B_MODE:
if ((rateIndex < MODE_B_SUPPORT_RATE_START) || (rateIndex > MODE_B_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
break;
case WMI_11GONLY_MODE:
if (wmip->wmi_ht_cap[A_BAND_24GHZ].enable){
if ((rateIndex < MODE_GONLY_SUPPORT_RATE_START) || (rateIndex > MODE_HT20_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
} else {
if ((rateIndex < MODE_GONLY_SUPPORT_RATE_START) || (rateIndex > MODE_GONLY_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
}
break;
case WMI_11G_MODE:
case WMI_11AG_MODE:
if (wmip->wmi_ht_cap[A_BAND_24GHZ].enable){
if ((rateIndex < MODE_G_SUPPORT_RATE_START) || (rateIndex > MODE_HT20_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
} else {
if ((rateIndex < MODE_G_SUPPORT_RATE_START) || (rateIndex > MODE_G_SUPPORT_RATE_STOP)) {
isValid = FALSE;
}
}
break;
default:
A_ASSERT(FALSE);
break;
}
return isValid;
}
A_INT8
wmi_validate_bitrate(struct wmi_t *wmip, A_INT32 rate, A_INT8 *rate_idx)
{
A_INT8 i;
A_UINT8 sgi;
sgi = wmip->wmi_ht_cap[A_BAND_24GHZ].short_GI_20MHz;
if(wmip->wmi_phyMode == WMI_11A_MODE) {
if(wmip->wmi_ht_cap[A_BAND_5GHZ].chan_width_40M_supported) {
sgi = wmip->wmi_ht_cap[A_BAND_5GHZ].short_GI_40MHz;
} else {
sgi = wmip->wmi_ht_cap[A_BAND_5GHZ].short_GI_20MHz;
}
}
for (i=0;;i++)
{
if (wmi_rateTable[(A_UINT32) i][sgi] == 0) {
return A_EINVAL;
}
if (wmi_rateTable[(A_UINT32) i][sgi] == rate) {
break;
}
}
if(wmi_is_bitrate_index_valid(wmip, (A_INT32) i) != TRUE) {
return A_EINVAL;
}
*rate_idx = i;
return A_OK;
}
A_STATUS
wmi_set_fixrates_cmd(struct wmi_t *wmip, A_UINT32 *fixRatesMask)
{
void *osbuf;
WMI_FIX_RATES_CMD *cmd;
A_STATUS status;
#if 0
A_INT32 rateIndex;
/* This check does not work for AR6003 as the HT modes are enabled only when
* the STA is connected to a HT_BSS and is not based only on channel. It is
* safe to skip this check however because rate control will only use rates
* that are permitted by the valid rate mask and the fix rate mask. Meaning
* the fix rate mask is not sufficient by itself to cause an invalid rate
* to be used. */
/* Make sure all rates in the mask are valid in the current PHY mode */
for(rateIndex = 0; rateIndex < MAX_NUMBER_OF_SUPPORT_RATES; rateIndex++) {
if((1 << rateIndex) & (A_UINT32)fixRatesMask) {
if(wmi_is_bitrate_index_valid(wmip, rateIndex) != TRUE) {
A_DPRINTF(DBG_WMI, (DBGFMT "Set Fix Rates command failed: Given rate is illegal in current PHY mode\n", DBGARG));
return A_EINVAL;
}
}
}
#endif
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_FIX_RATES_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->fixRateMask[0] = fixRatesMask[0];
cmd->fixRateMask[1] = fixRatesMask[1];
status = wmi_cmd_send(wmip, osbuf, WMI_SET_FIXRATES_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_ratemask_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_FIXRATES_CMDID);
}
A_STATUS
wmi_get_channelList_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_CHANNEL_LIST_CMDID);
}
/*
* used to generate a wmi sey channel Parameters cmd.
* mode should always be specified and corresponds to the phy mode of the
* wlan.
* numChan should alway sbe specified. If zero indicates that all available
* channels should be used.
* channelList is an array of channel frequencies (in Mhz) which the radio
* should limit its operation to. It should be NULL if numChan == 0. Size of
* array should correspond to numChan entries.
*/
A_STATUS
wmi_set_channelParams_cmd(struct wmi_t *wmip, A_UINT8 scanParam,
WMI_PHY_MODE mode, A_INT8 numChan,
A_UINT16 *channelList)
{
void *osbuf;
WMI_CHANNEL_PARAMS_CMD *cmd;
A_INT8 size;
A_STATUS status;
if (wmip->wmi_phyMode != mode) {
wmi_free_allnodes(wmip);
}
size = sizeof (*cmd);
if (numChan) {
if (numChan > WMI_MAX_CHANNELS) {
return A_EINVAL;
}
size += sizeof(A_UINT16) * (numChan - 1);
}
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_CHANNEL_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
wmip->wmi_phyMode = mode;
wmip->wmi_user_phy = mode;
cmd->scanParam = scanParam;
cmd->phyMode = mode;
cmd->numChannels = numChan;
A_MEMCPY(cmd->channelList, channelList, numChan * sizeof(A_UINT16));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_CHANNEL_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
void
wmi_cache_configure_rssithreshold(struct wmi_t *wmip, WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd)
{
SQ_THRESHOLD_PARAMS *sq_thresh =
&wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_RSSI];
/*
* Parse the command and store the threshold values here. The checks
* for valid values can be put here
*/
sq_thresh->weight = rssiCmd->weight;
sq_thresh->polling_interval = rssiCmd->pollTime;
sq_thresh->upper_threshold[0] = rssiCmd->thresholdAbove1_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->upper_threshold[1] = rssiCmd->thresholdAbove2_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->upper_threshold[2] = rssiCmd->thresholdAbove3_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->upper_threshold[3] = rssiCmd->thresholdAbove4_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->upper_threshold[4] = rssiCmd->thresholdAbove5_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->upper_threshold[5] = rssiCmd->thresholdAbove6_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->upper_threshold_valid_count = 6;
/* List sorted in descending order */
sq_thresh->lower_threshold[0] = rssiCmd->thresholdBelow6_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->lower_threshold[1] = rssiCmd->thresholdBelow5_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->lower_threshold[2] = rssiCmd->thresholdBelow4_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->lower_threshold[3] = rssiCmd->thresholdBelow3_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->lower_threshold[4] = rssiCmd->thresholdBelow2_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->lower_threshold[5] = rssiCmd->thresholdBelow1_Val - SIGNAL_QUALITY_NOISE_FLOOR;
sq_thresh->lower_threshold_valid_count = 6;
if (!rssi_event_value) {
/*
* Configuring the thresholds to their extremes allows the host to get an
* event from the target which is used for the configuring the correct
* thresholds
*/
rssiCmd->thresholdAbove1_Val = sq_thresh->upper_threshold[0];
rssiCmd->thresholdBelow1_Val = sq_thresh->lower_threshold[0];
} else {
/*
* In case the user issues multiple times of rssi_threshold_setting,
* we should not use the extreames anymore, the target does not expect that.
*/
rssiCmd->thresholdAbove1_Val = ar6000_get_upper_threshold(rssi_event_value, sq_thresh,
sq_thresh->upper_threshold_valid_count);
rssiCmd->thresholdBelow1_Val = ar6000_get_lower_threshold(rssi_event_value, sq_thresh,
sq_thresh->lower_threshold_valid_count);
}
}
A_STATUS
wmi_set_rssi_threshold_params(struct wmi_t *wmip,
WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd)
{
/* Check these values are in ascending order */
if( rssiCmd->thresholdAbove6_Val <= rssiCmd->thresholdAbove5_Val ||
rssiCmd->thresholdAbove5_Val <= rssiCmd->thresholdAbove4_Val ||
rssiCmd->thresholdAbove4_Val <= rssiCmd->thresholdAbove3_Val ||
rssiCmd->thresholdAbove3_Val <= rssiCmd->thresholdAbove2_Val ||
rssiCmd->thresholdAbove2_Val <= rssiCmd->thresholdAbove1_Val ||
rssiCmd->thresholdBelow6_Val <= rssiCmd->thresholdBelow5_Val ||
rssiCmd->thresholdBelow5_Val <= rssiCmd->thresholdBelow4_Val ||
rssiCmd->thresholdBelow4_Val <= rssiCmd->thresholdBelow3_Val ||
rssiCmd->thresholdBelow3_Val <= rssiCmd->thresholdBelow2_Val ||
rssiCmd->thresholdBelow2_Val <= rssiCmd->thresholdBelow1_Val)
{
return A_EINVAL;
}
wmi_cache_configure_rssithreshold(wmip, rssiCmd);
return (wmi_send_rssi_threshold_params(wmip, rssiCmd));
}
A_STATUS
wmi_set_ip_cmd(struct wmi_t *wmip, WMI_SET_IP_CMD *ipCmd)
{
void *osbuf;
WMI_SET_IP_CMD *cmd;
A_STATUS status;
/* Multicast address are not valid */
if((*((A_UINT8*)&ipCmd->ips[0]) >= 0xE0) ||
(*((A_UINT8*)&ipCmd->ips[1]) >= 0xE0)) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(WMI_SET_IP_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_SET_IP_CMD));
cmd = (WMI_SET_IP_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMCPY(cmd, ipCmd, sizeof(WMI_SET_IP_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_IP_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_host_sleep_mode_cmd(struct wmi_t *wmip,
WMI_SET_HOST_SLEEP_MODE_CMD *hostModeCmd)
{
void *osbuf;
A_INT8 size;
WMI_SET_HOST_SLEEP_MODE_CMD *cmd;
A_UINT16 activeTsids=0;
A_UINT8 streamExists=0;
A_UINT8 i;
A_STATUS status;
if( hostModeCmd->awake == hostModeCmd->asleep) {
return A_EINVAL;
}
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_SET_HOST_SLEEP_MODE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, hostModeCmd, sizeof(WMI_SET_HOST_SLEEP_MODE_CMD));
if(hostModeCmd->asleep) {
/*
* Relinquish credits from all implicitly created pstreams since when we
* go to sleep. If user created explicit thinstreams exists with in a
* fatpipe leave them intact for the user to delete
*/
LOCK_WMI(pWmiPriv);
streamExists = pWmiPriv->wmi_fatPipeExists;
UNLOCK_WMI(pWmiPriv);
for(i=0;i< WMM_NUM_AC;i++) {
if (streamExists & (1<<i)) {
LOCK_WMI(pWmiPriv);
activeTsids = pWmiPriv->wmi_streamExistsForAC[i];
UNLOCK_WMI(pWmiPriv);
/* If there are no user created thin streams delete the fatpipe */
if(!activeTsids) {
streamExists &= ~(1<<i);
/*Indicate inactivity to drv layer for this fatpipe(pstream)*/
A_WMI_STREAM_TX_INACTIVE(wmip->wmi_devt,i);
}
}
}
/* Update the fatpipes that exists*/
LOCK_WMI(pWmiPriv);
pWmiPriv->wmi_fatPipeExists = streamExists;
UNLOCK_WMI(pWmiPriv);
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_HOST_SLEEP_MODE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_wow_mode_cmd(struct wmi_t *wmip,
WMI_SET_WOW_MODE_CMD *wowModeCmd)
{
void *osbuf;
A_INT8 size;
WMI_SET_WOW_MODE_CMD *cmd;
A_STATUS status;
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_SET_WOW_MODE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, wowModeCmd, sizeof(WMI_SET_WOW_MODE_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_WOW_MODE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_wow_list_cmd(struct wmi_t *wmip,
WMI_GET_WOW_LIST_CMD *wowListCmd)
{
void *osbuf;
A_INT8 size;
WMI_GET_WOW_LIST_CMD *cmd;
A_STATUS status;
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_GET_WOW_LIST_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, wowListCmd, sizeof(WMI_GET_WOW_LIST_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_GET_WOW_LIST_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
static A_STATUS
wmi_get_wow_list_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_GET_WOW_LIST_REPLY *reply;
if (len < sizeof(WMI_GET_WOW_LIST_REPLY)) {
return A_EINVAL;
}
reply = (WMI_GET_WOW_LIST_REPLY *)datap;
A_WMI_WOW_LIST_EVENT(wmip->wmi_devt, reply->num_filters,
reply);
return A_OK;
}
A_STATUS wmi_add_wow_pattern_cmd(struct wmi_t *wmip,
WMI_ADD_WOW_PATTERN_CMD *addWowCmd,
A_UINT8* pattern, A_UINT8* mask,
A_UINT8 pattern_size)
{
void *osbuf;
A_INT8 size;
WMI_ADD_WOW_PATTERN_CMD *cmd;
A_UINT8 *filter_mask = NULL;
A_STATUS status;
size = sizeof (*cmd);
size += ((2 * addWowCmd->filter_size)* sizeof(A_UINT8));
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_ADD_WOW_PATTERN_CMD *)(A_NETBUF_DATA(osbuf));
cmd->filter_list_id = addWowCmd->filter_list_id;
cmd->filter_offset = addWowCmd->filter_offset;
cmd->filter_size = addWowCmd->filter_size;
A_MEMCPY(cmd->filter, pattern, addWowCmd->filter_size);
filter_mask = (A_UINT8*)(cmd->filter + cmd->filter_size);
A_MEMCPY(filter_mask, mask, addWowCmd->filter_size);
status = wmi_cmd_send(wmip, osbuf, WMI_ADD_WOW_PATTERN_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_del_wow_pattern_cmd(struct wmi_t *wmip,
WMI_DEL_WOW_PATTERN_CMD *delWowCmd)
{
void *osbuf;
A_INT8 size;
WMI_DEL_WOW_PATTERN_CMD *cmd;
A_STATUS status;
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_DEL_WOW_PATTERN_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, delWowCmd, sizeof(WMI_DEL_WOW_PATTERN_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_DEL_WOW_PATTERN_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
void
wmi_cache_configure_snrthreshold(struct wmi_t *wmip, WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd)
{
SQ_THRESHOLD_PARAMS *sq_thresh =
&wmip->wmi_SqThresholdParams[SIGNAL_QUALITY_METRICS_SNR];
/*
* Parse the command and store the threshold values here. The checks
* for valid values can be put here
*/
sq_thresh->weight = snrCmd->weight;
sq_thresh->polling_interval = snrCmd->pollTime;
sq_thresh->upper_threshold[0] = snrCmd->thresholdAbove1_Val;
sq_thresh->upper_threshold[1] = snrCmd->thresholdAbove2_Val;
sq_thresh->upper_threshold[2] = snrCmd->thresholdAbove3_Val;
sq_thresh->upper_threshold[3] = snrCmd->thresholdAbove4_Val;
sq_thresh->upper_threshold_valid_count = 4;
/* List sorted in descending order */
sq_thresh->lower_threshold[0] = snrCmd->thresholdBelow4_Val;
sq_thresh->lower_threshold[1] = snrCmd->thresholdBelow3_Val;
sq_thresh->lower_threshold[2] = snrCmd->thresholdBelow2_Val;
sq_thresh->lower_threshold[3] = snrCmd->thresholdBelow1_Val;
sq_thresh->lower_threshold_valid_count = 4;
if (!snr_event_value) {
/*
* Configuring the thresholds to their extremes allows the host to get an
* event from the target which is used for the configuring the correct
* thresholds
*/
snrCmd->thresholdAbove1_Val = (A_UINT8)sq_thresh->upper_threshold[0];
snrCmd->thresholdBelow1_Val = (A_UINT8)sq_thresh->lower_threshold[0];
} else {
/*
* In case the user issues multiple times of snr_threshold_setting,
* we should not use the extreames anymore, the target does not expect that.
*/
snrCmd->thresholdAbove1_Val = ar6000_get_upper_threshold(snr_event_value, sq_thresh,
sq_thresh->upper_threshold_valid_count);
snrCmd->thresholdBelow1_Val = ar6000_get_lower_threshold(snr_event_value, sq_thresh,
sq_thresh->lower_threshold_valid_count);
}
}
A_STATUS
wmi_set_snr_threshold_params(struct wmi_t *wmip,
WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd)
{
if( snrCmd->thresholdAbove4_Val <= snrCmd->thresholdAbove3_Val ||
snrCmd->thresholdAbove3_Val <= snrCmd->thresholdAbove2_Val ||
snrCmd->thresholdAbove2_Val <= snrCmd->thresholdAbove1_Val ||
snrCmd->thresholdBelow4_Val <= snrCmd->thresholdBelow3_Val ||
snrCmd->thresholdBelow3_Val <= snrCmd->thresholdBelow2_Val ||
snrCmd->thresholdBelow2_Val <= snrCmd->thresholdBelow1_Val)
{
return A_EINVAL;
}
wmi_cache_configure_snrthreshold(wmip, snrCmd);
return (wmi_send_snr_threshold_params(wmip, snrCmd));
}
A_STATUS
wmi_clr_rssi_snr(struct wmi_t *wmip)
{
void *osbuf;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(int));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
status = wmi_cmd_send(wmip, osbuf, WMI_CLR_RSSI_SNR_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_lq_threshold_params(struct wmi_t *wmip,
WMI_LQ_THRESHOLD_PARAMS_CMD *lqCmd)
{
void *osbuf;
A_INT8 size;
WMI_LQ_THRESHOLD_PARAMS_CMD *cmd;
A_STATUS status;
/* These values are in ascending order */
if( lqCmd->thresholdAbove4_Val <= lqCmd->thresholdAbove3_Val ||
lqCmd->thresholdAbove3_Val <= lqCmd->thresholdAbove2_Val ||
lqCmd->thresholdAbove2_Val <= lqCmd->thresholdAbove1_Val ||
lqCmd->thresholdBelow4_Val <= lqCmd->thresholdBelow3_Val ||
lqCmd->thresholdBelow3_Val <= lqCmd->thresholdBelow2_Val ||
lqCmd->thresholdBelow2_Val <= lqCmd->thresholdBelow1_Val ) {
return A_EINVAL;
}
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_LQ_THRESHOLD_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, lqCmd, sizeof(WMI_LQ_THRESHOLD_PARAMS_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_LQ_THRESHOLD_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_error_report_bitmask(struct wmi_t *wmip, A_UINT32 mask)
{
void *osbuf;
A_INT8 size;
WMI_TARGET_ERROR_REPORT_BITMASK *cmd;
A_STATUS status;
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_TARGET_ERROR_REPORT_BITMASK *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
cmd->bitmask = mask;
status = wmi_cmd_send(wmip, osbuf, WMI_TARGET_ERROR_REPORT_BITMASK_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_challenge_resp_cmd(struct wmi_t *wmip, A_UINT32 cookie, A_UINT32 source)
{
void *osbuf;
WMIX_HB_CHALLENGE_RESP_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMIX_HB_CHALLENGE_RESP_CMD *)(A_NETBUF_DATA(osbuf));
cmd->cookie = cookie;
cmd->source = source;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_HB_CHALLENGE_RESP_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_config_debug_module_cmd(struct wmi_t *wmip, A_UINT16 mmask,
A_UINT16 tsr, A_BOOL rep, A_UINT16 size,
A_UINT32 valid)
{
void *osbuf;
WMIX_DBGLOG_CFG_MODULE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMIX_DBGLOG_CFG_MODULE_CMD *)(A_NETBUF_DATA(osbuf));
cmd->config.cfgmmask = mmask;
cmd->config.cfgtsr = tsr;
cmd->config.cfgrep = rep;
cmd->config.cfgsize = size;
cmd->config.cfgvalid = valid;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_DBGLOG_CFG_MODULE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_stats_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_STATISTICS_CMDID);
}
A_STATUS
wmi_addBadAp_cmd(struct wmi_t *wmip, A_UINT8 apIndex, A_UINT8 *bssid)
{
void *osbuf;
WMI_ADD_BAD_AP_CMD *cmd;
A_STATUS status;
if ((bssid == NULL) || (apIndex > WMI_MAX_BAD_AP_INDEX)) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_ADD_BAD_AP_CMD *)(A_NETBUF_DATA(osbuf));
cmd->badApIndex = apIndex;
A_MEMCPY(cmd->bssid, bssid, sizeof(cmd->bssid));
status = wmi_cmd_send(wmip, osbuf, WMI_ADD_BAD_AP_CMDID, SYNC_BEFORE_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_deleteBadAp_cmd(struct wmi_t *wmip, A_UINT8 apIndex)
{
void *osbuf;
WMI_DELETE_BAD_AP_CMD *cmd;
A_STATUS status;
if (apIndex > WMI_MAX_BAD_AP_INDEX) {
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_DELETE_BAD_AP_CMD *)(A_NETBUF_DATA(osbuf));
cmd->badApIndex = apIndex;
status = wmi_cmd_send(wmip, osbuf, WMI_DELETE_BAD_AP_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_abort_scan_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_ABORT_SCAN_CMDID);
}
A_STATUS
wmi_set_txPwr_cmd(struct wmi_t *wmip, A_UINT8 dbM)
{
void *osbuf;
WMI_SET_TX_PWR_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_TX_PWR_CMD *)(A_NETBUF_DATA(osbuf));
cmd->dbM = dbM;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_TX_PWR_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_txPwr_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_TX_PWR_CMDID);
}
A_UINT16
wmi_get_mapped_qos_queue(struct wmi_t *wmip, A_UINT8 trafficClass)
{
A_UINT16 activeTsids=0;
LOCK_WMI(pWmiPriv);
activeTsids = pWmiPriv->wmi_streamExistsForAC[trafficClass];
UNLOCK_WMI(pWmiPriv);
return activeTsids;
}
A_STATUS
wmi_get_roam_tbl_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_ROAM_TBL_CMDID);
}
A_STATUS
wmi_get_roam_data_cmd(struct wmi_t *wmip, A_UINT8 roamDataType)
{
void *osbuf;
A_UINT32 size = sizeof(A_UINT8);
WMI_TARGET_ROAM_DATA *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(size); /* no payload */
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_TARGET_ROAM_DATA *)(A_NETBUF_DATA(osbuf));
cmd->roamDataType = roamDataType;
status = wmi_cmd_send(wmip, osbuf, WMI_GET_ROAM_DATA_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_roam_ctrl_cmd(struct wmi_t *wmip, WMI_SET_ROAM_CTRL_CMD *p,
A_UINT8 size)
{
void *osbuf;
WMI_SET_ROAM_CTRL_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_SET_ROAM_CTRL_CMD *)(A_NETBUF_DATA(osbuf));
if (size)
{
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, p, size);
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_ROAM_CTRL_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_powersave_timers_cmd(struct wmi_t *wmip,
WMI_POWERSAVE_TIMERS_POLICY_CMD *pCmd,
A_UINT8 size)
{
void *osbuf;
WMI_POWERSAVE_TIMERS_POLICY_CMD *cmd;
A_STATUS status;
/* These timers can't be zero */
if(!pCmd->psPollTimeout || !pCmd->triggerTimeout ||
!(pCmd->apsdTimPolicy == IGNORE_TIM_ALL_QUEUES_APSD ||
pCmd->apsdTimPolicy == PROCESS_TIM_ALL_QUEUES_APSD) ||
!(pCmd->simulatedAPSDTimPolicy == IGNORE_TIM_SIMULATED_APSD ||
pCmd->simulatedAPSDTimPolicy == PROCESS_TIM_SIMULATED_APSD))
return A_EINVAL;
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_POWERSAVE_TIMERS_POLICY_CMD *)(A_NETBUF_DATA(osbuf));
if (size)
{
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, pCmd, size);
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#ifdef CONFIG_HOST_GPIO_SUPPORT
/* Send a command to Target to change GPIO output pins. */
A_STATUS
wmi_gpio_output_set(struct wmi_t *wmip,
A_UINT32 set_mask,
A_UINT32 clear_mask,
A_UINT32 enable_mask,
A_UINT32 disable_mask)
{
void *osbuf;
WMIX_GPIO_OUTPUT_SET_CMD *output_set;
int size;
A_STATUS status;
size = sizeof(*output_set);
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - set=0x%x clear=0x%x enb=0x%x dis=0x%x\n", DBGARG,
set_mask, clear_mask, enable_mask, disable_mask));
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
output_set = (WMIX_GPIO_OUTPUT_SET_CMD *)(A_NETBUF_DATA(osbuf));
output_set->set_mask = set_mask;
output_set->clear_mask = clear_mask;
output_set->enable_mask = enable_mask;
output_set->disable_mask = disable_mask;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_GPIO_OUTPUT_SET_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/* Send a command to the Target requesting state of the GPIO input pins */
A_STATUS
wmi_gpio_input_get(struct wmi_t *wmip)
{
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
return wmi_simple_cmd_xtnd(wmip, WMIX_GPIO_INPUT_GET_CMDID);
}
/* Send a command to the Target that changes the value of a GPIO register. */
A_STATUS
wmi_gpio_register_set(struct wmi_t *wmip,
A_UINT32 gpioreg_id,
A_UINT32 value)
{
void *osbuf;
WMIX_GPIO_REGISTER_SET_CMD *register_set;
int size;
A_STATUS status;
size = sizeof(*register_set);
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - reg=%d value=0x%x\n", DBGARG, gpioreg_id, value));
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
register_set = (WMIX_GPIO_REGISTER_SET_CMD *)(A_NETBUF_DATA(osbuf));
register_set->gpioreg_id = gpioreg_id;
register_set->value = value;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_GPIO_REGISTER_SET_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/* Send a command to the Target to fetch the value of a GPIO register. */
A_STATUS
wmi_gpio_register_get(struct wmi_t *wmip,
A_UINT32 gpioreg_id)
{
void *osbuf;
WMIX_GPIO_REGISTER_GET_CMD *register_get;
int size;
A_STATUS status;
size = sizeof(*register_get);
A_DPRINTF(DBG_WMI, (DBGFMT "Enter - reg=%d\n", DBGARG, gpioreg_id));
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
register_get = (WMIX_GPIO_REGISTER_GET_CMD *)(A_NETBUF_DATA(osbuf));
register_get->gpioreg_id = gpioreg_id;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_GPIO_REGISTER_GET_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/* Send a command to the Target acknowledging some GPIO interrupts. */
A_STATUS
wmi_gpio_intr_ack(struct wmi_t *wmip,
A_UINT32 ack_mask)
{
void *osbuf;
WMIX_GPIO_INTR_ACK_CMD *intr_ack;
int size;
A_STATUS status;
size = sizeof(*intr_ack);
A_DPRINTF(DBG_WMI, (DBGFMT "Enter ack_mask=0x%x\n", DBGARG, ack_mask));
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
intr_ack = (WMIX_GPIO_INTR_ACK_CMD *)(A_NETBUF_DATA(osbuf));
intr_ack->ack_mask = ack_mask;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_GPIO_INTR_ACK_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#endif /* CONFIG_HOST_GPIO_SUPPORT */
A_STATUS
wmi_set_access_params_cmd(struct wmi_t *wmip, A_UINT8 ac, A_UINT16 txop, A_UINT8 eCWmin,
A_UINT8 eCWmax, A_UINT8 aifsn)
{
void *osbuf;
WMI_SET_ACCESS_PARAMS_CMD *cmd;
A_STATUS status;
if ((eCWmin > WMI_MAX_CW_ACPARAM) || (eCWmax > WMI_MAX_CW_ACPARAM) ||
(aifsn > WMI_MAX_AIFSN_ACPARAM) || (ac >= WMM_NUM_AC))
{
return A_EINVAL;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_ACCESS_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
cmd->txop = txop;
cmd->eCWmin = eCWmin;
cmd->eCWmax = eCWmax;
cmd->aifsn = aifsn;
cmd->ac = ac;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_ACCESS_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_retry_limits_cmd(struct wmi_t *wmip, A_UINT8 frameType,
A_UINT8 trafficClass, A_UINT8 maxRetries,
A_UINT8 enableNotify)
{
void *osbuf;
WMI_SET_RETRY_LIMITS_CMD *cmd;
A_STATUS status;
if ((frameType != MGMT_FRAMETYPE) && (frameType != CONTROL_FRAMETYPE) &&
(frameType != DATA_FRAMETYPE))
{
return A_EINVAL;
}
if (maxRetries > WMI_MAX_RETRIES) {
return A_EINVAL;
}
if (frameType != DATA_FRAMETYPE) {
trafficClass = 0;
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_RETRY_LIMITS_CMD *)(A_NETBUF_DATA(osbuf));
cmd->frameType = frameType;
cmd->trafficClass = trafficClass;
cmd->maxRetries = maxRetries;
cmd->enableNotify = enableNotify;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_RETRY_LIMITS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
void
wmi_get_current_bssid(struct wmi_t *wmip, A_UINT8 *bssid)
{
if (bssid != NULL) {
A_MEMCPY(bssid, wmip->wmi_bssid, ATH_MAC_LEN);
}
}
A_STATUS
wmi_set_adhoc_bconIntvl_cmd(struct wmi_t *wmip, A_UINT16 intvl)
{
void *osbuf;
WMI_BEACON_INT_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_BEACON_INT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->beaconInterval = intvl;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BEACON_INT_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_voice_pkt_size_cmd(struct wmi_t *wmip, A_UINT16 voicePktSize)
{
void *osbuf;
WMI_SET_VOICE_PKT_SIZE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_VOICE_PKT_SIZE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->voicePktSize = voicePktSize;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_VOICE_PKT_SIZE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_max_sp_len_cmd(struct wmi_t *wmip, A_UINT8 maxSPLen)
{
void *osbuf;
WMI_SET_MAX_SP_LEN_CMD *cmd;
A_STATUS status;
/* maxSPLen is a two-bit value. If user trys to set anything
* other than this, then its invalid
*/
if(maxSPLen & ~0x03)
return A_EINVAL;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_MAX_SP_LEN_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->maxSPLen = maxSPLen;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_MAX_SP_LEN_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_UINT8
wmi_determine_userPriority(
A_UINT8 *pkt,
A_UINT32 layer2Pri)
{
A_UINT8 ipPri;
iphdr *ipHdr = (iphdr *)pkt;
/* Determine IPTOS priority */
/*
* IP Tos format :
* (Refer Pg 57 WMM-test-plan-v1.2)
* IP-TOS - 8bits
* : DSCP(6-bits) ECN(2-bits)
* : DSCP - P2 P1 P0 X X X
* where (P2 P1 P0) form 802.1D
*/
ipPri = ipHdr->ip_tos >> 5;
ipPri &= 0x7;
if ((layer2Pri & 0x7) > ipPri)
return ((A_UINT8)layer2Pri & 0x7);
else
return ipPri;
}
A_UINT8
convert_userPriority_to_trafficClass(A_UINT8 userPriority)
{
return (up_to_ac[userPriority & 0x7]);
}
A_UINT8
wmi_get_power_mode_cmd(struct wmi_t *wmip)
{
return wmip->wmi_powerMode;
}
A_STATUS
wmi_verify_tspec_params(WMI_CREATE_PSTREAM_CMD *pCmd, A_BOOL tspecCompliance)
{
A_STATUS ret = A_OK;
#define TSPEC_SUSPENSION_INTERVAL_ATHEROS_DEF (~0)
#define TSPEC_SERVICE_START_TIME_ATHEROS_DEF 0
#define TSPEC_MAX_BURST_SIZE_ATHEROS_DEF 0
#define TSPEC_DELAY_BOUND_ATHEROS_DEF 0
#define TSPEC_MEDIUM_TIME_ATHEROS_DEF 0
#define TSPEC_SBA_ATHEROS_DEF 0x2000 /* factor is 1 */
/* Verify TSPEC params for ATHEROS compliance */
if(tspecCompliance == ATHEROS_COMPLIANCE) {
if ((pCmd->suspensionInt != TSPEC_SUSPENSION_INTERVAL_ATHEROS_DEF) ||
(pCmd->serviceStartTime != TSPEC_SERVICE_START_TIME_ATHEROS_DEF) ||
(pCmd->minDataRate != pCmd->meanDataRate) ||
(pCmd->minDataRate != pCmd->peakDataRate) ||
(pCmd->maxBurstSize != TSPEC_MAX_BURST_SIZE_ATHEROS_DEF) ||
(pCmd->delayBound != TSPEC_DELAY_BOUND_ATHEROS_DEF) ||
(pCmd->sba != TSPEC_SBA_ATHEROS_DEF) ||
(pCmd->mediumTime != TSPEC_MEDIUM_TIME_ATHEROS_DEF)) {
A_DPRINTF(DBG_WMI, (DBGFMT "Invalid TSPEC params\n", DBGARG));
//A_PRINTF("%s: Invalid TSPEC params\n", __func__);
ret = A_EINVAL;
}
}
return ret;
}
#ifdef CONFIG_HOST_TCMD_SUPPORT
static A_STATUS
wmi_tcmd_test_report_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_TCMD_RX_REPORT_EVENT(wmip->wmi_devt, datap, len);
return A_OK;
}
#endif /* CONFIG_HOST_TCMD_SUPPORT*/
A_STATUS
wmi_set_authmode_cmd(struct wmi_t *wmip, A_UINT8 mode)
{
void *osbuf;
WMI_SET_AUTH_MODE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_AUTH_MODE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->mode = mode;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_AUTH_MODE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_reassocmode_cmd(struct wmi_t *wmip, A_UINT8 mode)
{
void *osbuf;
WMI_SET_REASSOC_MODE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_REASSOC_MODE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->mode = mode;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_REASSOC_MODE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_lpreamble_cmd(struct wmi_t *wmip, A_UINT8 status, A_UINT8 preamblePolicy)
{
void *osbuf;
WMI_SET_LPREAMBLE_CMD *cmd;
A_STATUS wmi_cmd_send_status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_LPREAMBLE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->status = status;
cmd->preamblePolicy = preamblePolicy;
wmi_cmd_send_status = wmi_cmd_send(wmip, osbuf, WMI_SET_LPREAMBLE_CMDID,
NO_SYNC_WMIFLAG);
if (wmi_cmd_send_status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return wmi_cmd_send_status;
}
A_STATUS
wmi_set_rts_cmd(struct wmi_t *wmip, A_UINT16 threshold)
{
void *osbuf;
WMI_SET_RTS_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_RTS_CMD*)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->threshold = threshold;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_RTS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_wmm_cmd(struct wmi_t *wmip, WMI_WMM_STATUS status)
{
void *osbuf;
WMI_SET_WMM_CMD *cmd;
A_STATUS wmi_cmd_send_status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_WMM_CMD*)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->status = status;
wmi_cmd_send_status = wmi_cmd_send(wmip, osbuf, WMI_SET_WMM_CMDID,
NO_SYNC_WMIFLAG);
if (wmi_cmd_send_status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return wmi_cmd_send_status;
}
A_STATUS
wmi_set_qos_supp_cmd(struct wmi_t *wmip, A_UINT8 status)
{
void *osbuf;
WMI_SET_QOS_SUPP_CMD *cmd;
A_STATUS wmi_cmd_send_status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_QOS_SUPP_CMD*)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->status = status;
wmi_cmd_send_status = wmi_cmd_send(wmip, osbuf, WMI_SET_QOS_SUPP_CMDID,
NO_SYNC_WMIFLAG);
if (wmi_cmd_send_status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return wmi_cmd_send_status;
}
A_STATUS
wmi_set_wmm_txop(struct wmi_t *wmip, WMI_TXOP_CFG cfg)
{
void *osbuf;
WMI_SET_WMM_TXOP_CMD *cmd;
A_STATUS status;
if( !((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)) )
return A_EINVAL;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_WMM_TXOP_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->txopEnable = cfg;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_WMM_TXOP_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_country(struct wmi_t *wmip, A_UCHAR *countryCode)
{
void *osbuf;
WMI_AP_SET_COUNTRY_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_AP_SET_COUNTRY_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
A_MEMCPY(cmd->countryCode,countryCode,3);
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_COUNTRY_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#ifdef CONFIG_HOST_TCMD_SUPPORT
/* WMI layer doesn't need to know the data type of the test cmd.
This would be beneficial for customers like Qualcomm, who might
have different test command requirements from differnt manufacturers
*/
A_STATUS
wmi_test_cmd(struct wmi_t *wmip, A_UINT8 *buf, A_UINT32 len)
{
void *osbuf;
char *data;
A_STATUS status;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
osbuf= A_NETBUF_ALLOC(len);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, len);
data = A_NETBUF_DATA(osbuf);
A_MEMCPY(data, buf, len);
status = wmi_cmd_send(wmip, osbuf, WMI_TEST_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#endif
A_STATUS
wmi_set_bt_status_cmd(struct wmi_t *wmip, A_UINT8 streamType, A_UINT8 status)
{
void *osbuf;
WMI_SET_BT_STATUS_CMD *cmd;
A_STATUS wmi_cmd_send_status;
AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Enter - streamType=%d, status=%d\n", streamType, status));
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_BT_STATUS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->streamType = streamType;
cmd->status = status;
wmi_cmd_send_status = wmi_cmd_send(wmip, osbuf, WMI_SET_BT_STATUS_CMDID,
NO_SYNC_WMIFLAG);
if (wmi_cmd_send_status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return wmi_cmd_send_status;
}
A_STATUS
wmi_set_bt_params_cmd(struct wmi_t *wmip, WMI_SET_BT_PARAMS_CMD* cmd)
{
void *osbuf;
WMI_SET_BT_PARAMS_CMD* alloc_cmd;
A_STATUS status;
AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("cmd params is %d\n", cmd->paramType));
if (cmd->paramType == BT_PARAM_SCO) {
AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("sco params %d %d %d %d %d %d %d %d %d %d %d %d\n", cmd->info.scoParams.numScoCyclesForceTrigger,
cmd->info.scoParams.dataResponseTimeout,
cmd->info.scoParams.stompScoRules,
cmd->info.scoParams.scoOptFlags,
cmd->info.scoParams.stompDutyCyleVal,
cmd->info.scoParams.stompDutyCyleMaxVal,
cmd->info.scoParams.psPollLatencyFraction,
cmd->info.scoParams.noSCOSlots,
cmd->info.scoParams.noIdleSlots,
cmd->info.scoParams.scoOptOffRssi,
cmd->info.scoParams.scoOptOnRssi,
cmd->info.scoParams.scoOptRtsCount));
}
else if (cmd->paramType == BT_PARAM_A2DP) {
AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("A2DP params %d %d %d %d %d %d %d %d\n", cmd->info.a2dpParams.a2dpWlanUsageLimit,
cmd->info.a2dpParams.a2dpBurstCntMin,
cmd->info.a2dpParams.a2dpDataRespTimeout,
cmd->info.a2dpParams.a2dpOptFlags,
cmd->info.a2dpParams.isCoLocatedBtRoleMaster,
cmd->info.a2dpParams.a2dpOptOffRssi,
cmd->info.a2dpParams.a2dpOptOnRssi,
cmd->info.a2dpParams.a2dpOptRtsCount));
}
else if (cmd->paramType == BT_PARAM_ANTENNA_CONFIG) {
AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Ant config %d\n", cmd->info.antType));
}
else if (cmd->paramType == BT_PARAM_COLOCATED_BT_DEVICE) {
AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("co-located BT %d\n", cmd->info.coLocatedBtDev));
}
else if (cmd->paramType == BT_PARAM_ACLCOEX) {
AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("ACL params %d %d %d\n", cmd->info.aclCoexParams.aclWlanMediumUsageTime,
cmd->info.aclCoexParams.aclBtMediumUsageTime,
cmd->info.aclCoexParams.aclDataRespTimeout));
}
else if (cmd->paramType == BT_PARAM_11A_SEPARATE_ANT) {
A_DPRINTF(DBG_WMI, (DBGFMT "11A ant\n", DBGARG));
}
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BT_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd, cmd, sizeof(*cmd));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BT_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_fe_ant_cmd(struct wmi_t *wmip, WMI_SET_BTCOEX_FE_ANT_CMD * cmd)
{
void *osbuf;
WMI_SET_BTCOEX_FE_ANT_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_FE_ANT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_FE_ANT_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_FE_ANT_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_colocated_bt_dev_cmd(struct wmi_t *wmip,
WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD * cmd)
{
void *osbuf;
WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMD));
A_PRINTF("AR6K: BTCOEX colocated bt = %d (1: qct-3wire, 2: csr-3wire 3: ath-3wire)\n", alloc_cmd->btcoexCoLocatedBTdev);
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_btinquiry_page_config_cmd(struct wmi_t *wmip,
WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD* cmd)
{
void *osbuf;
WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_sco_config_cmd(struct wmi_t *wmip,
WMI_SET_BTCOEX_SCO_CONFIG_CMD * cmd)
{
void *osbuf;
WMI_SET_BTCOEX_SCO_CONFIG_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_SCO_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_SCO_CONFIG_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_SCO_CONFIG_CMDID ,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_a2dp_config_cmd(struct wmi_t *wmip,
WMI_SET_BTCOEX_A2DP_CONFIG_CMD * cmd)
{
void *osbuf;
WMI_SET_BTCOEX_A2DP_CONFIG_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_A2DP_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_A2DP_CONFIG_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_A2DP_CONFIG_CMDID ,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_aclcoex_config_cmd(struct wmi_t *wmip,
WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD * cmd)
{
void *osbuf;
WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID ,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_debug_cmd(struct wmi_t *wmip, WMI_SET_BTCOEX_DEBUG_CMD * cmd)
{
void *osbuf;
WMI_SET_BTCOEX_DEBUG_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_DEBUG_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_DEBUG_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_DEBUG_CMDID ,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_btcoex_bt_operating_status_cmd(struct wmi_t * wmip,
WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD * cmd)
{
void *osbuf;
WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID ,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_btcoex_config_cmd(struct wmi_t * wmip, WMI_GET_BTCOEX_CONFIG_CMD * cmd)
{
void *osbuf;
WMI_GET_BTCOEX_CONFIG_CMD *alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_GET_BTCOEX_CONFIG_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd,cmd,sizeof(WMI_GET_BTCOEX_CONFIG_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_GET_BTCOEX_CONFIG_CMDID ,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_btcoex_stats_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_GET_BTCOEX_STATS_CMDID);
}
A_STATUS
wmi_get_keepalive_configured(struct wmi_t *wmip)
{
void *osbuf;
WMI_GET_KEEPALIVE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_GET_KEEPALIVE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
status = wmi_cmd_send(wmip, osbuf, WMI_GET_KEEPALIVE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_UINT8
wmi_get_keepalive_cmd(struct wmi_t *wmip)
{
return wmip->wmi_keepaliveInterval;
}
A_STATUS
wmi_set_keepalive_cmd(struct wmi_t *wmip, A_UINT8 keepaliveInterval)
{
void *osbuf;
WMI_SET_KEEPALIVE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_KEEPALIVE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->keepaliveInterval = keepaliveInterval;
wmip->wmi_keepaliveInterval = keepaliveInterval;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_KEEPALIVE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_params_cmd(struct wmi_t *wmip, A_UINT32 opcode, A_UINT32 length, A_CHAR* buffer)
{
void *osbuf;
WMI_SET_PARAMS_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd) + length);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd) + length);
cmd = (WMI_SET_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->opcode = opcode;
cmd->length = length;
if (length)
{
A_MEMCPY(cmd->buffer, buffer, length);
}
status = wmi_cmd_send(wmip, osbuf, WMI_SET_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_mcast_filter_cmd(struct wmi_t *wmip, A_UINT8 *filter)
{
void *osbuf;
A_BOOL mcast_ipv6 = FALSE;
WMI_SET_MCAST_FILTER_CMD *cmd;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
if(filter[0] == 0x33 && filter[1] == 0x33) {
mcast_ipv6 = TRUE;
}
else
{
if(filter[0] == 0x01 && filter[1] == 0x00 && filter[2] == 0x5e && filter[3] <= 0x7F) {
mcast_ipv6 = FALSE;
}
else {
return A_BAD_ADDRESS;
}
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_MCAST_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
if(mcast_ipv6) {
cmd->multicast_mac[0] = 0x33;
cmd->multicast_mac[1] = 0x33;
cmd->multicast_mac[2] = filter[2];
cmd->multicast_mac[3] = filter[3];
}
else {
cmd->multicast_mac[0] = 0x01;
cmd->multicast_mac[1] = 0x00;
cmd->multicast_mac[2] = 0x5e;
cmd->multicast_mac[3] = filter[3]&0x7F;
}
cmd->multicast_mac[4] = filter[4];
cmd->multicast_mac[5] = filter[5];
return (wmi_cmd_send(wmip, osbuf, WMI_SET_MCAST_FILTER_CMDID,
NO_SYNC_WMIFLAG));
}
A_STATUS
wmi_del_mcast_filter_cmd(struct wmi_t *wmip, A_UINT8 *filter)
{
void *osbuf;
A_BOOL mcast_ipv6 = FALSE;
WMI_SET_MCAST_FILTER_CMD *cmd;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
if(filter[0] == 0x33 && filter[1] == 0x33) {
mcast_ipv6 = TRUE;
}
else
{
if(filter[0] == 0x01 && filter[1] == 0x00 && filter[2] == 0x5e && filter[3] <= 0x7F) {
mcast_ipv6 = FALSE;
}
else {
return A_BAD_ADDRESS;
}
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_MCAST_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
if(mcast_ipv6) {
cmd->multicast_mac[0] = 0x33;
cmd->multicast_mac[1] = 0x33;
cmd->multicast_mac[2] = filter[2];
cmd->multicast_mac[3] = filter[3];
}
else {
cmd->multicast_mac[0] = 0x01;
cmd->multicast_mac[1] = 0x00;
cmd->multicast_mac[2] = 0x5e;
cmd->multicast_mac[3] = filter[3]&0x7F;
}
cmd->multicast_mac[4] = filter[4];
cmd->multicast_mac[5] = filter[5];
return (wmi_cmd_send(wmip, osbuf, WMI_DEL_MCAST_FILTER_CMDID,
NO_SYNC_WMIFLAG));
}
A_STATUS
wmi_mcast_filter_cmd(struct wmi_t *wmip, A_UINT8 enable)
{
void *osbuf;
WMI_MCAST_FILTER_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_MCAST_FILTER_CMD *)(A_NETBUF_DATA(osbuf));
cmd->enable = enable;
status = wmi_cmd_send(wmip, osbuf, WMI_MCAST_FILTER_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_appie_cmd(struct wmi_t *wmip, A_UINT8 mgmtFrmType, A_UINT8 ieLen,
A_UINT8 *ieInfo)
{
void *osbuf;
WMI_SET_APPIE_CMD *cmd;
A_UINT16 cmdLen;
A_STATUS status;
cmdLen = sizeof(*cmd) + ieLen - 1;
osbuf = A_NETBUF_ALLOC(cmdLen);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, cmdLen);
cmd = (WMI_SET_APPIE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, cmdLen);
cmd->mgmtFrmType = mgmtFrmType;
cmd->ieLen = ieLen;
A_MEMCPY(cmd->ieInfo, ieInfo, ieLen);
status = wmi_cmd_send(wmip, osbuf, WMI_SET_APPIE_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#ifdef HS20_ENABLE
A_STATUS
wmi_send_action_frame_cmd(struct wmi_t *wmip, A_UINT16 ieLen, A_UINT8 *ieInfo)
{
void *osbuf;
WMI_SEND_ACTION_CMD *cmd;
A_STATUS status;
A_UINT16 cmdLen;
cmdLen = sizeof(*cmd) + ieLen - 1;
osbuf = A_NETBUF_ALLOC(cmdLen);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, cmdLen);
cmd = (WMI_SEND_ACTION_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, cmdLen);
A_MEMCPY(cmd->ieInfo, ieInfo, cmdLen);
status = wmi_cmd_send(wmip, osbuf, WMI_SEND_HS20_ACTION_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#endif /* HS20_ENABLE */
A_STATUS
wmi_set_halparam_cmd(struct wmi_t *wmip, A_UINT8 *cmd, A_UINT16 dataLen)
{
void *osbuf;
A_UINT8 *data;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(dataLen);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, dataLen);
data = A_NETBUF_DATA(osbuf);
A_MEMCPY(data, cmd, dataLen);
status = wmi_cmd_send(wmip, osbuf, WMI_SET_WHALPARAM_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_INT32
wmi_get_rate(A_INT8 rateindex)
{
if (rateindex == RATE_AUTO) {
return 0;
} else {
A_UINT32 sgi;
/* SGI is stored as the MSB of the rateindex */
if (rateindex & 0x80) {
rateindex &= 0x7f;
sgi = 1;
} else {
sgi = 0;
}
if (rateindex > RATE_MCS_7_40) {
rateindex = RATE_MCS_7_40;
}
return(wmi_rateTable[(A_UINT32) rateindex][sgi]);
}
}
void
wmi_node_return (struct wmi_t *wmip, bss_t *bss)
{
if (NULL != bss)
{
wlan_node_return(&wmip->wmi_scan_table, bss);
}
}
void
wmi_node_update_timestamp(struct wmi_t *wmip, bss_t *bss)
{
if (NULL != bss) {
wlan_node_update_timestamp(&wmip->wmi_scan_table, bss);
}
}
void wmi_setup_node(struct wmi_t *wmip, bss_t *bss, const A_UINT8 *bssid)
{
wlan_setup_node(&wmip->wmi_scan_table, bss, bssid);
}
bss_t *wmi_node_alloc(struct wmi_t *wmip, A_UINT8 len)
{
return wlan_node_alloc(&wmip->wmi_scan_table, len);
}
void
wmi_set_nodeage(struct wmi_t *wmip, A_UINT32 nodeAge)
{
wlan_set_nodeage(&wmip->wmi_scan_table,nodeAge);
}
bss_t *
wmi_find_Ssidnode (struct wmi_t *wmip, A_UCHAR *pSsid,
A_UINT32 ssidLength, A_BOOL bIsWPA2, A_BOOL bMatchSSID)
{
bss_t *node = NULL;
node = wlan_find_Ssidnode (&wmip->wmi_scan_table, pSsid,
ssidLength, bIsWPA2, bMatchSSID);
return node;
}
void
wmi_free_allnodes(struct wmi_t *wmip)
{
wmi_scan_report_lock(wmip);
wlan_free_allnodes(&wmip->wmi_scan_table);
wmi_scan_report_unlock(wmip);
}
bss_t *
wmi_find_node(struct wmi_t *wmip, const A_UINT8 *macaddr)
{
bss_t *ni=NULL;
ni=wlan_find_node(&wmip->wmi_scan_table,macaddr);
return ni;
}
void
wmi_free_node(struct wmi_t *wmip, const A_UINT8 *macaddr)
{
bss_t *ni=NULL;
ni=wlan_find_node(&wmip->wmi_scan_table,macaddr);
if (ni != NULL) {
wlan_node_return(&wmip->wmi_scan_table, ni);
wlan_node_reclaim(&wmip->wmi_scan_table, ni);
}
return;
}
A_STATUS
wmi_dset_open_reply(struct wmi_t *wmip,
A_UINT32 status,
A_UINT32 access_cookie,
A_UINT32 dset_size,
A_UINT32 dset_version,
A_UINT32 targ_handle,
A_UINT32 targ_reply_fn,
A_UINT32 targ_reply_arg)
{
void *osbuf;
WMIX_DSETOPEN_REPLY_CMD *open_reply;
A_STATUS wmi_cmd_send_xtnd_status;
A_DPRINTF(DBG_WMI, (DBGFMT "Enter - wmip=0x%lx\n", DBGARG, (unsigned long)wmip));
osbuf = A_NETBUF_ALLOC(sizeof(*open_reply));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*open_reply));
open_reply = (WMIX_DSETOPEN_REPLY_CMD *)(A_NETBUF_DATA(osbuf));
open_reply->status = status;
open_reply->targ_dset_handle = targ_handle;
open_reply->targ_reply_fn = targ_reply_fn;
open_reply->targ_reply_arg = targ_reply_arg;
open_reply->access_cookie = access_cookie;
open_reply->size = dset_size;
open_reply->version = dset_version;
wmi_cmd_send_xtnd_status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_DSETOPEN_REPLY_CMDID,
NO_SYNC_WMIFLAG);
if (wmi_cmd_send_xtnd_status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return wmi_cmd_send_xtnd_status;
}
static A_STATUS
wmi_get_pmkid_list_event_rx(struct wmi_t *wmip, A_UINT8 *datap, A_UINT32 len)
{
WMI_PMKID_LIST_REPLY *reply;
A_UINT32 expected_len;
if (len < sizeof(WMI_PMKID_LIST_REPLY)) {
return A_EINVAL;
}
reply = (WMI_PMKID_LIST_REPLY *)datap;
expected_len = sizeof(reply->numPMKID) + reply->numPMKID * WMI_PMKID_LEN;
if (len < expected_len) {
return A_EINVAL;
}
A_WMI_PMKID_LIST_EVENT(wmip->wmi_devt, reply->numPMKID,
reply->pmkidList, reply->bssidList[0]);
return A_OK;
}
static A_STATUS
wmi_set_params_event_rx(struct wmi_t *wmip, A_UINT8 *datap, A_UINT32 len)
{
WMI_SET_PARAMS_REPLY *reply;
if (len < sizeof(WMI_SET_PARAMS_REPLY)) {
return A_EINVAL;
}
reply = (WMI_SET_PARAMS_REPLY *)datap;
if (A_OK == reply->status)
{
}
else
{
}
return A_OK;
}
#ifdef CONFIG_HOST_DSET_SUPPORT
A_STATUS
wmi_dset_data_reply(struct wmi_t *wmip,
A_UINT32 status,
A_UINT8 *user_buf,
A_UINT32 length,
A_UINT32 targ_buf,
A_UINT32 targ_reply_fn,
A_UINT32 targ_reply_arg)
{
void *osbuf;
WMIX_DSETDATA_REPLY_CMD *data_reply;
A_UINT32 size;
A_STATUS wmi_cmd_send_xtnd_status;
size = sizeof(*data_reply) + length;
if (size <= length) {
return A_ERROR;
}
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - length=%d status=%d\n", DBGARG, length, status));
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
data_reply = (WMIX_DSETDATA_REPLY_CMD *)(A_NETBUF_DATA(osbuf));
data_reply->status = status;
data_reply->targ_buf = targ_buf;
data_reply->targ_reply_fn = targ_reply_fn;
data_reply->targ_reply_arg = targ_reply_arg;
data_reply->length = length;
if (status == A_OK) {
if (a_copy_from_user(data_reply->buf, user_buf, length)) {
A_NETBUF_FREE(osbuf);
return A_ERROR;
}
}
wmi_cmd_send_xtnd_status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_DSETDATA_REPLY_CMDID,
NO_SYNC_WMIFLAG);
if (wmi_cmd_send_xtnd_status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return wmi_cmd_send_xtnd_status;
}
#endif /* CONFIG_HOST_DSET_SUPPORT */
A_STATUS
wmi_set_wsc_status_cmd(struct wmi_t *wmip, A_UINT32 status)
{
void *osbuf;
char *cmd;
A_STATUS wmi_cmd_send_status;
wps_enable = status;
#ifdef AR6K_ALLOC_DEBUG
osbuf = a_netbuf_alloc(sizeof(1), __func__, __LINE__);
#else
osbuf = a_netbuf_alloc(sizeof(1));
#endif
if (osbuf == NULL) {
return A_NO_MEMORY;
}
a_netbuf_put(osbuf, sizeof(1));
cmd = (char *)(a_netbuf_to_data(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd[0] = (status?1:0);
wmi_cmd_send_status = wmi_cmd_send(wmip, osbuf, WMI_SET_WSC_STATUS_CMDID,
NO_SYNC_WMIFLAG);
if (wmi_cmd_send_status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return wmi_cmd_send_status;
}
#if defined(CONFIG_TARGET_PROFILE_SUPPORT)
A_STATUS
wmi_prof_cfg_cmd(struct wmi_t *wmip,
A_UINT32 period,
A_UINT32 nbins)
{
void *osbuf;
WMIX_PROF_CFG_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMIX_PROF_CFG_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->period = period;
cmd->nbins = nbins;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_PROF_CFG_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_prof_addr_set_cmd(struct wmi_t *wmip, A_UINT32 addr)
{
void *osbuf;
WMIX_PROF_ADDR_SET_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMIX_PROF_ADDR_SET_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->addr = addr;
status = wmi_cmd_send_xtnd(wmip, osbuf, WMIX_PROF_ADDR_SET_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_prof_start_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd_xtnd(wmip, WMIX_PROF_START_CMDID);
}
A_STATUS
wmi_prof_stop_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd_xtnd(wmip, WMIX_PROF_STOP_CMDID);
}
A_STATUS
wmi_prof_count_get_cmd(struct wmi_t *wmip)
{
return wmi_simple_cmd_xtnd(wmip, WMIX_PROF_COUNT_GET_CMDID);
}
/* Called to handle WMIX_PROF_CONT_EVENTID */
static A_STATUS
wmi_prof_count_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMIX_PROF_COUNT_EVENT *prof_data = (WMIX_PROF_COUNT_EVENT *)datap;
A_DPRINTF(DBG_WMI,
(DBGFMT "Enter - addr=0x%x count=%d\n", DBGARG,
prof_data->addr, prof_data->count));
A_WMI_PROF_COUNT_RX(prof_data->addr, prof_data->count);
return A_OK;
}
#endif /* CONFIG_TARGET_PROFILE_SUPPORT */
#ifdef OS_ROAM_MANAGEMENT
#define ETHERNET_MAC_ADDRESS_LENGTH 6
void
wmi_scan_indication (struct wmi_t *wmip)
{
struct ieee80211_node_table *nt;
A_UINT32 gen;
A_UINT32 size;
A_UINT32 bsssize;
bss_t *bss;
A_UINT32 numbss;
PNDIS_802_11_BSSID_SCAN_INFO psi;
PBYTE pie;
NDIS_802_11_FIXED_IEs *pFixed;
NDIS_802_11_VARIABLE_IEs *pVar;
A_UINT32 RateSize;
struct ar6kScanIndication
{
NDIS_802_11_STATUS_INDICATION ind;
NDIS_802_11_BSSID_SCAN_INFO_LIST slist;
} *pAr6kScanIndEvent;
nt = &wmip->wmi_scan_table;
++nt->nt_si_gen;
gen = nt->nt_si_gen;
size = offsetof(struct ar6kScanIndication, slist) +
offsetof(NDIS_802_11_BSSID_SCAN_INFO_LIST, BssidScanInfo);
numbss = 0;
IEEE80211_NODE_LOCK(nt);
//calc size
for (bss = nt->nt_node_first; bss; bss = bss->ni_list_next) {
if (bss->ni_si_gen != gen) {
bsssize = offsetof(NDIS_802_11_BSSID_SCAN_INFO, Bssid) + offsetof(NDIS_WLAN_BSSID_EX, IEs);
bsssize = bsssize + sizeof(NDIS_802_11_FIXED_IEs);
#ifdef SUPPORT_WPA2
if (bss->ni_cie.ie_rsn) {
bsssize = bsssize + bss->ni_cie.ie_rsn[1] + 2;
}
#endif
if (bss->ni_cie.ie_wpa) {
bsssize = bsssize + bss->ni_cie.ie_wpa[1] + 2;
}
// bsssize must be a multiple of 4 to maintain alignment.
bsssize = (bsssize + 3) & ~3;
size += bsssize;
numbss++;
}
}
if (0 == numbss)
{
// RETAILMSG(1, (L"AR6K: scan indication: 0 bss\n"));
ar6000_scan_indication (wmip->wmi_devt, NULL, 0);
IEEE80211_NODE_UNLOCK (nt);
return;
}
pAr6kScanIndEvent = A_MALLOC(size);
if (NULL == pAr6kScanIndEvent)
{
IEEE80211_NODE_UNLOCK(nt);
return;
}
A_MEMZERO(pAr6kScanIndEvent, size);
//copy data
pAr6kScanIndEvent->ind.StatusType = Ndis802_11StatusType_BssidScanInfoList;
pAr6kScanIndEvent->slist.Version = 1;
pAr6kScanIndEvent->slist.NumItems = numbss;
psi = &pAr6kScanIndEvent->slist.BssidScanInfo[0];
for (bss = nt->nt_node_first; bss; bss = bss->ni_list_next) {
if (bss->ni_si_gen != gen) {
bss->ni_si_gen = gen;
//Set scan time
psi->ScanTime = bss->ni_tstamp - WLAN_NODE_INACT_TIMEOUT_MSEC;
// Copy data to bssid_ex
bsssize = offsetof(NDIS_WLAN_BSSID_EX, IEs);
bsssize = bsssize + sizeof(NDIS_802_11_FIXED_IEs);
#ifdef SUPPORT_WPA2
if (bss->ni_cie.ie_rsn) {
bsssize = bsssize + bss->ni_cie.ie_rsn[1] + 2;
}
#endif
if (bss->ni_cie.ie_wpa) {
bsssize = bsssize + bss->ni_cie.ie_wpa[1] + 2;
}
// bsssize must be a multiple of 4 to maintain alignment.
bsssize = (bsssize + 3) & ~3;
psi->Bssid.Length = bsssize;
memcpy (psi->Bssid.MacAddress, bss->ni_macaddr, ETHERNET_MAC_ADDRESS_LENGTH);
//if (((bss->ni_macaddr[3] == 0xCE) && (bss->ni_macaddr[4] == 0xF0) && (bss->ni_macaddr[5] == 0xE7)) ||
// ((bss->ni_macaddr[3] == 0x03) && (bss->ni_macaddr[4] == 0xE2) && (bss->ni_macaddr[5] == 0x70)))
// RETAILMSG (1, (L"%x\n",bss->ni_macaddr[5]));
psi->Bssid.Ssid.SsidLength = 0;
pie = bss->ni_cie.ie_ssid;
if (pie) {
// Format of SSID IE is:
// Type (1 octet)
// Length (1 octet)
// SSID (Length octets)
//
// Validation of the IE should have occurred within WMI.
//
if (pie[1] <= 32) {
psi->Bssid.Ssid.SsidLength = pie[1];
memcpy(psi->Bssid.Ssid.Ssid, &pie[2], psi->Bssid.Ssid.SsidLength);
}
}
psi->Bssid.Privacy = (bss->ni_cie.ie_capInfo & 0x10) ? 1 : 0;
//Post the RSSI value relative to the Standard Noise floor value.
psi->Bssid.Rssi = bss->ni_rssi;
if (bss->ni_cie.ie_chan >= 2412 && bss->ni_cie.ie_chan <= 2484) {
if (bss->ni_cie.ie_rates && bss->ni_cie.ie_xrates) {
psi->Bssid.NetworkTypeInUse = Ndis802_11OFDM24;
}
else {
psi->Bssid.NetworkTypeInUse = Ndis802_11DS;
}
}
else {
psi->Bssid.NetworkTypeInUse = Ndis802_11OFDM5;
}
psi->Bssid.Configuration.Length = sizeof(psi->Bssid.Configuration);
psi->Bssid.Configuration.BeaconPeriod = bss->ni_cie.ie_beaconInt; // Units are Kmicroseconds (1024 us)
psi->Bssid.Configuration.ATIMWindow = 0;
psi->Bssid.Configuration.DSConfig = bss->ni_cie.ie_chan * 1000;
psi->Bssid.InfrastructureMode = ((bss->ni_cie.ie_capInfo & 0x03) == 0x01 ) ? Ndis802_11Infrastructure : Ndis802_11IBSS;
RateSize = 0;
pie = bss->ni_cie.ie_rates;
if (pie) {
RateSize = (pie[1] < NDIS_802_11_LENGTH_RATES_EX) ? pie[1] : NDIS_802_11_LENGTH_RATES_EX;
memcpy(psi->Bssid.SupportedRates, &pie[2], RateSize);
}
pie = bss->ni_cie.ie_xrates;
if (pie && RateSize < NDIS_802_11_LENGTH_RATES_EX) {
memcpy(psi->Bssid.SupportedRates + RateSize, &pie[2],
(pie[1] < (NDIS_802_11_LENGTH_RATES_EX - RateSize)) ? pie[1] : (NDIS_802_11_LENGTH_RATES_EX - RateSize));
}
// Copy the fixed IEs
psi->Bssid.IELength = sizeof(NDIS_802_11_FIXED_IEs);
pFixed = (NDIS_802_11_FIXED_IEs *)psi->Bssid.IEs;
memcpy(pFixed->Timestamp, bss->ni_cie.ie_tstamp, sizeof(pFixed->Timestamp));
pFixed->BeaconInterval = bss->ni_cie.ie_beaconInt;
pFixed->Capabilities = bss->ni_cie.ie_capInfo;
// Copy selected variable IEs
pVar = (NDIS_802_11_VARIABLE_IEs *)((PBYTE)pFixed + sizeof(NDIS_802_11_FIXED_IEs));
#ifdef SUPPORT_WPA2
// Copy the WPAv2 IE
if (bss->ni_cie.ie_rsn) {
pie = bss->ni_cie.ie_rsn;
psi->Bssid.IELength += pie[1] + 2;
memcpy(pVar, pie, pie[1] + 2);
pVar = (NDIS_802_11_VARIABLE_IEs *)((PBYTE)pVar + pie[1] + 2);
}
#endif
// Copy the WPAv1 IE
if (bss->ni_cie.ie_wpa) {
pie = bss->ni_cie.ie_wpa;
psi->Bssid.IELength += pie[1] + 2;
memcpy(pVar, pie, pie[1] + 2);
pVar = (NDIS_802_11_VARIABLE_IEs *)((PBYTE)pVar + pie[1] + 2);
}
// Advance buffer pointer
psi = (PNDIS_802_11_BSSID_SCAN_INFO)((BYTE*)psi + bsssize + FIELD_OFFSET(NDIS_802_11_BSSID_SCAN_INFO, Bssid));
}
}
IEEE80211_NODE_UNLOCK(nt);
// wmi_free_allnodes(wmip);
// RETAILMSG(1, (L"AR6K: scan indication: %u bss\n", numbss));
ar6000_scan_indication (wmip->wmi_devt, pAr6kScanIndEvent, size);
A_FREE(pAr6kScanIndEvent);
}
#endif
A_UINT8
ar6000_get_upper_threshold(A_INT16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh,
A_UINT32 size)
{
A_UINT32 index;
A_UINT8 threshold = (A_UINT8)sq_thresh->upper_threshold[size - 1];
/* The list is already in sorted order. Get the next lower value */
for (index = 0; index < size; index ++) {
if (rssi < sq_thresh->upper_threshold[index]) {
threshold = (A_UINT8)sq_thresh->upper_threshold[index];
break;
}
}
return threshold;
}
A_UINT8
ar6000_get_lower_threshold(A_INT16 rssi, SQ_THRESHOLD_PARAMS *sq_thresh,
A_UINT32 size)
{
A_UINT32 index;
A_UINT8 threshold = (A_UINT8)sq_thresh->lower_threshold[size - 1];
/* The list is already in sorted order. Get the next lower value */
for (index = 0; index < size; index ++) {
if (rssi > sq_thresh->lower_threshold[index]) {
threshold = (A_UINT8)sq_thresh->lower_threshold[index];
break;
}
}
return threshold;
}
static A_STATUS
wmi_send_rssi_threshold_params(struct wmi_t *wmip,
WMI_RSSI_THRESHOLD_PARAMS_CMD *rssiCmd)
{
void *osbuf;
A_INT8 size;
WMI_RSSI_THRESHOLD_PARAMS_CMD *cmd;
A_STATUS status;
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_RSSI_THRESHOLD_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, rssiCmd, sizeof(WMI_RSSI_THRESHOLD_PARAMS_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
static A_STATUS
wmi_send_snr_threshold_params(struct wmi_t *wmip,
WMI_SNR_THRESHOLD_PARAMS_CMD *snrCmd)
{
void *osbuf;
A_INT8 size;
WMI_SNR_THRESHOLD_PARAMS_CMD *cmd;
A_STATUS status;
size = sizeof (*cmd);
osbuf = A_NETBUF_ALLOC(size);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, size);
cmd = (WMI_SNR_THRESHOLD_PARAMS_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, size);
A_MEMCPY(cmd, snrCmd, sizeof(WMI_SNR_THRESHOLD_PARAMS_CMD));
status = wmi_cmd_send(wmip, osbuf, WMI_SNR_THRESHOLD_PARAMS_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_target_event_report_cmd(struct wmi_t *wmip, WMI_SET_TARGET_EVENT_REPORT_CMD* cmd)
{
void *osbuf;
WMI_SET_TARGET_EVENT_REPORT_CMD* alloc_cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
alloc_cmd = (WMI_SET_TARGET_EVENT_REPORT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(alloc_cmd, sizeof(*cmd));
A_MEMCPY(alloc_cmd, cmd, sizeof(*cmd));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_TARGET_EVENT_REPORT_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
bss_t *wmi_rm_current_bss (struct wmi_t *wmip, A_UINT8 *id)
{
wmi_get_current_bssid (wmip, id);
return wlan_node_remove (&wmip->wmi_scan_table, id);
}
A_STATUS wmi_add_current_bss (struct wmi_t *wmip, A_UINT8 *id, bss_t *bss)
{
wlan_setup_node (&wmip->wmi_scan_table, bss, id);
return A_OK;
}
#ifdef ATH_AR6K_11N_SUPPORT
static A_STATUS
wmi_addba_req_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_ADDBA_REQ_EVENT *cmd = (WMI_ADDBA_REQ_EVENT *)datap;
A_WMI_AGGR_RECV_ADDBA_REQ_EVT(wmip->wmi_devt, cmd);
return A_OK;
}
static A_STATUS
wmi_addba_resp_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_ADDBA_RESP_EVENT *cmd = (WMI_ADDBA_RESP_EVENT *)datap;
A_WMI_AGGR_RECV_ADDBA_RESP_EVT(wmip->wmi_devt, cmd);
return A_OK;
}
static A_STATUS
wmi_delba_req_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_DELBA_EVENT *cmd = (WMI_DELBA_EVENT *)datap;
A_WMI_AGGR_RECV_DELBA_REQ_EVT(wmip->wmi_devt, cmd);
return A_OK;
}
A_STATUS
wmi_btcoex_config_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_BTCOEX_CONFIG_EVENT(wmip->wmi_devt, datap, len);
return A_OK;
}
A_STATUS
wmi_btcoex_stats_event_rx(struct wmi_t * wmip,A_UINT8 * datap,int len)
{
A_DPRINTF(DBG_WMI, (DBGFMT "Enter\n", DBGARG));
A_WMI_BTCOEX_STATS_EVENT(wmip->wmi_devt, datap, len);
return A_OK;
}
#endif
static A_STATUS
wmi_hci_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_HCI_EVENT *cmd = (WMI_HCI_EVENT *)datap;
A_WMI_HCI_EVENT_EVT(wmip->wmi_devt, cmd);
return A_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// ////
//// AP mode functions ////
//// ////
////////////////////////////////////////////////////////////////////////////////
/*
* IOCTL: AR6000_XIOCTL_AP_COMMIT_CONFIG
*
* When AR6K in AP mode, This command will be called after
* changing ssid, channel etc. It will pass the profile to
* target with a flag which will indicate which parameter changed,
* also if this flag is 0, there was no change in parametes, so
* commit cmd will not be sent to target. Without calling this IOCTL
* the changes will not take effect.
*/
A_STATUS
wmi_ap_profile_commit(struct wmi_t *wmip, WMI_CONNECT_CMD *p)
{
void *osbuf;
WMI_CONNECT_CMD *cm;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cm));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cm));
cm = (WMI_CONNECT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cm, sizeof(*cm));
A_MEMCPY(cm,p,sizeof(*cm));
status = wmi_cmd_send(wmip, osbuf, WMI_AP_CONFIG_COMMIT_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/*
* IOCTL: AR6000_XIOCTL_AP_HIDDEN_SSID
*
* This command will be used to enable/disable hidden ssid functioanlity of
* beacon. If it is enabled, ssid will be NULL in beacon.
*/
A_STATUS
wmi_ap_set_hidden_ssid(struct wmi_t *wmip, A_UINT8 hidden_ssid)
{
void *osbuf;
WMI_AP_HIDDEN_SSID_CMD *hs;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_HIDDEN_SSID_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_HIDDEN_SSID_CMD));
hs = (WMI_AP_HIDDEN_SSID_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(hs, sizeof(*hs));
hs->hidden_ssid = hidden_ssid;
A_DPRINTF(DBG_WMI, (DBGFMT "AR6000_XIOCTL_AP_HIDDEN_SSID %d\n", DBGARG , hidden_ssid));
status = wmi_cmd_send(wmip, osbuf, WMI_AP_HIDDEN_SSID_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/*
* IOCTL: AR6000_XIOCTL_AP_SET_MAX_NUM_STA
*
* This command is used to limit max num of STA that can connect
* with this AP. This value should not exceed AP_MAX_NUM_STA (this
* is max num of STA supported by AP). Value was already validated
* in ioctl.c
*/
A_STATUS
wmi_ap_set_num_sta(struct wmi_t *wmip, A_UINT8 num_sta)
{
void *osbuf;
WMI_AP_NUM_STA_CMD *ns;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_NUM_STA_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_NUM_STA_CMD));
ns = (WMI_AP_NUM_STA_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(ns, sizeof(*ns));
ns->num_sta = num_sta;
A_DPRINTF(DBG_WMI, (DBGFMT "AR6000_XIOCTL_AP_SET_MAX_NUM_STA %d\n", DBGARG , num_sta));
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_NUM_STA_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/*
* IOCTL: AR6000_XIOCTL_AP_SET_ACL_MAC
*
* This command is used to send list of mac of STAs which will
* be allowed to connect with this AP. When this list is empty
* firware will allow all STAs till the count reaches AP_MAX_NUM_STA.
*/
A_STATUS
wmi_ap_acl_mac_list(struct wmi_t *wmip, WMI_AP_ACL_MAC_CMD *acl)
{
void *osbuf;
WMI_AP_ACL_MAC_CMD *a;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_ACL_MAC_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_ACL_MAC_CMD));
a = (WMI_AP_ACL_MAC_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(a, sizeof(*a));
A_MEMCPY(a,acl,sizeof(*acl));
status = wmi_cmd_send(wmip, osbuf, WMI_AP_ACL_MAC_LIST_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/*
* IOCTL: AR6000_XIOCTL_AP_SET_MLME
*
* This command is used to send list of mac of STAs which will
* be allowed to connect with this AP. When this list is empty
* firware will allow all STAs till the count reaches AP_MAX_NUM_STA.
*/
A_STATUS
wmi_ap_set_mlme(struct wmi_t *wmip, A_UINT8 cmd, A_UINT8 *mac, A_UINT16 reason)
{
void *osbuf;
WMI_AP_SET_MLME_CMD *mlme;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_MLME_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_MLME_CMD));
mlme = (WMI_AP_SET_MLME_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(mlme, sizeof(*mlme));
mlme->cmd = cmd;
A_MEMCPY(mlme->mac, mac, ATH_MAC_LEN);
mlme->reason = reason;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_MLME_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
static A_STATUS
wmi_pspoll_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_PSPOLL_EVENT *ev;
if (len < sizeof(WMI_PSPOLL_EVENT)) {
return A_EINVAL;
}
ev = (WMI_PSPOLL_EVENT *)datap;
A_WMI_PSPOLL_EVENT(wmip->wmi_devt, ev->aid);
return A_OK;
}
static A_STATUS
wmi_dtimexpiry_event_rx(struct wmi_t *wmip, A_UINT8 *datap,int len)
{
A_WMI_DTIMEXPIRY_EVENT(wmip->wmi_devt);
return A_OK;
}
#ifdef WAPI_ENABLE
static A_STATUS
wmi_wapi_rekey_event_rx(struct wmi_t *wmip, A_UINT8 *datap,int len)
{
A_UINT8 *ev;
if (len < 7) {
return A_EINVAL;
}
ev = (A_UINT8 *)datap;
A_WMI_WAPI_REKEY_EVENT(wmip->wmi_devt, *ev, &ev[1]);
return A_OK;
}
#endif
#ifdef CONFIG_WLAN_RFKILL
static A_STATUS wmi_rfkill_get_mode_cmd_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
A_STATUS status = A_OK;
do
{
if(len < sizeof(WMI_RFKILL_MODE_CMD))
{
status = A_EINVAL;
break;
}
A_WMI_RFKILL_GET_MODE_CMD_EVENT(wmip->wmi_devt,datap,len);
}while(FALSE);
return status;
}
static A_STATUS wmi_rfkill_state_change_event(struct wmi_t *wmip, A_UINT8* datap,int len)
{
A_STATUS status = A_OK;
A_UINT8 *ev = NULL;
if (len < sizeof(A_UINT8))
{
return A_EINVAL;
}
ev = (A_UINT8*)datap;
A_WMI_RFKILL_STATE_CHANGE_EVENT(wmip->wmi_devt, *ev);
return status;
}
A_STATUS wmi_set_rfkill_mode_cmd(struct wmi_t *wmip,WMI_RFKILL_MODE_CMD *pCmd)
{
A_STATUS status = A_OK;
void *osbuf = NULL;
WMI_RFKILL_MODE_CMD *prfkill_set_mode_cmd = NULL;
do
{
osbuf = A_NETBUF_ALLOC(sizeof(WMI_RFKILL_MODE_CMD));
if(NULL == osbuf)
{
status = A_NO_MEMORY;
break;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_RFKILL_MODE_CMD));
prfkill_set_mode_cmd = (WMI_RFKILL_MODE_CMD*)(A_NETBUF_DATA(osbuf));
A_MEMZERO(prfkill_set_mode_cmd, sizeof(WMI_RFKILL_MODE_CMD));
A_MEMCPY(prfkill_set_mode_cmd,pCmd, sizeof(WMI_RFKILL_MODE_CMD));
status = wmi_cmd_send(wmip,
osbuf,
WMI_SET_RFKILL_MODE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
}while(FALSE);
return status;
}
A_STATUS wmi_get_rfkill_mode_cmd(struct wmi_t *wmip)
{
A_STATUS status = A_OK;
status = wmi_simple_cmd(wmip,WMI_GET_RFKILL_MODE_CMDID);
return status;
}
#endif /* CONFIG_WLAN_RFKILL */
A_STATUS
wmi_set_pvb_cmd(struct wmi_t *wmip, A_UINT16 aid, A_BOOL flag)
{
WMI_AP_SET_PVB_CMD *cmd;
void *osbuf = NULL;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_PVB_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_PVB_CMD));
cmd = (WMI_AP_SET_PVB_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->aid = aid;
cmd->flag = flag;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_PVB_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_ap_conn_inact_time(struct wmi_t *wmip, A_UINT32 period)
{
WMI_AP_CONN_INACT_CMD *cmd;
void *osbuf = NULL;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_CONN_INACT_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_CONN_INACT_CMD));
cmd = (WMI_AP_CONN_INACT_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->period = period;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_CONN_INACT_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_ap_bgscan_time(struct wmi_t *wmip, A_UINT32 period, A_UINT32 dwell)
{
WMI_AP_PROT_SCAN_TIME_CMD *cmd;
void *osbuf = NULL;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_PROT_SCAN_TIME_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_PROT_SCAN_TIME_CMD));
cmd = (WMI_AP_PROT_SCAN_TIME_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->period_min = period;
cmd->dwell_ms = dwell;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_PROT_SCAN_TIME_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_ap_set_dtim(struct wmi_t *wmip, A_UINT8 dtim)
{
WMI_AP_SET_DTIM_CMD *cmd;
void *osbuf = NULL;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_DTIM_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_DTIM_CMD));
cmd = (WMI_AP_SET_DTIM_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->dtim = dtim;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
/*
* IOCTL: AR6000_XIOCTL_AP_SET_ACL_POLICY
*
* This command is used to set ACL policay. While changing policy, if you
* want to retain the existing MAC addresses in the ACL list, policy should be
* OR with AP_ACL_RETAIN_LIST_MASK, else the existing list will be cleared.
* If there is no chage in policy, the list will be intact.
*/
A_STATUS
wmi_ap_set_acl_policy(struct wmi_t *wmip, A_UINT8 policy)
{
void *osbuf;
WMI_AP_ACL_POLICY_CMD *po;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_ACL_POLICY_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_ACL_POLICY_CMD));
po = (WMI_AP_ACL_POLICY_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(po, sizeof(*po));
po->policy = policy;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_ACL_POLICY_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_ap_set_rateset(struct wmi_t *wmip, A_UINT8 rateset)
{
void *osbuf;
WMI_AP_SET_11BG_RATESET_CMD *rs;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_11BG_RATESET_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_11BG_RATESET_CMD));
rs = (WMI_AP_SET_11BG_RATESET_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(rs, sizeof(*rs));
rs->rateset = rateset;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_11BG_RATESET_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#ifdef ATH_AR6K_11N_SUPPORT
A_STATUS
wmi_set_ht_cap_cmd(struct wmi_t *wmip, WMI_SET_HT_CAP_CMD *cmd)
{
void *osbuf;
WMI_SET_HT_CAP_CMD *htCap;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*htCap));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*htCap));
A_MEMCPY(&wmip->wmi_ht_cap[cmd->band], cmd, sizeof(WMI_SET_HT_CAP_CMD));
wmip->wmi_user_ht[cmd->band] = wmip->wmi_ht_cap[cmd->band].enable;
htCap = (WMI_SET_HT_CAP_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(htCap, sizeof(*htCap));
A_MEMCPY(htCap, cmd, sizeof(*htCap));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_HT_CAP_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_get_ht_cap_cmd(struct wmi_t *wmip, WMI_SET_HT_CAP_CMD *cmd)
{
A_MEMCPY(cmd, &wmip->wmi_ht_cap[cmd->band], sizeof(WMI_SET_HT_CAP_CMD));
return A_OK;
}
A_STATUS
wmi_set_ht_op_cmd(struct wmi_t *wmip, A_UINT8 sta_chan_width)
{
void *osbuf;
WMI_SET_HT_OP_CMD *htInfo;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*htInfo));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*htInfo));
htInfo = (WMI_SET_HT_OP_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(htInfo, sizeof(*htInfo));
htInfo->sta_chan_width = sta_chan_width;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_HT_OP_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#endif
A_STATUS
wmi_set_tx_select_rates_cmd(struct wmi_t *wmip, A_UINT32 *pMaskArray)
{
void *osbuf;
WMI_SET_TX_SELECT_RATES_CMD *pData;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*pData));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*pData));
pData = (WMI_SET_TX_SELECT_RATES_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMCPY(pData, pMaskArray, sizeof(*pData));
status = wmi_cmd_send(wmip, osbuf, WMI_SET_TX_SELECT_RATES_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_send_hci_cmd(struct wmi_t *wmip, A_UINT8 *buf, A_UINT16 sz)
{
void *osbuf;
WMI_HCI_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd) + sz);
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd) + sz);
cmd = (WMI_HCI_CMD *)(A_NETBUF_DATA(osbuf));
cmd->cmd_buf_sz = sz;
A_MEMCPY(cmd->buf, buf, sz);
status = wmi_cmd_send(wmip, osbuf, WMI_HCI_CMD_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#ifdef ATH_AR6K_11N_SUPPORT
A_STATUS
wmi_allow_aggr_cmd(struct wmi_t *wmip, A_UINT16 tx_tidmask, A_UINT16 rx_tidmask)
{
void *osbuf;
WMI_ALLOW_AGGR_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_ALLOW_AGGR_CMD *)(A_NETBUF_DATA(osbuf));
cmd->tx_allow_aggr = tx_tidmask;
cmd->rx_allow_aggr = rx_tidmask;
status = wmi_cmd_send(wmip, osbuf, WMI_ALLOW_AGGR_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_setup_aggr_cmd(struct wmi_t *wmip, A_UINT8 tid)
{
void *osbuf;
WMI_ADDBA_REQ_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_ADDBA_REQ_CMD *)(A_NETBUF_DATA(osbuf));
cmd->tid = tid;
status = wmi_cmd_send(wmip, osbuf, WMI_ADDBA_REQ_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_delete_aggr_cmd (struct wmi_t *wmip, A_UINT8 tid, A_UINT8 uplink)
{
void *osbuf;
WMI_DELBA_REQ_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_DELBA_REQ_CMD *)(A_NETBUF_DATA(osbuf));
cmd->tid = tid;
cmd->is_sender_initiator = uplink; /* uplink =1 - uplink direction, 0=downlink direction */
/* Delete the local aggr state, on host */
status = wmi_cmd_send(wmip, osbuf, WMI_DELBA_REQ_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
#endif
A_STATUS
wmi_set_rx_frame_format_cmd(struct wmi_t *wmip, A_UINT8 rxMetaVersion,
A_BOOL rxDot11Hdr, A_BOOL defragOnHost)
{
void *osbuf;
WMI_RX_FRAME_FORMAT_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_RX_FRAME_FORMAT_CMD *)(A_NETBUF_DATA(osbuf));
cmd->dot11Hdr = (rxDot11Hdr==TRUE)? 1:0;
cmd->defragOnHost = (defragOnHost==TRUE)? 1:0;
cmd->metaVersion = rxMetaVersion; /* */
/* Delete the local aggr state, on host */
status = wmi_cmd_send(wmip, osbuf, WMI_RX_FRAME_FORMAT_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_tx_mac_rules_cmd (struct wmi_t *wmip, A_UINT32 rules)
{
void *osbuf;
WMI_CONFIG_TX_MAC_RULES_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_CONFIG_TX_MAC_RULES_CMD *)(A_NETBUF_DATA(osbuf));
cmd->rules = rules;
status = wmi_cmd_send(wmip, osbuf, WMI_CONFIG_TX_MAC_RULES_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_promiscuous_mode_cmd (struct wmi_t *wmip, A_BOOL bMode)
{
void *osbuf;
WMI_SET_PROMISCUOUS_MODE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_PROMISCUOUS_MODE_CMD *)(A_NETBUF_DATA(osbuf));
cmd->enable = (bMode==TRUE)? 1:0;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_PROMISCUOUS_MODE_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_thin_mode_cmd(struct wmi_t *wmip, A_BOOL bThinMode)
{
void *osbuf;
WMI_SET_THIN_MODE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_THIN_MODE_CMD *)(A_NETBUF_DATA(osbuf));
cmd->enable = (bThinMode==TRUE)? 1:0;
/* Delete the local aggr state, on host */
status = wmi_cmd_send(wmip, osbuf, WMI_SET_THIN_MODE_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_wlan_conn_precedence_cmd(struct wmi_t *wmip, BT_WLAN_CONN_PRECEDENCE precedence)
{
void *osbuf;
WMI_SET_BT_WLAN_CONN_PRECEDENCE *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_BT_WLAN_CONN_PRECEDENCE *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->precedence = precedence;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_pmk_cmd(struct wmi_t *wmip, A_UINT8 *pmk)
{
void *osbuf;
WMI_SET_PMK_CMD *p;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_SET_PMK_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_SET_PMK_CMD));
p = (WMI_SET_PMK_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(p, sizeof(*p));
A_MEMCPY(p->pmk, pmk, WMI_PMK_LEN);
status = wmi_cmd_send(wmip, osbuf, WMI_SET_PMK_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_passphrase_cmd(struct wmi_t *wmip, WMI_SET_PASSPHRASE_CMD *cmd)
{
void *osbuf;
WMI_SET_PASSPHRASE_CMD *p;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_SET_PASSPHRASE_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_SET_PASSPHRASE_CMD));
p = (WMI_SET_PASSPHRASE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(p, sizeof(*p));
A_MEMCPY(p->ssid, cmd->ssid, WMI_MAX_SSID_LEN);
p->ssid_len = cmd->ssid_len;
A_MEMCPY(p->passphrase, cmd->passphrase, WMI_PASSPHRASE_LEN);
p->passphrase_len = cmd->passphrase_len;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_PASSPHRASE_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_excess_tx_retry_thres_cmd(struct wmi_t *wmip, WMI_SET_EXCESS_TX_RETRY_THRES_CMD *cmd)
{
void *osbuf;
WMI_SET_EXCESS_TX_RETRY_THRES_CMD *p;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_SET_EXCESS_TX_RETRY_THRES_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_SET_EXCESS_TX_RETRY_THRES_CMD));
p = (WMI_SET_EXCESS_TX_RETRY_THRES_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(p, sizeof(*p));
p->threshold = cmd->threshold;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_SGI_cmd(struct wmi_t *wmip, A_UINT32 *sgiMask, A_UINT8 sgiPERThreshold)
{
void *osbuf;
WMI_SET_TX_SGI_PARAM_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY ;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_TX_SGI_PARAM_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->sgiMask[0] = sgiMask[0];
cmd->sgiMask[1] = sgiMask[1];
cmd->sgiPERThreshold = sgiPERThreshold;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_TX_SGI_PARAM_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
static A_STATUS wmi_set_host_sleep_mode_cmd_processed(struct wmi_t *wmip,
A_UINT8 *datap, A_UINT8 len)
{
/* If the callback function pointer has been set, call the function */
if (wmip->host_sleep_mode_event_fn) {
wmip->host_sleep_mode_event_fn(wmip->host_sleep_mode_event_fn_arg);
}
return A_OK;
}
bss_t *
wmi_find_matching_Ssidnode (struct wmi_t *wmip, A_UCHAR *pSsid,
A_UINT32 ssidLength,
A_UINT32 dot11AuthMode, A_UINT32 authMode,
A_UINT32 pairwiseCryptoType, A_UINT32 grpwiseCryptoTyp)
{
bss_t *node = NULL;
node = wlan_find_matching_Ssidnode (&wmip->wmi_scan_table, pSsid,
ssidLength, dot11AuthMode, authMode, pairwiseCryptoType, grpwiseCryptoTyp);
return node;
}
A_UINT16
wmi_ieee2freq (int chan)
{
A_UINT16 freq = 0;
freq = wlan_ieee2freq (chan);
return freq;
}
A_UINT32
wmi_freq2ieee (A_UINT16 freq)
{
A_UINT16 chan = 0;
chan = wlan_freq2ieee (freq);
return chan;
}
A_STATUS
wmi_beacon2bssnode (struct wmi_t *wmip, A_UINT8 *datap, int len, A_UINT8 *bssid, A_UINT16 channel)
{
A_STATUS status = A_OK;
bss_t *bss = NULL;
bss = wlan_node_alloc (&wmip->wmi_scan_table, len);
if (bss == NULL) {
return A_NO_MEMORY;
}
bss->ni_snr = 95;
bss->ni_rssi = -58;
A_ASSERT(bss->ni_buf != NULL);
if (bss->ni_buf == NULL)
return A_ERROR;
A_MEMCPY(bss->ni_buf, datap, len);
bss->ni_framelen = len;
if (wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie) != A_OK) {
wlan_node_free(bss);
return A_EINVAL;
}
/*
* Update the frequency in ie_chan, overwriting of channel number
* which is done in wlan_parse_beacon
*/
bss->ni_cie.ie_chan = channel;
wlan_setup_node(&wmip->wmi_scan_table, bss, bssid);
return status;
}
//WAC
A_STATUS
wmi_wac_enable_cmd(struct wmi_t *wmip, WMI_WAC_ENABLE_CMD *param)
{
void *osbuf;
WMI_WAC_ENABLE_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_WAC_ENABLE_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->enable = param->enable;
cmd->period = param->period;
cmd->threshold = param->threshold;
cmd->rssi = param->rssi;
A_MEMCPY(cmd->wps_pin, param->wps_pin, 8);
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("WAC ENABLE: 0x%x\n", WMI_ENABLE_WAC_CMDID));
status = wmi_cmd_send(wmip, osbuf, WMI_ENABLE_WAC_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_wac_scan_reply_cmd(struct wmi_t *wmip, WAC_SUBCMD param)
{
void *osbuf;
WMI_WAC_SCAN_REPLY_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_WAC_SCAN_REPLY_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->cmdid = param;
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("WAC SCAN REPLY: 0x%x\n", WMI_WAC_SCAN_REPLY_CMDID));
status = wmi_cmd_send(wmip, osbuf, WMI_WAC_SCAN_REPLY_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_wac_ctrl_req_cmd(struct wmi_t *wmip, WMI_WAC_CTRL_REQ_CMD *param)
{
void *osbuf;
WMI_WAC_CTRL_REQ_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_WAC_CTRL_REQ_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->req = param->req;
cmd->cmd = param->cmd;
cmd->frame = param->frame;
A_MEMCPY(cmd->ie, param->ie, 17);
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("WAC CTRL REQ: 0x%x\n", WMI_WAC_CTRL_REQ_CMDID));
status = wmi_cmd_send(wmip, osbuf, WMI_WAC_CTRL_REQ_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_assoc_req_report_cmd (struct wmi_t *wmip, A_UINT8 host_accept, A_UINT8 host_reaspncode, A_UINT8 target_status, A_UINT8 *sta_mac_addr, A_UINT8 rspType)
{
void *osbuf;
WMI_SEND_ASSOCRES_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC (sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT (osbuf, sizeof(*cmd));
cmd = (WMI_SEND_ASSOCRES_CMD *)(A_NETBUF_DATA(osbuf));
A_MEMZERO (cmd, sizeof(*cmd));
cmd->host_accept = host_accept;
cmd->host_reasonCode = host_reaspncode;
cmd->target_status = target_status;
A_MEMCPY (cmd->sta_mac_addr, sta_mac_addr, ATH_MAC_LEN);
cmd->rspType = rspType;
status = wmi_cmd_send(wmip, osbuf, WMI_SEND_ASSOC_RES_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_assoc_req_enable_cmd (struct wmi_t *wmip, A_UINT8 enable)
{
void *osbuf;
WMI_SET_ASSOCREQ_RELAY *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(*cmd));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(*cmd));
cmd = (WMI_SET_ASSOCREQ_RELAY *)(A_NETBUF_DATA(osbuf));
A_MEMZERO(cmd, sizeof(*cmd));
cmd->enable = enable;
status = wmi_cmd_send(wmip, osbuf, WMI_SET_ASSOC_REQ_RELAY_CMDID,
NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
static A_STATUS
wmi_report_assoc_req_rx(struct wmi_t *wmip, A_UINT8 *datap, int len)
{
WMI_ASSOCREQ_EVENT *ev;
if (len < sizeof(WMI_ASSOCREQ_EVENT))
{
return A_EINVAL;
}
ev = (WMI_ASSOCREQ_EVENT *) datap;
A_WMI_ASSOC_REQ_REPORT_EVENT(wmip->wmi_devt, ev->status, ev->rspType, datap, len);
return A_OK;
}
A_STATUS
wmi_force_target_assert(struct wmi_t *wmip)
{
return wmi_simple_cmd(wmip, WMI_FORCE_TARGET_ASSERT_CMDID);
}
/*
* This command will be used to enable/disable AP uAPSD feature
*/
A_STATUS
wmi_ap_set_apsd(struct wmi_t *wmip, A_UINT8 enable)
{
void *osbuf;
WMI_AP_SET_APSD_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_SET_APSD_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_SET_APSD_CMD));
cmd = (WMI_AP_SET_APSD_CMD *)(A_NETBUF_DATA(osbuf));
cmd->enable = enable;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_APSD_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_set_apsd_buffered_traffic_cmd(struct wmi_t *wmip, A_UINT16 aid, A_UINT16 bitmap, A_UINT32 flags)
{
WMI_AP_APSD_BUFFERED_TRAFFIC_CMD *cmd;
void *osbuf;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_APSD_BUFFERED_TRAFFIC_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_APSD_BUFFERED_TRAFFIC_CMD));
cmd = (WMI_AP_APSD_BUFFERED_TRAFFIC_CMD *)(A_NETBUF_DATA(osbuf));
cmd->aid = aid;
cmd->bitmap = bitmap;
cmd->flags = flags;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_sta_bmiss_enhance_cmd(struct wmi_t *wmip, A_UINT8 enable)
{
WMI_STA_BMISS_ENHANCE_CMD *cmd;
void *osbuf;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_STA_BMISS_ENHANCE_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_STA_BMISS_ENHANCE_CMD));
cmd = (WMI_STA_BMISS_ENHANCE_CMD *)(A_NETBUF_DATA(osbuf));
cmd->enable = enable;
status = wmi_cmd_send(wmip, osbuf, WMI_STA_BMISS_ENHANCE_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}
A_STATUS
wmi_ap_set_idle_close_time(struct wmi_t *wmip, A_UINT32 time_val)
{
void *osbuf;
WMI_AP_IDLE_CLOSE_TIME_CMD *cmd;
A_STATUS status;
osbuf = A_NETBUF_ALLOC(sizeof(WMI_AP_IDLE_CLOSE_TIME_CMD));
if (osbuf == NULL) {
return A_NO_MEMORY;
}
A_NETBUF_PUT(osbuf, sizeof(WMI_AP_IDLE_CLOSE_TIME_CMD));
cmd = (WMI_AP_IDLE_CLOSE_TIME_CMD *)(A_NETBUF_DATA(osbuf));
cmd->time_val_sec = time_val;
status = wmi_cmd_send(wmip, osbuf, WMI_AP_SET_IDLE_CLOSE_TIME_CMDID, NO_SYNC_WMIFLAG);
if (status != A_OK) {
A_NETBUF_FREE(osbuf);
}
return status;
}