| /* |
| * Copyright (c) 2012-2016 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_process.cc contains beacon processing related |
| * functions |
| * |
| * Author: Sandesh Goel |
| * Date: 02/25/02 |
| * History:- |
| * Date Modified by Modification Information |
| * -------------------------------------------------------------------- |
| * |
| */ |
| |
| #include "cds_api.h" |
| #include "wni_cfg.h" |
| |
| #include "cfg_api.h" |
| #include "lim_api.h" |
| #include "utils_api.h" |
| #include "sch_debug.h" |
| #include "sch_api.h" |
| |
| #include "lim_utils.h" |
| #include "lim_send_messages.h" |
| #include "lim_sta_hash_api.h" |
| |
| #include "rrm_api.h" |
| |
| #ifdef FEATURE_WLAN_DIAG_SUPPORT |
| #include "host_diag_core_log.h" |
| #endif /* FEATURE_WLAN_DIAG_SUPPORT */ |
| |
| #include "wma.h" |
| /** |
| * Number of bytes of variation in beacon length from the last beacon |
| * to trigger reprogramming of rx delay register |
| */ |
| #define SCH_BEACON_LEN_DELTA 3 |
| |
| /* calculate 2^cw - 1 */ |
| #define CW_GET(cw) (((cw) == 0) ? 1 : ((1 << (cw)) - 1)) |
| |
| static void |
| ap_beacon_process_5_ghz(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, |
| tpSchBeaconStruct bcn_struct, |
| tpUpdateBeaconParams bcn_prm, tpPESession session, |
| uint32_t phy_mode) |
| { |
| tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); |
| if (!session->htCapability) |
| return; |
| |
| if (bcn_struct->channelNumber != session->currentOperChannel) |
| return; |
| |
| /* 11a (non HT) AP overlaps or */ |
| /* HT AP with HT op mode as mixed overlaps. */ |
| /* HT AP with HT op mode as overlap legacy overlaps. */ |
| if (!bcn_struct->HTInfo.present |
| || (eSIR_HT_OP_MODE_MIXED == bcn_struct->HTInfo.opMode) |
| || (eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode)) { |
| lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, |
| &(mac_ctx->lim.gLimOverlap11aParams)); |
| |
| if (mac_ctx->lim.gLimOverlap11aParams.numSta |
| && !mac_ctx->lim.gLimOverlap11aParams.protectionEnabled) { |
| lim_update_11a_protection(mac_ctx, true, true, |
| bcn_prm, session); |
| } |
| return; |
| } |
| /* HT AP with HT20 op mode overlaps. */ |
| if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT != bcn_struct->HTInfo.opMode) |
| return; |
| |
| lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, |
| &(mac_ctx->lim.gLimOverlapHt20Params)); |
| |
| if (mac_ctx->lim.gLimOverlapHt20Params.numSta |
| && !mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled) |
| lim_enable_ht20_protection(mac_ctx, true, true, |
| bcn_prm, session); |
| } |
| |
| static void |
| ap_beacon_process_24_ghz(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, |
| tpSchBeaconStruct bcn_struct, |
| tpUpdateBeaconParams bcn_prm, tpPESession session, |
| uint32_t phy_mode) |
| { |
| tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); |
| bool tmp_exp = false; |
| /* We are 11G AP. */ |
| if ((phy_mode == WNI_CFG_PHY_MODE_11G) && |
| (false == session->htCapability)) { |
| if (bcn_struct->channelNumber != session->currentOperChannel) |
| return; |
| |
| tmp_exp = (!bcn_struct->erpPresent |
| && !bcn_struct->HTInfo.present) |
| /* if erp not present then 11B AP overlapping */ |
| || (!mac_ctx->roam.configParam.ignore_peer_erp_info && |
| bcn_struct->erpPresent && |
| (bcn_struct->erpIEInfo.useProtection |
| || bcn_struct->erpIEInfo.nonErpPresent)); |
| if (!tmp_exp) |
| return; |
| #ifdef FEATURE_WLAN_ESE |
| if (session->isESEconnection) |
| QDF_TRACE(QDF_MODULE_ID_PE, |
| QDF_TRACE_LEVEL_INFO, |
| FL("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d"), |
| bcn_struct->erpPresent, |
| bcn_struct->erpIEInfo.useProtection, |
| bcn_struct->erpIEInfo.nonErpPresent); |
| #endif |
| lim_enable_overlap11g_protection(mac_ctx, bcn_prm, |
| mac_hdr, session); |
| return; |
| } |
| /* handling the case when HT AP has overlapping legacy BSS. */ |
| if (!session->htCapability) |
| return; |
| |
| if (bcn_struct->channelNumber != session->currentOperChannel) |
| return; |
| |
| tmp_exp = (!bcn_struct->erpPresent && !bcn_struct->HTInfo.present) |
| /* if erp not present then 11B AP overlapping */ |
| || (!mac_ctx->roam.configParam.ignore_peer_erp_info && |
| bcn_struct->erpPresent && |
| (bcn_struct->erpIEInfo.useProtection |
| || bcn_struct->erpIEInfo.nonErpPresent)); |
| if (tmp_exp) { |
| #ifdef FEATURE_WLAN_ESE |
| if (session->isESEconnection) { |
| QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, |
| FL("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d"), |
| bcn_struct->erpPresent, |
| bcn_struct->erpIEInfo.useProtection, |
| bcn_struct->erpIEInfo.nonErpPresent); |
| } |
| #endif |
| lim_enable_overlap11g_protection(mac_ctx, bcn_prm, |
| mac_hdr, session); |
| } |
| /* 11g device overlaps */ |
| tmp_exp = bcn_struct->erpPresent |
| && !(bcn_struct->erpIEInfo.useProtection |
| || bcn_struct->erpIEInfo.nonErpPresent) |
| && !(bcn_struct->HTInfo.present); |
| if (tmp_exp) { |
| lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, |
| &(session->gLimOverlap11gParams)); |
| |
| if (session->gLimOverlap11gParams.numSta |
| && !session->gLimOverlap11gParams.protectionEnabled) |
| lim_enable_ht_protection_from11g(mac_ctx, true, true, |
| bcn_prm, session); |
| } |
| /* ht device overlaps. |
| * here we will check for HT related devices only which might need |
| * protection. check for 11b and 11g is already done in the previous |
| * blocks. so we will not check for HT operating mode as MIXED. |
| */ |
| if (!bcn_struct->HTInfo.present) |
| return; |
| |
| /* |
| * if we are not already in mixed mode or legacy mode as HT operating |
| * mode and received beacon has HT operating mode as legacy then we need |
| * to enable protection from 11g station. we don't need protection from |
| * 11b because if that's needed then our operating mode would have |
| * already been set to legacy in the previous blocks. |
| */ |
| if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode) && |
| !mac_ctx->roam.configParam.ignore_peer_ht_opmode) { |
| if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == mac_ctx->lim.gHTOperMode |
| || eSIR_HT_OP_MODE_MIXED == mac_ctx->lim.gHTOperMode) |
| return; |
| lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, |
| &(session->gLimOverlap11gParams)); |
| if (session->gLimOverlap11gParams.numSta |
| && !session->gLimOverlap11gParams.protectionEnabled) |
| lim_enable_ht_protection_from11g(mac_ctx, true, true, |
| bcn_prm, session); |
| return; |
| } |
| |
| if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == bcn_struct->HTInfo.opMode) { |
| lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, |
| &(session->gLimOverlapHt20Params)); |
| if (session->gLimOverlapHt20Params.numSta |
| && !session->gLimOverlapHt20Params.protectionEnabled) |
| lim_enable_ht20_protection(mac_ctx, true, true, |
| bcn_prm, session); |
| } |
| } |
| |
| /** |
| * ap_beacon_process() - processes incoming beacons |
| * |
| * @mac_ctx: mac global context |
| * @rx_pkt_info: incoming beacon packet |
| * @bcn_struct: beacon struct |
| * @bcn_prm: beacon params |
| * @session: pe session entry |
| * |
| * Return: void |
| */ |
| static void |
| ap_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, |
| tpSchBeaconStruct bcn_struct, |
| tpUpdateBeaconParams bcn_prm, tpPESession session) |
| { |
| uint32_t phy_mode; |
| tSirRFBand rf_band = SIR_BAND_UNKNOWN; |
| /* Get RF band from session */ |
| rf_band = session->limRFBand; |
| |
| lim_get_phy_mode(mac_ctx, &phy_mode, session); |
| |
| if (SIR_BAND_5_GHZ == rf_band) |
| ap_beacon_process_5_ghz(mac_ctx, rx_pkt_info, bcn_struct, |
| bcn_prm, session, phy_mode); |
| else if (SIR_BAND_2_4_GHZ == rf_band) |
| ap_beacon_process_24_ghz(mac_ctx, rx_pkt_info, bcn_struct, |
| bcn_prm, session, phy_mode); |
| mac_ctx->sch.gSchBcnIgnored++; |
| } |
| |
| /* -------------------------------------------------------------------- */ |
| |
| /** |
| * __sch_beacon_process_no_session |
| * |
| * FUNCTION: |
| * Process the received beacon frame when |
| * -- Station is not scanning |
| * -- No corresponding session is found |
| * |
| * LOGIC: |
| * Following scenarios exist when Session Does not exist: |
| * * IBSS Beacons, when IBSS session already exists with same SSID, |
| * but from STA which has not yet joined and has a different BSSID. |
| * - invoke lim_handle_ibs_scoalescing with the session context of existing IBSS session. |
| * |
| * * IBSS Beacons when IBSS session does not exist, only Infra or BT-AMP session exists, |
| * then save the beacon in the scan results and throw it away. |
| * |
| * * Infra Beacons |
| * - beacons received when no session active |
| * should not come here, it should be handled as part of scanning, |
| * else they should not be getting received, should update scan results and drop it if that happens. |
| * - beacons received when IBSS session active: |
| * update scan results and drop it. |
| * - beacons received when Infra session(STA) is active: |
| * update scan results and drop it |
| * - beacons received when BT-STA session is active: |
| * update scan results and drop it. |
| * - beacons received when Infra/BT-STA or Infra/IBSS is active. |
| * update scan results and drop it. |
| * |
| |
| */ |
| static void __sch_beacon_process_no_session(tpAniSirGlobal pMac, |
| tpSchBeaconStruct pBeacon, |
| uint8_t *pRxPacketInfo) |
| { |
| tpPESession psessionEntry = NULL; |
| |
| psessionEntry = lim_is_ibss_session_active(pMac); |
| if (psessionEntry != NULL) { |
| lim_handle_ibss_coalescing(pMac, pBeacon, pRxPacketInfo, |
| psessionEntry); |
| } |
| /* If station(STA/BT-STA/BT-AP/IBSS) mode, Always save the |
| * beacon in the scan results, if atleast one session is |
| * active. sch_beacon_process_no_session will be called only |
| * when there is atleast one session active, so not checking |
| * it again here. |
| */ |
| lim_check_and_add_bss_description(pMac, pBeacon, pRxPacketInfo, false, |
| false); |
| return; |
| } |
| |
| /** |
| * get_operating_channel_width() - Get operating channel width |
| * @stads - station entry. |
| * |
| * This function returns the operating channel width based on |
| * the supported channel width entry. |
| * |
| * Return: tSirMacHTChannelWidth on success |
| */ |
| static tSirMacHTChannelWidth get_operating_channel_width(tpDphHashNode stads) |
| { |
| tSirMacHTChannelWidth ch_width = eHT_CHANNEL_WIDTH_20MHZ; |
| |
| if (stads->vhtSupportedChannelWidthSet == |
| WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) |
| ch_width = eHT_CHANNEL_WIDTH_160MHZ; |
| else if (stads->vhtSupportedChannelWidthSet == |
| WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) |
| ch_width = eHT_CHANNEL_WIDTH_160MHZ; |
| else if (stads->vhtSupportedChannelWidthSet == |
| WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) |
| ch_width = eHT_CHANNEL_WIDTH_80MHZ; |
| else if (stads->htSupportedChannelWidthSet) |
| ch_width = eHT_CHANNEL_WIDTH_40MHZ; |
| else |
| ch_width = eHT_CHANNEL_WIDTH_20MHZ; |
| |
| return ch_width; |
| } |
| |
| /* |
| * sch_bcn_process_sta() - Process the received beacon frame for sta, |
| * bt_amp_sta |
| * |
| * @mac_ctx: mac_ctx |
| * @bcn: beacon struct |
| * @rx_pkt_info: received packet info |
| * @session: pe session pointer |
| * @bssIdx: bss index |
| * @beaconParams: update beacon params |
| * @sendProbeReq: out flag to indicate if probe rsp is to be sent |
| * @pMh: mac header |
| * |
| * Process the received beacon frame for sta |
| * |
| * Return: success of failure of operation |
| */ |
| static bool |
| sch_bcn_process_sta(tpAniSirGlobal mac_ctx, |
| tpSchBeaconStruct bcn, |
| uint8_t *rx_pkt_info, |
| tpPESession session, uint8_t *bssIdx, |
| tUpdateBeaconParams *beaconParams, |
| uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) |
| { |
| uint32_t bi; |
| tpDphHashNode pStaDs = NULL; |
| /* |
| * This handles two cases: |
| * -- Infra STA receving beacons from AP |
| */ |
| /* Always save the beacon into LIM's cached scan results */ |
| lim_check_and_add_bss_description(mac_ctx, bcn, rx_pkt_info, |
| false, false); |
| |
| /** |
| * This is the Beacon received from the AP we're currently associated |
| * with. Check if there are any changes in AP's capabilities |
| */ |
| if ((uint8_t) bcn->channelNumber != session->currentOperChannel) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Channel Change from %d --> %d - Ignoring beacon!"), |
| session->currentOperChannel, |
| bcn->channelNumber);) |
| return false; |
| } |
| lim_detect_change_in_ap_capabilities(mac_ctx, bcn, session); |
| if (lim_get_sta_hash_bssidx(mac_ctx, DPH_STA_HASH_INDEX_PEER, bssIdx, |
| session) != eSIR_SUCCESS) |
| return false; |
| |
| beaconParams->bssIdx = *bssIdx; |
| qdf_mem_copy((uint8_t *) &session->lastBeaconTimeStamp, |
| (uint8_t *) bcn->timeStamp, sizeof(uint64_t)); |
| session->lastBeaconDtimCount = bcn->tim.dtimCount; |
| session->currentBssBeaconCnt++; |
| if (session->lastBeaconDtimPeriod != bcn->tim.dtimPeriod) { |
| session->lastBeaconDtimPeriod = bcn->tim.dtimPeriod; |
| lim_send_set_dtim_period(mac_ctx, bcn->tim.dtimPeriod, |
| session); |
| } |
| MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, |
| session->peSessionId, bcn->timeStamp[0]);) |
| MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, |
| session->peSessionId, bcn->timeStamp[1]);) |
| |
| /* Read beacon interval session Entry */ |
| bi = session->beaconParams.beaconInterval; |
| if (bi != bcn->beaconInterval) { |
| PELOG1(sch_log(mac_ctx, LOG1, |
| FL("Beacon interval changed from %d to %d"), |
| bcn->beaconInterval, bi);) |
| |
| bi = bcn->beaconInterval; |
| session->beaconParams.beaconInterval = (uint16_t) bi; |
| beaconParams->paramChangeBitmap |= PARAM_BCN_INTERVAL_CHANGED; |
| beaconParams->beaconInterval = (uint16_t) bi; |
| } |
| |
| if (bcn->cfPresent) { |
| cfg_set_int(mac_ctx, WNI_CFG_CFP_PERIOD, |
| bcn->cfParamSet.cfpPeriod); |
| lim_send_cf_params(mac_ctx, *bssIdx, |
| bcn->cfParamSet.cfpCount, |
| bcn->cfParamSet.cfpPeriod); |
| } |
| |
| /* No need to send DTIM Period and Count to HAL/SMAC */ |
| /* SMAC already parses TIM bit. */ |
| if (bcn->timPresent) |
| cfg_set_int(mac_ctx, WNI_CFG_DTIM_PERIOD, bcn->tim.dtimPeriod); |
| |
| if (mac_ctx->lim.gLimProtectionControl != |
| WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) |
| lim_decide_sta_protection(mac_ctx, bcn, beaconParams, session); |
| |
| if (bcn->erpPresent) { |
| if (bcn->erpIEInfo.barkerPreambleMode) |
| lim_enable_short_preamble(mac_ctx, false, |
| beaconParams, session); |
| else |
| lim_enable_short_preamble(mac_ctx, true, |
| beaconParams, session); |
| } |
| lim_update_short_slot(mac_ctx, bcn, beaconParams, session); |
| |
| pStaDs = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, |
| &session->dph.dphHashTable); |
| if ((bcn->wmeEdcaPresent && (session->limWmeEnabled)) |
| || (bcn->edcaPresent && (session->limQosEnabled))) { |
| if (bcn->edcaParams.qosInfo.count != |
| session->gLimEdcaParamSetCount) { |
| if (sch_beacon_edca_process(mac_ctx, &bcn->edcaParams, |
| session) != eSIR_SUCCESS) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("EDCA parameter processing error"));) |
| } else if (pStaDs != NULL) { |
| /* If needed, downgrade the EDCA parameters */ |
| lim_set_active_edca_params(mac_ctx, |
| session->gLimEdcaParams, session); |
| lim_send_edca_params(mac_ctx, |
| session->gLimEdcaParamsActive, |
| pStaDs->bssId); |
| } else { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Self Entry missing in Hash Table"));) |
| } |
| } |
| return true; |
| } |
| |
| if ((bcn->qosCapabilityPresent && session->limQosEnabled) |
| && (bcn->qosCapability.qosInfo.count != |
| session->gLimEdcaParamSetCount)) |
| *sendProbeReq = true; |
| |
| return true; |
| } |
| |
| /** |
| * update_nss() - Function to update NSS |
| * @mac_ctx: pointer to Global Mac structure |
| * @sta_ds: pointer to tpDphHashNode |
| * @beacon: pointer to tpSchBeaconStruct |
| * @session_entry: pointer to tpPESession |
| * @mgmt_hdr: pointer to tpSirMacMgmtHdr |
| * |
| * function to update NSS |
| * |
| * Return: none |
| */ |
| static void update_nss(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, |
| tpSchBeaconStruct beacon, tpPESession session_entry, |
| tpSirMacMgmtHdr mgmt_hdr) |
| { |
| if (sta_ds->vhtSupportedRxNss != (beacon->OperatingMode.rxNSS + 1)) { |
| sta_ds->vhtSupportedRxNss = beacon->OperatingMode.rxNSS; |
| lim_set_nss_change(mac_ctx, session_entry, |
| sta_ds->vhtSupportedRxNss, sta_ds->staIndex, |
| mgmt_hdr->sa); |
| } |
| } |
| |
| /* |
| * sch_bcn_process_sta_ibss() - Process the received beacon frame |
| * for sta, bt_amp_sta and ibss |
| * |
| * @mac_ctx: mac_ctx |
| * @bcn: beacon struct |
| * @rx_pkt_info: received packet info |
| * @session: pe session pointer |
| * @bssIdx: bss index |
| * @beaconParams: update beacon params |
| * @sendProbeReq: out flag to indicate if probe rsp is to be sent |
| * @pMh: mac header |
| * |
| * Process the received beacon frame for sta and ibss |
| * |
| * Return: void |
| */ |
| static void |
| sch_bcn_process_sta_ibss(tpAniSirGlobal mac_ctx, |
| tpSchBeaconStruct bcn, |
| uint8_t *rx_pkt_info, |
| tpPESession session, uint8_t *bssIdx, |
| tUpdateBeaconParams *beaconParams, |
| uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) |
| { |
| tpDphHashNode pStaDs = NULL; |
| uint16_t aid; |
| uint8_t operMode; |
| uint8_t chWidth = 0; |
| uint8_t cb_mode; |
| uint32_t fw_vht_ch_wd = wma_get_vht_ch_width(); |
| bool skip_opmode_update = false; |
| |
| if (CHAN_ENUM_14 >= session->currentOperChannel) |
| cb_mode = mac_ctx->roam.configParam.channelBondingMode24GHz; |
| else |
| cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz; |
| /* check for VHT capability */ |
| pStaDs = dph_lookup_hash_entry(mac_ctx, pMh->sa, &aid, |
| &session->dph.dphHashTable); |
| if ((NULL == pStaDs) || |
| (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode) || |
| ((NULL != pStaDs) && |
| (STA_INVALID_IDX == pStaDs->staIndex))) |
| return; |
| |
| if (session->vhtCapability && bcn->OperatingMode.present) { |
| operMode = get_operating_channel_width(pStaDs); |
| if ((operMode == eHT_CHANNEL_WIDTH_80MHZ) && |
| (bcn->OperatingMode.chanWidth > eHT_CHANNEL_WIDTH_80MHZ)) |
| skip_opmode_update = true; |
| |
| if (!skip_opmode_update && |
| (operMode != bcn->OperatingMode.chanWidth)) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("received OpMode Chanwidth %d, staIdx = %d"), |
| bcn->OperatingMode.chanWidth, pStaDs->staIndex);) |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("MAC - %0x:%0x:%0x:%0x:%0x:%0x"), |
| pMh->sa[0], pMh->sa[1], |
| pMh->sa[2], pMh->sa[3], |
| pMh->sa[4], pMh->sa[5]);) |
| |
| if ((bcn->OperatingMode.chanWidth >= |
| eHT_CHANNEL_WIDTH_160MHZ) && |
| (fw_vht_ch_wd > eHT_CHANNEL_WIDTH_80MHZ)) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 160MHz"));) |
| pStaDs->vhtSupportedChannelWidthSet = |
| WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_40MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_160MHZ; |
| } else if (bcn->OperatingMode.chanWidth >= |
| eHT_CHANNEL_WIDTH_80MHZ) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 80MHz"));) |
| pStaDs->vhtSupportedChannelWidthSet = |
| WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_40MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_80MHZ; |
| } else if (bcn->OperatingMode.chanWidth == |
| eHT_CHANNEL_WIDTH_40MHZ) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 40MHz"));) |
| pStaDs->vhtSupportedChannelWidthSet = |
| WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_40MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_40MHZ; |
| } else if (bcn->OperatingMode.chanWidth == |
| eHT_CHANNEL_WIDTH_20MHZ) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 20MHz"));) |
| pStaDs->vhtSupportedChannelWidthSet = |
| WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_20MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_20MHZ; |
| } |
| lim_check_vht_op_mode_change(mac_ctx, session, |
| chWidth, pStaDs->staIndex, pMh->sa); |
| update_nss(mac_ctx, pStaDs, bcn, session, pMh); |
| } |
| return; |
| } |
| |
| if (!(session->vhtCapability && bcn->VHTOperation.present)) |
| return; |
| |
| operMode = pStaDs->vhtSupportedChannelWidthSet; |
| if ((operMode == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && |
| (operMode < bcn->VHTOperation.chanWidth)) |
| skip_opmode_update = true; |
| |
| if (!skip_opmode_update && |
| (operMode != bcn->VHTOperation.chanWidth)) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("received VHTOP CHWidth %d staIdx = %d"), |
| bcn->VHTOperation.chanWidth, pStaDs->staIndex);) |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"), |
| pMh->sa[0], pMh->sa[1], |
| pMh->sa[2], pMh->sa[3], |
| pMh->sa[4], pMh->sa[5]);) |
| |
| if ((bcn->VHTOperation.chanWidth >= |
| WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) && |
| (fw_vht_ch_wd > eHT_CHANNEL_WIDTH_80MHZ)) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 160MHz"));) |
| pStaDs->vhtSupportedChannelWidthSet = |
| bcn->VHTOperation.chanWidth; |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_40MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_160MHZ; |
| } else if (bcn->VHTOperation.chanWidth >= |
| WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 80MHz"));) |
| pStaDs->vhtSupportedChannelWidthSet = |
| WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_40MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_80MHZ; |
| } else if (bcn->VHTOperation.chanWidth == |
| WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ) { |
| pStaDs->vhtSupportedChannelWidthSet = |
| WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; |
| if (bcn->HTCaps.supportedChannelWidthSet) { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 40MHz"));) |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_40MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_40MHZ; |
| } else { |
| PELOGE(sch_log(mac_ctx, LOGE, |
| FL("Updating the CH Width to 20MHz"));) |
| pStaDs->htSupportedChannelWidthSet = |
| eHT_CHANNEL_WIDTH_20MHZ; |
| chWidth = eHT_CHANNEL_WIDTH_20MHZ; |
| } |
| } |
| lim_check_vht_op_mode_change(mac_ctx, session, chWidth, |
| pStaDs->staIndex, pMh->sa); |
| } |
| return; |
| } |
| |
| /** |
| * get_local_power_constraint_beacon() - extracts local constraint |
| * from beacon |
| * @bcn: beacon structure |
| * @local_constraint: local constraint pointer |
| * |
| * Return: None |
| */ |
| #ifdef FEATURE_WLAN_ESE |
| static void get_local_power_constraint_beacon( |
| tpSchBeaconStruct bcn, |
| int8_t *local_constraint) |
| { |
| if (bcn->eseTxPwr.present) |
| *local_constraint = bcn->eseTxPwr.power_limit; |
| } |
| #else |
| static void get_local_power_constraint_beacon( |
| tpSchBeaconStruct bcn, |
| int8_t *local_constraint) |
| { |
| |
| } |
| #endif |
| |
| /* |
| * __sch_beacon_process_for_session() - Process the received beacon frame when |
| * station is not scanning and corresponding session is found |
| * |
| * |
| * @mac_ctx: mac_ctx |
| * @bcn: beacon struct |
| * @rx_pkt_info: received packet info |
| * @session: pe session pointer |
| * |
| * Following scenarios exist when Session exists |
| * IBSS STA receving beacons from IBSS Peers, who are part of IBSS. |
| * - call lim_handle_ibs_scoalescing with that session context. |
| * Infra STA receving beacons from AP to which it is connected |
| * - call sch_beacon_processFromAP with that session's context. |
| * - call sch_beacon_processFromAP with that session's context. |
| * (here need to make sure BTAP creates session entry for BT STA) |
| * - just update the beacon count for heart beat purposes for now, |
| * for now, don't process the beacon. |
| * Infra/IBSS both active and receives IBSS beacon: |
| * - call lim_handle_ibs_scoalescing with that session context. |
| * Infra/IBSS both active and receives Infra beacon: |
| * - call sch_beacon_processFromAP with that session's context. |
| * any updates to EDCA parameters will be effective for IBSS as well, |
| * even though no WMM for IBSS ?? Need to figure out how to handle |
| * this scenario. |
| * Infra/BTSTA both active and receive Infra beacon. |
| * - change in EDCA parameters on Infra affect the BTSTA link. |
| * Update the same parameters on BT link |
| * Infra/BTSTA both active and receive BT-AP beacon. |
| * - update beacon cnt for heartbeat |
| * Infra/BTAP both active and receive Infra beacon. |
| * - BT-AP starts advertising BE parameters from Infra AP, if they get |
| * changed. |
| * Infra/BTAP both active and receive BTSTA beacon. |
| * - update beacon cnt for heartbeat |
| * |
| * Return: void |
| */ |
| static void __sch_beacon_process_for_session(tpAniSirGlobal mac_ctx, |
| tpSchBeaconStruct bcn, |
| uint8_t *rx_pkt_info, |
| tpPESession session) |
| { |
| uint8_t bssIdx = 0; |
| tUpdateBeaconParams beaconParams; |
| uint8_t sendProbeReq = false; |
| tpSirMacMgmtHdr pMh = WMA_GET_RX_MAC_HEADER(rx_pkt_info); |
| int8_t regMax = 0, maxTxPower = 0, local_constraint; |
| qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); |
| beaconParams.paramChangeBitmap = 0; |
| |
| if (LIM_IS_IBSS_ROLE(session)) { |
| lim_handle_ibss_coalescing(mac_ctx, bcn, rx_pkt_info, session); |
| } else if (LIM_IS_STA_ROLE(session)) { |
| if (false == sch_bcn_process_sta(mac_ctx, bcn, |
| rx_pkt_info, session, &bssIdx, |
| &beaconParams, &sendProbeReq, pMh)) |
| return; |
| } |
| |
| if (session->htCapability && bcn->HTInfo.present && |
| !LIM_IS_IBSS_ROLE(session)) |
| lim_update_sta_run_time_ht_switch_chnl_params(mac_ctx, |
| &bcn->HTInfo, bssIdx, session); |
| |
| if (LIM_IS_STA_ROLE(session) |
| || LIM_IS_IBSS_ROLE(session)) { |
| /* Channel Switch information element updated */ |
| if (bcn->channelSwitchPresent) { |
| /* |
| * on receiving channel switch announcement from AP, |
| * delete all TDLS peers before leaving BSS and proceed |
| * for channel switch |
| */ |
| if (LIM_IS_STA_ROLE(session)) |
| lim_delete_tdls_peers(mac_ctx, session); |
| |
| lim_update_channel_switch(mac_ctx, bcn, session); |
| } else if (session->gLimSpecMgmt.dot11hChanSwState == |
| eLIM_11H_CHANSW_RUNNING) { |
| lim_cancel_dot11h_channel_switch(mac_ctx, session); |
| } |
| } |
| if (LIM_IS_STA_ROLE(session) |
| || LIM_IS_IBSS_ROLE(session)) |
| sch_bcn_process_sta_ibss(mac_ctx, bcn, |
| rx_pkt_info, session, &bssIdx, |
| &beaconParams, &sendProbeReq, pMh); |
| /* Obtain the Max Tx power for the current regulatory */ |
| regMax = cfg_get_regulatory_max_transmit_power(mac_ctx, |
| session->currentOperChannel); |
| |
| local_constraint = regMax; |
| |
| if (mac_ctx->roam.configParam.allow_tpc_from_ap) { |
| get_local_power_constraint_beacon(bcn, &local_constraint); |
| sch_log(mac_ctx, LOG1, "ESE localPowerConstraint = %d,", |
| local_constraint); |
| |
| if (mac_ctx->rrm.rrmPEContext.rrmEnable && |
| bcn->powerConstraintPresent) { |
| local_constraint = regMax; |
| local_constraint -= |
| bcn->localPowerConstraint.localPowerConstraints; |
| sch_log(mac_ctx, LOG1, "localPowerConstraint = %d,", |
| local_constraint); |
| } |
| } |
| |
| maxTxPower = lim_get_max_tx_power(regMax, local_constraint, |
| mac_ctx->roam.configParam.nTxPowerCap); |
| |
| sch_log(mac_ctx, LOG1, "RegMax = %d, MaxTx pwr = %d", |
| regMax, maxTxPower); |
| |
| |
| /* If maxTxPower is increased or decreased */ |
| if (maxTxPower != session->maxTxPower) { |
| sch_log(mac_ctx, LOG1, |
| FL("Local power constraint change, Updating new maxTx power %d from old pwr %d"), |
| maxTxPower, session->maxTxPower); |
| if (lim_send_set_max_tx_power_req(mac_ctx, maxTxPower, session) |
| == eSIR_SUCCESS) |
| session->maxTxPower = maxTxPower; |
| } |
| |
| /* Indicate to LIM that Beacon is received */ |
| if (bcn->HTInfo.present) |
| lim_received_hb_handler(mac_ctx, |
| (uint8_t) bcn->HTInfo.primaryChannel, session); |
| else |
| lim_received_hb_handler(mac_ctx, (uint8_t) bcn->channelNumber, |
| session); |
| |
| /* |
| * I don't know if any additional IE is required here. Currently, not |
| * include addIE. |
| */ |
| if (sendProbeReq) |
| lim_send_probe_req_mgmt_frame(mac_ctx, &session->ssId, |
| session->bssId, session->currentOperChannel, |
| session->selfMacAddr, session->dot11mode, 0, NULL); |
| |
| if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) |
| && beaconParams.paramChangeBitmap) { |
| PELOGW(sch_log(mac_ctx, LOGW, |
| FL("Beacon for session[%d] got changed."), |
| session->peSessionId);) |
| PELOGW(sch_log(mac_ctx, LOGW, |
| FL("sending beacon param change bitmap: 0x%x "), |
| beaconParams.paramChangeBitmap);) |
| lim_send_beacon_params(mac_ctx, &beaconParams, session); |
| } |
| } |
| |
| /** |
| * sch_beacon_process() - process the beacon frame |
| * @mac_ctx: mac global context |
| * @rx_pkt_info: pointer to buffer descriptor |
| * |
| * Return: None |
| */ |
| void |
| sch_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, |
| tpPESession session) |
| { |
| static tSchBeaconStruct bcn; |
| tUpdateBeaconParams bcn_prm; |
| tpPESession ap_session = NULL; |
| uint8_t i; |
| |
| qdf_mem_zero(&bcn_prm, sizeof(tUpdateBeaconParams)); |
| bcn_prm.paramChangeBitmap = 0; |
| mac_ctx->sch.gSchBcnRcvCnt++; |
| /* Convert the beacon frame into a structure */ |
| if (sir_convert_beacon_frame2_struct(mac_ctx, (uint8_t *) rx_pkt_info, |
| &bcn) != eSIR_SUCCESS) { |
| PELOGE(sch_log(mac_ctx, LOGE, FL("beacon parsing failed"));) |
| mac_ctx->sch.gSchBcnParseErrorCnt++; |
| return; |
| } |
| |
| if (bcn.ssidPresent) |
| bcn.ssId.ssId[bcn.ssId.length] = 0; |
| /* |
| * First process the beacon in the context of any existing AP or BTAP |
| * session. This takes cares of following two scenarios: |
| * - session = NULL: |
| * e.g. beacon received from a neighboring BSS, you want to apply the |
| * protection settings to BTAP/InfraAP beacons |
| * - session is non NULL: |
| * e.g. beacon received is from the INFRA AP to which you are connected |
| * on another concurrent link. In this case also, we want to apply the |
| * protection settings(as advertised by Infra AP) to BTAP beacons |
| */ |
| for (i = 0; i < mac_ctx->lim.maxBssId; i++) { |
| ap_session = pe_find_session_by_session_id(mac_ctx, i); |
| if (!((ap_session != NULL) && |
| (!(WMA_GET_OFFLOADSCANLEARN(rx_pkt_info))))) |
| continue; |
| |
| if (!LIM_IS_AP_ROLE(ap_session)) |
| continue; |
| |
| bcn_prm.bssIdx = ap_session->bssIdx; |
| if (ap_session->gLimProtectionControl != |
| WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) |
| ap_beacon_process(mac_ctx, rx_pkt_info, |
| &bcn, &bcn_prm, ap_session); |
| |
| if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) |
| && bcn_prm.paramChangeBitmap) { |
| /* Update the bcn and apply the new settings to HAL */ |
| sch_set_fixed_beacon_fields(mac_ctx, ap_session); |
| PELOG1(sch_log(mac_ctx, LOG1, |
| FL("Beacon for PE session[%d] got changed."), |
| ap_session->peSessionId);) |
| PELOG1(sch_log(mac_ctx, LOG1, |
| FL("sending beacon param change bitmap: 0x%x"), |
| bcn_prm.paramChangeBitmap);) |
| lim_send_beacon_params(mac_ctx, &bcn_prm, ap_session); |
| } |
| } |
| |
| /* |
| * Now process the beacon in the context of the BSS which is |
| * transmitting the beacons, if one is found |
| */ |
| if (session == NULL) |
| __sch_beacon_process_no_session(mac_ctx, &bcn, rx_pkt_info); |
| else |
| __sch_beacon_process_for_session(mac_ctx, &bcn, rx_pkt_info, |
| session); |
| } |
| |
| /** |
| * sch_beacon_edca_process(): Process the EDCA parameter set in the received |
| * beacon frame |
| * |
| * @mac_ctx: mac global context |
| * @edca: reference to edca parameters in beacon struct |
| * @session : pesession entry |
| * |
| * @return status of operation |
| */ |
| tSirRetStatus |
| sch_beacon_edca_process(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *edca, |
| tpPESession session) |
| { |
| uint8_t i; |
| #ifdef FEATURE_WLAN_DIAG_SUPPORT |
| host_log_qos_edca_pkt_type *log_ptr = NULL; |
| #endif /* FEATURE_WLAN_DIAG_SUPPORT */ |
| |
| sch_log(pMac, LOG2, |
| FL("Updating parameter set count: Old %d ---> new %d"), |
| session->gLimEdcaParamSetCount, edca->qosInfo.count); |
| |
| session->gLimEdcaParamSetCount = edca->qosInfo.count; |
| session->gLimEdcaParams[EDCA_AC_BE] = edca->acbe; |
| session->gLimEdcaParams[EDCA_AC_BK] = edca->acbk; |
| session->gLimEdcaParams[EDCA_AC_VI] = edca->acvi; |
| session->gLimEdcaParams[EDCA_AC_VO] = edca->acvo; |
| |
| if (pMac->roam.configParam.enable_edca_params) { |
| session->gLimEdcaParams[EDCA_AC_VO].aci.aifsn = |
| pMac->roam.configParam.edca_vo_aifs; |
| session->gLimEdcaParams[EDCA_AC_VI].aci.aifsn = |
| pMac->roam.configParam.edca_vi_aifs; |
| session->gLimEdcaParams[EDCA_AC_BK].aci.aifsn = |
| pMac->roam.configParam.edca_bk_aifs; |
| session->gLimEdcaParams[EDCA_AC_BE].aci.aifsn = |
| pMac->roam.configParam.edca_be_aifs; |
| |
| session->gLimEdcaParams[EDCA_AC_VO].cw.min = |
| pMac->roam.configParam.edca_vo_cwmin; |
| session->gLimEdcaParams[EDCA_AC_VI].cw.min = |
| pMac->roam.configParam.edca_vi_cwmin; |
| session->gLimEdcaParams[EDCA_AC_BK].cw.min = |
| pMac->roam.configParam.edca_bk_cwmin; |
| session->gLimEdcaParams[EDCA_AC_BE].cw.min = |
| pMac->roam.configParam.edca_be_cwmin; |
| |
| session->gLimEdcaParams[EDCA_AC_VO].cw.max = |
| pMac->roam.configParam.edca_vo_cwmax; |
| session->gLimEdcaParams[EDCA_AC_VI].cw.max = |
| pMac->roam.configParam.edca_vi_cwmax; |
| session->gLimEdcaParams[EDCA_AC_BK].cw.max = |
| pMac->roam.configParam.edca_bk_cwmax; |
| session->gLimEdcaParams[EDCA_AC_BE].cw.max = |
| pMac->roam.configParam.edca_be_cwmax; |
| } |
| #ifdef FEATURE_WLAN_DIAG_SUPPORT |
| WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type, |
| LOG_WLAN_QOS_EDCA_C); |
| if (log_ptr) { |
| log_ptr->aci_be = session->gLimEdcaParams[EDCA_AC_BE].aci.aci; |
| log_ptr->cw_be = |
| session->gLimEdcaParams[EDCA_AC_BE].cw.max << 4 |
| | session->gLimEdcaParams[EDCA_AC_BE].cw.min; |
| log_ptr->txoplimit_be = |
| session->gLimEdcaParams[EDCA_AC_BE].txoplimit; |
| log_ptr->aci_bk = |
| session->gLimEdcaParams[EDCA_AC_BK].aci.aci; |
| log_ptr->cw_bk = |
| session->gLimEdcaParams[EDCA_AC_BK].cw.max << 4 |
| | session->gLimEdcaParams[EDCA_AC_BK].cw.min; |
| log_ptr->txoplimit_bk = |
| session->gLimEdcaParams[EDCA_AC_BK].txoplimit; |
| log_ptr->aci_vi = |
| session->gLimEdcaParams[EDCA_AC_VI].aci.aci; |
| log_ptr->cw_vi = |
| session->gLimEdcaParams[EDCA_AC_VI].cw.max << 4 |
| | session->gLimEdcaParams[EDCA_AC_VI].cw.min; |
| log_ptr->txoplimit_vi = |
| session->gLimEdcaParams[EDCA_AC_VI].txoplimit; |
| log_ptr->aci_vo = |
| session->gLimEdcaParams[EDCA_AC_VO].aci.aci; |
| log_ptr->cw_vo = |
| session->gLimEdcaParams[EDCA_AC_VO].cw.max << 4 |
| | session->gLimEdcaParams[EDCA_AC_VO].cw.min; |
| log_ptr->txoplimit_vo = |
| session->gLimEdcaParams[EDCA_AC_VO].txoplimit; |
| } |
| WLAN_HOST_DIAG_LOG_REPORT(log_ptr); |
| #endif /* FEATURE_WLAN_DIAG_SUPPORT */ |
| sch_log(pMac, LOG1, |
| FL("Edsa param enabled in ini %d. Updating Local EDCA Params(gLimEdcaParams) to: "), |
| pMac->roam.configParam.enable_edca_params); |
| for (i = 0; i < MAX_NUM_AC; i++) { |
| sch_log(pMac, LOG1, |
| FL("AC[%d]: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d"), |
| i, session->gLimEdcaParams[i].aci.aifsn, |
| session->gLimEdcaParams[i].aci.acm, |
| session->gLimEdcaParams[i].cw.min, |
| session->gLimEdcaParams[i].cw.max, |
| session->gLimEdcaParams[i].txoplimit); |
| } |
| return eSIR_SUCCESS; |
| } |