blob: 97bd859c445fdc033d3a70d9475000e48419814f [file] [log] [blame]
/*
* Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
*
* 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.
*/
/*===========================================================================
s a p A p i L i n k C n t l . C
OVERVIEW:
This software unit holds the implementation of the WLAN SAP modules
Link Control functions.
The functions externalized by this module are to be called ONLY by other
WLAN modules (HDD)
DEPENDENCIES:
Are listed for each API below.
===========================================================================*/
/*----------------------------------------------------------------------------
* Include Files
* -------------------------------------------------------------------------*/
#include "qdf_trace.h"
/* Pick up the CSR callback definition */
#include "csr_api.h"
#include "ani_global.h"
#include "csr_inside_api.h"
#include "sme_api.h"
/* SAP Internal API header file */
#include "sap_internal.h"
#include "wlan_policy_mgr_api.h"
#include "wma.h"
#include <wlan_objmgr_vdev_obj.h>
#include <wlan_objmgr_pdev_obj.h>
#include "wlan_reg_services_api.h"
#include <wlan_scan_utils_api.h>
/*----------------------------------------------------------------------------
* Preprocessor Definitions and Constants
* -------------------------------------------------------------------------*/
#define SAP_DEBUG
/*----------------------------------------------------------------------------
* Type Declarations
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Global Data Definitions
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Static Variable Definitions
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Static Function Declarations and Definitions
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Externalized Function Definitions
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Function Declarations and Documentation
* -------------------------------------------------------------------------*/
QDF_STATUS wlansap_scan_callback(tHalHandle hal_handle,
struct sap_context *sap_ctx,
uint8_t session_id,
uint32_t scan_id, eCsrScanStatus scan_status)
{
tScanResultHandle result = NULL;
QDF_STATUS get_result_status = QDF_STATUS_E_FAILURE;
tWLAN_SAPEvent sapEvent; /* State machine event */
uint8_t operChannel = 0;
QDF_STATUS sap_sm_status;
uint32_t event;
tpAniSirGlobal mac_ctx;
if (NULL != hal_handle) {
mac_ctx = PMAC_STRUCT(hal_handle);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"In %s invalid hHal", __func__);
return QDF_STATUS_E_FAILURE;
}
if (sap_ctx->sapsMachine == eSAP_DISCONNECTED) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
"In %s BSS already stopped", __func__);
if (sap_ctx->channelList != NULL) {
qdf_mem_free(sap_ctx->channelList);
sap_ctx->channelList = NULL;
sap_ctx->num_of_channel = 0;
}
return QDF_STATUS_E_FAILURE;
}
switch (scan_status) {
case eCSR_SCAN_SUCCESS:
/* sapScanCompleteCallback with eCSR_SCAN_SUCCESS */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"In %s, CSR scanStatus = %s (%d)", __func__,
"eCSR_SCAN_SUCCESS", scan_status);
/**
* Get scan results, Run channel selection algorithm,
* select channel and keep in sap_ctx->Channel
*/
get_result_status =
sme_scan_get_result(hal_handle, sap_ctx->sessionId, NULL,
&result);
event = eSAP_MAC_SCAN_COMPLETE;
if ((get_result_status != QDF_STATUS_SUCCESS)
&& (get_result_status != QDF_STATUS_E_NULL_VALUE)) {
/* No scan results */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"In %s, Get scan result failed! ret = %d",
__func__, get_result_status);
break;
}
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
if (scan_id != 0) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: Sending ACS Scan skip event", __func__);
sap_signal_hdd_event(sap_ctx, NULL,
eSAP_ACS_SCAN_SUCCESS_EVENT,
(void *) eSAP_STATUS_SUCCESS);
} else
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: ACS scan id: %d (skipped ACS SCAN)",
__func__, scan_id);
#endif
operChannel = sap_select_channel(hal_handle, sap_ctx, result);
sme_scan_result_purge(result);
break;
default:
event = eSAP_CHANNEL_SELECTION_FAILED;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"In %s, CSR scanStatus = %s (%d)", __func__,
"eCSR_SCAN_ABORT/FAILURE", scan_status);
}
if (operChannel == SAP_CHANNEL_NOT_SELECTED)
#ifdef SOFTAP_CHANNEL_RANGE
{
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: No suitable channel selected due to DFS, LTE"
"COEX and concurrent mode restrictions", __func__);
sap_ctx->sapsMachine = eSAP_CH_SELECT;
event = eSAP_CHANNEL_SELECTION_FAILED;
}
#else
sap_ctx->channel = SAP_DEFAULT_24GHZ_CHANNEL;
#endif
else {
sap_ctx->channel = operChannel;
}
sap_ctx->ch_params.ch_width = sap_ctx->acs_cfg->ch_width;
wlan_reg_set_channel_params(mac_ctx->pdev, sap_ctx->channel,
sap_ctx->secondary_ch,
&sap_ctx->ch_params);
#ifdef SOFTAP_CHANNEL_RANGE
if (sap_ctx->channelList != NULL) {
/* Always free up the memory for channel selection whatever
* the result */
qdf_mem_free(sap_ctx->channelList);
sap_ctx->channelList = NULL;
sap_ctx->num_of_channel = 0;
}
#endif
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"In %s, Channel selected = %d", __func__,
sap_ctx->channel);
/* Fill in the event structure */
sapEvent.event = event;
/* pCsrRoamInfo; */
sapEvent.params = 0;
/* roamstatus */
sapEvent.u1 = scan_status;
/* roamResult */
sapEvent.u2 = 0;
/* Handle event */
sap_sm_status = sap_fsm(sap_ctx, &sapEvent);
return sap_sm_status;
} /* wlansap_scan_callback */
/**
* sap_config_acs_result : Generate ACS result params based on ch constraints
* @sap_ctx: pointer to SAP context data struct
* @hal: HAL Handle pointer
*
* This function calculates the ACS result params: ht sec channel, vht channel
* information and channel bonding based on selected ACS channel.
*
* Return: None
*/
void sap_config_acs_result(tHalHandle hal, struct sap_context *sap_ctx,
uint32_t sec_ch)
{
uint32_t channel = sap_ctx->acs_cfg->pri_ch;
struct ch_params ch_params = {0};
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
ch_params.ch_width = sap_ctx->acs_cfg->ch_width;
wlan_reg_set_channel_params(mac_ctx->pdev, channel, sec_ch,
&ch_params);
sap_ctx->acs_cfg->ch_width = ch_params.ch_width;
if (sap_ctx->acs_cfg->ch_width > CH_WIDTH_40MHZ)
sap_ctx->acs_cfg->vht_seg0_center_ch =
ch_params.center_freq_seg0;
else
sap_ctx->acs_cfg->vht_seg0_center_ch = 0;
if (sap_ctx->acs_cfg->ch_width == CH_WIDTH_80P80MHZ)
sap_ctx->acs_cfg->vht_seg1_center_ch =
ch_params.center_freq_seg1;
else
sap_ctx->acs_cfg->vht_seg1_center_ch = 0;
if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch - 4;
else if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch + 4;
else
sap_ctx->acs_cfg->ht_sec_ch = 0;
}
/**
* sap_hdd_signal_event_handler() - routine to inform hostapd via callback
*
* ctx: pointer to sap context which was passed to callback
*
* this routine will be registered as callback to sme_close_session, so upon
* closure of sap session it notifies the hostapd
*
* Return: QDF_STATUS
*/
static QDF_STATUS sap_hdd_signal_event_handler(void *ctx)
{
struct sap_context *sap_ctx = ctx;
QDF_STATUS status;
if (NULL == sap_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("sap context is not valid"));
return QDF_STATUS_E_FAILURE;
}
status = sap_signal_hdd_event(sap_ctx, NULL,
sap_ctx->sap_state,
(void *) sap_ctx->sap_status);
return status;
}
/**
* acs_scan_done_status_str() - parse scan status to string
* @status: scan status
*
* This function parse scan status to string
*
* Return: status string
*
*/
static const char *acs_scan_done_status_str(eCsrScanStatus status)
{
switch (status) {
case eCSR_SCAN_SUCCESS:
return "Success";
case eCSR_SCAN_FAILURE:
return "Failure";
case eCSR_SCAN_ABORT:
return "Abort";
case eCSR_SCAN_FOUND_PEER:
return "Found peer";
default:
return "Unknown";
}
}
QDF_STATUS wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle,
struct sap_context *sap_ctx,
uint8_t sessionid,
uint32_t scanid,
eCsrScanStatus scan_status)
{
tScanResultHandle presult = NULL;
QDF_STATUS scan_get_result_status = QDF_STATUS_E_FAILURE;
uint8_t oper_channel = 0;
QDF_STATUS status = QDF_STATUS_E_FAILURE;
host_log_acs_scan_done(acs_scan_done_status_str(scan_status),
sessionid, scanid);
if (eCSR_SCAN_SUCCESS != scan_status) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("CSR scan_status = eCSR_SCAN_ABORT/FAILURE (%d), choose default channel"),
scan_status);
oper_channel =
sap_select_default_oper_chan(sap_ctx->acs_cfg);
sap_ctx->channel = oper_channel;
sap_ctx->acs_cfg->pri_ch = oper_channel;
sap_config_acs_result(hal_handle, sap_ctx,
sap_ctx->acs_cfg->ht_sec_ch);
sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED;
sap_ctx->sap_status = eSAP_STATUS_SUCCESS;
goto close_session;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR scan_status = eCSR_SCAN_SUCCESS (%d)"), scan_status);
/*
* Now do
* 1. Get scan results
* 2. Run channel selection algorithm
* select channel and store in sap_context->Channel
*/
scan_get_result_status = sme_scan_get_result(hal_handle,
sap_ctx->sessionId,
NULL, &presult);
if ((scan_get_result_status != QDF_STATUS_SUCCESS) &&
(scan_get_result_status != QDF_STATUS_E_NULL_VALUE)) {
/*
* No scan results So, set the operation channel not selected
* to allow the default channel to be set when reporting to HDD
*/
oper_channel = SAP_CHANNEL_NOT_SELECTED;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Get scan result failed! ret = %d"),
scan_get_result_status);
} else {
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
if (scanid != 0) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Sending ACS Scan skip event"));
sap_signal_hdd_event(sap_ctx, NULL,
eSAP_ACS_SCAN_SUCCESS_EVENT,
(void *) eSAP_STATUS_SUCCESS);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("ACS scanid: %d (skipped ACS SCAN)"),
scanid);
}
#endif
oper_channel = sap_select_channel(hal_handle, sap_ctx, presult);
sme_scan_result_purge(presult);
}
if (oper_channel == SAP_CHANNEL_NOT_SELECTED) {
#ifdef SOFTAP_CHANNEL_RANGE
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("No suitable channel selected"));
sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED;
sap_ctx->sap_status = eSAP_STATUS_FAILURE;
goto close_session;
} else {
#else
sap_ctx->channel =
sap_select_default_oper_chan(sap_ctx->acs_cfg);
} else {
#endif
/* Valid Channel Found from scan results. */
sap_ctx->acs_cfg->pri_ch = oper_channel;
sap_ctx->channel = oper_channel;
}
sap_config_acs_result(hal_handle, sap_ctx,
sap_ctx->acs_cfg->ht_sec_ch);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Channel selected = %d"), sap_ctx->channel);
sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED;
sap_ctx->sap_status = eSAP_STATUS_SUCCESS;
close_session:
#ifdef SOFTAP_CHANNEL_RANGE
if (sap_ctx->channelList != NULL) {
/*
* Always free up the memory for
* channel selection whatever
* the result
*/
qdf_mem_free(sap_ctx->channelList);
sap_ctx->channelList = NULL;
sap_ctx->num_of_channel = 0;
}
#endif
sap_hdd_signal_event_handler(sap_ctx);
return status;
}
/**
* wlansap_roam_process_ch_change_success() - handles the case for
* eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS in function wlansap_roam_callback()
*
* @mac_ctx: mac global context
* @sap_ctx: sap context
* @csr_roam_info: raom info struct
* @ret_status: update return status
*
* Return: void
*/
static void
wlansap_roam_process_ch_change_success(tpAniSirGlobal mac_ctx,
struct sap_context *sap_ctx,
struct csr_roam_info *csr_roam_info,
QDF_STATUS *ret_status)
{
tWLAN_SAPEvent sap_event;
QDF_STATUS qdf_status;
bool is_ch_dfs = false;
/*
* Channel change is successful. If the new channel is a DFS channel,
* then we will to perform channel availability check for 60 seconds
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: changing target channel to [%d]"),
mac_ctx->sap.SapDfsInfo.target_channel);
sap_ctx->channel = mac_ctx->sap.SapDfsInfo.target_channel;
/*
* Identify if this is channel change in radar detected state
* Also if we are waiting for sap to stop, don't proceed further
* to restart SAP again.
*/
if ((eSAP_DISCONNECTING != sap_ctx->sapsMachine) ||
sap_ctx->stop_bss_in_progress) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("sapdfs: state [%d] Stop BSS in progress [%d], not starting SAP after channel change"),
sap_ctx->sapsMachine,
sap_ctx->stop_bss_in_progress);
return;
}
if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) {
is_ch_dfs = true;
} else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) {
if (wlan_reg_get_channel_state(mac_ctx->pdev,
sap_ctx->channel) ==
CHANNEL_STATE_DFS ||
wlan_reg_get_channel_state(mac_ctx->pdev,
sap_ctx->ch_params.center_freq_seg1 -
SIR_80MHZ_START_CENTER_CH_DIFF) ==
CHANNEL_STATE_DFS)
is_ch_dfs = true;
} else {
if (wlan_reg_get_channel_state(mac_ctx->pdev,
sap_ctx->channel) ==
CHANNEL_STATE_DFS)
is_ch_dfs = true;
}
/* check if currently selected channel is a DFS channel */
if (is_ch_dfs && sap_ctx->pre_cac_complete) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, FL(
"sapdfs: eSAP_DISCONNECTING => eSAP_STARTING, on pre cac"));
/* Start beaconing on the new pre cac channel */
wlansap_start_beacon_req(sap_ctx);
sap_ctx->sapsMachine = eSAP_STARTING;
mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false;
sap_event.event = eSAP_MAC_START_BSS_SUCCESS;
sap_event.params = csr_roam_info;
sap_event.u1 = eCSR_ROAM_INFRA_IND;
sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED;
} else if (is_ch_dfs) {
if ((false == mac_ctx->sap.SapDfsInfo.ignore_cac)
&& (eSAP_DFS_DO_NOT_SKIP_CAC ==
mac_ctx->sap.SapDfsInfo.cac_state)) {
sap_ctx->sapsMachine = eSAP_DISCONNECTED;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: from state eSAP_DISCONNECTING => DISCONNECTED with ignore cac false on sapctx[%pK]"),
sap_ctx);
/* DFS Channel */
sap_event.event = eSAP_DFS_CHANNEL_CAC_START;
sap_event.params = csr_roam_info;
sap_event.u1 = 0;
sap_event.u2 = 0;
} else {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: from state eSAP_DISCONNECTING => eSAP_STARTING with ignore cac true on sapctx[%pK]"),
sap_ctx);
/* Start beaconing on the new channel */
wlansap_start_beacon_req(sap_ctx);
sap_ctx->sapsMachine = eSAP_STARTING;
mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false;
sap_event.event = eSAP_MAC_START_BSS_SUCCESS;
sap_event.params = csr_roam_info;
sap_event.u1 = eCSR_ROAM_INFRA_IND;
sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED;
}
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: from state eSAP_DISCONNECTING => eSAP_STARTING on sapctx[%pK]"),
sap_ctx);
/* non-DFS channel */
sap_ctx->sapsMachine = eSAP_STARTING;
mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false;
sap_event.event = eSAP_MAC_START_BSS_SUCCESS;
sap_event.params = csr_roam_info;
sap_event.u1 = eCSR_ROAM_INFRA_IND;
sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED;
}
/* Handle the event */
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
*ret_status = QDF_STATUS_E_FAILURE;
}
/**
* wlansap_roam_process_dfs_chansw_update() - handles the case for
* eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS in wlansap_roam_callback()
*
* @hal: hal global context
* @sap_ctx: sap context
* @ret_status: update return status
*
* Return: void
*/
static void
wlansap_roam_process_dfs_chansw_update(tHalHandle hHal,
struct sap_context *sap_ctx,
QDF_STATUS *ret_status)
{
tWLAN_SAPEvent sap_event;
uint8_t intf;
QDF_STATUS qdf_status;
tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal);
uint8_t dfs_beacon_start_req = 0;
bool sap_scc_dfs;
if (sap_ctx->csr_roamProfile.disableDFSChSwitch) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
FL("sapdfs: DFS channel switch disabled"));
/*
* Send a beacon start request to PE. CSA IE required flag from
* beacon template will be cleared by now. A new beacon template
* with no CSA IE will be sent to firmware.
*/
dfs_beacon_start_req = true;
sap_ctx->pre_cac_complete = false;
*ret_status = sme_roam_start_beacon_req(hHal, sap_ctx->bssid,
dfs_beacon_start_req);
return;
}
/*
* Irrespective of whether the channel switch IE was sent out
* successfully or not, SAP should still vacate the channel immediately
*/
if (eSAP_STARTED != sap_ctx->sapsMachine) {
/* Further actions to be taken here */
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_WARN,
FL("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state"),
sap_ctx->sapsMachine);
return;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: from state eSAP_STARTED => eSAP_DISCONNECTING"));
/* SAP to be moved to DISCONNECTING state */
sap_ctx->sapsMachine = eSAP_DISCONNECTING;
sap_ctx->is_chan_change_inprogress = true;
/*
* The associated stations have been informed to move to a different
* channel. However, the AP may not always select the advertised channel
* for operation if the radar is seen. In that case, the stations will
* experience link-loss and return back through scanning if they wish to
*/
/*
* Send channel change request. From spec it is required that the AP
* should continue to operate in the same mode as it is operating
* currently. For e.g. 20/40/80 MHz operation
*/
if (mac_ctx->sap.SapDfsInfo.target_channel)
wlan_reg_set_channel_params(mac_ctx->pdev,
mac_ctx->sap.SapDfsInfo.target_channel,
0, &sap_ctx->ch_params);
/*
* Fetch the number of SAP interfaces. If the number of sap Interface
* more than one then we will make is_sap_ready_for_chnl_chng to true
* for that sapctx. If there is only one SAP interface then process
* immediately. If Dual BAND SAP is enabled then also process
* immediately, as in this case the both SAP will be in different band
* and channel change on one SAP doesn't mean channel change on
* other interface.
*
* For example,
* Let's say SAP(2G) + SAP(5G-DFS) is initial connection which triggered
* DualBand HW mode and if SAP(5G-DFS) is moving to some channel then
* SAP(2G) doesn't need to move.
*
* If both SAPs are not doing SCC DFS then each of them can change the
* channel independently. Channel change of one SAP became dependent
* second SAP's channel change due to some previous platform's single
* radio limitation.
*
*/
sap_scc_dfs = sap_is_conc_sap_doing_scc_dfs(hHal, sap_ctx);
if (sap_get_total_number_sap_intf(hHal) <= 1 ||
policy_mgr_is_current_hwmode_dbs(mac_ctx->psoc) ||
!sap_scc_dfs) {
/* Send channel switch request */
sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ;
sap_event.params = 0;
sap_event.u1 = 0;
sap_event.u2 = 0;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: Posting event eWNI_SME_CHANNEL_CHANGE_REQ to sapFSM"));
/* Handle event */
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
*ret_status = QDF_STATUS_E_FAILURE;
return;
}
sap_ctx->is_sap_ready_for_chnl_chng = true;
/*
* now check if the con-current sap interface is ready
* for channel change. If yes then we issue channel change for
* both the SAPs. If no then simply return success & we will
* issue channel change when second AP's 5 CSA beacon Tx is
* completed.
*
* This check is added to take care of following scenario:
* if SAP1 + SAP2 is doing DFS SCC and radar is detected on that channel
* then SAP1 sends 5 beacons with CSA/ECSA IE and wait for SAP2 to
* finish sending 5 beacons. if SAP1 changes channel before SAP2 finish
* sending beacons then it ends up in
* (SAP1 new channel + SAP2 old channel) MCC with DFS scenario
* which causes some of the stability issues in old platforms.
*/
if (false ==
is_concurrent_sap_ready_for_channel_change(hHal, sap_ctx)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: sapctx[%pK] ready but not concurrent sap"),
sap_ctx);
*ret_status = QDF_STATUS_SUCCESS;
return;
}
/* Issue channel change req for each sapctx */
for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) {
struct sap_context *sap_context;
if (!((QDF_SAP_MODE == mac_ctx->sap.sapCtxList[intf].sapPersona)
&& (mac_ctx->sap.sapCtxList[intf].sap_context != NULL)))
continue;
sap_context = mac_ctx->sap.sapCtxList[intf].sap_context;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs:issue chnl change for sapctx[%pK]"),
sap_context);
/* Send channel switch request */
sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ;
sap_event.params = 0;
sap_event.u1 = 0;
sap_event.u2 = 0;
/* Handle event */
qdf_status = sap_fsm(sap_context, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("post chnl chng req failed, sap[%pK]"),
sap_ctx);
*ret_status = QDF_STATUS_E_FAILURE;
} else {
sap_context->is_sap_ready_for_chnl_chng = false;
}
}
return;
}
/**
* wlansap_roam_process_dfs_radar_found() - handles the case for
* eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND in wlansap_roam_callback()
*
* @mac_ctx: mac global context
* @sap_ctx: sap context
* @ret_status: update return status
*
* Return: result of operation
*/
static void
wlansap_roam_process_dfs_radar_found(tpAniSirGlobal mac_ctx,
struct sap_context *sap_ctx,
QDF_STATUS *ret_status)
{
QDF_STATUS qdf_status;
tWLAN_SAPEvent sap_event;
if (eSAP_DFS_CAC_WAIT == sap_ctx->sapsMachine) {
if (sap_ctx->csr_roamProfile.disableDFSChSwitch) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"sapdfs: DFS channel switch disabled");
return;
}
if (false == mac_ctx->sap.SapDfsInfo.sap_radar_found_status) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"sapdfs: sap_radar_found_status is false");
return;
}
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs:Posting event eSAP_DFS_CHANNEL_CAC_RADAR_FOUND"));
/*
* If Radar is found, while in DFS CAC WAIT State then post stop
* and destroy the CAC timer and post a
* eSAP_DFS_CHANNEL_CAC_RADAR_FOUND to sapFsm.
*/
if (!sap_ctx->dfs_cac_offload) {
qdf_mc_timer_stop(&mac_ctx->
sap.SapDfsInfo.sap_dfs_cac_timer);
qdf_mc_timer_destroy(&mac_ctx->
sap.SapDfsInfo.sap_dfs_cac_timer);
}
mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running = false;
/*
* User space is already indicated the CAC start and if
* CAC end on this channel is not indicated, the user
* space will be in some undefined state (e.g., UI frozen)
*/
qdf_status = sap_signal_hdd_event(sap_ctx, NULL,
eSAP_DFS_CAC_INTERRUPTED,
(void *) eSAP_STATUS_SUCCESS);
if (QDF_STATUS_SUCCESS != qdf_status) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Failed to send CAC end"));
/* Want to still proceed and try to switch channel.
* Lets try not to be on the DFS channel
*/
}
sap_event.event = eSAP_DFS_CHANNEL_CAC_RADAR_FOUND;
sap_event.params = 0;
sap_event.u1 = 0;
sap_event.u2 = 0;
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
*ret_status = QDF_STATUS_E_FAILURE;
return;
}
if (eSAP_STARTED == sap_ctx->sapsMachine) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs:Posting event eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START"));
/*
* Radar found on the operating channel in STARTED state,
* new operating channel has already been selected. Send
* request to SME-->PE for sending CSA IE
*/
sap_event.event = eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START;
sap_event.params = 0;
sap_event.u1 = 0;
sap_event.u2 = 0;
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
*ret_status = QDF_STATUS_E_FAILURE;
return;
}
/* Further actions to be taken here */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state"),
sap_ctx->sapsMachine);
return;
}
/**
* wlansap_roam_process_infra_assoc_ind() - handles the case for
* eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND in wlansap_roam_callback()
*
* @sap_ctx: sap context
* @roam_result: roam result
* @csr_roam_info: roam info struct
* @ret_status: update return status
*
* Return: result of operation
*/
static void
wlansap_roam_process_infra_assoc_ind(struct sap_context *sap_ctx,
eCsrRoamResult roam_result,
struct csr_roam_info *csr_roam_info,
QDF_STATUS *ret_status)
{
QDF_STATUS qdf_status;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND (%d)"),
roam_result);
sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen;
if (sap_ctx->nStaWPARSnReqIeLength)
qdf_mem_copy(sap_ctx->pStaWpaRsnReqIE, csr_roam_info->prsnIE,
sap_ctx->nStaWPARSnReqIeLength);
sap_ctx->SapQosCfg.WmmIsEnabled = csr_roam_info->wmmEnabledSta;
/* MAC filtering */
qdf_status = sap_is_peer_mac_allowed(sap_ctx,
(uint8_t *) csr_roam_info->peerMac.bytes);
if (QDF_STATUS_SUCCESS == qdf_status) {
qdf_status = sap_signal_hdd_event(sap_ctx,
csr_roam_info, eSAP_STA_ASSOC_IND,
(void *) eSAP_STATUS_SUCCESS);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") fail"),
roam_result, MAC_ADDR_ARRAY(
csr_roam_info->peerMac.bytes));
*ret_status = QDF_STATUS_E_FAILURE;
}
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") not allowed"),
roam_result,
MAC_ADDR_ARRAY(csr_roam_info->peerMac.bytes));
*ret_status = QDF_STATUS_E_FAILURE;
}
return;
}
static void wlansap_update_vendor_acs_chan(tpAniSirGlobal mac_ctx,
struct sap_context *sap_ctx)
{
int intf;
tHalHandle hal;
hal = CDS_GET_HAL_CB();
if (!hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("null hal"));
return;
}
mac_ctx->sap.SapDfsInfo.target_channel =
sap_ctx->dfs_vendor_channel;
mac_ctx->sap.SapDfsInfo.new_chanWidth =
sap_ctx->dfs_vendor_chan_bw;
mac_ctx->sap.SapDfsInfo.new_ch_params.ch_width =
sap_ctx->dfs_vendor_chan_bw;
if (mac_ctx->sap.SapDfsInfo.target_channel != 0) {
mac_ctx->sap.SapDfsInfo.cac_state =
eSAP_DFS_DO_NOT_SKIP_CAC;
sap_cac_reset_notify(hal);
return;
}
/* App failed to provide new channel, try random channel algo */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("failed to get channel from userspace"));
/* Issue stopbss for each sapctx */
for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) {
struct sap_context *sap_context;
if (((QDF_SAP_MODE ==
mac_ctx->sap.sapCtxList[intf].sapPersona) ||
(QDF_P2P_GO_MODE ==
mac_ctx->sap.sapCtxList[intf].sapPersona)) &&
mac_ctx->sap.sapCtxList[intf].sap_context !=
NULL) {
sap_context =
mac_ctx->sap.sapCtxList[intf].sap_context;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
FL("sapdfs: no available channel for sapctx[%pK], StopBss"),
sap_context);
wlansap_stop_bss(sap_context);
}
}
}
QDF_STATUS
wlansap_roam_callback(void *ctx, struct csr_roam_info *csr_roam_info,
uint32_t roamId,
eRoamCmdStatus roam_status, eCsrRoamResult roam_result)
{
/* sap_ctx value */
struct sap_context *sap_ctx;
/* State machine event */
tWLAN_SAPEvent sap_event;
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS;
tHalHandle hal;
tpAniSirGlobal mac_ctx = NULL;
uint8_t intf;
bool sta_sap_scc_on_dfs_chan;
if (QDF_IS_STATUS_ERROR(wlansap_context_get(ctx)))
return QDF_STATUS_E_FAILURE;
sap_ctx = ctx;
hal = CDS_GET_HAL_CB();
if (!hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid handle"));
wlansap_context_put(sap_ctx);
return QDF_STATUS_E_NOMEM;
}
mac_ctx = PMAC_STRUCT(hal);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("roam_status = %d, roam_result = %d"),
roam_status, roam_result);
sta_sap_scc_on_dfs_chan =
policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(mac_ctx->psoc);
switch (roam_status) {
case eCSR_ROAM_INFRA_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_status = eCSR_ROAM_INFRA_IND (%d)"),
roam_status);
if (roam_result == eCSR_ROAM_RESULT_INFRA_START_FAILED) {
/* Fill in the event structure */
sap_event.event = eSAP_MAC_START_FAILS;
sap_event.params = csr_roam_info;
sap_event.u1 = roam_status;
sap_event.u2 = roam_result;
/* Handle event */
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
}
break;
case eCSR_ROAM_LOSTLINK:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_status = eCSR_ROAM_LOSTLINK (%d)"),
roam_status);
break;
case eCSR_ROAM_MIC_ERROR_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_status = eCSR_ROAM_MIC_ERROR_IND (%d)"),
roam_status);
break;
case eCSR_ROAM_SET_KEY_COMPLETE:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_status = eCSR_ROAM_SET_KEY_COMPLETE (%d)"),
roam_status);
if (roam_result == eCSR_ROAM_RESULT_FAILURE)
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_SET_KEY_EVENT,
(void *) eSAP_STATUS_FAILURE);
break;
case eCSR_ROAM_ASSOCIATION_COMPLETION:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_status = eCSR_ROAM_ASSOCIATION_COMPLETION (%d)"),
roam_status);
if (roam_result == eCSR_ROAM_RESULT_FAILURE)
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_REASSOC_EVENT,
(void *) eSAP_STATUS_FAILURE);
break;
case eCSR_ROAM_DISASSOCIATED:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_status = eCSR_ROAM_DISASSOCIATED (%d)"),
roam_status);
if (roam_result == eCSR_ROAM_RESULT_MIC_FAILURE)
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_MIC_FAILURE_EVENT,
(void *) eSAP_STATUS_FAILURE);
break;
case eCSR_ROAM_WPS_PBC_PROBE_REQ_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_status = eCSR_ROAM_WPS_PBC_PROBE_REQ_IND (%d)"),
roam_status);
break;
case eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS:
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_DISCONNECT_ALL_P2P_CLIENT,
(void *) eSAP_STATUS_SUCCESS);
break;
case eCSR_ROAM_SEND_P2P_STOP_BSS:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Received stopbss"));
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_MAC_TRIG_STOP_BSS_EVENT,
(void *) eSAP_STATUS_SUCCESS);
break;
case eCSR_ROAM_CHANNEL_COMPLETE_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Received new channel from app"));
wlansap_update_vendor_acs_chan(mac_ctx, sap_ctx);
break;
case eCSR_ROAM_DFS_RADAR_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Received Radar Indication"));
if (sta_sap_scc_on_dfs_chan) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_HIGH,
FL("Ignore the Radar indication"));
break;
}
if (sap_ctx->sapsMachine != eSAP_STARTED &&
sap_ctx->sapsMachine != eSAP_DFS_CAC_WAIT) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Ignore Radar event in sap state %d"),
sap_ctx->sapsMachine);
break;
}
if (sap_ctx->is_pre_cac_on) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: Radar detect on pre cac:%d"),
sap_ctx->sessionId);
if (!sap_ctx->dfs_cac_offload) {
qdf_mc_timer_stop(
&mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer);
qdf_mc_timer_destroy(
&mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer);
}
mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running =
false;
sap_signal_hdd_event(sap_ctx, NULL,
eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC,
(void *) eSAP_STATUS_SUCCESS);
break;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: Indicate eSAP_DFS_RADAR_DETECT to HDD"));
sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_RADAR_DETECT,
(void *) eSAP_STATUS_SUCCESS);
mac_ctx->sap.SapDfsInfo.target_channel =
sap_indicate_radar(sap_ctx);
/* if there is an assigned next channel hopping */
if (0 < mac_ctx->sap.SapDfsInfo.user_provided_target_channel) {
mac_ctx->sap.SapDfsInfo.target_channel =
mac_ctx->sap.SapDfsInfo.user_provided_target_channel;
mac_ctx->sap.SapDfsInfo.user_provided_target_channel =
0;
}
/* if external acs enabled */
if (sap_ctx->vendor_acs_dfs_lte_enabled &&
!mac_ctx->sap.SapDfsInfo.target_channel) {
/* Return from here, processing will be done later */
return 0;
}
if (mac_ctx->sap.SapDfsInfo.target_channel != 0) {
mac_ctx->sap.SapDfsInfo.cac_state =
eSAP_DFS_DO_NOT_SKIP_CAC;
sap_cac_reset_notify(hal);
break;
}
/* Issue stopbss for each sapctx */
for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) {
struct sap_context *sap_context;
struct csr_roam_profile *profile;
if (((QDF_SAP_MODE ==
mac_ctx->sap.sapCtxList[intf].sapPersona) ||
(QDF_P2P_GO_MODE ==
mac_ctx->sap.sapCtxList[intf].sapPersona)) &&
mac_ctx->sap.sapCtxList[intf].sap_context !=
NULL) {
sap_context =
mac_ctx->sap.sapCtxList[intf].sap_context;
profile = &sap_context->csr_roamProfile;
if (!wlan_reg_is_passive_or_disable_ch(
mac_ctx->pdev,
profile->operationChannel))
continue;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
FL("sapdfs: no available channel for sapctx[%pK], StopBss"),
sap_context);
sap_signal_hdd_event(sap_context, NULL,
eSAP_STOP_BSS_DUE_TO_NO_CHNL,
(void *) eSAP_STATUS_SUCCESS);
}
}
break;
case eCSR_ROAM_DFS_CHAN_SW_NOTIFY:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Received Chan Sw Update Notification"));
break;
case eCSR_ROAM_SET_CHANNEL_RSP:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Received set channel response"));
/* SAP channel change request processing is completed */
sap_ctx->is_chan_change_inprogress = false;
break;
case eCSR_ROAM_CAC_COMPLETE_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Received cac complete indication"));
break;
case eCSR_ROAM_EXT_CHG_CHNL_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("Received set channel Indication"));
break;
default:
break;
}
switch (roam_result) {
case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND:
if (csr_roam_info)
wlansap_roam_process_infra_assoc_ind(sap_ctx,
roam_result,
csr_roam_info, &qdf_ret_status);
break;
case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF:
if (!csr_roam_info) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"csr_roam_info is NULL");
qdf_ret_status = QDF_STATUS_E_NULL_VALUE;
break;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF (%d)"),
roam_result);
sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen;
if (sap_ctx->nStaWPARSnReqIeLength)
qdf_mem_copy(sap_ctx->pStaWpaRsnReqIE,
csr_roam_info->prsnIE,
sap_ctx->nStaWPARSnReqIeLength);
sap_ctx->SapQosCfg.WmmIsEnabled =
csr_roam_info->wmmEnabledSta;
/* Fill in the event structure */
qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_ASSOC_EVENT,
(void *) eSAP_STATUS_SUCCESS);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_DEAUTH_IND:
case eCSR_ROAM_RESULT_DISASSOC_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_DEAUTH/DISASSOC_IND (%d)"),
roam_result);
/* Fill in the event structure */
qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_DISASSOC_EVENT,
(void *) eSAP_STATUS_SUCCESS);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_MIC_ERROR_GROUP:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP (%d)"),
roam_result);
/*
* Fill in the event structure
* TODO: support for group key MIC failure event to be handled
*/
qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_MIC_FAILURE_EVENT,
(void *) NULL);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_MIC_ERROR_UNICAST:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST (%d)"),
roam_result);
/*
* Fill in the event structure
* TODO: support for unicast key MIC failure event to be handled
*/
qdf_status =
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_MIC_FAILURE_EVENT,
(void *) NULL);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
qdf_ret_status = QDF_STATUS_E_FAILURE;
}
break;
case eCSR_ROAM_RESULT_AUTHENTICATED:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_AUTHENTICATED (%d)"),
roam_result);
/* Fill in the event structure */
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_SET_KEY_EVENT,
(void *) eSAP_STATUS_SUCCESS);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_ASSOCIATED:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_ASSOCIATED (%d)"),
roam_result);
/* Fill in the event structure */
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_REASSOC_EVENT,
(void *) eSAP_STATUS_SUCCESS);
break;
case eCSR_ROAM_RESULT_INFRA_STARTED:
if (!csr_roam_info) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"csr_roam_info is NULL");
qdf_ret_status = QDF_STATUS_E_NULL_VALUE;
break;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STARTED (%d)"),
roam_result);
/*
* In the current implementation, hostapd is not aware that
* drive will support DFS. Hence, driver should inform
* eSAP_MAC_START_BSS_SUCCESS to upper layers and then perform
* CAC underneath
*/
sap_event.event = eSAP_MAC_START_BSS_SUCCESS;
sap_event.params = csr_roam_info;
sap_ctx->sap_sta_id = csr_roam_info->staId;
sap_event.u1 = roam_status;
sap_event.u2 = roam_result;
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_INFRA_STOPPED:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STOPPED (%d)"),
roam_result);
/* Fill in the event structure */
sap_event.event = eSAP_MAC_READY_FOR_CONNECTIONS;
sap_event.params = csr_roam_info;
sap_event.u1 = roam_status;
sap_event.u2 = roam_result;
/* Handle event */
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND (%d)"),
roam_result);
/*
* Fill in the event structure
* TODO: support for group key MIC failure event to be handled
*/
qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_WPS_PBC_PROBE_REQ_EVENT,
(void *) NULL);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_FORCED:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_FORCED (%d)"),
roam_result);
/*
* This event can be used to inform hdd about user triggered
* disassoc event
* Fill in the event structure
*/
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_DISASSOC_EVENT,
(void *) eSAP_STATUS_SUCCESS);
break;
case eCSR_ROAM_RESULT_NONE:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_NONE (%d)"),
roam_result);
/*
* This event can be used to inform hdd about user triggered
* disassoc event
* Fill in the event structure
*/
if (roam_status == eCSR_ROAM_SET_KEY_COMPLETE)
sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_STA_SET_KEY_EVENT,
(void *) eSAP_STATUS_SUCCESS);
break;
case eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("CSR roam_result = eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED (%d)"),
roam_result);
/* Fill in the event structure */
qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_MAX_ASSOC_EXCEEDED,
NULL);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND:
if (sta_sap_scc_on_dfs_chan)
break;
wlansap_roam_process_dfs_radar_found(mac_ctx, sap_ctx,
&qdf_ret_status);
break;
case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS:
wlansap_roam_process_dfs_chansw_update(hal, sap_ctx,
&qdf_ret_status);
break;
case eCSR_ROAM_RESULT_CAC_END_IND:
sap_dfs_cac_timer_callback(hal);
break;
case eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS:
wlansap_roam_process_ch_change_success(mac_ctx, sap_ctx,
csr_roam_info, &qdf_ret_status);
break;
case eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE:
/* This is much more serious issue, we have to vacate the
* channel due to the presence of radar but our channel change
* failed, stop the BSS operation completely and inform hostapd
*/
sap_event.event = eWNI_SME_CHANNEL_CHANGE_RSP;
sap_event.params = 0;
sap_event.u1 = eCSR_ROAM_INFRA_IND;
sap_event.u2 = eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE;
qdf_status = sap_fsm(sap_ctx, &sap_event);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
case eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND:
qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info,
eSAP_ECSA_CHANGE_CHAN_IND, NULL);
if (!QDF_IS_STATUS_SUCCESS(qdf_status))
qdf_ret_status = QDF_STATUS_E_FAILURE;
break;
default:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("CSR roam_result = %s (%d) not handled"),
get_e_csr_roam_result_str(roam_result),
roam_result);
break;
}
wlansap_context_put(sap_ctx);
return qdf_ret_status;
}
void sap_scan_event_callback(struct wlan_objmgr_vdev *vdev,
struct scan_event *event, void *arg)
{
uint32_t scan_id;
uint8_t session_id;
bool success = false;
eCsrScanStatus scan_status = eCSR_SCAN_FAILURE;
tHalHandle hal_handle;
struct sap_context *sap_ctx = arg;
session_id = wlan_vdev_get_id(vdev);
scan_id = event->scan_id;
hal_handle = cds_get_context(QDF_MODULE_ID_SME);
if (!hal_handle) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL,
FL("invalid h_hal"));
return;
}
if (!util_is_scan_completed(event, &success))
return;
if (success)
scan_status = eCSR_SCAN_SUCCESS;
if (!sap_ctx->sap_acs_pre_start_bss)
wlansap_scan_callback(hal_handle, arg, session_id, scan_id,
scan_status);
else
wlansap_pre_start_bss_acs_scan_callback(hal_handle,
arg, session_id,
scan_id, scan_status);
}