blob: 365b3492fa017d684dc417e93dd1d35e3a424181 [file] [log] [blame]
/*
* Copyright (c) 2012-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_beacon_gen.cc contains beacon generation related
* functions
*
* Author: Sandesh Goel
* Date: 02/25/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
*
*/
#include "cds_api.h"
#include "wni_cfg.h"
#include "ani_global.h"
#include "sir_mac_prot_def.h"
#include "lim_utils.h"
#include "lim_api.h"
#include "wma_if.h"
#include "cfg_api.h"
#include "sch_api.h"
#include "parser_api.h"
#include "sch_debug.h"
/* */
/* March 15, 2006 */
/* Temporarily (maybe for all of Alpha-1), assuming TIM = 0 */
/* */
const uint8_t p2p_oui[] = { 0x50, 0x6F, 0x9A, 0x9 };
tSirRetStatus sch_get_p2p_ie_offset(uint8_t *pExtraIe, uint32_t extraIeLen,
uint16_t *pP2pIeOffset)
{
tSirRetStatus status = eSIR_FAILURE;
*pP2pIeOffset = 0;
/* Extra IE is not present */
if (0 == extraIeLen) {
return status;
}
/* Calculate the P2P IE Offset */
do {
if (*pExtraIe == 0xDD) {
if (cdf_mem_compare
((void *)(pExtraIe + 2), &p2p_oui, sizeof(p2p_oui))) {
status = eSIR_SUCCESS;
break;
}
}
(*pP2pIeOffset)++;
pExtraIe++;
} while (--extraIeLen > 0);
return status;
}
/**
* sch_append_addn_ie() - adds additional IEs to frame
* @mac_ctx: mac global context
* @session: pe session pointer
* @frm: frame where additional IE is to be added
* @max_bcn_size: max beacon size
* @num_bytes: final size
*
* Return: status of operation
*/
tSirRetStatus
sch_append_addn_ie(tpAniSirGlobal mac_ctx, tpPESession session,
uint8_t *frm, uint32_t max_bcn_size, uint32_t *num_bytes)
{
tSirRetStatus status = eSIR_FAILURE;
uint32_t present, len;
uint8_t add_ie[WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN];
uint8_t *p2p_ie = NULL;
uint8_t noa_len = 0;
uint8_t noa_strm[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN];
present = (session->addIeParams.probeRespBCNDataLen != 0);
if (!present)
return status;
len = session->addIeParams.probeRespBCNDataLen;
if (!(len <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN && len &&
((len + *num_bytes) <= max_bcn_size)))
return status;
cdf_mem_copy(&add_ie[0], session->addIeParams.probeRespBCNData_buff,
len);
p2p_ie = limGetP2pIEPtr(mac_ctx, &add_ie[0], len);
if ((p2p_ie != NULL) && !mac_ctx->beacon_offload) {
/* get NoA attribute stream P2P IE */
noa_len = lim_get_noa_attr_stream(mac_ctx, noa_strm, session);
if (noa_len) {
if ((noa_len + len) <=
WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) {
cdf_mem_copy(&add_ie[len], noa_strm, noa_len);
len += noa_len;
p2p_ie[1] += noa_len;
} else {
sch_log(mac_ctx, LOGE,
FL("Not able to insert NoA because of length constraint"));
}
}
}
if (len <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) {
cdf_mem_copy(frm, &add_ie[0], len);
*num_bytes = *num_bytes + len;
} else {
sch_log(mac_ctx, LOGW,
FL("Not able to insert because of len constraint %d"),
len);
}
return status;
}
/**
* sch_set_fixed_beacon_fields() - sets the fixed params in beacon frame
* @mac_ctx: mac global context
* @session: pe session entry
* @band: out param, band caclculated
* @opr_ch: operating channels
*
* Return: status of operation
*/
tSirRetStatus
sch_set_fixed_beacon_fields(tpAniSirGlobal mac_ctx, tpPESession session)
{
tpAniBeaconStruct bcn_struct = (tpAniBeaconStruct)
session->pSchBeaconFrameBegin;
tpSirMacMgmtHdr mac;
uint16_t offset;
uint8_t *ptr;
tDot11fBeacon1 *bcn_1;
tDot11fBeacon2 *bcn_2;
uint32_t i, n_status, n_bytes;
uint32_t wps_ap_enable = 0, tmp;
tDot11fIEWscProbeRes *wsc_prb_res;
uint8_t *extra_ie = NULL;
uint32_t extra_ie_len = 0;
uint16_t extra_ie_offset = 0;
uint16_t p2p_ie_offset = 0;
tSirRetStatus status = eSIR_SUCCESS;
bool is_vht_enabled = false;
bcn_1 = cdf_mem_malloc(sizeof(tDot11fBeacon1));
if (NULL == bcn_1) {
sch_log(mac_ctx, LOGE, FL("Failed to allocate memory"));
return eSIR_MEM_ALLOC_FAILED;
}
bcn_2 = cdf_mem_malloc(sizeof(tDot11fBeacon2));
if (NULL == bcn_2) {
sch_log(mac_ctx, LOGE, FL("Failed to allocate memory"));
cdf_mem_free(bcn_1);
return eSIR_MEM_ALLOC_FAILED;
}
wsc_prb_res = cdf_mem_malloc(sizeof(tDot11fIEWscProbeRes));
if (NULL == wsc_prb_res) {
sch_log(mac_ctx, LOGE, FL("Failed to allocate memory"));
cdf_mem_free(bcn_1);
cdf_mem_free(bcn_2);
return eSIR_MEM_ALLOC_FAILED;
}
sch_log(mac_ctx, LOG1, FL("Setting fixed beacon fields"));
/*
* First set the fixed fields:
* set the TFP headers, set the mac header
*/
cdf_mem_set((uint8_t *) &bcn_struct->macHdr, sizeof(tSirMacMgmtHdr), 0);
mac = (tpSirMacMgmtHdr) &bcn_struct->macHdr;
mac->fc.type = SIR_MAC_MGMT_FRAME;
mac->fc.subType = SIR_MAC_MGMT_BEACON;
for (i = 0; i < 6; i++)
mac->da[i] = 0xff;
cdf_mem_copy(mac->sa, session->selfMacAddr,
sizeof(session->selfMacAddr));
cdf_mem_copy(mac->bssId, session->bssId, sizeof(session->bssId));
mac->fc.fromDS = 0;
mac->fc.toDS = 0;
/* Now set the beacon body */
cdf_mem_set((uint8_t *) bcn_1, sizeof(tDot11fBeacon1), 0);
/* Skip over the timestamp (it'll be updated later). */
bcn_1->BeaconInterval.interval =
mac_ctx->sch.schObject.gSchBeaconInterval;
populate_dot11f_capabilities(mac_ctx, &bcn_1->Capabilities, session);
if (session->ssidHidden) {
bcn_1->SSID.present = 1;
/* rest of the fileds are 0 for hidden ssid */
if ((session->ssId.length) &&
(session->ssidHidden == eHIDDEN_SSID_ZERO_CONTENTS))
bcn_1->SSID.num_ssid = session->ssId.length;
} else {
populate_dot11f_ssid(mac_ctx, &session->ssId, &bcn_1->SSID);
}
populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL,
&bcn_1->SuppRates, session);
populate_dot11f_ds_params(mac_ctx, &bcn_1->DSParams,
session->currentOperChannel);
populate_dot11f_ibss_params(mac_ctx, &bcn_1->IBSSParams, session);
offset = sizeof(tAniBeaconStruct);
ptr = session->pSchBeaconFrameBegin + offset;
if (LIM_IS_AP_ROLE(session)) {
/* Initialize the default IE bitmap to zero */
cdf_mem_set((uint8_t *) &(session->DefProbeRspIeBitmap),
(sizeof(uint32_t) * 8), 0);
/* Initialize the default IE bitmap to zero */
cdf_mem_set((uint8_t *) &(session->probeRespFrame),
sizeof(session->probeRespFrame), 0);
/*
* Can be efficiently updated whenever new IE added in Probe
* response in future
*/
if (lim_update_probe_rsp_template_ie_bitmap_beacon1(mac_ctx,
bcn_1, session) != eSIR_SUCCESS)
sch_log(mac_ctx, LOGE,
FL("Failed to build ProbeRsp template"));
}
n_status = dot11f_pack_beacon1(mac_ctx, bcn_1, ptr,
SCH_MAX_BEACON_SIZE - offset, &n_bytes);
if (DOT11F_FAILED(n_status)) {
sch_log(mac_ctx, LOGE,
FL("Failed to packed a tDot11fBeacon1 (0x%08x.)."),
n_status);
cdf_mem_free(bcn_1);
cdf_mem_free(bcn_2);
cdf_mem_free(wsc_prb_res);
return eSIR_FAILURE;
} else if (DOT11F_WARNED(n_status)) {
sch_log(mac_ctx, LOGE,
FL("Warnings while packing a tDot11fBeacon1(0x%08x.)."),
n_status);
}
/*changed to correct beacon corruption */
cdf_mem_set((uint8_t *) bcn_2, sizeof(tDot11fBeacon2), 0);
session->schBeaconOffsetBegin = offset + (uint16_t) n_bytes;
sch_log(mac_ctx, LOG1, FL("Initialized beacon begin, offset %d"),
offset);
/* Initialize the 'new' fields at the end of the beacon */
if ((session->limSystemRole == eLIM_AP_ROLE) &&
session->dfsIncludeChanSwIe == true)
populate_dot_11_f_ext_chann_switch_ann(mac_ctx,
&bcn_2->ext_chan_switch_ann,
session);
populate_dot11f_country(mac_ctx, &bcn_2->Country, session);
if (bcn_1->Capabilities.qos)
populate_dot11f_edca_param_set(mac_ctx, &bcn_2->EDCAParamSet,
session);
if (session->lim11hEnable) {
populate_dot11f_power_constraints(mac_ctx,
&bcn_2->PowerConstraints);
populate_dot11f_tpc_report(mac_ctx, &bcn_2->TPCReport, session);
/* Need to insert channel switch announcement here */
if ((LIM_IS_AP_ROLE(session)
|| LIM_IS_P2P_DEVICE_GO(session))
&& session->dfsIncludeChanSwIe == true) {
/*
* Channel switch announcement only if radar is detected
* and SAP has instructed to announce channel switch IEs
* in beacon and probe responses
*/
populate_dot11f_chan_switch_ann(mac_ctx,
&bcn_2->ChanSwitchAnn, session);
/*
* TODO: depending the CB mode, extended channel switch
* announcement need to be called
*/
/*
populate_dot11f_ext_chan_switch_ann(mac_ctx,
&bcn_2->ExtChanSwitchAnn, session);
*/
#ifdef WLAN_FEATURE_11AC
/*
* TODO: If in 11AC mode, wider bw channel switch
* announcement needs to be called
*/
/*
populate_dot11f_wider_bw_chan_switch_ann(mac_ctx,
&bcn_2->WiderBWChanSwitchAnn, session);
*/
#endif
/*
* Populate the Channel Switch Wrapper Element if
* SAP operates in 40/80 Mhz Channel Width.
*/
if (true == session->dfsIncludeChanWrapperIe)
populate_dot11f_chan_switch_wrapper(mac_ctx,
&bcn_2->ChannelSwitchWrapper, session);
}
}
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
/* populate proprietary IE for MDM device operating in AP-MCC */
populate_dot11f_avoid_channel_ie(mac_ctx, &bcn_2->QComVendorIE,
session);
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
if (session->dot11mode != WNI_CFG_DOT11_MODE_11B)
populate_dot11f_erp_info(mac_ctx, &bcn_2->ERPInfo, session);
if (session->htCapability) {
populate_dot11f_ht_caps(mac_ctx, session, &bcn_2->HTCaps);
populate_dot11f_ht_info(mac_ctx, &bcn_2->HTInfo, session);
}
#ifdef WLAN_FEATURE_11AC
if (session->vhtCapability) {
sch_log(mac_ctx, LOGW, FL("Populate VHT IEs in Beacon"));
populate_dot11f_vht_caps(mac_ctx, session, &bcn_2->VHTCaps);
populate_dot11f_vht_operation(mac_ctx, session,
&bcn_2->VHTOperation);
is_vht_enabled = true;
/* following is for MU MIMO: we do not support it yet */
/*
populate_dot11f_vht_ext_bss_load( mac_ctx, &bcn2.VHTExtBssLoad);
*/
if (session->gLimOperatingMode.present)
populate_dot11f_operating_mode(mac_ctx,
&bcn_2->OperatingMode, session);
}
#endif
populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &bcn_2->ExtCap,
session);
populate_dot11f_ext_supp_rates(mac_ctx,
POPULATE_DOT11F_RATES_OPERATIONAL,
&bcn_2->ExtSuppRates, session);
if (session->pLimStartBssReq != NULL) {
populate_dot11f_wpa(mac_ctx, &session->pLimStartBssReq->rsnIE,
&bcn_2->WPA);
populate_dot11f_rsn_opaque(mac_ctx,
&session->pLimStartBssReq->rsnIE,
&bcn_2->RSNOpaque);
}
if (session->limWmeEnabled)
populate_dot11f_wmm(mac_ctx, &bcn_2->WMMInfoAp,
&bcn_2->WMMParams, &bcn_2->WMMCaps, session);
if (LIM_IS_AP_ROLE(session)) {
if (session->wps_state != SAP_WPS_DISABLED) {
populate_dot11f_beacon_wpsi_es(mac_ctx,
&bcn_2->WscBeacon, session);
}
} else {
if (wlan_cfg_get_int(mac_ctx,
(uint16_t) WNI_CFG_WPS_ENABLE, &tmp) != eSIR_SUCCESS)
sch_log(mac_ctx, LOGP, FL("Failed to cfg get id %d"),
WNI_CFG_WPS_ENABLE);
wps_ap_enable = tmp & WNI_CFG_WPS_ENABLE_AP;
if (wps_ap_enable)
populate_dot11f_wsc(mac_ctx, &bcn_2->WscBeacon);
if (mac_ctx->lim.wscIeInfo.wscEnrollmentState ==
eLIM_WSC_ENROLL_BEGIN) {
populate_dot11f_wsc_registrar_info(mac_ctx,
&bcn_2->WscBeacon);
mac_ctx->lim.wscIeInfo.wscEnrollmentState =
eLIM_WSC_ENROLL_IN_PROGRESS;
}
if (mac_ctx->lim.wscIeInfo.wscEnrollmentState ==
eLIM_WSC_ENROLL_END) {
de_populate_dot11f_wsc_registrar_info(mac_ctx,
&bcn_2->WscBeacon);
mac_ctx->lim.wscIeInfo.wscEnrollmentState =
eLIM_WSC_ENROLL_NOOP;
}
}
if ((LIM_IS_AP_ROLE(session))) {
/*
* Can be efficiently updated whenever new IE added in Probe
* response in future
*/
lim_update_probe_rsp_template_ie_bitmap_beacon2(mac_ctx, bcn_2,
&session->DefProbeRspIeBitmap[0],
&session->probeRespFrame);
/* update probe response WPS IE instead of beacon WPS IE */
if (session->wps_state != SAP_WPS_DISABLED) {
if (session->APWPSIEs.SirWPSProbeRspIE.FieldPresent)
populate_dot11f_probe_res_wpsi_es(mac_ctx,
wsc_prb_res, session);
else
wsc_prb_res->present = 0;
if (wsc_prb_res->present) {
set_probe_rsp_ie_bitmap(
&session->DefProbeRspIeBitmap[0],
SIR_MAC_WPA_EID);
cdf_mem_copy((void *)
&session->probeRespFrame.WscProbeRes,
(void *)wsc_prb_res,
sizeof(tDot11fIEWscProbeRes));
}
}
}
n_status = dot11f_pack_beacon2(mac_ctx, bcn_2,
session->pSchBeaconFrameEnd,
SCH_MAX_BEACON_SIZE, &n_bytes);
if (DOT11F_FAILED(n_status)) {
sch_log(mac_ctx, LOGE,
FL("Failed to packed a tDot11fBeacon2 (0x%08x.)."),
n_status);
cdf_mem_free(bcn_1);
cdf_mem_free(bcn_2);
cdf_mem_free(wsc_prb_res);
return eSIR_FAILURE;
} else if (DOT11F_WARNED(n_status)) {
sch_log(mac_ctx, LOGE,
FL("Warnings while packing a tDot11fBeacon2(0x%08x.)."),
n_status);
}
extra_ie = session->pSchBeaconFrameEnd + n_bytes;
extra_ie_offset = n_bytes;
/* TODO: Append additional IE here. */
sch_append_addn_ie(mac_ctx, session,
session->pSchBeaconFrameEnd + n_bytes,
SCH_MAX_BEACON_SIZE, &n_bytes);
session->schBeaconOffsetEnd = (uint16_t) n_bytes;
extra_ie_len = n_bytes - extra_ie_offset;
/* Get the p2p Ie Offset */
status = sch_get_p2p_ie_offset(extra_ie, extra_ie_len, &p2p_ie_offset);
if (eSIR_SUCCESS == status)
/* Update the P2P Ie Offset */
mac_ctx->sch.schObject.p2pIeOffset =
session->schBeaconOffsetBegin + TIM_IE_SIZE +
extra_ie_offset + p2p_ie_offset;
else
mac_ctx->sch.schObject.p2pIeOffset = 0;
sch_log(mac_ctx, LOG1, FL("Initialized beacon end, offset %d"),
session->schBeaconOffsetEnd);
mac_ctx->sch.schObject.fBeaconChanged = 1;
cdf_mem_free(bcn_1);
cdf_mem_free(bcn_2);
cdf_mem_free(wsc_prb_res);
return eSIR_SUCCESS;
}
tSirRetStatus lim_update_probe_rsp_template_ie_bitmap_beacon1(tpAniSirGlobal pMac,
tDot11fBeacon1 *beacon1,
tpPESession
psessionEntry)
{
uint32_t *DefProbeRspIeBitmap;
tDot11fProbeResponse *prb_rsp;
if (!psessionEntry) {
sch_log(pMac, LOGE, FL("PESession is null!"));
return eSIR_FAILURE;
}
DefProbeRspIeBitmap = &psessionEntry->DefProbeRspIeBitmap[0];
prb_rsp = &psessionEntry->probeRespFrame;
prb_rsp->BeaconInterval = beacon1->BeaconInterval;
cdf_mem_copy((void *)&prb_rsp->Capabilities,
(void *)&beacon1->Capabilities,
sizeof(beacon1->Capabilities));
/* SSID */
if (beacon1->SSID.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_SSID_EID);
/* populating it, because probe response has to go with SSID even in hidden case */
populate_dot11f_ssid(pMac, &psessionEntry->ssId, &prb_rsp->SSID);
}
/* supported rates */
if (beacon1->SuppRates.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_RATESET_EID);
cdf_mem_copy((void *)&prb_rsp->SuppRates,
(void *)&beacon1->SuppRates,
sizeof(beacon1->SuppRates));
}
/* DS Parameter set */
if (beacon1->DSParams.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_DS_PARAM_SET_EID);
cdf_mem_copy((void *)&prb_rsp->DSParams,
(void *)&beacon1->DSParams,
sizeof(beacon1->DSParams));
}
/* IBSS params will not be present in the Beacons transmitted by AP */
return eSIR_SUCCESS;
}
void lim_update_probe_rsp_template_ie_bitmap_beacon2(tpAniSirGlobal pMac,
tDot11fBeacon2 *beacon2,
uint32_t *DefProbeRspIeBitmap,
tDot11fProbeResponse *prb_rsp)
{
/* IBSS parameter set - will not be present in probe response tx by AP */
/* country */
if (beacon2->Country.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_COUNTRY_EID);
cdf_mem_copy((void *)&prb_rsp->Country,
(void *)&beacon2->Country,
sizeof(beacon2->Country));
}
/* Power constraint */
if (beacon2->PowerConstraints.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_PWR_CONSTRAINT_EID);
cdf_mem_copy((void *)&prb_rsp->PowerConstraints,
(void *)&beacon2->PowerConstraints,
sizeof(beacon2->PowerConstraints));
}
/* Channel Switch Annoouncement SIR_MAC_CHNL_SWITCH_ANN_EID */
if (beacon2->ChanSwitchAnn.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_CHNL_SWITCH_ANN_EID);
cdf_mem_copy((void *)&prb_rsp->ChanSwitchAnn,
(void *)&beacon2->ChanSwitchAnn,
sizeof(beacon2->ChanSwitchAnn));
}
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
if (beacon2->QComVendorIE.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_QCOM_VENDOR_EID);
cdf_mem_copy((void *)&prb_rsp->QComVendorIE,
(void *)&beacon2->QComVendorIE,
sizeof(beacon2->QComVendorIE));
}
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
/* ERP information */
if (beacon2->ERPInfo.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_ERP_INFO_EID);
cdf_mem_copy((void *)&prb_rsp->ERPInfo,
(void *)&beacon2->ERPInfo,
sizeof(beacon2->ERPInfo));
}
/* Extended supported rates */
if (beacon2->ExtSuppRates.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_EXTENDED_RATE_EID);
cdf_mem_copy((void *)&prb_rsp->ExtSuppRates,
(void *)&beacon2->ExtSuppRates,
sizeof(beacon2->ExtSuppRates));
}
/* WPA */
if (beacon2->WPA.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID);
cdf_mem_copy((void *)&prb_rsp->WPA, (void *)&beacon2->WPA,
sizeof(beacon2->WPA));
}
/* RSN */
if (beacon2->RSNOpaque.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_RSN_EID);
cdf_mem_copy((void *)&prb_rsp->RSNOpaque,
(void *)&beacon2->RSNOpaque,
sizeof(beacon2->RSNOpaque));
}
/* EDCA Parameter set */
if (beacon2->EDCAParamSet.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_EDCA_PARAM_SET_EID);
cdf_mem_copy((void *)&prb_rsp->EDCAParamSet,
(void *)&beacon2->EDCAParamSet,
sizeof(beacon2->EDCAParamSet));
}
/* Vendor specific - currently no vendor specific IEs added */
/* Requested IEs - currently we are not processing this will be added later */
/* HT capability IE */
if (beacon2->HTCaps.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_HT_CAPABILITIES_EID);
cdf_mem_copy((void *)&prb_rsp->HTCaps, (void *)&beacon2->HTCaps,
sizeof(beacon2->HTCaps));
}
/* HT Info IE */
if (beacon2->HTInfo.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_HT_INFO_EID);
cdf_mem_copy((void *)&prb_rsp->HTInfo, (void *)&beacon2->HTInfo,
sizeof(beacon2->HTInfo));
}
#ifdef WLAN_FEATURE_11AC
if (beacon2->VHTCaps.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_VHT_CAPABILITIES_EID);
cdf_mem_copy((void *)&prb_rsp->VHTCaps,
(void *)&beacon2->VHTCaps,
sizeof(beacon2->VHTCaps));
}
if (beacon2->VHTOperation.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_VHT_OPERATION_EID);
cdf_mem_copy((void *)&prb_rsp->VHTOperation,
(void *)&beacon2->VHTOperation,
sizeof(beacon2->VHTOperation));
}
if (beacon2->VHTExtBssLoad.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap,
SIR_MAC_VHT_EXT_BSS_LOAD_EID);
cdf_mem_copy((void *)&prb_rsp->VHTExtBssLoad,
(void *)&beacon2->VHTExtBssLoad,
sizeof(beacon2->VHTExtBssLoad));
}
#endif
/* WMM IE */
if (beacon2->WMMParams.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID);
cdf_mem_copy((void *)&prb_rsp->WMMParams,
(void *)&beacon2->WMMParams,
sizeof(beacon2->WMMParams));
}
/* WMM capability - most of the case won't be present */
if (beacon2->WMMCaps.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID);
cdf_mem_copy((void *)&prb_rsp->WMMCaps,
(void *)&beacon2->WMMCaps,
sizeof(beacon2->WMMCaps));
}
/* Extended Capability */
if (beacon2->ExtCap.present) {
set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, DOT11F_EID_EXTCAP);
cdf_mem_copy((void *)&prb_rsp->ExtCap,
(void *)&beacon2->ExtCap,
sizeof(beacon2->ExtCap));
}
}
void set_probe_rsp_ie_bitmap(uint32_t *IeBitmap, uint32_t pos)
{
uint32_t index, temp;
index = pos >> 5;
if (index >= 8) {
return;
}
temp = IeBitmap[index];
temp |= 1 << (pos & 0x1F);
IeBitmap[index] = temp;
}
/* -------------------------------------------------------------------- */
/**
* write_beacon_to_memory
*
* FUNCTION:
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param None
* @param size Size of the beacon to write to memory
* @param length Length field of the beacon to write to memory
* @return None
*/
void write_beacon_to_memory(tpAniSirGlobal pMac, uint16_t size, uint16_t length,
tpPESession psessionEntry)
{
uint16_t i;
tpAniBeaconStruct pBeacon;
/* copy end of beacon only if length > 0 */
if (length > 0) {
for (i = 0; i < psessionEntry->schBeaconOffsetEnd; i++)
psessionEntry->pSchBeaconFrameBegin[size++] =
psessionEntry->pSchBeaconFrameEnd[i];
}
/* Update the beacon length */
pBeacon = (tpAniBeaconStruct) psessionEntry->pSchBeaconFrameBegin;
/* Do not include the beaconLength indicator itself */
if (length == 0) {
pBeacon->beaconLength = 0;
/* Dont copy entire beacon, Copy length field alone */
size = 4;
} else
pBeacon->beaconLength = (uint32_t) size - sizeof(uint32_t);
/* write size bytes from pSchBeaconFrameBegin */
PELOG2(sch_log(pMac, LOG2, FL("Beacon size - %d bytes"), size);)
PELOG2(sir_dump_buf
(pMac, SIR_SCH_MODULE_ID, LOG2,
psessionEntry->pSchBeaconFrameBegin, size);
)
if (!pMac->sch.schObject.fBeaconChanged)
return;
pMac->sch.gSchGenBeacon = 1;
if (pMac->sch.gSchGenBeacon) {
pMac->sch.gSchBeaconsSent++;
/* */
/* Copy beacon data to SoftMAC shared memory... */
/* Do this by sending a message to HAL */
/* */
size = (size + 3) & (~3);
if (eSIR_SUCCESS !=
sch_send_beacon_req(pMac, psessionEntry->pSchBeaconFrameBegin,
size, psessionEntry))
PELOGE(sch_log
(pMac, LOGE,
FL
("sch_send_beacon_req() returned an error (zsize %d)"),
size);
)
else {
pMac->sch.gSchBeaconsWritten++;
}
}
pMac->sch.schObject.fBeaconChanged = 0;
}
/**
* sch_generate_tim
*
* FUNCTION:
* Generate TIM
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param pMac pointer to global mac structure
* @param **pPtr pointer to the buffer, where the TIM bit is to be written.
* @param *timLength pointer to limLength, which needs to be returned.
* @return None
*/
void sch_generate_tim(tpAniSirGlobal pMac, uint8_t **pPtr, uint16_t *timLength,
uint8_t dtimPeriod)
{
uint8_t *ptr = *pPtr;
uint32_t val = 0;
uint32_t minAid = 1; /* Always start with AID 1 as minimum */
uint32_t maxAid = HAL_NUM_STA;
/* Generate partial virtual bitmap */
uint8_t N1 = minAid / 8;
uint8_t N2 = maxAid / 8;
if (N1 & 1)
N1--;
*timLength = N2 - N1 + 4;
val = dtimPeriod;
/*
* Write 0xFF to firmware's field to detect firmware's mal-function
* early. DTIM count and bitmap control usually cannot be 0xFF, so it
* is easy to know that firmware never updated DTIM count/bitmap control
* field after host driver downloaded beacon template if end-user complaints
* that DTIM count and bitmapControl is 0xFF.
*/
*ptr++ = SIR_MAC_TIM_EID;
*ptr++ = (uint8_t) (*timLength);
/* location for dtimCount. will be filled in by FW. */
*ptr++ = 0xFF;
*ptr++ = (uint8_t) val;
/* location for bitmap control. will be filled in by FW. */
*ptr++ = 0xFF;
ptr += (N2 - N1 + 1);
PELOG2(sir_dump_buf
(pMac, SIR_SCH_MODULE_ID, LOG2, *pPtr, (*timLength) + 2);
)
* pPtr = ptr;
}
/* -------------------------------------------------------------------- */
/**
* @function: SchProcessPreBeaconInd
*
* @brief : Process the PreBeacon Indication from the Lim
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param : pMac - tpAniSirGlobal
*
* @return None
*/
void sch_process_pre_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tpBeaconGenParams pMsg = (tpBeaconGenParams) limMsg->bodyptr;
uint32_t beaconSize;
tpPESession psessionEntry;
uint8_t sessionId;
if ((psessionEntry =
pe_find_session_by_bssid(pMac, pMsg->bssId, &sessionId)) == NULL) {
PELOGE(sch_log(pMac, LOGE, FL("session lookup fails"));)
goto end;
}
beaconSize = psessionEntry->schBeaconOffsetBegin;
/* If SME is not in normal mode, no need to generate beacon */
if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE) {
PELOGE(sch_log
(pMac, LOG1,
FL("PreBeaconInd received in invalid state: %d"),
psessionEntry->limSmeState);
)
goto end;
}
switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) {
case eLIM_STA_IN_IBSS_ROLE:
case eLIM_BT_AMP_AP_ROLE:
case eLIM_BT_AMP_STA_ROLE:
/* generate IBSS parameter set */
if (psessionEntry->statypeForBss == STA_ENTRY_SELF)
write_beacon_to_memory(pMac, (uint16_t) beaconSize,
(uint16_t) beaconSize,
psessionEntry);
else
PELOGE(sch_log
(pMac, LOGE,
FL
("can not send beacon for PEER session entry"));
)
break;
case eLIM_AP_ROLE: {
uint8_t *ptr =
&psessionEntry->pSchBeaconFrameBegin[psessionEntry->
schBeaconOffsetBegin];
uint16_t timLength = 0;
if (psessionEntry->statypeForBss == STA_ENTRY_SELF) {
sch_generate_tim(pMac, &ptr, &timLength,
psessionEntry->dtimPeriod);
beaconSize += 2 + timLength;
write_beacon_to_memory(pMac, (uint16_t) beaconSize,
(uint16_t) beaconSize,
psessionEntry);
} else
PELOGE(sch_log
(pMac, LOGE,
FL
("can not send beacon for PEER session entry"));
)
}
break;
default:
PELOGE(sch_log
(pMac, LOGE,
FL
("Error-PE has Receive PreBeconGenIndication when System is in %d role"),
GET_LIM_SYSTEM_ROLE(psessionEntry));
)
}
end:
cdf_mem_free(pMsg);
}