blob: d3df1d31eba3729580f9e10ea4e00d4d5f00f831 [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_probe_rsp_frame.cc contains the code
* for processing Probe Response Frame.
* Author: Chandra Modumudi
* Date: 03/01/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
*
*/
#include "wni_api.h"
#include "wni_cfg.h"
#include "ani_global.h"
#include "sch_api.h"
#include "utils_api.h"
#include "lim_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"
#include "lim_send_messages.h"
#include "parser_api.h"
tSirRetStatus lim_validate_ie_information_in_probe_rsp_frame(uint8_t *pRxPacketInfo)
{
tSirRetStatus status = eSIR_SUCCESS;
if (WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) <
(SIR_MAC_B_PR_SSID_OFFSET + SIR_MAC_MIN_IE_LEN)) {
status = eSIR_FAILURE;
}
return status;
}
/**
* lim_process_probe_rsp_frame() - processes received Probe Response frame
* @mac_ctx: Pointer to Global MAC structure
* @rx_Packet_info: A pointer to Buffer descriptor + associated PDUs
* @session_entry: Handle to the session.
*
* This function processes received Probe Response frame.
* Frames with out-of-order IEs are dropped.
* In case of IBSS, join 'success' makes MLM state machine
* transition into 'BSS started' state. This may have to change
* depending on supporting what kinda Authentication in IBSS.
*
* Return: None
*/
void
lim_process_probe_rsp_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_Packet_info,
tpPESession session_entry)
{
uint8_t *body;
uint32_t frame_len = 0;
tSirMacAddr current_bssid;
tpSirMacMgmtHdr header;
tSirProbeRespBeacon *probe_rsp;
uint8_t qos_enabled = false;
uint8_t wme_enabled = false;
if (!session_entry) {
lim_log(mac_ctx, LOGE, FL("session_entry is NULL"));
return;
}
lim_log(mac_ctx, LOG1, "SessionId:%d ProbeRsp Frame is received",
session_entry->peSessionId);
probe_rsp = cdf_mem_malloc(sizeof(tSirProbeRespBeacon));
if (NULL == probe_rsp) {
lim_log(mac_ctx, LOGE,
FL
("Unable to allocate memory "));
return;
}
probe_rsp->ssId.length = 0;
probe_rsp->wpa.length = 0;
header = WMA_GET_RX_MAC_HEADER(rx_Packet_info);
lim_log(mac_ctx, LOG2,
FL("Rx Probe Response with length = %d from "MAC_ADDRESS_STR),
WMA_GET_RX_MPDU_LEN(rx_Packet_info),
MAC_ADDR_ARRAY(header->sa));
/* Validate IE information before processing Probe Response Frame */
if (lim_validate_ie_information_in_probe_rsp_frame(rx_Packet_info) !=
eSIR_SUCCESS) {
lim_log(mac_ctx, LOG1,
FL("Parse error ProbeResponse, length=%d"), frame_len);
cdf_mem_free(probe_rsp);
return;
}
frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info);
CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO,
FL("Probe Resp Frame Received: BSSID "
MAC_ADDRESS_STR " (RSSI %d)"),
MAC_ADDR_ARRAY(header->bssId),
(uint) abs((int8_t)WMA_GET_RX_RSSI_DB(rx_Packet_info)));
/* Get pointer to Probe Response frame body */
body = WMA_GET_RX_MPDU_DATA(rx_Packet_info);
/* Enforce Mandatory IEs */
if ((sir_convert_probe_frame2_struct(mac_ctx,
body, frame_len, probe_rsp) == eSIR_FAILURE) ||
!probe_rsp->ssidPresent) {
lim_log(mac_ctx, LOG1,
FL("Parse error ProbeResponse, length=%d"), frame_len);
cdf_mem_free(probe_rsp);
return;
}
lim_check_and_add_bss_description(mac_ctx, probe_rsp,
rx_Packet_info, false, true);
/* To Support BT-AMP */
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, probe_rsp,
rx_Packet_info, ((mac_ctx->lim.
gLimHalScanState == eLIM_HAL_SCANNING_STATE)
? true : false), true);
} else if (session_entry->limMlmState ==
eLIM_MLM_WT_JOIN_BEACON_STATE) {
/*
* Either Beacon/probe response is required.
* Hence store it in same buffer.
*/
if (session_entry->beacon != NULL) {
cdf_mem_free(session_entry->beacon);
session_entry->beacon = NULL;
}
session_entry->bcnLen =
WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info);
session_entry->beacon =
cdf_mem_malloc(session_entry->bcnLen);
if (NULL == session_entry->beacon) {
lim_log(mac_ctx, LOGE,
FL("No Memory to store beacon"));
} else {
/*
* Store the Beacon/ProbeRsp.
* This is sent to csr/hdd in join cnf response.
*/
cdf_mem_copy(session_entry->beacon,
WMA_GET_RX_MPDU_DATA
(rx_Packet_info),
session_entry->bcnLen);
}
/* STA in WT_JOIN_BEACON_STATE */
lim_check_and_announce_join_success(mac_ctx, probe_rsp,
header,
session_entry);
} else if (session_entry->limMlmState ==
eLIM_MLM_LINK_ESTABLISHED_STATE) {
tpDphHashNode sta_ds = NULL;
/*
* Check if this Probe Response is for
* our Probe Request sent upon reaching
* heart beat threshold
*/
sir_copy_mac_addr(current_bssid, session_entry->bssId);
if (!cdf_mem_compare(current_bssid, header->bssId,
sizeof(tSirMacAddr))) {
cdf_mem_free(probe_rsp);
return;
}
if (!LIM_IS_CONNECTION_ACTIVE(session_entry)) {
lim_log(mac_ctx, LOGW,
FL("Recved Probe Resp from AP,AP-alive"));
if (probe_rsp->HTInfo.present)
lim_received_hb_handler(mac_ctx,
probe_rsp->HTInfo.primaryChannel,
session_entry);
else
lim_received_hb_handler(mac_ctx,
(uint8_t)probe_rsp->channelNumber,
session_entry);
}
if (LIM_IS_STA_ROLE(session_entry)) {
if (probe_rsp->channelSwitchPresent) {
lim_update_channel_switch(mac_ctx,
probe_rsp,
session_entry);
} else if (session_entry->gLimSpecMgmt.dot11hChanSwState
== eLIM_11H_CHANSW_RUNNING) {
lim_cancel_dot11h_channel_switch(
mac_ctx, session_entry);
}
}
/*
* Now Process EDCA Parameters, if EDCAParamSet
* count is different.
* -- While processing beacons in link established
* state if it is determined that
* QoS Info IE has a different count for EDCA Params,
* and EDCA IE is not present in beacon,
* then probe req is sent out to get the EDCA params.
*/
sta_ds = dph_get_hash_entry(mac_ctx,
DPH_STA_HASH_INDEX_PEER,
&session_entry->dph.dphHashTable);
limGetQosMode(session_entry, &qos_enabled);
limGetWmeMode(session_entry, &wme_enabled);
lim_log(mac_ctx, LOG2,
FL("wmeEdcaPresent: %d wme_enabled: %d"),
probe_rsp->wmeEdcaPresent, wme_enabled);
lim_log(mac_ctx, LOG2,
FL("edcaPresent: %d, qos_enabled: %d"),
probe_rsp->edcaPresent, qos_enabled);
lim_log(mac_ctx, LOG2,
FL("edcaParams.qosInfo.count: %d"),
probe_rsp->edcaParams.qosInfo.count);
lim_log(mac_ctx, LOG2,
FL("schObject.gLimEdcaParamSetCount: %d"),
session_entry->gLimEdcaParamSetCount);
if (((probe_rsp->wmeEdcaPresent && wme_enabled) ||
(probe_rsp->edcaPresent && qos_enabled)) &&
(probe_rsp->edcaParams.qosInfo.count !=
session_entry->gLimEdcaParamSetCount)) {
if (sch_beacon_edca_process(mac_ctx,
&probe_rsp->edcaParams,
session_entry) != eSIR_SUCCESS) {
lim_log(mac_ctx, LOGE,
FL("EDCA param process error"));
} else if (sta_ds != NULL) {
/*
* If needed, downgrade the
* EDCA parameters
*/
lim_set_active_edca_params(mac_ctx,
session_entry->
gLimEdcaParams,
session_entry);
lim_send_edca_params(mac_ctx,
session_entry->
gLimEdcaParamsActive,
sta_ds->bssId);
} else {
lim_log(mac_ctx, LOGE,
FL("SelfEntry missing in Hash"));
}
}
if (session_entry->fWaitForProbeRsp == true) {
lim_log(mac_ctx, LOGW,
FL("Check probe resp for caps change"));
lim_detect_change_in_ap_capabilities(
mac_ctx, probe_rsp, session_entry);
}
} else {
if (LIM_IS_IBSS_ROLE(session_entry) &&
(session_entry->limMlmState ==
eLIM_MLM_BSS_STARTED_STATE))
lim_handle_ibss_coalescing(mac_ctx, probe_rsp,
rx_Packet_info, session_entry);
}
cdf_mem_free(probe_rsp);
/* Ignore Probe Response frame in all other states */
return;
}
/**
* lim_process_probe_rsp_frame_no_session() - process Probe Response frame
* @mac_ctx: Pointer to Global MAC structure
* @rx_packet_info: A pointer to Buffer descriptor + associated PDUs
*
* This function processes received Probe Response frame with no session.
*
* Return: None
*/
void
lim_process_probe_rsp_frame_no_session(tpAniSirGlobal mac_ctx,
uint8_t *rx_packet_info)
{
uint8_t *body;
uint32_t frame_len = 0;
tpSirMacMgmtHdr header;
tSirProbeRespBeacon *probe_rsp;
probe_rsp = cdf_mem_malloc(sizeof(tSirProbeRespBeacon));
if (NULL == probe_rsp) {
lim_log(mac_ctx, LOGE,
FL("Unable to allocate memory"));
return;
}
probe_rsp->ssId.length = 0;
probe_rsp->wpa.length = 0;
header = WMA_GET_RX_MAC_HEADER(rx_packet_info);
lim_log(mac_ctx, LOG2,
FL("Received Probe Response frame with length=%d from "),
WMA_GET_RX_MPDU_LEN(rx_packet_info));
lim_print_mac_addr(mac_ctx, header->sa, LOG2);
/* Validate IE information before processing Probe Response Frame */
if (lim_validate_ie_information_in_probe_rsp_frame(rx_packet_info) !=
eSIR_SUCCESS) {
lim_log(mac_ctx, LOG1,
FL("Parse error ProbeResponse, length=%d"), frame_len);
cdf_mem_free(probe_rsp);
return;
}
frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_packet_info);
CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO,
FL("Probe Resp Frame Received: BSSID "
MAC_ADDRESS_STR " (RSSI %d)"),
MAC_ADDR_ARRAY(header->bssId),
(uint) abs((int8_t)WMA_GET_RX_RSSI_DB(rx_packet_info)));
/*
* Get pointer to Probe Response frame body
*/
body = WMA_GET_RX_MPDU_DATA(rx_packet_info);
if (sir_convert_probe_frame2_struct(mac_ctx, body, frame_len,
probe_rsp) == eSIR_FAILURE) {
lim_log(mac_ctx, LOG1,
FL("Parse error ProbeResponse, length=%d\n"),
frame_len);
cdf_mem_free(probe_rsp);
return;
}
lim_log(mac_ctx, LOG2, FL("Save this probe rsp in LFR cache"));
lim_check_and_add_bss_description(mac_ctx, probe_rsp,
rx_packet_info, false, true);
cdf_mem_free(probe_rsp);
return;
}