blob: 1a11104162bffa2643826c89e19cef9cad01d200 [file] [log] [blame]
/*
* Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*
*
* This file sch_api.cc contains functions related to the API exposed
* by scheduler module
*
* Author: Sandesh Goel
* Date: 02/25/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
*
*/
#include "cds_api.h"
#include "ani_global.h"
#include "wni_cfg.h"
#include "sir_mac_prot_def.h"
#include "sir_mac_prop_exts.h"
#include "sir_common.h"
#include "cfg_api.h"
#include "lim_api.h"
#include "sch_api.h"
#include "sch_debug.h"
#include "sch_sys_params.h"
#include "lim_trace.h"
#include "lim_types.h"
#include "wma_types.h"
/* -------------------------------------------------------------------- */
/* */
/* Static Variables */
/* */
/* ------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/**
* sch_get_cfp_count
*
* FUNCTION:
* Function used by other Sirius modules to read CFPcount
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param None
* @return None
*/
uint8_t sch_get_cfp_count(tpAniSirGlobal pMac)
{
return pMac->sch.schObject.gSchCFPCount;
}
/* -------------------------------------------------------------------- */
/**
* sch_get_cfp_dur_remaining
*
* FUNCTION:
* Function used by other Sirius modules to read CFPDuration remaining
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param None
* @return None
*/
uint16_t sch_get_cfp_dur_remaining(tpAniSirGlobal pMac)
{
return pMac->sch.schObject.gSchCFPDurRemaining;
}
/* -------------------------------------------------------------------- */
/**
* sch_init_globals
*
* FUNCTION:
* Initialize globals
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param None
* @return None
*/
void sch_init_globals(tpAniSirGlobal pMac)
{
pMac->sch.gSchHcfEnabled = false;
pMac->sch.gSchScanRequested = false;
pMac->sch.gSchScanReqRcvd = false;
pMac->sch.gSchGenBeacon = 1;
pMac->sch.gSchBeaconsSent = 0;
pMac->sch.gSchBeaconsWritten = 0;
pMac->sch.gSchBcnParseErrorCnt = 0;
pMac->sch.gSchBcnIgnored = 0;
pMac->sch.gSchBBXportRcvCnt = 0;
pMac->sch.gSchUnknownRcvCnt = 0;
pMac->sch.gSchBcnRcvCnt = 0;
pMac->sch.gSchRRRcvCnt = 0;
pMac->sch.qosNullCnt = 0;
pMac->sch.numData = 0;
pMac->sch.numPoll = 0;
pMac->sch.numCorrupt = 0;
pMac->sch.numBogusInt = 0;
pMac->sch.numTxAct0 = 0;
pMac->sch.rrTimeout = SCH_RR_TIMEOUT;
pMac->sch.pollPeriod = SCH_POLL_PERIOD;
pMac->sch.multipleSched = 1;
pMac->sch.maxPollTimeouts = 20;
pMac->sch.checkCfbFlagStuck = 0;
}
/* -------------------------------------------------------------------- */
/**
* sch_post_message
*
* FUNCTION:
* Post the beacon message to the scheduler message queue
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param pMsg pointer to message
* @return None
*/
tSirRetStatus sch_post_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
{
sch_process_message(pMac, pMsg);
return eSIR_SUCCESS;
}
/* --------------------------------------------------------------------------- */
/**
* sch_send_start_scan_rsp
*
* FUNCTION:
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param None
* @return None
*/
void sch_send_start_scan_rsp(tpAniSirGlobal pMac)
{
tSirMsgQ msgQ;
uint32_t retCode;
PELOG1(sch_log(pMac, LOG1, FL("Sending LIM message to go into scan"));)
msgQ.type = SIR_SCH_START_SCAN_RSP;
if ((retCode = lim_post_msg_api(pMac, &msgQ)) != eSIR_SUCCESS)
sch_log(pMac, LOGE,
FL("Posting START_SCAN_RSP to LIM failed, reason=%X"),
retCode);
}
/**
* sch_send_beacon_req
*
* FUNCTION:
*
* LOGIC:
* 1) SCH received SIR_SCH_BEACON_GEN_IND
* 2) SCH updates TIM IE and other beacon related IE's
* 3) SCH sends WMA_SEND_BEACON_REQ to HAL. HAL then copies the beacon
* template to memory
*
* ASSUMPTIONS:
* Memory allocation is reqd to send this message and SCH allocates memory.
* The assumption is that HAL will "free" this memory.
*
* NOTE:
*
* @param pMac global
*
* @param beaconPayload
*
* @param size - Length of the beacon
*
* @return CDF_STATUS
*/
tSirRetStatus sch_send_beacon_req(tpAniSirGlobal pMac, uint8_t *beaconPayload,
uint16_t size, tpPESession psessionEntry)
{
tSirMsgQ msgQ;
tpSendbeaconParams beaconParams = NULL;
tSirRetStatus retCode;
sch_log(pMac, LOG2,
FL
("Indicating HAL to copy the beacon template [%d bytes] to memory"),
size);
beaconParams = cdf_mem_malloc(sizeof(tSendbeaconParams));
if (NULL == beaconParams)
return eSIR_MEM_ALLOC_FAILED;
msgQ.type = WMA_SEND_BEACON_REQ;
/* No Dialog Token reqd, as a response is not solicited */
msgQ.reserved = 0;
/* Fill in tSendbeaconParams members */
cdf_mem_copy(beaconParams->bssId, psessionEntry->bssId,
sizeof(psessionEntry->bssId));
if (LIM_IS_IBSS_ROLE(psessionEntry)) {
beaconParams->timIeOffset = 0;
} else {
beaconParams->timIeOffset = psessionEntry->schBeaconOffsetBegin;
}
/* p2pIeOffset should be atleast greater than timIeOffset */
if ((pMac->sch.schObject.p2pIeOffset != 0) &&
(pMac->sch.schObject.p2pIeOffset <
psessionEntry->schBeaconOffsetBegin)) {
sch_log(pMac, LOGE, FL("Invalid p2pIeOffset:[%d]"),
pMac->sch.schObject.p2pIeOffset);
CDF_ASSERT(0);
cdf_mem_free(beaconParams);
return eSIR_FAILURE;
}
beaconParams->p2pIeOffset = pMac->sch.schObject.p2pIeOffset;
#ifdef WLAN_SOFTAP_FW_BEACON_TX_PRNT_LOG
sch_log(pMac, LOGE, FL("TimIeOffset:[%d]"), beaconParams->TimIeOffset);
#endif
beaconParams->beacon = beaconPayload;
beaconParams->beaconLength = (uint32_t) size;
msgQ.bodyptr = beaconParams;
msgQ.bodyval = 0;
/* Keep a copy of recent beacon frame sent */
/* free previous copy of the beacon */
if (psessionEntry->beacon) {
cdf_mem_free(psessionEntry->beacon);
}
psessionEntry->bcnLen = 0;
psessionEntry->beacon = NULL;
psessionEntry->beacon = cdf_mem_malloc(size);
if (psessionEntry->beacon != NULL) {
cdf_mem_copy(psessionEntry->beacon, beaconPayload, size);
psessionEntry->bcnLen = size;
}
MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type));
if (eSIR_SUCCESS != (retCode = wma_post_ctrl_msg(pMac, &msgQ))) {
sch_log(pMac, LOGE,
FL("Posting SEND_BEACON_REQ to HAL failed, reason=%X"),
retCode);
} else {
sch_log(pMac, LOG2,
FL("Successfully posted WMA_SEND_BEACON_REQ to HAL"));
if (LIM_IS_AP_ROLE(psessionEntry) &&
(pMac->sch.schObject.fBeaconChanged)) {
if (eSIR_SUCCESS !=
(retCode =
lim_send_probe_rsp_template_to_hal(pMac, psessionEntry,
&psessionEntry->
DefProbeRspIeBitmap
[0]))) {
/* check whether we have to free any memory */
sch_log(pMac, LOGE,
FL
("FAILED to send probe response template with retCode %d"),
retCode);
}
}
}
return retCode;
}
uint32_t lim_remove_p2p_ie_from_add_ie(tpAniSirGlobal pMac,
tpPESession psessionEntry,
uint8_t *addIeWoP2pIe,
uint32_t *addnIELenWoP2pIe)
{
uint32_t left = psessionEntry->addIeParams.probeRespDataLen;
uint8_t *ptr = psessionEntry->addIeParams.probeRespData_buff;
uint8_t elem_id,elem_len;
uint32_t offset = 0;
uint8_t eid = 0xDD;
cdf_mem_copy(addIeWoP2pIe, ptr, left);
*addnIELenWoP2pIe = left;
if (addIeWoP2pIe != NULL) {
while (left >= 2) {
elem_id = ptr[0];
elem_len = ptr[1];
left -= 2;
if(elem_len > left) {
sch_log(pMac, LOGE, FL("Invalid IEs"));
return eSIR_FAILURE;
}
if ((elem_id == eid) &&
(cdf_mem_compare(&ptr[2],
"\x50\x6f\x9a\x09", 4))) {
left -= elem_len;
ptr += (elem_len + 2);
cdf_mem_copy(&addIeWoP2pIe[offset], ptr, left);
*addnIELenWoP2pIe -= (2 + elem_len);
} else {
left -= elem_len;
ptr += (elem_len + 2);
offset += 2 + elem_len;
}
}
}
return eSIR_SUCCESS;
}
uint32_t lim_send_probe_rsp_template_to_hal(tpAniSirGlobal pMac,
tpPESession psessionEntry,
uint32_t *IeBitmap)
{
tSirMsgQ msgQ;
uint8_t *pFrame2Hal = psessionEntry->pSchProbeRspTemplate;
tpSendProbeRespParams pprobeRespParams = NULL;
uint32_t retCode = eSIR_FAILURE;
uint32_t nPayload, nBytes, nStatus;
tpSirMacMgmtHdr pMacHdr;
uint32_t addnIEPresent = false;
uint32_t addnIELen = 0;
uint8_t *addIE = NULL;
uint8_t *addIeWoP2pIe = NULL;
uint32_t addnIELenWoP2pIe = 0;
uint32_t retStatus;
nStatus =
dot11f_get_packed_probe_response_size(pMac,
&psessionEntry->probeRespFrame,
&nPayload);
if (DOT11F_FAILED(nStatus)) {
sch_log(pMac, LOGE, FL("Failed to calculate the packed size f"
"or a Probe Response (0x%08x)."),
nStatus);
/* We'll fall back on the worst case scenario: */
nPayload = sizeof(tDot11fProbeResponse);
} else if (DOT11F_WARNED(nStatus)) {
sch_log(pMac, LOGE, FL("There were warnings while calculating"
"the packed size for a Probe Response "
"(0x%08x)."), nStatus);
}
nBytes = nPayload + sizeof(tSirMacMgmtHdr);
/* Check if probe response IE is present or not */
addnIEPresent = (psessionEntry->addIeParams.probeRespDataLen != 0);
if (addnIEPresent) {
/*
* probe response template should not have P2P IE.
* In case probe request has P2P IE or WPS IE, the
* probe request will be forwarded to the Host and
* Host will send the probe response. In other cases
* FW will send the probe response. So, if the template
* has P2P IE, the probe response sent to non P2P devices
* by the FW, may also have P2P IE which will fail
* P2P cert case 6.1.3
*/
addIeWoP2pIe = cdf_mem_malloc(psessionEntry->addIeParams.
probeRespDataLen);
if (NULL == addIeWoP2pIe) {
sch_log(pMac, LOGE,
FL("FAILED to alloc memory when removing P2P IE"));
return eSIR_MEM_ALLOC_FAILED;
}
retStatus = lim_remove_p2p_ie_from_add_ie(pMac, psessionEntry,
addIeWoP2pIe, &addnIELenWoP2pIe);
if (retStatus != eSIR_SUCCESS) {
cdf_mem_free(addIeWoP2pIe);
return eSIR_FAILURE;
}
/* Probe rsp IE available */
/*need to check the data length */
addIE =
cdf_mem_malloc(addnIELenWoP2pIe);
if (NULL == addIE) {
sch_log(pMac, LOGE,
FL
("Unable to get WNI_CFG_PROBE_RSP_ADDNIE_DATA1 length"));
cdf_mem_free(addIeWoP2pIe);
return eSIR_MEM_ALLOC_FAILED;
}
addnIELen = addnIELenWoP2pIe;
if (addnIELen <= WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN && addnIELen
&& (nBytes + addnIELen) <= SIR_MAX_PACKET_SIZE) {
cdf_mem_copy(addIE,
addIeWoP2pIe,
addnIELenWoP2pIe);
}
cdf_mem_free(addIeWoP2pIe);
}
if (addnIEPresent) {
if ((nBytes + addnIELen) <= SIR_MAX_PACKET_SIZE)
nBytes += addnIELen;
else
addnIEPresent = false; /* Dont include the IE. */
}
/* Paranoia: */
cdf_mem_set(pFrame2Hal, nBytes, 0);
/* Next, we fill out the buffer descriptor: */
lim_populate_mac_header(pMac, pFrame2Hal, SIR_MAC_MGMT_FRAME,
SIR_MAC_MGMT_PROBE_RSP,
psessionEntry->selfMacAddr,
psessionEntry->selfMacAddr);
pMacHdr = (tpSirMacMgmtHdr) pFrame2Hal;
sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId);
/* That done, pack the Probe Response: */
nStatus =
dot11f_pack_probe_response(pMac, &psessionEntry->probeRespFrame,
pFrame2Hal + sizeof(tSirMacMgmtHdr),
nPayload, &nPayload);
if (DOT11F_FAILED(nStatus)) {
sch_log(pMac, LOGE,
FL("Failed to pack a Probe Response (0x%08x)."),
nStatus);
cdf_mem_free(addIE);
return retCode; /* allocated! */
} else if (DOT11F_WARNED(nStatus)) {
sch_log(pMac, LOGE, FL("There were warnings while packing a P"
"robe Response (0x%08x)."), nStatus);
}
if (addnIEPresent) {
cdf_mem_copy(&pFrame2Hal[nBytes - addnIELen],
&addIE[0], addnIELen);
}
/* free the allocated Memory */
cdf_mem_free(addIE);
pprobeRespParams = cdf_mem_malloc(sizeof(tSendProbeRespParams));
if (NULL == pprobeRespParams) {
sch_log(pMac, LOGE,
FL
("lim_send_probe_rsp_template_to_hal: HAL probe response params malloc failed for bytes %d"),
nBytes);
} else {
sir_copy_mac_addr(pprobeRespParams->bssId, psessionEntry->bssId);
pprobeRespParams->pProbeRespTemplate = pFrame2Hal;
pprobeRespParams->probeRespTemplateLen = nBytes;
cdf_mem_copy(pprobeRespParams->ucProxyProbeReqValidIEBmap,
IeBitmap, (sizeof(uint32_t) * 8));
msgQ.type = WMA_SEND_PROBE_RSP_TMPL;
msgQ.reserved = 0;
msgQ.bodyptr = pprobeRespParams;
msgQ.bodyval = 0;
if (eSIR_SUCCESS != (retCode = wma_post_ctrl_msg(pMac, &msgQ))) {
/* free the allocated Memory */
sch_log(pMac, LOGE,
FL
("lim_send_probe_rsp_template_to_hal: FAIL bytes %d retcode[%X]"),
nBytes, retCode);
cdf_mem_free(pprobeRespParams);
} else {
sch_log(pMac, LOG1,
FL
("lim_send_probe_rsp_template_to_hal: Probe response template msg posted to HAL of bytes %d"),
nBytes);
}
}
return retCode;
}
/**
* sch_gen_timing_advert_frame() - Generate the TA frame and populate the buffer
* @pMac: the global MAC context
* @self_addr: the self MAC address
* @buf: the buffer that will contain the frame
* @timestamp_offset: return for the offset of the timestamp field
* @time_value_offset: return for the time_value field in the TA IE
*
* Return: the length of the buffer.
*/
int sch_gen_timing_advert_frame(tpAniSirGlobal mac_ctx, tSirMacAddr self_addr,
uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset)
{
tDot11fTimingAdvertisementFrame frame;
uint32_t payload_size, buf_size;
int status;
struct cdf_mac_addr wildcard_bssid = {
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
};
cdf_mem_zero((uint8_t *)&frame, sizeof(tDot11fTimingAdvertisementFrame));
/* Populate the TA fields */
status = populate_dot11f_timing_advert_frame(mac_ctx, &frame);
if (status) {
sch_log(mac_ctx, LOGE, FL("Error populating TA frame %x"),
status);
return status;
}
status = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx,
&frame, &payload_size);
if (DOT11F_FAILED(status)) {
sch_log(mac_ctx, LOGE, FL("Error getting packed frame size %x"),
status);
return status;
} else if (DOT11F_WARNED(status)) {
sch_log(mac_ctx, LOGW, FL("Warning getting packed frame size"));
}
buf_size = sizeof(tSirMacMgmtHdr) + payload_size;
*buf = cdf_mem_malloc(buf_size);
if (*buf == NULL) {
sch_log(mac_ctx, LOGE, FL("Cannot allocate memory"));
return eSIR_FAILURE;
}
cdf_mem_zero(*buf, buf_size);
payload_size = 0;
status = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame,
*buf + sizeof(tSirMacMgmtHdr), buf_size -
sizeof(tSirMacMgmtHdr), &payload_size);
sch_log(mac_ctx, LOGE, FL("TA payload size2 = %d"), payload_size);
if (DOT11F_FAILED(status)) {
sch_log(mac_ctx, LOGE, FL("Error packing frame %x"), status);
goto fail;
} else if (DOT11F_WARNED(status)) {
sch_log(mac_ctx, LOGE, FL("Warning packing frame"));
}
lim_populate_mac_header(mac_ctx, *buf, SIR_MAC_MGMT_FRAME,
SIR_MAC_MGMT_TIME_ADVERT, wildcard_bssid.bytes, self_addr);
/* The timestamp field is right after the header */
*timestamp_offset = sizeof(tSirMacMgmtHdr);
*time_value_offset = sizeof(tSirMacMgmtHdr) +
sizeof(tDot11fFfTimeStamp) + sizeof(tDot11fFfCapabilities);
/* Add the Country IE length */
dot11f_get_packed_ie_country(mac_ctx, &frame.Country,
time_value_offset);
/* Add 2 for Country IE EID and Length fields */
*time_value_offset += 2;
/* Add the PowerConstraint IE size */
if (frame.Country.present == 1)
*time_value_offset += 3;
/* Add the offset inside TA IE */
*time_value_offset += 3;
return payload_size + sizeof(tSirMacMgmtHdr);
fail:
if (*buf)
cdf_mem_free(*buf);
return status;
}