blob: 3a72a69ba418eae0ed68ba0d535476d09be311b7 [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 lim_process_beacon_frame.cc contains the code
* for processing Received Beacon Frame.
* Author: Chandra Modumudi
* Date: 03/01/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
*
*/
#include "wni_cfg.h"
#include "ani_global.h"
#include "cfg_api.h"
#include "sch_api.h"
#include "utils_api.h"
#include "lim_types.h"
#include "lim_utils.h"
#include "lim_assoc_utils.h"
#include "lim_prop_exts_utils.h"
#include "lim_ser_des_utils.h"
/**
* lim_process_beacon_frame() - to process beacon frames
* @mac_ctx: Pointer to Global MAC structure
* @rx_pkt_info: A pointer to RX packet info structure
* @session: A pointer to session
*
* This function is called by limProcessMessageQueue() upon Beacon
* frame reception.
* Note:
* 1. Beacons received in 'normal' state in IBSS are handled by
* Beacon Processing module.
*
* Return: none
*/
void
lim_process_beacon_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info,
tpPESession session)
{
tpSirMacMgmtHdr mac_hdr;
tSchBeaconStruct *bcn_ptr;
mac_ctx->lim.gLimNumBeaconsRcvd++;
/*
* here is it required to increment session specific heartBeat
* beacon counter
*/
mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info);
lim_log(mac_ctx, LOG2,
FL("Received Beacon frame with length=%d from "),
WMA_GET_RX_MPDU_LEN(rx_pkt_info));
lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG2);
/* Expect Beacon in any state as Scan is independent of LIM state */
bcn_ptr = cdf_mem_malloc(sizeof(*bcn_ptr));
if (NULL == bcn_ptr) {
lim_log(mac_ctx, LOGE,
FL("Unable to allocate memory"));
return;
}
/* Parse received Beacon */
if (sir_convert_beacon_frame2_struct(mac_ctx,
rx_pkt_info, bcn_ptr) !=
eSIR_SUCCESS) {
/*
* Received wrongly formatted/invalid Beacon.
* Ignore it and move on.
*/
lim_log(mac_ctx, LOGW,
FL("Received invalid Beacon in state %X"),
session->limMlmState);
lim_print_mlm_state(mac_ctx, LOGW,
session->limMlmState);
cdf_mem_free(bcn_ptr);
return;
}
/*
* during scanning, when any session is active, and
* beacon/Pr belongs to one of the session, fill up the
* following, TBD - HB couter
*/
if ((!session->lastBeaconDtimPeriod) &&
(sir_compare_mac_addr(session->bssId,
bcn_ptr->bssid))) {
cdf_mem_copy((uint8_t *)&session->lastBeaconTimeStamp,
(uint8_t *) bcn_ptr->timeStamp,
sizeof(uint64_t));
session->lastBeaconDtimCount =
bcn_ptr->tim.dtimCount;
session->lastBeaconDtimPeriod =
bcn_ptr->tim.dtimPeriod;
session->currentBssBeaconCnt++;
}
MTRACE(mac_trace(mac_ctx,
TRACE_CODE_RX_MGMT_TSF, 0, bcn_ptr->timeStamp[0]);)
MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, 0,
bcn_ptr->timeStamp[1]);)
lim_check_and_add_bss_description(mac_ctx, bcn_ptr,
rx_pkt_info, false, true);
if ((mac_ctx->lim.gLimMlmState ==
eLIM_MLM_WT_PROBE_RESP_STATE) ||
(mac_ctx->lim.gLimMlmState ==
eLIM_MLM_PASSIVE_SCAN_STATE)) {
lim_check_and_add_bss_description(mac_ctx, bcn_ptr,
rx_pkt_info,
((mac_ctx->lim.gLimHalScanState ==
eLIM_HAL_SCANNING_STATE) ? true : false),
false);
/*
* Calling dfsChannelList which will convert DFS channel
* to active channel for x secs if this channel is DFS
*/
lim_set_dfs_channel_list(mac_ctx,
bcn_ptr->channelNumber,
&mac_ctx->lim.dfschannelList);
} else if (session->limMlmState ==
eLIM_MLM_WT_JOIN_BEACON_STATE) {
if (session->beacon != NULL) {
cdf_mem_free(session->beacon);
session->beacon = NULL;
}
session->bcnLen = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info);
session->beacon = cdf_mem_malloc(session->bcnLen);
if (NULL == session->beacon) {
lim_log(mac_ctx, LOGE,
FL("fail to alloc mem to store bcn"));
} else {
/*
* Store the Beacon/ProbeRsp. This is sent to
* csr/hdd in join cnf response.
*/
cdf_mem_copy(session->beacon,
WMA_GET_RX_MPDU_DATA(rx_pkt_info),
session->bcnLen);
}
lim_check_and_announce_join_success(mac_ctx, bcn_ptr,
mac_hdr, session);
}
cdf_mem_free(bcn_ptr);
return;
}
/**---------------------------------------------------------------
\fn lim_process_beacon_frame_no_session
\brief This function is called by limProcessMessageQueue()
\ upon Beacon reception.
\
\param pMac
\param *pRxPacketInfo - A pointer to Rx packet info structure
\return None
------------------------------------------------------------------*/
void
lim_process_beacon_frame_no_session(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo)
{
tpSirMacMgmtHdr pHdr;
tSchBeaconStruct *pBeacon;
pMac->lim.gLimNumBeaconsRcvd++;
pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo);
lim_log(pMac, LOG2, FL("Received Beacon frame with length=%d from "),
WMA_GET_RX_MPDU_LEN(pRxPacketInfo));
lim_print_mac_addr(pMac, pHdr->sa, LOG2);
/**
* No session has been established. Expect Beacon only when
* 1. STA is in Scan mode waiting for Beacon/Probe response or
* 2. STA/AP is in Learn mode
*/
if ((pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) ||
(pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE) ||
(pMac->lim.gLimMlmState == eLIM_MLM_LEARN_STATE)) {
pBeacon = cdf_mem_malloc(sizeof(tSchBeaconStruct));
if (NULL == pBeacon) {
lim_log(pMac, LOGE,
FL
("Unable to allocate memory in lim_process_beacon_frame_no_session"));
return;
}
if (sir_convert_beacon_frame2_struct
(pMac, (uint8_t *) pRxPacketInfo,
pBeacon) != eSIR_SUCCESS) {
/* Received wrongly formatted/invalid Beacon. Ignore and move on. */
lim_log(pMac, LOGW,
FL
("Received invalid Beacon in global MLM state %X"),
pMac->lim.gLimMlmState);
lim_print_mlm_state(pMac, LOGW, pMac->lim.gLimMlmState);
cdf_mem_free(pBeacon);
return;
}
if ((pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) ||
(pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE)) {
lim_check_and_add_bss_description(pMac, pBeacon,
pRxPacketInfo, true,
false);
/* Calling dfsChannelList which will convert DFS channel
* to Active channel for x secs if this channel is DFS channel */
lim_set_dfs_channel_list(pMac, pBeacon->channelNumber,
&pMac->lim.dfschannelList);
} else if (pMac->lim.gLimMlmState == eLIM_MLM_LEARN_STATE) {
} /* end of eLIM_MLM_LEARN_STATE) */
cdf_mem_free(pBeacon);
} /* end of (eLIM_MLM_WT_PROBE_RESP_STATE) || (eLIM_MLM_PASSIVE_SCAN_STATE) */
else {
lim_log(pMac, LOG1, FL("Rcvd Beacon in unexpected MLM state %d"),
pMac->lim.gLimMlmState);
lim_print_mlm_state(pMac, LOG1, pMac->lim.gLimMlmState);
#ifdef WLAN_DEBUG
pMac->lim.gLimUnexpBcnCnt++;
#endif
}
return;
} /*** end lim_process_beacon_frame_no_session() ***/