qcacld-3.0: Move pre cac hdd code to new file

Move pre cac code related to hdd into a new file
wlan_hdd_pre_cac.c

Change-Id: Ia6b2e92a1bea03d7efe12a7dad27e345dc5ef53d
CRs-Fixed: 3174488
This commit is contained in:
Dundi Raviteja 2022-04-08 12:53:15 +05:30 committed by Madan Koyyalamudi
parent e42e7fb2a0
commit d3bb29db4c
9 changed files with 889 additions and 814 deletions

8
Kbuild
View File

@ -1667,6 +1667,14 @@ endif
$(call add-wlan-objs,ftm_time_sync,$(FTM_TIME_SYNC_OBJS))
########## WLAN PRE_CAC ##########
ifeq ($(CONFIG_FEATURE_WLAN_PRE_CAC), y)
WLAN_PRE_CAC_OBJS := $(HDD_SRC_DIR)/wlan_hdd_pre_cac.o
endif
$(call add-wlan-objs,wlan_pre_cac,$(WLAN_PRE_CAC_OBJS))
########## CLD TARGET_IF #######
CLD_TARGET_IF_DIR := components/target_if

View File

@ -3757,36 +3757,6 @@ static inline int wlan_hdd_get_cpu(void)
}
#endif
#ifdef PRE_CAC_SUPPORT
/**
* wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure
* @data: AP adapter
*
* Deletes the pre cac adapter
*
* Return: None
*/
void wlan_hdd_sap_pre_cac_failure(void *data);
/**
* hdd_clean_up_pre_cac_interface() - Clean up the pre cac interface
* @hdd_ctx: HDD context
*
* Cleans up the pre cac interface, if it exists
*
* Return: None
*/
void hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx);
#else
static inline void wlan_hdd_sap_pre_cac_failure(void *data)
{
}
static inline void
hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx)
{
}
#endif /* PRE_CAC_SUPPORT */
void wlan_hdd_txrx_pause_cb(uint8_t vdev_id,
enum netif_action_type action, enum netif_reason_type reason);

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. 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.
*/
#ifndef _WLAN_HDD_PRE_CAC_H_
#define _WLAN_HDD_PRE_CAC_H_
#ifdef PRE_CAC_SUPPORT
/* default pre cac channel bandwidth */
#define DEFAULT_PRE_CAC_BANDWIDTH CH_WIDTH_80MHZ
/**
* wlan_hdd_sap_pre_cac_success() - Process the pre cac success
* @data: AP adapter
*
* Return: None
*/
void wlan_hdd_sap_pre_cac_success(void *data);
/**
* wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure
* @data: AP adapter
*
* Deletes the pre cac adapter
*
* Return: None
*/
void wlan_hdd_sap_pre_cac_failure(void *data);
/**
* hdd_clean_up_pre_cac_interface() - Clean up the pre cac interface
* @hdd_ctx: HDD context
*
* Cleans up the pre cac interface, if it exists
*
* Return: None
*/
void hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx);
/**
* wlan_hdd_request_pre_cac() - Start pre CAC in the driver
* @hdd_ctx: the HDD context to operate against
* @chan_freq: channel freq option provided by userspace
*
* Sets the driver to the required hardware mode and start an adapter for
* pre CAC which will mimic an AP.
*
* Return: Zero on success, non-zero value on error
*/
int wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq);
/**
* hdd_send_conditional_chan_switch_status() - Send conditional channel switch
* status
* @hdd_ctx: HDD context
* @wdev: Wireless device structure
* @status: Status of conditional channel switch
* (0: Success, Non-zero: Failure)
*
* Sends the status of conditional channel switch to user space. This is named
* conditional channel switch because the SAP will move to the provided channel
* after some condition (pre-cac) is met.
*
* Return: None
*/
void hdd_send_conditional_chan_switch_status(struct hdd_context *hdd_ctx,
struct wireless_dev *wdev,
bool status);
/**
* hdd_close_pre_cac_adapter() - Close pre CAC adapter
* @hdd_ctx: the HDD context to operate against
*
* Return: None
*/
void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx);
#else
static inline void wlan_hdd_sap_pre_cac_success(void *data)
{
}
static inline void wlan_hdd_sap_pre_cac_failure(void *data)
{
}
static inline void
hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx)
{
}
static inline int
wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq)
{
return 0;
}
static inline void
hdd_send_conditional_chan_switch_status(struct hdd_context *hdd_ctx,
struct wireless_dev *wdev,
bool status)
{
}
static inline void
hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx)
{
}
#endif /* PRE_CAC_SUPPORT */
#endif /* _WLAN_HDD_PRE_CAC_H_ */

View File

@ -552,25 +552,6 @@ void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx,
int wlan_hdd_cfg80211_update_apies(struct hdd_adapter *adapter);
#ifdef PRE_CAC_SUPPORT
/**
* wlan_hdd_request_pre_cac() - Start pre CAC in the driver
* @hdd_ctx: the HDD context to operate against
* @chan_freq: channel freq option provided by userspace
*
* Sets the driver to the required hardware mode and start an adapter for
* pre CAC which will mimic an AP.
*
* Return: Zero on success, non-zero value on error
*/
int wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq);
#else
static inline int
wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq)
{
return 0;
}
#endif
int wlan_hdd_sap_cfg_dfs_override(struct hdd_adapter *adapter);
int wlan_hdd_enable_dfs_chan_scan(struct hdd_context *hdd_ctx,

View File

@ -109,6 +109,7 @@
#include "wlan_hdd_son.h"
#include "wlan_hdd_mcc_quota.h"
#include "wlan_hdd_wds.h"
#include "wlan_hdd_pre_cac.h"
#define ACS_SCAN_EXPIRY_TIMEOUT_S 4
@ -1079,194 +1080,6 @@ static QDF_STATUS hdd_send_radar_event(struct hdd_context *hdd_context,
return QDF_STATUS_SUCCESS;
}
#ifdef PRE_CAC_SUPPORT
/**
* hdd_send_conditional_chan_switch_status() - Send conditional channel switch
* status
* @hdd_ctx: HDD context
* @wdev: Wireless device structure
* @status: Status of conditional channel switch
* (0: Success, Non-zero: Failure)
*
* Sends the status of conditional channel switch to user space. This is named
* conditional channel switch because the SAP will move to the provided channel
* after some condition (pre-cac) is met.
*
* Return: None
*/
static void hdd_send_conditional_chan_switch_status(struct hdd_context *hdd_ctx,
struct wireless_dev *wdev,
bool status)
{
struct sk_buff *event;
hdd_enter_dev(wdev->netdev);
if (!hdd_ctx) {
hdd_err("Invalid HDD context pointer");
return;
}
event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
wdev, sizeof(uint32_t) + NLMSG_HDRLEN,
QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX,
GFP_KERNEL);
if (!event) {
hdd_err("cfg80211_vendor_event_alloc failed");
return;
}
if (nla_put_u32(event,
QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS,
status)) {
hdd_err("nla put failed");
kfree_skb(event);
return;
}
cfg80211_vendor_event(event, GFP_KERNEL);
}
/**
* wlan_hdd_set_pre_cac_complete_status() - Set pre cac complete status
* @ap_adapter: AP adapter
* @status: Status which can be true or false
*
* Sets the status of pre cac i.e., whether it is complete or not
*
* Return: Zero on success, non-zero on failure
*/
static int wlan_hdd_set_pre_cac_complete_status(struct hdd_adapter *ap_adapter,
bool status)
{
QDF_STATUS ret;
ret = wlan_sap_set_pre_cac_complete_status(
WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), status);
if (QDF_IS_STATUS_ERROR(ret))
return -EINVAL;
return 0;
}
/**
* __wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure
* @adapter: AP adapter
*
* Deletes the pre cac adapter
*
* Return: None
*/
static void __wlan_hdd_sap_pre_cac_failure(struct hdd_adapter *adapter)
{
struct hdd_context *hdd_ctx;
hdd_enter();
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
if (wlan_hdd_validate_context(hdd_ctx))
return;
hdd_stop_adapter(hdd_ctx, adapter);
hdd_exit();
}
/**
* wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure
* @data: AP adapter
*
* Deletes the pre cac adapter
*
* Return: None
*/
void wlan_hdd_sap_pre_cac_failure(void *data)
{
struct hdd_adapter *adapter = data;
struct osif_vdev_sync *vdev_sync;
int errno;
errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync);
if (errno)
return;
__wlan_hdd_sap_pre_cac_failure(data);
osif_vdev_sync_trans_stop(vdev_sync);
}
/**
* __wlan_hdd_sap_pre_cac_success() - Process the pre cac result
* @adapter: AP adapter
*
* Deletes the pre cac adapter and moves the existing SAP to the pre cac
* channel
*
* Return: None
*/
static void __wlan_hdd_sap_pre_cac_success(struct hdd_adapter *adapter)
{
struct hdd_adapter *ap_adapter;
int i;
struct hdd_context *hdd_ctx;
enum phy_ch_width pre_cac_ch_width;
hdd_enter();
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
if (!hdd_ctx) {
hdd_err("HDD context is null");
return;
}
pre_cac_ch_width = wlansap_get_chan_width(
WLAN_HDD_GET_SAP_CTX_PTR(adapter));
hdd_stop_adapter(hdd_ctx, adapter);
/* Prepare to switch AP from 2.4GHz channel to the pre CAC channel */
ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
if (!ap_adapter) {
hdd_err("failed to get SAP adapter, no restart on pre CAC channel");
return;
}
/*
* Setting of the pre cac complete status will ensure that on channel
* switch to the pre CAC DFS channel, there is no CAC again.
*/
wlan_hdd_set_pre_cac_complete_status(ap_adapter, true);
wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->vdev_id,
CSA_REASON_PRE_CAC_SUCCESS);
i = hdd_softap_set_channel_change(ap_adapter->dev,
ap_adapter->pre_cac_freq,
pre_cac_ch_width, false);
if (0 != i) {
hdd_err("failed to change channel");
wlan_hdd_set_pre_cac_complete_status(ap_adapter, false);
}
hdd_exit();
}
static void wlan_hdd_sap_pre_cac_success(void *data)
{
struct hdd_adapter *adapter = data;
struct osif_vdev_sync *vdev_sync;
int errno;
errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync);
if (errno)
return;
__wlan_hdd_sap_pre_cac_success(adapter);
osif_vdev_sync_trans_stop(vdev_sync);
}
#endif
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
/**
* hdd_handle_acs_scan_event() - handle acs scan event for SAP

View File

@ -164,7 +164,7 @@
#include "wlan_policy_mgr_ucfg.h"
#include "qdf_func_tracker.h"
#include "pld_common.h"
#include "wlan_hdd_pre_cac.h"
#ifdef CNSS_GENL
#ifdef CONFIG_CNSS_OUT_OF_TREE
@ -8099,39 +8099,6 @@ static inline void hdd_dump_func_call_map(void)
}
#endif
#ifdef PRE_CAC_SUPPORT
static void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx)
{
struct hdd_adapter *pre_cac_adapter;
struct osif_vdev_sync *vdev_sync;
int errno;
pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
SAP_PRE_CAC_IFNAME);
if (!pre_cac_adapter)
return;
errno = osif_vdev_sync_trans_start_wait(pre_cac_adapter->dev,
&vdev_sync);
if (errno)
return;
osif_vdev_sync_unregister(pre_cac_adapter->dev);
osif_vdev_sync_wait_for_ops(vdev_sync);
wlan_hdd_release_intf_addr(hdd_ctx, pre_cac_adapter->mac_addr.bytes);
hdd_close_adapter(hdd_ctx, pre_cac_adapter, true);
osif_vdev_sync_trans_stop(vdev_sync);
osif_vdev_sync_destroy(vdev_sync);
}
#else
static inline void
hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx)
{
}
#endif
QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter)
{
@ -19168,33 +19135,6 @@ void hdd_set_conparam(int32_t con_param)
curr_con_mode = con_param;
}
#ifdef PRE_CAC_SUPPORT
void hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx)
{
uint8_t vdev_id;
QDF_STATUS status;
struct hdd_adapter *precac_adapter;
status = wlan_sap_get_pre_cac_vdev_id(hdd_ctx->mac_handle, &vdev_id);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("failed to get pre cac vdev id");
return;
}
precac_adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
if (!precac_adapter) {
hdd_err("invalid pre cac adapter");
return;
}
qdf_create_work(0, &hdd_ctx->sap_pre_cac_work,
wlan_hdd_sap_pre_cac_failure,
(void *)precac_adapter);
qdf_sched_work(0, &hdd_ctx->sap_pre_cac_work);
}
#endif
/**
* hdd_svc_fw_crashed_ind() - API to send FW CRASHED IND to Userspace
*

View File

@ -54,6 +54,7 @@
#include "nan_ucfg_api.h"
#include "wlan_pkt_capture_ucfg_api.h"
#include "wlan_hdd_object_manager.h"
#include "wlan_hdd_pre_cac.h"
/* Ms to Time Unit Micro Sec */
#define MS_TO_TU_MUS(x) ((x) * 1024)

View File

@ -0,0 +1,755 @@
/*
* Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. 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.
*/
#include "osif_vdev_sync.h"
#include "wlan_hdd_hostapd.h"
#include "wlan_hdd_pre_cac.h"
void hdd_send_conditional_chan_switch_status(struct hdd_context *hdd_ctx,
struct wireless_dev *wdev,
bool status)
{
struct sk_buff *event;
hdd_enter_dev(wdev->netdev);
if (!hdd_ctx) {
hdd_err("Invalid HDD context pointer");
return;
}
event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
wdev, sizeof(uint32_t) + NLMSG_HDRLEN,
QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX,
GFP_KERNEL);
if (!event) {
hdd_err("cfg80211_vendor_event_alloc failed");
return;
}
if (nla_put_u32(event,
QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS,
status)) {
hdd_err("nla put failed");
kfree_skb(event);
return;
}
cfg80211_vendor_event(event, GFP_KERNEL);
}
/**
* wlan_hdd_set_pre_cac_complete_status() - Set pre cac complete status
* @ap_adapter: AP adapter
* @status: Status which can be true or false
*
* Sets the status of pre cac i.e., whether it is complete or not
*
* Return: Zero on success, non-zero on failure
*/
static int wlan_hdd_set_pre_cac_complete_status(struct hdd_adapter *ap_adapter,
bool status)
{
QDF_STATUS ret;
ret = wlan_sap_set_pre_cac_complete_status(
WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), status);
if (QDF_IS_STATUS_ERROR(ret))
return -EINVAL;
return 0;
}
/**
* __wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure
* @adapter: AP adapter
*
* Deletes the pre cac adapter
*
* Return: None
*/
static void __wlan_hdd_sap_pre_cac_failure(struct hdd_adapter *adapter)
{
struct hdd_context *hdd_ctx;
hdd_enter();
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
if (wlan_hdd_validate_context(hdd_ctx))
return;
hdd_stop_adapter(hdd_ctx, adapter);
hdd_exit();
}
/**
* wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure
* @data: AP adapter
*
* Deletes the pre cac adapter
*
* Return: None
*/
void wlan_hdd_sap_pre_cac_failure(void *data)
{
struct hdd_adapter *adapter = data;
struct osif_vdev_sync *vdev_sync;
int errno;
errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync);
if (errno)
return;
__wlan_hdd_sap_pre_cac_failure(data);
osif_vdev_sync_trans_stop(vdev_sync);
}
/**
* __wlan_hdd_sap_pre_cac_success() - Process the pre cac result
* @adapter: AP adapter
*
* Stops the pre cac adapter and moves the existing SAP to the pre cac
* channel
*
* Return: None
*/
static void __wlan_hdd_sap_pre_cac_success(struct hdd_adapter *adapter)
{
struct hdd_adapter *ap_adapter;
int i;
struct hdd_context *hdd_ctx;
enum phy_ch_width pre_cac_ch_width;
hdd_enter();
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
if (!hdd_ctx) {
hdd_err("HDD context is null");
return;
}
pre_cac_ch_width = wlansap_get_chan_width(
WLAN_HDD_GET_SAP_CTX_PTR(adapter));
hdd_stop_adapter(hdd_ctx, adapter);
/* Prepare to switch AP from 2.4GHz channel to the pre CAC channel */
ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
if (!ap_adapter) {
hdd_err("failed to get SAP adapter, no restart on pre CAC channel");
return;
}
/*
* Setting of the pre cac complete status will ensure that on channel
* switch to the pre CAC DFS channel, there is no CAC again.
*/
wlan_hdd_set_pre_cac_complete_status(ap_adapter, true);
wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->vdev_id,
CSA_REASON_PRE_CAC_SUCCESS);
i = hdd_softap_set_channel_change(ap_adapter->dev,
ap_adapter->pre_cac_freq,
pre_cac_ch_width, false);
if (i) {
hdd_err("failed to change channel");
wlan_hdd_set_pre_cac_complete_status(ap_adapter, false);
}
hdd_exit();
}
void wlan_hdd_sap_pre_cac_success(void *data)
{
struct hdd_adapter *adapter = data;
struct osif_vdev_sync *vdev_sync;
int errno;
errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync);
if (errno)
return;
__wlan_hdd_sap_pre_cac_success(adapter);
osif_vdev_sync_trans_stop(vdev_sync);
}
void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx)
{
struct hdd_adapter *pre_cac_adapter;
struct osif_vdev_sync *vdev_sync;
int errno;
pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
SAP_PRE_CAC_IFNAME);
if (!pre_cac_adapter)
return;
errno = osif_vdev_sync_trans_start_wait(pre_cac_adapter->dev,
&vdev_sync);
if (errno)
return;
osif_vdev_sync_unregister(pre_cac_adapter->dev);
osif_vdev_sync_wait_for_ops(vdev_sync);
wlan_hdd_release_intf_addr(hdd_ctx, pre_cac_adapter->mac_addr.bytes);
hdd_close_adapter(hdd_ctx, pre_cac_adapter, true);
osif_vdev_sync_trans_stop(vdev_sync);
osif_vdev_sync_destroy(vdev_sync);
}
void hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx)
{
uint8_t vdev_id;
QDF_STATUS status;
struct hdd_adapter *precac_adapter;
status = wlan_sap_get_pre_cac_vdev_id(hdd_ctx->mac_handle, &vdev_id);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("failed to get pre cac vdev id");
return;
}
precac_adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id);
if (!precac_adapter) {
hdd_err("invalid pre cac adapter");
return;
}
qdf_create_work(0, &hdd_ctx->sap_pre_cac_work,
wlan_hdd_sap_pre_cac_failure,
(void *)precac_adapter);
qdf_sched_work(0, &hdd_ctx->sap_pre_cac_work);
}
/**
* wlan_hdd_set_pre_cac_status() - Set the pre cac status
* @pre_cac_adapter: AP adapter used for pre cac
* @status: Status (true or false)
*
* Sets the status of pre cac i.e., whether the pre cac is active or not
*
* Return: Zero on success, non-zero on failure
*/
static int wlan_hdd_set_pre_cac_status(struct hdd_adapter *pre_cac_adapter,
bool status)
{
QDF_STATUS ret;
ret = wlan_sap_set_pre_cac_status(
WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter), status);
if (QDF_IS_STATUS_ERROR(ret))
return -EINVAL;
return 0;
}
/**
* wlan_hdd_set_chan_freq_before_pre_cac() - Save the channel before pre cac
* @ap_adapter: AP adapter
* @freq_before_pre_cac: Channel
*
* Saves the channel frequency which the AP was beaconing on before moving to
* the pre cac channel. If radar is detected on the pre cac channel, this saved
* channel will be used for AP operations.
*
* Return: Zero on success, non-zero on failure
*/
static int
wlan_hdd_set_chan_freq_before_pre_cac(struct hdd_adapter *ap_adapter,
qdf_freq_t freq_before_pre_cac)
{
QDF_STATUS ret;
struct sap_context *sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter);
ret = wlan_sap_set_chan_freq_before_pre_cac(sap_ctx,
freq_before_pre_cac);
if (QDF_IS_STATUS_ERROR(ret))
return -EINVAL;
return 0;
}
/**
* wlan_hdd_validate_and_get_pre_cac_ch() - Validate and get pre cac channel
* @hdd_ctx: HDD context
* @ap_adapter: AP adapter
* @chan_freq: Channel frequency requested by userspace
* @pre_cac_chan_freq: Pointer to the pre CAC channel frequency storage
*
* Validates the channel provided by userspace. If user provided channel 0,
* a valid outdoor channel must be selected from the regulatory channel.
*
* Return: Zero on success and non zero value on error
*/
static int wlan_hdd_validate_and_get_pre_cac_ch(struct hdd_context *hdd_ctx,
struct hdd_adapter *ap_adapter,
uint32_t chan_freq,
uint32_t *pre_cac_chan_freq)
{
uint32_t i;
QDF_STATUS status;
uint32_t weight_len = 0;
uint32_t len = CFG_VALID_CHANNEL_LIST_LEN;
uint32_t freq_list[NUM_CHANNELS] = {0};
uint8_t pcl_weights[NUM_CHANNELS] = {0};
mac_handle_t mac_handle;
if (!chan_freq) {
/* Channel is not obtained from PCL because PCL may not have
* the entire channel list. For example: if SAP is up on
* channel 6 and PCL is queried for the next SAP interface,
* if SCC is preferred, the PCL will contain only the channel
* 6. But, we are in need of a DFS channel. So, going with the
* first channel from the valid channel list.
*/
status = policy_mgr_get_valid_chans(hdd_ctx->psoc,
freq_list, &len);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failed to get channel list");
return -EINVAL;
}
policy_mgr_update_with_safe_channel_list(hdd_ctx->psoc,
freq_list, &len,
pcl_weights,
weight_len);
for (i = 0; i < len; i++) {
if (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev,
freq_list[i])) {
*pre_cac_chan_freq = freq_list[i];
break;
}
}
if (*pre_cac_chan_freq == 0) {
hdd_err("unable to find outdoor channel");
return -EINVAL;
}
} else {
/* Only when driver selects a channel, check is done for
* unnsafe and NOL channels. When user provides a fixed channel
* the user is expected to take care of this.
*/
mac_handle = hdd_ctx->mac_handle;
if (!sme_is_channel_valid(mac_handle, chan_freq) ||
!wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, chan_freq)) {
hdd_err("Invalid channel for pre cac:%d", chan_freq);
return -EINVAL;
}
*pre_cac_chan_freq = chan_freq;
}
hdd_debug("selected pre cac channel:%d", *pre_cac_chan_freq);
return 0;
}
static int wlan_set_def_pre_cac_chan(struct hdd_context *hdd_ctx,
uint32_t pre_cac_ch_freq,
struct cfg80211_chan_def *chandef,
enum nl80211_channel_type *chantype,
enum phy_ch_width *ch_width)
{
enum nl80211_channel_type channel_type;
struct ieee80211_channel *ieee_chan;
struct ch_params ch_params = {0};
ieee_chan = ieee80211_get_channel(hdd_ctx->wiphy,
pre_cac_ch_freq);
if (!ieee_chan) {
hdd_err("channel converion failed %d", pre_cac_ch_freq);
return -EINVAL;
}
ch_params.ch_width = *ch_width;
wlan_reg_set_channel_params_for_freq(hdd_ctx->pdev,
pre_cac_ch_freq, 0,
&ch_params);
switch (ch_params.sec_ch_offset) {
case HIGH_PRIMARY_CH:
channel_type = NL80211_CHAN_HT40MINUS;
break;
case LOW_PRIMARY_CH:
channel_type = NL80211_CHAN_HT40PLUS;
break;
default:
channel_type = NL80211_CHAN_HT20;
break;
}
cfg80211_chandef_create(chandef, ieee_chan, channel_type);
switch (ch_params.ch_width) {
case CH_WIDTH_80MHZ:
chandef->width = NL80211_CHAN_WIDTH_80;
break;
case CH_WIDTH_80P80MHZ:
chandef->width = NL80211_CHAN_WIDTH_80P80;
if (ch_params.mhz_freq_seg1)
chandef->center_freq2 = ch_params.mhz_freq_seg1;
break;
case CH_WIDTH_160MHZ:
chandef->width = NL80211_CHAN_WIDTH_160;
break;
default:
break;
}
if (ch_params.ch_width == CH_WIDTH_80MHZ ||
ch_params.ch_width == CH_WIDTH_80P80MHZ ||
ch_params.ch_width == CH_WIDTH_160MHZ) {
if (ch_params.mhz_freq_seg0)
chandef->center_freq1 = ch_params.mhz_freq_seg0;
}
*chantype = channel_type;
*ch_width = ch_params.ch_width;
hdd_debug("pre cac ch def: chan:%d width:%d freq1:%d freq2:%d",
chandef->chan->center_freq, chandef->width,
chandef->center_freq1, chandef->center_freq2);
return 0;
}
/**
* __wlan_hdd_request_pre_cac() - Start pre CAC in the driver
* @hdd_ctx: the HDD context to operate against
* @chan_freq: Channel frequency option provided by userspace
* @out_adapter: out parameter for the newly created pre-cac adapter
*
* Sets the driver to the required hardware mode and start an adapter for
* pre CAC which will mimic an AP.
*
* Return: Zero on success, non-zero value on error
*/
static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
uint32_t chan_freq,
struct hdd_adapter **out_adapter)
{
uint8_t *mac_addr = NULL;
uint32_t pre_cac_chan_freq = 0;
int ret;
struct hdd_adapter *ap_adapter, *pre_cac_adapter;
struct hdd_ap_ctx *hdd_ap_ctx;
QDF_STATUS status;
struct wiphy *wiphy;
struct net_device *dev;
struct cfg80211_chan_def chandef;
enum nl80211_channel_type channel_type;
mac_handle_t mac_handle;
bool val;
enum phy_ch_width cac_ch_width;
struct hdd_adapter_create_param params = {0};
qdf_freq_t freq;
if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc)) {
hdd_debug("Pre CAC is not supported on non-dbs platforms");
return -EINVAL;
}
pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
SAP_PRE_CAC_IFNAME);
if (pre_cac_adapter) {
/* Flush existing pre_cac work */
if (hdd_ctx->sap_pre_cac_work.fn)
cds_flush_work(&hdd_ctx->sap_pre_cac_work);
} else {
if (policy_mgr_get_connection_count(hdd_ctx->psoc) > 1) {
hdd_err("pre cac not allowed in concurrency");
return -EINVAL;
}
}
ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
if (!ap_adapter) {
hdd_err("unable to get SAP adapter");
return -EINVAL;
}
if (qdf_atomic_read(&ap_adapter->ch_switch_in_progress)) {
hdd_err("pre cac not allowed during CSA");
return -EINVAL;
}
mac_handle = hdd_ctx->mac_handle;
val = wlan_sap_is_pre_cac_active(mac_handle);
if (val) {
hdd_err("pre cac is already in progress");
return -EINVAL;
}
hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter);
if (!hdd_ap_ctx) {
hdd_err("SAP context is NULL");
return -EINVAL;
}
if (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev,
hdd_ap_ctx->operating_chan_freq)) {
hdd_err("SAP is already on DFS channel:%d",
hdd_ap_ctx->operating_chan_freq);
return -EINVAL;
}
if (!WLAN_REG_IS_24GHZ_CH_FREQ(hdd_ap_ctx->operating_chan_freq)) {
hdd_err("pre CAC alllowed only when SAP is in 2.4GHz:%d",
hdd_ap_ctx->operating_chan_freq);
return -EINVAL;
}
hdd_debug("channel: %d", chan_freq);
ret = wlan_hdd_validate_and_get_pre_cac_ch(
hdd_ctx, ap_adapter, chan_freq, &pre_cac_chan_freq);
if (ret != 0) {
hdd_err("can't validate pre-cac channel");
goto release_intf_addr_and_return_failure;
}
hdd_debug("starting pre cac SAP adapter");
if (!pre_cac_adapter) {
mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE);
if (!mac_addr) {
hdd_err("can't add virtual intf: Not getting valid mac addr");
return -EINVAL;
}
/**
* Starting a SAP adapter:
* Instead of opening an adapter, we could just do a SME open
* session for AP type. But, start BSS would still need an
* adapter. So, this option is not taken.
*
* hdd open adapter is going to register this precac interface
* with user space. This interface though exposed to user space
* will be in DOWN state. Consideration was done to avoid this
* registration to the user space. But, as part of SAP
* operations multiple events are sent to user space. Some of
* these events received from unregistered interface was
* causing crashes. So, retaining the registration.
*
* So, this interface would remain registered and will remain
* in DOWN state for the CAC duration. We will add notes in the
* feature announcement to not use this temporary interface for
* any activity from user space.
*/
params.is_add_virtual_iface = 1;
pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE,
SAP_PRE_CAC_IFNAME, mac_addr,
NET_NAME_UNKNOWN, true,
&params);
if (!pre_cac_adapter) {
hdd_err("error opening the pre cac adapter");
goto release_intf_addr_and_return_failure;
}
}
sap_clear_global_dfs_param(mac_handle,
WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter));
/*
* This interface is internally created by the driver. So, no interface
* up comes for this interface from user space and hence starting
* the adapter internally.
*/
if (hdd_start_adapter(pre_cac_adapter)) {
hdd_err("error starting the pre cac adapter");
goto close_pre_cac_adapter;
}
hdd_debug("preparing for start ap/bss on the pre cac adapter");
wiphy = hdd_ctx->wiphy;
dev = pre_cac_adapter->dev;
/* Since this is only a dummy interface lets us use the IEs from the
* other active SAP interface. In regular scenarios, these IEs would
* come from the user space entity
*/
pre_cac_adapter->session.ap.beacon = qdf_mem_malloc(
sizeof(*ap_adapter->session.ap.beacon));
if (!pre_cac_adapter->session.ap.beacon)
goto stop_close_pre_cac_adapter;
qdf_mem_copy(pre_cac_adapter->session.ap.beacon,
ap_adapter->session.ap.beacon,
sizeof(*pre_cac_adapter->session.ap.beacon));
pre_cac_adapter->session.ap.sap_config.ch_width_orig =
ap_adapter->session.ap.sap_config.ch_width_orig;
pre_cac_adapter->session.ap.sap_config.authType =
ap_adapter->session.ap.sap_config.authType;
/* The orginal premise is that on moving from 2.4GHz to 5GHz, the SAP
* will continue to operate on the same bandwidth as that of the 2.4GHz
* operations. Only bandwidths 20MHz/40MHz are possible on 2.4GHz band.
* Now some customer request to start AP on higher BW such as 80Mhz.
* Hence use max possible supported BW based on phymode configurated
* on SAP.
*/
cac_ch_width = wlansap_get_max_bw_by_phymode(
WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter));
if (cac_ch_width > DEFAULT_PRE_CAC_BANDWIDTH)
cac_ch_width = DEFAULT_PRE_CAC_BANDWIDTH;
qdf_mem_zero(&chandef, sizeof(struct cfg80211_chan_def));
if (wlan_set_def_pre_cac_chan(hdd_ctx, pre_cac_chan_freq,
&chandef, &channel_type,
&cac_ch_width)) {
hdd_err("error set pre_cac channel %d", pre_cac_chan_freq);
goto close_pre_cac_adapter;
}
pre_cac_adapter->session.ap.sap_config.ch_width_orig =
hdd_map_nl_chan_width(chandef.width);
hdd_debug("existing ap phymode:%d pre cac ch_width:%d freq:%d",
ap_adapter->session.ap.sap_config.SapHw_mode,
cac_ch_width, pre_cac_chan_freq);
/*
* Doing update after opening and starting pre-cac adapter will make
* sure that driver won't do hardware mode change if there are any
* initial hick-ups or issues in pre-cac adapter's configuration.
* Since current SAP is in 2.4GHz and pre CAC channel is in 5GHz, this
* connection update should result in DBS mode
*/
status = policy_mgr_update_and_wait_for_connection_update(
hdd_ctx->psoc, ap_adapter->vdev_id, pre_cac_chan_freq,
POLICY_MGR_UPDATE_REASON_PRE_CAC);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("error in moving to DBS mode");
goto stop_close_pre_cac_adapter;
}
ret = wlan_hdd_set_channel(wiphy, dev, &chandef, channel_type);
if (ret != 0) {
hdd_err("failed to set channel");
goto stop_close_pre_cac_adapter;
}
status = wlan_hdd_cfg80211_start_bss(pre_cac_adapter, NULL,
PRE_CAC_SSID,
qdf_str_len(PRE_CAC_SSID),
NL80211_HIDDEN_SSID_NOT_IN_USE,
false);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("start bss failed");
goto stop_close_pre_cac_adapter;
}
/*
* The pre cac status is set here. But, it would not be reset explicitly
* anywhere, since after the pre cac success/failure, the pre cac
* adapter itself would be removed.
*/
ret = wlan_hdd_set_pre_cac_status(pre_cac_adapter, true);
if (ret != 0) {
hdd_err("failed to set pre cac status");
goto stop_close_pre_cac_adapter;
}
freq = hdd_ap_ctx->operating_chan_freq;
ret = wlan_hdd_set_chan_freq_before_pre_cac(ap_adapter,
freq);
if (ret != 0) {
hdd_err("failed to set channel before pre cac");
goto stop_close_pre_cac_adapter;
}
ap_adapter->pre_cac_freq = pre_cac_chan_freq;
pre_cac_adapter->is_pre_cac_adapter = true;
*out_adapter = pre_cac_adapter;
return 0;
stop_close_pre_cac_adapter:
hdd_stop_adapter(hdd_ctx, pre_cac_adapter);
qdf_mem_free(pre_cac_adapter->session.ap.beacon);
pre_cac_adapter->session.ap.beacon = NULL;
close_pre_cac_adapter:
hdd_close_adapter(hdd_ctx, pre_cac_adapter, false);
release_intf_addr_and_return_failure:
/*
* Release the interface address as the adapter
* failed to start, if you don't release then next
* adapter which is trying to come wouldn't get valid
* mac address. Remember we have limited pool of mac addresses
*/
if (mac_addr)
wlan_hdd_release_intf_addr(hdd_ctx, mac_addr);
return -EINVAL;
}
static int
wlan_hdd_start_pre_cac_trans(struct hdd_context *hdd_ctx,
struct osif_vdev_sync **out_vdev_sync,
bool *is_vdev_sync_created)
{
struct hdd_adapter *adapter, *next_adapter = NULL;
wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_START_PRE_CAC_TRANS;
int errno;
hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
dbgid) {
if (!qdf_str_cmp(adapter->dev->name, SAP_PRE_CAC_IFNAME)) {
errno = osif_vdev_sync_trans_start(adapter->dev,
out_vdev_sync);
hdd_adapter_dev_put_debug(adapter, dbgid);
if (next_adapter)
hdd_adapter_dev_put_debug(next_adapter,
dbgid);
return errno;
}
hdd_adapter_dev_put_debug(adapter, dbgid);
}
errno = osif_vdev_sync_create_and_trans(hdd_ctx->parent_dev,
out_vdev_sync);
if (errno)
return errno;
*is_vdev_sync_created = true;
return 0;
}
int wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq)
{
struct hdd_adapter *adapter;
struct osif_vdev_sync *vdev_sync;
int errno;
bool is_vdev_sync_created = false;
errno = wlan_hdd_start_pre_cac_trans(hdd_ctx, &vdev_sync,
&is_vdev_sync_created);
if (errno)
return errno;
errno = __wlan_hdd_request_pre_cac(hdd_ctx, chan_freq, &adapter);
if (errno)
goto destroy_sync;
if (is_vdev_sync_created)
osif_vdev_sync_register(adapter->dev, vdev_sync);
osif_vdev_sync_trans_stop(vdev_sync);
return 0;
destroy_sync:
osif_vdev_sync_trans_stop(vdev_sync);
if (is_vdev_sync_created)
osif_vdev_sync_destroy(vdev_sync);
return errno;
}

View File

@ -33,522 +33,7 @@
#include <qdf_str.h>
#include <wlan_hdd_includes.h>
#include <wlan_hdd_sap_cond_chan_switch.h>
#ifdef PRE_CAC_SUPPORT
/* default pre cac channel bandwidth */
#define DEFAULT_PRE_CAC_BANDWIDTH CH_WIDTH_80MHZ
/**
* wlan_hdd_set_pre_cac_status() - Set the pre cac status
* @pre_cac_adapter: AP adapter used for pre cac
* @status: Status (true or false)
*
* Sets the status of pre cac i.e., whether the pre cac is active or not
*
* Return: Zero on success, non-zero on failure
*/
static int wlan_hdd_set_pre_cac_status(struct hdd_adapter *pre_cac_adapter,
bool status)
{
QDF_STATUS ret;
ret = wlan_sap_set_pre_cac_status(
WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter), status);
if (QDF_IS_STATUS_ERROR(ret))
return -EINVAL;
return 0;
}
/**
* wlan_hdd_set_chan_freq_before_pre_cac() - Save the channel before pre cac
* @ap_adapter: AP adapter
* @freq_before_pre_cac: Channel
*
* Saves the channel frequency which the AP was beaconing on before moving to
* the pre cac channel. If radar is detected on the pre cac channel, this saved
* channel will be used for AP operations.
*
* Return: Zero on success, non-zero on failure
*/
static int
wlan_hdd_set_chan_freq_before_pre_cac(struct hdd_adapter *ap_adapter,
qdf_freq_t freq_before_pre_cac)
{
QDF_STATUS ret;
struct sap_context *sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter);
ret = wlan_sap_set_chan_freq_before_pre_cac(sap_ctx,
freq_before_pre_cac);
if (QDF_IS_STATUS_ERROR(ret))
return -EINVAL;
return 0;
}
/**
* wlan_hdd_validate_and_get_pre_cac_ch() - Validate and get pre cac channel
* @hdd_ctx: HDD context
* @ap_adapter: AP adapter
* @chan_freq: Channel frequency requested by userspace
* @pre_cac_chan_freq: Pointer to the pre CAC channel frequency storage
*
* Validates the channel provided by userspace. If user provided channel 0,
* a valid outdoor channel must be selected from the regulatory channel.
*
* Return: Zero on success and non zero value on error
*/
static int wlan_hdd_validate_and_get_pre_cac_ch(struct hdd_context *hdd_ctx,
struct hdd_adapter *ap_adapter,
uint32_t chan_freq,
uint32_t *pre_cac_chan_freq)
{
uint32_t i;
QDF_STATUS status;
uint32_t weight_len = 0;
uint32_t len = CFG_VALID_CHANNEL_LIST_LEN;
uint32_t freq_list[NUM_CHANNELS] = {0};
uint8_t pcl_weights[NUM_CHANNELS] = {0};
mac_handle_t mac_handle;
if (!chan_freq) {
/* Channel is not obtained from PCL because PCL may not have
* the entire channel list. For example: if SAP is up on
* channel 6 and PCL is queried for the next SAP interface,
* if SCC is preferred, the PCL will contain only the channel
* 6. But, we are in need of a DFS channel. So, going with the
* first channel from the valid channel list.
*/
status = policy_mgr_get_valid_chans(hdd_ctx->psoc,
freq_list, &len);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failed to get channel list");
return -EINVAL;
}
policy_mgr_update_with_safe_channel_list(hdd_ctx->psoc,
freq_list, &len,
pcl_weights,
weight_len);
for (i = 0; i < len; i++) {
if (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev,
freq_list[i])) {
*pre_cac_chan_freq = freq_list[i];
break;
}
}
if (*pre_cac_chan_freq == 0) {
hdd_err("unable to find outdoor channel");
return -EINVAL;
}
} else {
/* Only when driver selects a channel, check is done for
* unnsafe and NOL channels. When user provides a fixed channel
* the user is expected to take care of this.
*/
mac_handle = hdd_ctx->mac_handle;
if (!sme_is_channel_valid(mac_handle, chan_freq) ||
!wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, chan_freq)) {
hdd_err("Invalid channel for pre cac:%d", chan_freq);
return -EINVAL;
}
*pre_cac_chan_freq = chan_freq;
}
hdd_debug("selected pre cac channel:%d", *pre_cac_chan_freq);
return 0;
}
static int wlan_set_def_pre_cac_chan(struct hdd_context *hdd_ctx,
uint32_t pre_cac_ch_freq,
struct cfg80211_chan_def *chandef,
enum nl80211_channel_type *chantype,
enum phy_ch_width *ch_width)
{
enum nl80211_channel_type channel_type;
struct ieee80211_channel *ieee_chan;
struct ch_params ch_params = {0};
ieee_chan = ieee80211_get_channel(hdd_ctx->wiphy,
pre_cac_ch_freq);
if (!ieee_chan) {
hdd_err("channel converion failed %d", pre_cac_ch_freq);
return -EINVAL;
}
ch_params.ch_width = *ch_width;
wlan_reg_set_channel_params_for_freq(hdd_ctx->pdev,
pre_cac_ch_freq, 0,
&ch_params);
switch (ch_params.sec_ch_offset) {
case HIGH_PRIMARY_CH:
channel_type = NL80211_CHAN_HT40MINUS;
break;
case LOW_PRIMARY_CH:
channel_type = NL80211_CHAN_HT40PLUS;
break;
default:
channel_type = NL80211_CHAN_HT20;
break;
}
cfg80211_chandef_create(chandef, ieee_chan, channel_type);
switch (ch_params.ch_width) {
case CH_WIDTH_80MHZ:
chandef->width = NL80211_CHAN_WIDTH_80;
break;
case CH_WIDTH_80P80MHZ:
chandef->width = NL80211_CHAN_WIDTH_80P80;
if (ch_params.mhz_freq_seg1)
chandef->center_freq2 = ch_params.mhz_freq_seg1;
break;
case CH_WIDTH_160MHZ:
chandef->width = NL80211_CHAN_WIDTH_160;
break;
default:
break;
}
if (ch_params.ch_width == CH_WIDTH_80MHZ ||
ch_params.ch_width == CH_WIDTH_80P80MHZ ||
ch_params.ch_width == CH_WIDTH_160MHZ) {
if (ch_params.mhz_freq_seg0)
chandef->center_freq1 = ch_params.mhz_freq_seg0;
}
*chantype = channel_type;
*ch_width = ch_params.ch_width;
hdd_debug("pre cac ch def: chan:%d width:%d freq1:%d freq2:%d",
chandef->chan->center_freq, chandef->width,
chandef->center_freq1, chandef->center_freq2);
return 0;
}
/**
* __wlan_hdd_request_pre_cac() - Start pre CAC in the driver
* @hdd_ctx: the HDD context to operate against
* @chan_freq: Channel frequency option provided by userspace
* @out_adapter: out parameter for the newly created pre-cac adapter
*
* Sets the driver to the required hardware mode and start an adapter for
* pre CAC which will mimic an AP.
*
* Return: Zero on success, non-zero value on error
*/
static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx,
uint32_t chan_freq,
struct hdd_adapter **out_adapter)
{
uint8_t *mac_addr = NULL;
uint32_t pre_cac_chan_freq = 0;
int ret;
struct hdd_adapter *ap_adapter, *pre_cac_adapter;
struct hdd_ap_ctx *hdd_ap_ctx;
QDF_STATUS status;
struct wiphy *wiphy;
struct net_device *dev;
struct cfg80211_chan_def chandef;
enum nl80211_channel_type channel_type;
mac_handle_t mac_handle;
bool val;
enum phy_ch_width cac_ch_width;
struct hdd_adapter_create_param params = {0};
if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc)) {
hdd_debug("Pre CAC is not supported on non-dbs platforms");
return -EINVAL;
}
pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx,
SAP_PRE_CAC_IFNAME);
if (pre_cac_adapter) {
/* Flush existing pre_cac work */
if (hdd_ctx->sap_pre_cac_work.fn)
cds_flush_work(&hdd_ctx->sap_pre_cac_work);
} else {
if (policy_mgr_get_connection_count(hdd_ctx->psoc) > 1) {
hdd_err("pre cac not allowed in concurrency");
return -EINVAL;
}
}
ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
if (!ap_adapter) {
hdd_err("unable to get SAP adapter");
return -EINVAL;
}
if (qdf_atomic_read(&ap_adapter->ch_switch_in_progress)) {
hdd_err("pre cac not allowed during CSA");
return -EINVAL;
}
mac_handle = hdd_ctx->mac_handle;
val = wlan_sap_is_pre_cac_active(mac_handle);
if (val) {
hdd_err("pre cac is already in progress");
return -EINVAL;
}
hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter);
if (!hdd_ap_ctx) {
hdd_err("SAP context is NULL");
return -EINVAL;
}
if (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev,
hdd_ap_ctx->operating_chan_freq)) {
hdd_err("SAP is already on DFS channel:%d",
hdd_ap_ctx->operating_chan_freq);
return -EINVAL;
}
if (!WLAN_REG_IS_24GHZ_CH_FREQ(hdd_ap_ctx->operating_chan_freq)) {
hdd_err("pre CAC alllowed only when SAP is in 2.4GHz:%d",
hdd_ap_ctx->operating_chan_freq);
return -EINVAL;
}
hdd_debug("channel: %d", chan_freq);
ret = wlan_hdd_validate_and_get_pre_cac_ch(
hdd_ctx, ap_adapter, chan_freq, &pre_cac_chan_freq);
if (ret != 0) {
hdd_err("can't validate pre-cac channel");
goto release_intf_addr_and_return_failure;
}
hdd_debug("starting pre cac SAP adapter");
if (!pre_cac_adapter) {
mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE);
if (!mac_addr) {
hdd_err("can't add virtual intf: Not getting valid mac addr");
return -EINVAL;
}
/**
* Starting a SAP adapter:
* Instead of opening an adapter, we could just do a SME open
* session for AP type. But, start BSS would still need an
* adapter. So, this option is not taken.
*
* hdd open adapter is going to register this precac interface
* with user space. This interface though exposed to user space
* will be in DOWN state. Consideration was done to avoid this
* registration to the user space. But, as part of SAP
* operations multiple events are sent to user space. Some of
* these events received from unregistered interface was
* causing crashes. So, retaining the registration.
*
* So, this interface would remain registered and will remain
* in DOWN state for the CAC duration. We will add notes in the
* feature announcement to not use this temporary interface for
* any activity from user space.
*/
params.is_add_virtual_iface = 1;
pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE,
SAP_PRE_CAC_IFNAME, mac_addr,
NET_NAME_UNKNOWN, true,
&params);
if (!pre_cac_adapter) {
hdd_err("error opening the pre cac adapter");
goto release_intf_addr_and_return_failure;
}
}
sap_clear_global_dfs_param(mac_handle,
WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter));
/*
* This interface is internally created by the driver. So, no interface
* up comes for this interface from user space and hence starting
* the adapter internally.
*/
if (hdd_start_adapter(pre_cac_adapter)) {
hdd_err("error starting the pre cac adapter");
goto close_pre_cac_adapter;
}
hdd_debug("preparing for start ap/bss on the pre cac adapter");
wiphy = hdd_ctx->wiphy;
dev = pre_cac_adapter->dev;
/* Since this is only a dummy interface lets us use the IEs from the
* other active SAP interface. In regular scenarios, these IEs would
* come from the user space entity
*/
pre_cac_adapter->session.ap.beacon = qdf_mem_malloc(
sizeof(*ap_adapter->session.ap.beacon));
if (!pre_cac_adapter->session.ap.beacon)
goto stop_close_pre_cac_adapter;
qdf_mem_copy(pre_cac_adapter->session.ap.beacon,
ap_adapter->session.ap.beacon,
sizeof(*pre_cac_adapter->session.ap.beacon));
pre_cac_adapter->session.ap.sap_config.ch_width_orig =
ap_adapter->session.ap.sap_config.ch_width_orig;
pre_cac_adapter->session.ap.sap_config.authType =
ap_adapter->session.ap.sap_config.authType;
/* The orginal premise is that on moving from 2.4GHz to 5GHz, the SAP
* will continue to operate on the same bandwidth as that of the 2.4GHz
* operations. Only bandwidths 20MHz/40MHz are possible on 2.4GHz band.
* Now some customer request to start AP on higher BW such as 80Mhz.
* Hence use max possible supported BW based on phymode configurated
* on SAP.
*/
cac_ch_width = wlansap_get_max_bw_by_phymode(
WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter));
if (cac_ch_width > DEFAULT_PRE_CAC_BANDWIDTH)
cac_ch_width = DEFAULT_PRE_CAC_BANDWIDTH;
qdf_mem_zero(&chandef, sizeof(struct cfg80211_chan_def));
if (wlan_set_def_pre_cac_chan(hdd_ctx, pre_cac_chan_freq,
&chandef, &channel_type,
&cac_ch_width)) {
hdd_err("error set pre_cac channel %d", pre_cac_chan_freq);
goto close_pre_cac_adapter;
}
pre_cac_adapter->session.ap.sap_config.ch_width_orig =
hdd_map_nl_chan_width(chandef.width);
hdd_debug("existing ap phymode:%d pre cac ch_width:%d freq:%d",
ap_adapter->session.ap.sap_config.SapHw_mode,
cac_ch_width, pre_cac_chan_freq);
/*
* Doing update after opening and starting pre-cac adapter will make
* sure that driver won't do hardware mode change if there are any
* initial hick-ups or issues in pre-cac adapter's configuration.
* Since current SAP is in 2.4GHz and pre CAC channel is in 5GHz, this
* connection update should result in DBS mode
*/
status = policy_mgr_update_and_wait_for_connection_update(
hdd_ctx->psoc, ap_adapter->vdev_id, pre_cac_chan_freq,
POLICY_MGR_UPDATE_REASON_PRE_CAC);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("error in moving to DBS mode");
goto stop_close_pre_cac_adapter;
}
ret = wlan_hdd_set_channel(wiphy, dev, &chandef, channel_type);
if (ret != 0) {
hdd_err("failed to set channel");
goto stop_close_pre_cac_adapter;
}
status = wlan_hdd_cfg80211_start_bss(pre_cac_adapter, NULL,
PRE_CAC_SSID, qdf_str_len(PRE_CAC_SSID),
NL80211_HIDDEN_SSID_NOT_IN_USE, false);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("start bss failed");
goto stop_close_pre_cac_adapter;
}
/*
* The pre cac status is set here. But, it would not be reset explicitly
* anywhere, since after the pre cac success/failure, the pre cac
* adapter itself would be removed.
*/
ret = wlan_hdd_set_pre_cac_status(pre_cac_adapter, true);
if (ret != 0) {
hdd_err("failed to set pre cac status");
goto stop_close_pre_cac_adapter;
}
ret = wlan_hdd_set_chan_freq_before_pre_cac(ap_adapter,
hdd_ap_ctx->operating_chan_freq);
if (ret != 0) {
hdd_err("failed to set channel before pre cac");
goto stop_close_pre_cac_adapter;
}
ap_adapter->pre_cac_freq = pre_cac_chan_freq;
pre_cac_adapter->is_pre_cac_adapter = true;
*out_adapter = pre_cac_adapter;
return 0;
stop_close_pre_cac_adapter:
hdd_stop_adapter(hdd_ctx, pre_cac_adapter);
qdf_mem_free(pre_cac_adapter->session.ap.beacon);
pre_cac_adapter->session.ap.beacon = NULL;
close_pre_cac_adapter:
hdd_close_adapter(hdd_ctx, pre_cac_adapter, false);
release_intf_addr_and_return_failure:
/*
* Release the interface address as the adapter
* failed to start, if you don't release then next
* adapter which is trying to come wouldn't get valid
* mac address. Remember we have limited pool of mac addresses
*/
if (mac_addr)
wlan_hdd_release_intf_addr(hdd_ctx, mac_addr);
return -EINVAL;
}
static int
wlan_hdd_start_pre_cac_trans(struct hdd_context *hdd_ctx,
struct osif_vdev_sync **out_vdev_sync,
bool *is_vdev_sync_created)
{
struct hdd_adapter *adapter, *next_adapter = NULL;
wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_START_PRE_CAC_TRANS;
int errno;
hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
dbgid) {
if (!qdf_str_cmp(adapter->dev->name, SAP_PRE_CAC_IFNAME)) {
errno = osif_vdev_sync_trans_start(adapter->dev,
out_vdev_sync);
hdd_adapter_dev_put_debug(adapter, dbgid);
if (next_adapter)
hdd_adapter_dev_put_debug(next_adapter,
dbgid);
return errno;
}
hdd_adapter_dev_put_debug(adapter, dbgid);
}
errno = osif_vdev_sync_create_and_trans(hdd_ctx->parent_dev,
out_vdev_sync);
if (errno)
return errno;
*is_vdev_sync_created = true;
return 0;
}
int wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq)
{
struct hdd_adapter *adapter;
struct osif_vdev_sync *vdev_sync;
int errno;
bool is_vdev_sync_created = false;
errno = wlan_hdd_start_pre_cac_trans(hdd_ctx, &vdev_sync,
&is_vdev_sync_created);
if (errno)
return errno;
errno = __wlan_hdd_request_pre_cac(hdd_ctx, chan_freq, &adapter);
if (errno)
goto destroy_sync;
if (is_vdev_sync_created)
osif_vdev_sync_register(adapter->dev, vdev_sync);
osif_vdev_sync_trans_stop(vdev_sync);
return 0;
destroy_sync:
osif_vdev_sync_trans_stop(vdev_sync);
if (is_vdev_sync_created)
osif_vdev_sync_destroy(vdev_sync);
return errno;
}
#endif
#include "wlan_hdd_pre_cac.h"
const struct nla_policy conditional_chan_switch_policy[
QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX + 1] = {