diff --git a/Kbuild b/Kbuild index ce0e1d073265..1f803ef912c7 100644 --- a/Kbuild +++ b/Kbuild @@ -166,6 +166,46 @@ ifeq ($(CONFIG_WLAN_FEATURE_PACKET_FILTERING), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_packet_filter.o endif +ifeq ($(CONFIG_FEATURE_RSSI_MONITOR), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_rssi_monitor.o +endif + +ifeq ($(CONFIG_FEATURE_BSS_TRANSITION), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_bss_transition.o +endif + +ifeq ($(CONFIG_FEATURE_STATION_INFO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_station_info.o +endif + +ifeq ($(CONFIG_FEATURE_TX_POWER), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tx_power.o +endif + +ifeq ($(CONFIG_FEATURE_OTA_TEST), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ota_test.o +endif + +ifeq ($(CONFIG_FEATURE_ACTIVE_TOS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_active_tos.o +endif + +ifeq ($(CONFIG_FEATURE_SAR_LIMITS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sar_limits.o +endif + +ifeq ($(CONFIG_FEATURE_CONCURRENCY_MATRIX), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_concurrency_matrix.o +endif + +ifeq ($(CONFIG_FEATURE_SAP_COND_CHAN_SWITCH), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sap_cond_chan_switch.o +endif + +ifeq ($(CONFIG_FEATURE_P2P_LISTEN_OFFLOAD), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_p2p_listen_offload.o +endif + ########### Driver Synchronization Core (DSC) ########### DSC_DIR := components/dsc DSC_INC_DIR := $(DSC_DIR)/inc @@ -2093,12 +2133,23 @@ ifeq ($(CONFIG_QCA6290_11AX), y) cppflags-y += -DQCA_WIFI_QCA6290_11AX endif - cppflags-$(CONFIG_WLAN_FEATURE_11AX) += -DWLAN_FEATURE_11AX cppflags-$(CONFIG_WLAN_FEATURE_11AX) += -DWLAN_FEATURE_11AX_BSS_COLOR cppflags-$(CONFIG_LITHIUM) += -DFEATURE_AST +# Vendor Commands +cppflags-$(CONFIG_FEATURE_RSSI_MONITOR) += -DFEATURE_RSSI_MONITOR +cppflags-$(CONFIG_FEATURE_BSS_TRANSITION) += -DFEATURE_BSS_TRANSITION +cppflags-$(CONFIG_FEATURE_STATION_INFO) += -DFEATURE_STATION_INFO +cppflags-$(CONFIG_FEATURE_TX_POWER) += -DFEATURE_TX_POWER +cppflags-$(CONFIG_FEATURE_OTA_TEST) += -DFEATURE_OTA_TEST +cppflags-$(CONFIG_FEATURE_ACTIVE_TOS) += -DFEATURE_ACTIVE_TOS +cppflags-$(CONFIG_FEATURE_SAR_LIMITS) += -DFEATURE_SAR_LIMITS +cppflags-$(CONFIG_FEATURE_CONCURRENCY_MATRIX) += -DFEATURE_CONCURRENCY_MATRIX +cppflags-$(CONFIG_FEATURE_SAP_COND_CHAN_SWITCH) += -DFEATURE_SAP_COND_CHAN_SWITCH +cppflags-$(CONFIG_FEATURE_P2P_LISTEN_OFFLOAD) += -DFEATURE_P2P_LISTEN_OFFLOAD + # Dummy flag for WIN/MCL converged data path compilation cppflags-y += -DDP_PRINT_ENABLE=0 cppflags-y += -DATH_SUPPORT_WRAP=0 diff --git a/configs/default_defconfig b/configs/default_defconfig index fa1166dcb434..35368f9caa65 100644 --- a/configs/default_defconfig +++ b/configs/default_defconfig @@ -573,6 +573,18 @@ CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y CONFIG_WLAN_FEATURE_TWT := y CONFIG_WLAN_FEATURE_BMI := y +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := y +CONFIG_FEATURE_BSS_TRANSITION := y +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := y +CONFIG_FEATURE_OTA_TEST := y +CONFIG_FEATURE_ACTIVE_TOS := y +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y + ifeq ($(CONFIG_HELIUMPLUS), y) ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y diff --git a/configs/genoa.common b/configs/genoa.common index 7868788867b8..6eed4baa5768 100644 --- a/configs/genoa.common +++ b/configs/genoa.common @@ -3,7 +3,7 @@ #features not required for GENOA IOT, compilation errors are there. CONFIG_SUPPORT_11AX := y CONFIG_160MHZ_SUPPORT := y -CONFIG_FEATURE_STATS_EXT := y +CONFIG_FEATURE_STATS_EXT := n CONFIG_QCA_IBSS_SUPPORT := y #required features @@ -114,6 +114,18 @@ CONFIG_WLAN_FEATURE_SAE := y CONFIG_CHNL_MATRIX_RESTRICTION := n CONFIG_WLAN_FEATURE_BMI := n +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := n +CONFIG_FEATURE_BSS_TRANSITION := n +CONFIG_FEATURE_STATION_INFO := n +CONFIG_FEATURE_TX_POWER := n +CONFIG_FEATURE_OTA_TEST := n +CONFIG_FEATURE_ACTIVE_TOS := n +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := n +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := n +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := n + ifeq ($(CONFIG_ARCH_SDM845), y) ifeq ($(CONFIG_IPA_OFFLOAD), y) CONFIG_ENABLE_SMMU_S1_TRANSLATION := y diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 946cd132bd6b..8be54edb5c01 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1631,36 +1631,6 @@ enum hdd_sta_smps_param { HDD_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE = 5 }; -/** - * tos - Type of service requested by the application - * TOS_BK: Back ground traffic - * TOS_BE: Best effort traffic - * TOS_VI: Video traffic - * TOS_VO: Voice traffic - */ -enum tos { - TOS_BK = 0, - TOS_BE = 1, - TOS_VI = 2, - TOS_VO = 3, -}; - -#define HDD_AC_BK_BIT 1 -#define HDD_AC_BE_BIT 2 -#define HDD_AC_VI_BIT 4 -#define HDD_AC_VO_BIT 8 - -#define HDD_MAX_OFF_CHAN_TIME_FOR_VO 20 -#define HDD_MAX_OFF_CHAN_TIME_FOR_VI 20 -#define HDD_MAX_OFF_CHAN_TIME_FOR_BE 40 -#define HDD_MAX_OFF_CHAN_TIME_FOR_BK 40 - -#define HDD_MAX_AC 4 -#define HDD_MAX_OFF_CHAN_ENTRIES 2 - -#define HDD_AC_BIT_INDX 0 -#define HDD_DWELL_TIME_INDX 1 - /** * enum RX_OFFLOAD - Receive offload modes * @CFG_LRO_ENABLED: Large Rx offload @@ -2931,22 +2901,6 @@ void hdd_restart_sap(struct hdd_adapter *ap_adapter); void hdd_check_and_restart_sap_with_non_dfs_acs(void); bool hdd_set_connection_in_progress(bool value); -/** - * wlan_hdd_sap_get_valid_channellist() - Get SAPs valid channel list - * @ap_adapter: adapter - * @channel_count: valid channel count - * @channel_list: valid channel list - * @band: frequency band - * - * This API returns valid channel list for SAP after removing nol and - * channel which lies outside of configuration. - * - * Return: Zero on success, non-zero on failure - */ -int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter, - uint32_t *channel_count, - uint8_t *channel_list, - enum band_info band); /** * wlan_hdd_init_chan_info() - initialize channel info variables * @hdd_ctx: hdd ctx @@ -3211,19 +3165,6 @@ void hdd_dp_trace_init(struct hdd_config *config) {} void hdd_set_rx_mode_rps(bool enable); -/** - * hdd_set_limit_off_chan_for_tos() - set limit off-chan command parameters - * @adapter: pointer adapter context - * @tos: type of service - * @status: status of the traffic (active/inactive) - * - * This function updates the limit off-channel command parameters to WMA - * - * Return: 0 on success or non zero value on failure - */ -int hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, enum tos tos, - bool is_tos_active); - /** * hdd_drv_ops_inactivity_handler() - Timeout handler for driver ops * inactivity timer diff --git a/core/hdd/inc/wlan_hdd_p2p.h b/core/hdd/inc/wlan_hdd_p2p.h index 876ff193101e..9796b2894572 100644 --- a/core/hdd/inc/wlan_hdd_p2p.h +++ b/core/hdd/inc/wlan_hdd_p2p.h @@ -123,30 +123,6 @@ void wlan_hdd_roc_request_dequeue(struct work_struct *work); int wlan_hdd_set_power_save(struct hdd_adapter *adapter, struct p2p_ps_config *ps_config); -/** - * wlan_hdd_listen_offload_start() - hdd set listen offload start - * @adapter: adapter context - * @params: listen offload parameters - * - * This function sets listen offload start parameters. - * - * Return: 0 - success - * others - failure - */ -int wlan_hdd_listen_offload_start(struct hdd_adapter *adapter, - struct sir_p2p_lo_start *params); - -/** - * wlan_hdd_listen_offload_stop() - hdd set listen offload stop - * @adapter: adapter context - * - * This function sets listen offload stop parameters. - * - * Return: 0 - success - * others - failure - */ -int wlan_hdd_listen_offload_stop(struct hdd_adapter *adapter); - /** * wlan_hdd_set_mas() - Function to set MAS value to FW * @adapter: Pointer to HDD adapter diff --git a/core/hdd/src/wlan_hdd_active_tos.c b/core/hdd/src/wlan_hdd_active_tos.c new file mode 100644 index 000000000000..7884835d0a23 --- /dev/null +++ b/core/hdd/src/wlan_hdd_active_tos.c @@ -0,0 +1,227 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_active_tos.c + * + * WLAN active tos functions + * + */ + +#include +#include +#include +#include +#include +#include + +/** + * tos - Type of service requested by the application + * TOS_BK: Back ground traffic + * TOS_BE: Best effort traffic + * TOS_VI: Video traffic + * TOS_VO: Voice traffic + */ +enum tos { + TOS_BK = 0, + TOS_BE = 1, + TOS_VI = 2, + TOS_VO = 3, +}; + +#define HDD_AC_BK_BIT 1 +#define HDD_AC_BE_BIT 2 +#define HDD_AC_VI_BIT 4 +#define HDD_AC_VO_BIT 8 + +#define HDD_MAX_OFF_CHAN_TIME_FOR_VO 20 +#define HDD_MAX_OFF_CHAN_TIME_FOR_VI 20 +#define HDD_MAX_OFF_CHAN_TIME_FOR_BE 40 +#define HDD_MAX_OFF_CHAN_TIME_FOR_BK 40 + +#define HDD_MAX_AC 4 +#define HDD_MAX_OFF_CHAN_ENTRIES 2 + +#define HDD_AC_BIT_INDX 0 +#define HDD_DWELL_TIME_INDX 1 + +static int limit_off_chan_tbl[HDD_MAX_AC][HDD_MAX_OFF_CHAN_ENTRIES] = { + { HDD_AC_BK_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BK }, + { HDD_AC_BE_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BE }, + { HDD_AC_VI_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VI }, + { HDD_AC_VO_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VO }, +}; + +static const struct nla_policy +wlan_hdd_set_limit_off_channel_param_policy +[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START] = {.type = NLA_U8 }, +}; + +/** + * hdd_set_limit_off_chan_for_tos() - set limit off-channel command parameters + * @adapter: HDD adapter + * @tos: type of service + * @is_tos_active: status of the traffic + * + * Return: 0 on success and non zero value on failure + */ + +static int +hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, + enum tos tos, + bool is_tos_active) +{ + int ac_bit; + struct hdd_context *hdd_ctx; + uint32_t max_off_chan_time = 0; + QDF_STATUS status; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + + if (ret < 0) + return ret; + + ac_bit = limit_off_chan_tbl[tos][HDD_AC_BIT_INDX]; + + if (is_tos_active) + adapter->active_ac |= ac_bit; + else + adapter->active_ac &= ~ac_bit; + + if (adapter->active_ac) { + if (adapter->active_ac & HDD_AC_VO_BIT) { + max_off_chan_time = + limit_off_chan_tbl[TOS_VO][HDD_DWELL_TIME_INDX]; + policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, + PM_LATENCY); + } else if (adapter->active_ac & HDD_AC_VI_BIT) { + max_off_chan_time = + limit_off_chan_tbl[TOS_VI][HDD_DWELL_TIME_INDX]; + policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, + PM_LATENCY); + } else { + /*ignore this command if only BE/BK is active */ + is_tos_active = false; + policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, + hdd_ctx->config->conc_system_pref); + } + } else { + /* No active tos */ + policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, + hdd_ctx->config->conc_system_pref); + } + + status = sme_send_limit_off_channel_params(hdd_ctx->mac_handle, + adapter->session_id, + is_tos_active, + max_off_chan_time, + hdd_ctx->config->nRestTimeConc, + true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to set limit off chan params"); + ret = -EINVAL; + } + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_limit_offchan_param() - set limit off-channel cmd + * parameters + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to limit off-channel command parameters. + * @data_len: the length in byte of limit off-channel command parameters. + * + * This is called when application wants to limit the off channel time due to + * active voip traffic. + * + * Return: An error code or 0 on success. + */ +static int +__wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1]; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + uint8_t tos; + uint8_t tos_status; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret < 0) + return ret; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX, + data, data_len, + wlan_hdd_set_limit_off_channel_param_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]) { + hdd_err("attr tos failed"); + goto fail; + } + + tos = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]); + if (tos >= HDD_MAX_AC) { + hdd_err("tos value %d exceeded Max value %d", + tos, HDD_MAX_AC); + goto fail; + } + hdd_debug("tos %d", tos); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]) { + hdd_err("attr tos active failed"); + goto fail; + } + tos_status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]); + + hdd_debug("tos status %d", tos_status); + ret = hdd_set_limit_off_chan_for_tos(adapter, tos, tos_status); + +fail: + return ret; +} + +int wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) + +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_limit_offchan_param(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_active_tos.h b/core/hdd/src/wlan_hdd_active_tos.h new file mode 100644 index 000000000000..80f39c4ac2e9 --- /dev/null +++ b/core/hdd/src/wlan_hdd_active_tos.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_ACTIVE_TOS_H +#define __WLAN_HDD_ACTIVE_TOS_H + +/** + * DOC: wlan_hdd_active_tos_h + * + * WLAN Host Device Driver ACTIVE TOS API specification + */ + +#ifdef FEATURE_ACTIVE_TOS +/** + * wlan_hdd_cfg80211_set_limit_offchan_param() - set limit off-channel cmd + * parameters + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to limit off-channel command parameters. + * @data_len: the length in byte of limit off-channel command parameters. + * + * This is called when application wants to limit the off channel time due to + * active voip traffic. + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +#define FEATURE_ACTIVE_TOS_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_limit_offchan_param \ +}, +#else /* FEATURE_ACTIVE_TOS */ +#define FEATURE_ACTIVE_TOS_VENDOR_COMMANDS +#endif /* FEATURE_ACTIVE_TOS */ + +#endif /* __WLAN_HDD_ACTIVE_TOS_H */ + diff --git a/core/hdd/src/wlan_hdd_bss_transition.c b/core/hdd/src/wlan_hdd_bss_transition.c new file mode 100644 index 000000000000..fd4b01224572 --- /dev/null +++ b/core/hdd/src/wlan_hdd_bss_transition.c @@ -0,0 +1,270 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_bss_transition.c + * + * WLAN bss transition functions + * + */ + +#include +#include +#include +#include +#include +#include + +/** + * wlan_hdd_is_bt_in_progress() - check if bt activity is in progress + * @hdd_ctx : HDD context + * + * Return: true if BT activity is in progress else false + */ +static bool wlan_hdd_is_bt_in_progress(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->bt_a2dp_active || hdd_ctx->bt_vo_active) + return true; + + return false; +} + +/** + * wlan_hdd_fill_btm_resp() - Fill bss candidate response buffer + * @reply_skb : pointer to reply_skb + * @info : bss candidate information + * @index : attribute type index for nla_next_start() + * + * Return : 0 on success and errno on failure + */ +static int wlan_hdd_fill_btm_resp(struct sk_buff *reply_skb, + struct bss_candidate_info *info, + int index) +{ + struct nlattr *attr; + + attr = nla_nest_start(reply_skb, index); + if (!attr) { + hdd_err("nla_nest_start failed"); + kfree_skb(reply_skb); + return -EINVAL; + } + + if (nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID, + ETH_ALEN, info->bssid.bytes) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS, + info->status)) { + hdd_err("nla_put failed"); + kfree_skb(reply_skb); + return -EINVAL; + } + + nla_nest_end(reply_skb, attr); + + return 0; +} + +/** + * __wlan_hdd_cfg80211_fetch_bss_transition_status() - fetch bss transition + * status + * @wiphy : WIPHY structure pointer + * @wdev : Wireless device structure pointer + * @data : Pointer to the data received + * @data_len : Length of the data received + * + * This function is used to fetch transition status for candidate bss. The + * transition status is either accept or reason for reject. + * + * Return : 0 on success and errno on failure + */ +static int +__wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1]; + uint8_t transition_reason; + struct nlattr *attr; + struct sk_buff *reply_skb; + int rem, j; + int ret; + bool is_bt_in_progress; + struct bss_candidate_info candidate_info[MAX_CANDIDATE_INFO]; + uint16_t nof_candidates, i = 0; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + mac_handle_t mac_handle; + + const struct nla_policy + btm_params_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO] = { + .type = NLA_NESTED}, + }; + const struct nla_policy + btm_cand_list_policy[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] + = {[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = { + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = { + .type = NLA_U32}, + }; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (adapter->device_mode != QDF_STA_MODE || + hdd_sta_ctx->conn_info.connState != eConnectionState_Associated) { + hdd_err("Command is either not invoked for STA mode (device mode: %d) or STA is not associated (Connection state: %d)", + adapter->device_mode, hdd_sta_ctx->conn_info.connState); + return -EINVAL; + } + + ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, + data_len, btm_params_policy); + if (ret) { + hdd_err("Attribute parse failed"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] || + !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO]) { + hdd_err("Missing attributes"); + return -EINVAL; + } + + transition_reason = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON]); + + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO], + rem) { + ret = wlan_cfg80211_nla_parse_nested(tb_msg, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX, + attr, btm_cand_list_policy); + if (ret) { + hdd_err("Attribute parse failed"); + return -EINVAL; + } + + if (!tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]) { + hdd_err("Missing BSSID attribute"); + return -EINVAL; + } + + qdf_mem_copy((void *)candidate_info[i].bssid.bytes, + nla_data(tb_msg[ + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]), + QDF_MAC_ADDR_SIZE); + i++; + if (i == MAX_CANDIDATE_INFO) + break; + } + + /* + * Determine status for each candidate and fill in the status field. + * Also arrange the candidates in the order of preference. + */ + nof_candidates = i; + + is_bt_in_progress = wlan_hdd_is_bt_in_progress(hdd_ctx); + + mac_handle = hdd_ctx->mac_handle; + ret = sme_get_bss_transition_status(mac_handle, transition_reason, + &hdd_sta_ctx->conn_info.bssId, + candidate_info, + nof_candidates, + is_bt_in_progress); + if (ret) + return -EINVAL; + + /* Prepare the reply and send it to userspace */ + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + ((QDF_MAC_ADDR_SIZE + sizeof(uint32_t)) * + nof_candidates) + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("reply buffer alloc failed"); + return -ENOMEM; + } + + attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO); + if (!attr) { + hdd_err("nla_nest_start failed"); + kfree_skb(reply_skb); + return -EINVAL; + } + + /* + * Order candidates as - accepted candidate list followed by rejected + * candidate list + */ + for (i = 0, j = 0; i < nof_candidates; i++) { + /* copy accepted candidate list */ + if (candidate_info[i].status == QCA_STATUS_ACCEPT) { + if (wlan_hdd_fill_btm_resp(reply_skb, + &candidate_info[i], j)) + return -EINVAL; + j++; + } + } + for (i = 0; i < nof_candidates; i++) { + /* copy rejected candidate list */ + if (candidate_info[i].status != QCA_STATUS_ACCEPT) { + if (wlan_hdd_fill_btm_resp(reply_skb, + &candidate_info[i], j)) + return -EINVAL; + j++; + } + } + nla_nest_end(reply_skb, attr); + + hdd_exit(); + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +int wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_fetch_bss_transition_status(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_bss_transition.h b/core/hdd/src/wlan_hdd_bss_transition.h new file mode 100644 index 000000000000..86ba2470ae64 --- /dev/null +++ b/core/hdd/src/wlan_hdd_bss_transition.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_BSS_TRANSITION_H +#define __WLAN_HDD_BSS_TRANSITION_H + +/** + * DOC: wlan_hdd_bss_transition_h + * + * WLAN Host Device Driver BSS transition API specification + */ + +#ifdef FEATURE_BSS_TRANSITION +/** + * wlan_hdd_cfg80211_fetch_bss_transition_status() - fetch bss transition status + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to fetch transition status for candidate bss. The + * transition status is either accept or reason for reject. + * + * Return: 0 on success and errno on failure + */ +int +wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +#define FEATURE_BSS_TRANSITION_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_fetch_bss_transition_status \ +}, +#else /* FEATURE_BSS_TRANSITION */ +#define FEATURE_BSS_TRANSITION_VENDOR_COMMANDS +#endif /* FEATURE_BSS_TRANSITION */ + +#endif /* __WLAN_HDD_BSS_TRANSITION_H */ + diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 82e7538402be..e3d7bd2fb53d 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -107,6 +107,16 @@ #include #include #include "wlan_tdls_cfg_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define g_mode_rates_size (12) #define a_mode_rates_size (8) @@ -160,10 +170,6 @@ #define IS_DFS_MODE_VALID(mode) ((mode >= DFS_MODE_NONE && \ mode <= DFS_MODE_DEPRIORITIZE)) - -#define MAX_TXPOWER_SCALE 4 -#define CDS_MAX_FEATURE_SET 8 - /* * Number of DPTRACE records to dump when a cfg80211 disconnect with reason * WLAN_REASON_DEAUTH_LEAVING DEAUTH is received from user-space. @@ -1376,10 +1382,9 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST }, #endif /* FEATURE_WLAN_EXTSCAN */ - [QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = { - .vendor_id = QCA_NL80211_VENDOR_ID, - .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI - }, + + FEATURE_RSSI_MONITOR_VENDOR_EVENTS + #ifdef WLAN_FEATURE_TSF [QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX] = { .vendor_id = QCA_NL80211_VENDOR_ID, @@ -2098,6 +2103,70 @@ static void hdd_get_freq_list(uint8_t *channel_list, uint32_t *freq_list, freq_list[count] = cds_chan_to_freq(channel_list[count]); } +/** + * wlan_hdd_sap_get_valid_channellist() - Get SAPs valid channel list + * @ap_adapter: adapter + * @channel_count: valid channel count + * @channel_list: valid channel list + * @band: frequency band + * + * This API returns valid channel list for SAP after removing nol and + * channel which lies outside of configuration. + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter, + uint32_t *channel_count, + uint8_t *channel_list, + enum band_info band) +{ + tsap_config_t *sap_config; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t tmp_chan_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t chan_count; + uint8_t i; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev = hdd_ctx->hdd_pdev; + uint8_t tmp_chan; + + sap_config = &adapter->session.ap.sap_config; + + status = + policy_mgr_get_valid_chans(hdd_ctx->hdd_psoc, + tmp_chan_list, + &chan_count); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get channel list"); + return -EINVAL; + } + + for (i = 0; i < chan_count; i++) { + tmp_chan = tmp_chan_list[i]; + if (*channel_count < QDF_MAX_NUM_CHAN) { + if ((band == BAND_2G) && + (WLAN_REG_IS_24GHZ_CH(tmp_chan)) && + (!wlan_reg_is_disable_ch(pdev, tmp_chan))) { + channel_list[*channel_count] = tmp_chan; + *channel_count += 1; + } else if ((band == BAND_5G) && + (WLAN_REG_IS_5GHZ_CH(tmp_chan)) && + (!wlan_reg_is_disable_ch(pdev, tmp_chan))) { + channel_list[*channel_count] = tmp_chan; + *channel_count += 1; + } + } else { + break; + } + } + + if (*channel_count == 0) { + hdd_err("no valid channel found"); + return -EINVAL; + } + + return 0; +} + int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter, uint8_t reason) { @@ -3186,128 +3255,6 @@ wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy, return ret; } -#define MAX_CONCURRENT_MATRIX \ - QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX -#define MATRIX_CONFIG_PARAM_SET_SIZE_MAX \ - QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX -static const struct nla_policy -wlan_hdd_get_concurrency_matrix_policy[MAX_CONCURRENT_MATRIX + 1] = { - [MATRIX_CONFIG_PARAM_SET_SIZE_MAX] = {.type = NLA_U32}, -}; - -/** - * __wlan_hdd_cfg80211_get_concurrency_matrix() - to retrieve concurrency matrix - * @wiphy: pointer phy adapter - * @wdev: pointer to wireless device structure - * @data: pointer to data buffer - * @data_len: length of data - * - * This routine will give concurrency matrix - * - * Return: int status code - */ -static int __wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - uint32_t feature_set_matrix[CDS_MAX_FEATURE_SET] = {0}; - uint8_t i, feature_sets, max_feature_sets; - struct nlattr *tb[MAX_CONCURRENT_MATRIX + 1]; - struct sk_buff *reply_skb; - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - int ret; - - hdd_enter_dev(wdev->netdev); - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EPERM; - } - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret) - return ret; - - if (wlan_cfg80211_nla_parse(tb, MAX_CONCURRENT_MATRIX, data, data_len, - wlan_hdd_get_concurrency_matrix_policy)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - /* Parse and fetch max feature set */ - if (!tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]) { - hdd_err("Attr max feature set size failed"); - return -EINVAL; - } - max_feature_sets = nla_get_u32(tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]); - hdd_debug("Max feature set size: %d", max_feature_sets); - - /* Fill feature combination matrix */ - feature_sets = 0; - feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | - WIFI_FEATURE_P2P; - feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | - WIFI_FEATURE_NAN; - /* Add more feature combinations here */ - - feature_sets = QDF_MIN(feature_sets, max_feature_sets); - hdd_debug("Number of feature sets: %d", feature_sets); - hdd_debug("Feature set matrix"); - for (i = 0; i < feature_sets; i++) - hdd_debug("[%d] 0x%02X", i, feature_set_matrix[i]); - - reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + - sizeof(u32) * feature_sets + NLMSG_HDRLEN); - if (!reply_skb) { - hdd_err("Feature set matrix: buffer alloc fail"); - return -ENOMEM; - } - - if (nla_put_u32(reply_skb, - QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE, - feature_sets) || - nla_put(reply_skb, - QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET, - sizeof(u32) * feature_sets, - feature_set_matrix)) { - hdd_err("nla put fail"); - kfree_skb(reply_skb); - return -EINVAL; - } - return cfg80211_vendor_cmd_reply(reply_skb); -} - -#undef MAX_CONCURRENT_MATRIX -#undef MATRIX_CONFIG_PARAM_SET_SIZE_MAX - -/** - * wlan_hdd_cfg80211_get_concurrency_matrix() - get concurrency matrix - * @wiphy: pointer to wireless wiphy structure. - * @wdev: pointer to wireless_dev structure. - * @data: Pointer to the data to be passed via vendor interface - * @data_len:Length of the data to be passed - * - * Retrieves the concurrency feature set matrix - * - * Return: 0 on success, negative errno on failure - */ -static int -wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_get_concurrency_matrix(wiphy, wdev, - data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - /** * wlan_hdd_cfg80211_set_feature() - Set the bitmask for supported features * @feature_flags: pointer to the byte array of features. @@ -4393,575 +4340,6 @@ static int wlan_hdd_cfg80211_handle_wisa_cmd(struct wiphy *wiphy, return ret; } -/* - * define short names for the global vendor params - * used by __wlan_hdd_cfg80211_get_station_cmd() - */ -#define STATION_INVALID \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INVALID -#define STATION_INFO \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO -#define STATION_ASSOC_FAIL_REASON \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_ASSOC_FAIL_REASON -#define STATION_REMOTE \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_REMOTE -#define STATION_MAX \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX - -/* define short names for get station info attributes */ -#define LINK_INFO_STANDARD_NL80211_ATTR \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_LINK_STANDARD_NL80211_ATTR -#define AP_INFO_STANDARD_NL80211_ATTR \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_STANDARD_NL80211_ATTR -#define INFO_ROAM_COUNT \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT -#define INFO_AKM \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM -#define WLAN802_11_MODE \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE -#define AP_INFO_HS20_INDICATION \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION -#define HT_OPERATION \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HT_OPERATION -#define VHT_OPERATION \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_VHT_OPERATION -#define INFO_ASSOC_FAIL_REASON \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_FAIL_REASON -#define REMOTE_MAX_PHY_RATE \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_MAX_PHY_RATE -#define REMOTE_TX_PACKETS \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_PACKETS -#define REMOTE_TX_BYTES \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_BYTES -#define REMOTE_RX_PACKETS \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_PACKETS -#define REMOTE_RX_BYTES \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_BYTES -#define REMOTE_LAST_TX_RATE \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_LAST_TX_RATE -#define REMOTE_LAST_RX_RATE \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_LAST_RX_RATE -#define REMOTE_WMM \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_WMM -#define REMOTE_SUPPORTED_MODE \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_SUPPORTED_MODE -#define REMOTE_AMPDU \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_AMPDU -#define REMOTE_TX_STBC \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_STBC -#define REMOTE_RX_STBC \ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_STBC -#define REMOTE_CH_WIDTH\ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_CH_WIDTH -#define REMOTE_SGI_ENABLE\ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_SGI_ENABLE -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) - #define REMOTE_PAD\ - QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_PAD -#endif - -static const struct nla_policy -hdd_get_station_policy[STATION_MAX + 1] = { - [STATION_INFO] = {.type = NLA_FLAG}, - [STATION_ASSOC_FAIL_REASON] = {.type = NLA_FLAG}, - [STATION_REMOTE] = {.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE}, -}; - -#ifdef QCA_SUPPORT_CP_STATS -static int hdd_get_sta_congestion(struct hdd_adapter *adapter, - uint32_t *congestion) -{ - QDF_STATUS status; - struct cca_stats cca_stats; - - status = ucfg_mc_cp_stats_cca_stats_get(adapter->hdd_vdev, &cca_stats); - if (QDF_IS_STATUS_ERROR(status)) - return -EINVAL; - - *congestion = cca_stats.congestion; - return 0; -} -#else -static int hdd_get_sta_congestion(struct hdd_adapter *adapter, - uint32_t *congestion) -{ - struct hdd_station_ctx *hdd_sta_ctx; - - hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); - *congestion = hdd_sta_ctx->conn_info.cca; - return 0; -} -#endif - -/** - * hdd_get_station_assoc_fail() - Handle get station assoc fail - * @hdd_ctx: HDD context within host driver - * @wdev: wireless device - * - * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION_ASSOC_FAIL. - * Validate cmd attributes and send the station info to upper layers. - * - * Return: Success(0) or reason code for failure - */ -static int hdd_get_station_assoc_fail(struct hdd_context *hdd_ctx, - struct hdd_adapter *adapter) -{ - struct sk_buff *skb = NULL; - uint32_t nl_buf_len; - struct hdd_station_ctx *hdd_sta_ctx; - uint32_t congestion; - - nl_buf_len = NLMSG_HDRLEN; - nl_buf_len += sizeof(uint32_t); - skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); - - if (!skb) { - hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); - return -ENOMEM; - } - - hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); - - if (nla_put_u32(skb, INFO_ASSOC_FAIL_REASON, - hdd_sta_ctx->conn_info.assoc_status_code)) { - hdd_err("put fail"); - goto fail; - } - - if (hdd_get_sta_congestion(adapter, &congestion)) - congestion = 0; - - hdd_info("congestion:%d", congestion); - if (nla_put_u32(skb, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, - congestion)) { - hdd_err("put fail"); - goto fail; - } - - return cfg80211_vendor_cmd_reply(skb); -fail: - if (skb) - kfree_skb(skb); - return -EINVAL; -} - -/** - * hdd_map_auth_type() - transform auth type specific to - * vendor command - * @auth_type: csr auth type - * - * Return: Success(0) or reason code for failure - */ -static int hdd_convert_auth_type(uint32_t auth_type) -{ - uint32_t ret_val; - - switch (auth_type) { - case eCSR_AUTH_TYPE_OPEN_SYSTEM: - ret_val = QCA_WLAN_AUTH_TYPE_OPEN; - break; - case eCSR_AUTH_TYPE_SHARED_KEY: - ret_val = QCA_WLAN_AUTH_TYPE_SHARED; - break; - case eCSR_AUTH_TYPE_WPA: - ret_val = QCA_WLAN_AUTH_TYPE_WPA; - break; - case eCSR_AUTH_TYPE_WPA_PSK: - ret_val = QCA_WLAN_AUTH_TYPE_WPA_PSK; - break; - case eCSR_AUTH_TYPE_AUTOSWITCH: - ret_val = QCA_WLAN_AUTH_TYPE_AUTOSWITCH; - break; - case eCSR_AUTH_TYPE_WPA_NONE: - ret_val = QCA_WLAN_AUTH_TYPE_WPA_NONE; - break; - case eCSR_AUTH_TYPE_RSN: - ret_val = QCA_WLAN_AUTH_TYPE_RSN; - break; - case eCSR_AUTH_TYPE_RSN_PSK: - ret_val = QCA_WLAN_AUTH_TYPE_RSN_PSK; - break; - case eCSR_AUTH_TYPE_FT_RSN: - ret_val = QCA_WLAN_AUTH_TYPE_FT; - break; - case eCSR_AUTH_TYPE_FT_RSN_PSK: - ret_val = QCA_WLAN_AUTH_TYPE_FT_PSK; - break; - case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: - ret_val = QCA_WLAN_AUTH_TYPE_WAI; - break; - case eCSR_AUTH_TYPE_WAPI_WAI_PSK: - ret_val = QCA_WLAN_AUTH_TYPE_WAI_PSK; - break; - case eCSR_AUTH_TYPE_CCKM_WPA: - ret_val = QCA_WLAN_AUTH_TYPE_CCKM_WPA; - break; - case eCSR_AUTH_TYPE_CCKM_RSN: - ret_val = QCA_WLAN_AUTH_TYPE_CCKM_RSN; - break; - case eCSR_AUTH_TYPE_RSN_PSK_SHA256: - ret_val = QCA_WLAN_AUTH_TYPE_SHA256_PSK; - break; - case eCSR_AUTH_TYPE_RSN_8021X_SHA256: - ret_val = QCA_WLAN_AUTH_TYPE_SHA256; - break; - case eCSR_NUM_OF_SUPPORT_AUTH_TYPE: - case eCSR_AUTH_TYPE_FAILED: - case eCSR_AUTH_TYPE_NONE: - default: - ret_val = QCA_WLAN_AUTH_TYPE_INVALID; - break; - } - return ret_val; -} - -/** - * hdd_map_dot_11_mode() - transform dot11mode type specific to - * vendor command - * @dot11mode: dot11mode - * - * Return: Success(0) or reason code for failure - */ -static int hdd_convert_dot11mode(uint32_t dot11mode) -{ - uint32_t ret_val; - - switch (dot11mode) { - case eCSR_CFG_DOT11_MODE_11A: - ret_val = QCA_WLAN_802_11_MODE_11A; - break; - case eCSR_CFG_DOT11_MODE_11B: - ret_val = QCA_WLAN_802_11_MODE_11B; - break; - case eCSR_CFG_DOT11_MODE_11G: - ret_val = QCA_WLAN_802_11_MODE_11G; - break; - case eCSR_CFG_DOT11_MODE_11N: - ret_val = QCA_WLAN_802_11_MODE_11N; - break; - case eCSR_CFG_DOT11_MODE_11AC: - ret_val = QCA_WLAN_802_11_MODE_11AC; - break; - case eCSR_CFG_DOT11_MODE_AUTO: - case eCSR_CFG_DOT11_MODE_ABG: - default: - ret_val = QCA_WLAN_802_11_MODE_INVALID; - } - return ret_val; -} - -/** - * hdd_add_tx_bitrate() - add tx bitrate attribute - * @skb: pointer to sk buff - * @hdd_sta_ctx: pointer to hdd station context - * @idx: attribute index - * - * Return: Success(0) or reason code for failure - */ -static int32_t hdd_add_tx_bitrate(struct sk_buff *skb, - struct hdd_station_ctx *hdd_sta_ctx, - int idx) -{ - struct nlattr *nla_attr; - uint32_t bitrate, bitrate_compat; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) { - hdd_err("nla_nest_start failed"); - goto fail; - } - - /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ - bitrate = cfg80211_calculate_bitrate(&hdd_sta_ctx-> - cache_conn_info.txrate); - - /* report 16-bit bitrate only if we can */ - bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; - - if (bitrate > 0) { - if (nla_put_u32(skb, NL80211_RATE_INFO_BITRATE32, bitrate)) { - hdd_err("put fail bitrate: %u", bitrate); - goto fail; - } - } else { - hdd_err("Invalid bitrate: %u", bitrate); - } - - if (bitrate_compat > 0) { - if (nla_put_u16(skb, NL80211_RATE_INFO_BITRATE, - bitrate_compat)) { - hdd_err("put fail bitrate_compat: %u", bitrate_compat); - goto fail; - } - } else { - hdd_err("Invalid bitrate_compat: %u", bitrate_compat); - } - - if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS, - hdd_sta_ctx->cache_conn_info.txrate.nss)) { - hdd_err("put fail"); - goto fail; - } - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_sta_info() - add station info attribute - * @skb: pointer to sk buff - * @hdd_sta_ctx: pointer to hdd station context - * @idx: attribute index - * - * Return: Success(0) or reason code for failure - */ -static int32_t hdd_add_sta_info(struct sk_buff *skb, - struct hdd_station_ctx *hdd_sta_ctx, int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) { - hdd_err("nla_nest_start failed"); - goto fail; - } - - if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, - (hdd_sta_ctx->cache_conn_info.signal + 100))) { - hdd_err("put fail"); - goto fail; - } - if (hdd_add_tx_bitrate(skb, hdd_sta_ctx, NL80211_STA_INFO_TX_BITRATE)) { - hdd_err("hdd_add_tx_bitrate failed"); - goto fail; - } - - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_survey_info() - add survey info attribute - * @skb: pointer to sk buff - * @hdd_sta_ctx: pointer to hdd station context - * @idx: attribute index - * - * Return: Success(0) or reason code for failure - */ -static int32_t hdd_add_survey_info(struct sk_buff *skb, - struct hdd_station_ctx *hdd_sta_ctx, - int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) - goto fail; - if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY, - hdd_sta_ctx->cache_conn_info.freq) || - nla_put_u8(skb, NL80211_SURVEY_INFO_NOISE, - (hdd_sta_ctx->cache_conn_info.noise + 100))) { - hdd_err("put fail"); - goto fail; - } - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_link_standard_info() - add link info attribute - * @skb: pointer to sk buff - * @hdd_sta_ctx: pointer to hdd station context - * @idx: attribute index - * - * Return: Success(0) or reason code for failure - */ -static int32_t -hdd_add_link_standard_info(struct sk_buff *skb, - struct hdd_station_ctx *hdd_sta_ctx, int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) { - hdd_err("nla_nest_start failed"); - goto fail; - } - - if (nla_put(skb, - NL80211_ATTR_SSID, - hdd_sta_ctx->cache_conn_info.last_ssid.SSID.length, - hdd_sta_ctx->cache_conn_info.last_ssid.SSID.ssId)) { - hdd_err("put fail"); - goto fail; - } - if (nla_put(skb, NL80211_ATTR_MAC, QDF_MAC_ADDR_SIZE, - hdd_sta_ctx->cache_conn_info.bssId.bytes)) { - hdd_err("put bssid failed"); - goto fail; - } - if (hdd_add_survey_info(skb, hdd_sta_ctx, NL80211_ATTR_SURVEY_INFO)) { - hdd_err("hdd_add_survey_info failed"); - goto fail; - } - - if (hdd_add_sta_info(skb, hdd_sta_ctx, NL80211_ATTR_STA_INFO)) { - hdd_err("hdd_add_sta_info failed"); - goto fail; - } - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_ap_standard_info() - add ap info attribute - * @skb: pointer to sk buff - * @hdd_sta_ctx: pointer to hdd station context - * @idx: attribute index - * - * Return: Success(0) or reason code for failure - */ -static int32_t -hdd_add_ap_standard_info(struct sk_buff *skb, - struct hdd_station_ctx *hdd_sta_ctx, int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) - goto fail; - if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present) - if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, - sizeof(hdd_sta_ctx->cache_conn_info.vht_caps), - &hdd_sta_ctx->cache_conn_info.vht_caps)) { - hdd_err("put fail"); - goto fail; - } - if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present) - if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, - sizeof(hdd_sta_ctx->cache_conn_info.ht_caps), - &hdd_sta_ctx->cache_conn_info.ht_caps)) { - hdd_err("put fail"); - goto fail; - } - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_get_station_info() - send BSS information to supplicant - * @hdd_ctx: pointer to hdd context - * @adapter: pointer to adapter - * - * Return: 0 if success else error status - */ -static int hdd_get_station_info(struct hdd_context *hdd_ctx, - struct hdd_adapter *adapter) -{ - struct sk_buff *skb = NULL; - uint8_t *tmp_hs20 = NULL; - uint32_t nl_buf_len; - struct hdd_station_ctx *hdd_sta_ctx; - - hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); - - nl_buf_len = NLMSG_HDRLEN; - nl_buf_len += sizeof(hdd_sta_ctx-> - cache_conn_info.last_ssid.SSID.length) + - QDF_MAC_ADDR_SIZE + - sizeof(hdd_sta_ctx->cache_conn_info.freq) + - sizeof(hdd_sta_ctx->cache_conn_info.noise) + - sizeof(hdd_sta_ctx->cache_conn_info.signal) + - (sizeof(uint32_t) * 2) + - sizeof(hdd_sta_ctx->cache_conn_info.txrate.nss) + - sizeof(hdd_sta_ctx->cache_conn_info.roam_count) + - sizeof(hdd_sta_ctx->cache_conn_info.last_auth_type) + - sizeof(hdd_sta_ctx->cache_conn_info.dot11Mode); - if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present) - nl_buf_len += sizeof(hdd_sta_ctx->cache_conn_info.vht_caps); - if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present) - nl_buf_len += sizeof(hdd_sta_ctx->cache_conn_info.ht_caps); - if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) { - tmp_hs20 = (uint8_t *)&(hdd_sta_ctx-> - cache_conn_info.hs20vendor_ie); - nl_buf_len += (sizeof(hdd_sta_ctx-> - cache_conn_info.hs20vendor_ie) - 1); - } - if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) - nl_buf_len += sizeof(hdd_sta_ctx-> - cache_conn_info.ht_operation); - if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) - nl_buf_len += sizeof(hdd_sta_ctx-> - cache_conn_info.vht_operation); - - - skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); - if (!skb) { - hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); - return -ENOMEM; - } - - if (hdd_add_link_standard_info(skb, hdd_sta_ctx, - LINK_INFO_STANDARD_NL80211_ATTR)) { - hdd_err("put fail"); - goto fail; - } - if (hdd_add_ap_standard_info(skb, hdd_sta_ctx, - AP_INFO_STANDARD_NL80211_ATTR)) { - hdd_err("put fail"); - goto fail; - } - if (nla_put_u32(skb, INFO_ROAM_COUNT, - hdd_sta_ctx->cache_conn_info.roam_count) || - nla_put_u32(skb, INFO_AKM, - hdd_convert_auth_type( - hdd_sta_ctx->cache_conn_info.last_auth_type)) || - nla_put_u32(skb, WLAN802_11_MODE, - hdd_convert_dot11mode( - hdd_sta_ctx->cache_conn_info.dot11Mode))) { - hdd_err("put fail"); - goto fail; - } - if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) - if (nla_put(skb, HT_OPERATION, - (sizeof(hdd_sta_ctx->cache_conn_info.ht_operation)), - &hdd_sta_ctx->cache_conn_info.ht_operation)) { - hdd_err("put fail"); - goto fail; - } - if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) - if (nla_put(skb, VHT_OPERATION, - (sizeof(hdd_sta_ctx-> - cache_conn_info.vht_operation)), - &hdd_sta_ctx->cache_conn_info.vht_operation)) { - hdd_err("put fail"); - goto fail; - } - if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) - if (nla_put(skb, AP_INFO_HS20_INDICATION, - (sizeof(hdd_sta_ctx->cache_conn_info.hs20vendor_ie) - - 1), - tmp_hs20 + 1)) { - hdd_err("put fail"); - goto fail; - } - - return cfg80211_vendor_cmd_reply(skb); -fail: - if (skb) - kfree_skb(skb); - return -EINVAL; -} - struct hdd_station_info *hdd_get_stainfo(struct hdd_station_info *astainfo, struct qdf_mac_addr mac_addr) { @@ -4980,638 +4358,6 @@ struct hdd_station_info *hdd_get_stainfo(struct hdd_station_info *astainfo, return stainfo; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) -static inline int32_t remote_station_put_u64(struct sk_buff *skb, - int32_t attrtype, - uint64_t value) -{ - return nla_put_u64_64bit(skb, attrtype, value, REMOTE_PAD); -} -#else -static inline int32_t remote_station_put_u64(struct sk_buff *skb, - int32_t attrtype, - uint64_t value) -{ - return nla_put_u64(skb, attrtype, value); -} -#endif - -/** - * hdd_add_survey_info_sap_get_len - get data length used in - * hdd_add_survey_info_sap() - * - * This function calculates the data length used in hdd_add_survey_info_sap() - * - * Return: total data length used in hdd_add_survey_info_sap() - */ -static uint32_t hdd_add_survey_info_sap_get_len(void) -{ - return ((NLA_HDRLEN) + (sizeof(uint32_t) + NLA_HDRLEN)); -} - -/** - * hdd_add_survey_info - add survey info attribute - * @skb: pointer to response skb buffer - * @stainfo: station information - * @idx: attribute type index for nla_next_start() - * - * This function adds survey info attribute to response skb buffer - * - * Return : 0 on success and errno on failure - */ -static int32_t hdd_add_survey_info_sap(struct sk_buff *skb, - struct hdd_station_info *stainfo, - int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) - goto fail; - if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY, - stainfo->freq)) { - hdd_err("put fail"); - goto fail; - } - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_tx_bitrate_sap_get_len - get data length used in - * hdd_add_tx_bitrate_sap() - * - * This function calculates the data length used in hdd_add_tx_bitrate_sap() - * - * Return: total data length used in hdd_add_tx_bitrate_sap() - */ -static uint32_t hdd_add_tx_bitrate_sap_get_len(void) -{ - return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN)); -} - -/** - * hdd_add_tx_bitrate_sap - add vhs nss info attribute - * @skb: pointer to response skb buffer - * @stainfo: station information - * @idx: attribute type index for nla_next_start() - * - * This function adds vht nss attribute to response skb buffer - * - * Return : 0 on success and errno on failure - */ -static int hdd_add_tx_bitrate_sap(struct sk_buff *skb, - struct hdd_station_info *stainfo, - int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) - goto fail; - - if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS, - stainfo->nss)) { - hdd_err("put fail"); - goto fail; - } - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_sta_info_sap_get_len - get data length used in - * hdd_add_sta_info_sap() - * - * This function calculates the data length used in hdd_add_sta_info_sap() - * - * Return: total data length used in hdd_add_sta_info_sap() - */ -static uint32_t hdd_add_sta_info_sap_get_len(void) -{ - return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN) + - hdd_add_tx_bitrate_sap_get_len()); -} - -/** - * hdd_add_sta_info_sap - add sta signal info attribute - * @skb: pointer to response skb buffer - * @stainfo: station information - * @idx: attribute type index for nla_next_start() - * - * This function adds sta signal attribute to response skb buffer - * - * Return : 0 on success and errno on failure - */ -static int32_t hdd_add_sta_info_sap(struct sk_buff *skb, int8_t rssi, - struct hdd_station_info *stainfo, int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) - goto fail; - - if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, rssi)) { - hdd_err("put fail"); - goto fail; - } - if (hdd_add_tx_bitrate_sap(skb, stainfo, NL80211_STA_INFO_TX_BITRATE)) - goto fail; - - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_link_standard_info_sap_get_len - get data length used in - * hdd_add_link_standard_info_sap() - * - * This function calculates the data length used in - * hdd_add_link_standard_info_sap() - * - * Return: total data length used in hdd_add_link_standard_info_sap() - */ -static uint32_t hdd_add_link_standard_info_sap_get_len(void) -{ - return ((NLA_HDRLEN) + - hdd_add_survey_info_sap_get_len() + - hdd_add_sta_info_sap_get_len() + - (sizeof(uint32_t) + NLA_HDRLEN)); -} - -/** - * hdd_add_link_standard_info_sap - add add link info attribut - * @skb: pointer to response skb buffer - * @stainfo: station information - * @idx: attribute type index for nla_next_start() - * - * This function adds link info attribut to response skb buffer - * - * Return : 0 on success and errno on failure - */ -static int hdd_add_link_standard_info_sap(struct sk_buff *skb, int8_t rssi, - struct hdd_station_info *stainfo, - int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) - goto fail; - if (hdd_add_survey_info_sap(skb, stainfo, NL80211_ATTR_SURVEY_INFO)) - goto fail; - if (hdd_add_sta_info_sap(skb, rssi, stainfo, NL80211_ATTR_STA_INFO)) - goto fail; - - if (nla_put_u32(skb, NL80211_ATTR_REASON_CODE, stainfo->reason_code)) { - hdd_err("Reason code put fail"); - goto fail; - } - - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_add_ap_standard_info_sap_get_len - get data length used in - * hdd_add_ap_standard_info_sap() - * @stainfo: station information - * - * This function calculates the data length used in - * hdd_add_ap_standard_info_sap() - * - * Return: total data length used in hdd_add_ap_standard_info_sap() - */ -static uint32_t hdd_add_ap_standard_info_sap_get_len( - struct hdd_station_info *stainfo) -{ - uint32_t len; - - len = NLA_HDRLEN; - if (stainfo->vht_present) - len += (sizeof(stainfo->vht_caps) + NLA_HDRLEN); - if (stainfo->ht_present) - len += (sizeof(stainfo->ht_caps) + NLA_HDRLEN); - - return len; -} - -/** - * hdd_add_ap_standard_info_sap - add HT and VHT info attributes - * @skb: pointer to response skb buffer - * @stainfo: station information - * @idx: attribute type index for nla_next_start() - * - * This function adds HT and VHT info attributes to response skb buffer - * - * Return : 0 on success and errno on failure - */ -static int hdd_add_ap_standard_info_sap(struct sk_buff *skb, - struct hdd_station_info *stainfo, - int idx) -{ - struct nlattr *nla_attr; - - nla_attr = nla_nest_start(skb, idx); - if (!nla_attr) - goto fail; - - if (stainfo->vht_present) { - if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, - sizeof(stainfo->vht_caps), - &stainfo->vht_caps)) { - hdd_err("put fail"); - goto fail; - } - } - if (stainfo->ht_present) { - if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, - sizeof(stainfo->ht_caps), - &stainfo->ht_caps)) { - hdd_err("put fail"); - goto fail; - } - } - nla_nest_end(skb, nla_attr); - return 0; -fail: - return -EINVAL; -} - -/** - * hdd_decode_ch_width - decode channel band width based - * @ch_width: encoded enum value holding channel band width - * - * This function decodes channel band width from the given encoded enum value. - * - * Returns: decoded channel band width. - */ -static uint8_t hdd_decode_ch_width(tSirMacHTChannelWidth ch_width) -{ - switch (ch_width) { - case 0: - return 20; - case 1: - return 40; - case 2: - return 80; - case 3: - case 4: - return 160; - default: - hdd_debug("invalid enum: %d", ch_width); - return 20; - } -} - -/** - * hdd_get_cached_station_remote() - get cached(deleted) peer's info - * @hdd_ctx: hdd context - * @adapter: hostapd interface - * @mac_addr: mac address of requested peer - * - * This function collect and indicate the cached(deleted) peer's info - * - * Return: 0 on success, otherwise error value - */ - -static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx, - struct hdd_adapter *adapter, - struct qdf_mac_addr mac_addr) -{ - struct hdd_station_info *stainfo = hdd_get_stainfo( - adapter->cache_sta_info, - mac_addr); - struct sk_buff *skb = NULL; - uint32_t nl_buf_len = NLMSG_HDRLEN; - uint8_t channel_width; - - if (!stainfo) { - hdd_err("peer " MAC_ADDRESS_STR " not found", - MAC_ADDR_ARRAY(mac_addr.bytes)); - return -EINVAL; - } - - nl_buf_len += hdd_add_link_standard_info_sap_get_len() + - hdd_add_ap_standard_info_sap_get_len(stainfo) + - (sizeof(stainfo->dot11_mode) + NLA_HDRLEN) + - (sizeof(stainfo->ch_width) + NLA_HDRLEN) + - (sizeof(stainfo->tx_rate) + NLA_HDRLEN) + - (sizeof(stainfo->rx_rate) + NLA_HDRLEN); - - skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); - if (!skb) { - hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); - return -ENOMEM; - } - - if (hdd_add_link_standard_info_sap(skb, stainfo->rssi, stainfo, - LINK_INFO_STANDARD_NL80211_ATTR)) { - hdd_err("link standard put fail"); - goto fail; - } - - if (hdd_add_ap_standard_info_sap(skb, stainfo, - AP_INFO_STANDARD_NL80211_ATTR)) { - hdd_err("ap standard put fail"); - goto fail; - } - - /* upper layer expects decoded channel BW */ - channel_width = hdd_decode_ch_width(stainfo->ch_width); - - if (nla_put_u32(skb, REMOTE_SUPPORTED_MODE, - hdd_convert_dot11mode( - stainfo->mode)) || - nla_put_u8(skb, REMOTE_CH_WIDTH, channel_width)) { - hdd_err("remote ch put fail"); - goto fail; - } - if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate)) { - hdd_err("tx rate put fail"); - goto fail; - } - if (nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate)) { - hdd_err("rx rate put fail"); - goto fail; - } - - qdf_mem_zero(stainfo, sizeof(*stainfo)); - - return cfg80211_vendor_cmd_reply(skb); -fail: - if (skb) - kfree_skb(skb); - - return -EINVAL; -} - -/** - * hdd_get_cached_station_remote() - get connected peer's info - * @hdd_ctx: hdd context - * @adapter: hostapd interface - * @mac_addr: mac address of requested peer - * - * This function collect and indicate the connected peer's info - * - * Return: 0 on success, otherwise error value - */ -static int hdd_get_connected_station_info(struct hdd_context *hdd_ctx, - struct hdd_adapter *adapter, - struct qdf_mac_addr mac_addr, - struct hdd_station_info *stainfo) -{ - struct sk_buff *skb = NULL; - uint32_t nl_buf_len; - struct sir_peer_info_ext peer_info; - bool txrx_rate = true; - - nl_buf_len = NLMSG_HDRLEN; - nl_buf_len += (sizeof(stainfo->max_phy_rate) + NLA_HDRLEN) + - (sizeof(stainfo->tx_packets) + NLA_HDRLEN) + - (sizeof(stainfo->tx_bytes) + NLA_HDRLEN) + - (sizeof(stainfo->rx_packets) + NLA_HDRLEN) + - (sizeof(stainfo->rx_bytes) + NLA_HDRLEN) + - (sizeof(stainfo->is_qos_enabled) + NLA_HDRLEN) + - (sizeof(stainfo->mode) + NLA_HDRLEN); - - if (!hdd_ctx->config->sap_get_peer_info || - wlan_hdd_get_peer_info(adapter, mac_addr, &peer_info)) { - hdd_err("fail to get tx/rx rate"); - txrx_rate = false; - } else { - stainfo->tx_rate = peer_info.tx_rate; - stainfo->rx_rate = peer_info.rx_rate; - nl_buf_len += (sizeof(stainfo->tx_rate) + NLA_HDRLEN) + - (sizeof(stainfo->rx_rate) + NLA_HDRLEN); - } - - /* below info is only valid for HT/VHT mode */ - if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) - nl_buf_len += (sizeof(stainfo->ampdu) + NLA_HDRLEN) + - (sizeof(stainfo->tx_stbc) + NLA_HDRLEN) + - (sizeof(stainfo->rx_stbc) + NLA_HDRLEN) + - (sizeof(stainfo->ch_width) + NLA_HDRLEN) + - (sizeof(stainfo->sgi_enable) + NLA_HDRLEN); - - hdd_info("buflen %d hdrlen %d", nl_buf_len, NLMSG_HDRLEN); - - skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, - nl_buf_len); - if (!skb) { - hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); - goto fail; - } - - hdd_info("stainfo"); - hdd_info("maxrate %x tx_pkts %x tx_bytes %llx", - stainfo->max_phy_rate, stainfo->tx_packets, - stainfo->tx_bytes); - hdd_info("rx_pkts %x rx_bytes %llx mode %x", - stainfo->rx_packets, stainfo->rx_bytes, - stainfo->mode); - if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) { - hdd_info("ampdu %d tx_stbc %d rx_stbc %d", - stainfo->ampdu, stainfo->tx_stbc, - stainfo->rx_stbc); - hdd_info("wmm %d chwidth %d sgi %d", - stainfo->is_qos_enabled, - stainfo->ch_width, - stainfo->sgi_enable); - } - - if (nla_put_u32(skb, REMOTE_MAX_PHY_RATE, stainfo->max_phy_rate) || - nla_put_u32(skb, REMOTE_TX_PACKETS, stainfo->tx_packets) || - remote_station_put_u64(skb, REMOTE_TX_BYTES, stainfo->tx_bytes) || - nla_put_u32(skb, REMOTE_RX_PACKETS, stainfo->rx_packets) || - remote_station_put_u64(skb, REMOTE_RX_BYTES, stainfo->rx_bytes) || - nla_put_u8(skb, REMOTE_WMM, stainfo->is_qos_enabled) || - nla_put_u8(skb, REMOTE_SUPPORTED_MODE, stainfo->mode)) { - hdd_err("put fail"); - goto fail; - } - - if (txrx_rate) { - if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate) || - nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate)) { - hdd_err("put fail"); - goto fail; - } else { - hdd_info("tx_rate %x rx_rate %x", - stainfo->tx_rate, stainfo->rx_rate); - } - } - - if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) { - if (nla_put_u8(skb, REMOTE_AMPDU, stainfo->ampdu) || - nla_put_u8(skb, REMOTE_TX_STBC, stainfo->tx_stbc) || - nla_put_u8(skb, REMOTE_RX_STBC, stainfo->rx_stbc) || - nla_put_u8(skb, REMOTE_CH_WIDTH, stainfo->ch_width) || - nla_put_u8(skb, REMOTE_SGI_ENABLE, stainfo->sgi_enable)) { - hdd_err("put fail"); - goto fail; - } - } - - return cfg80211_vendor_cmd_reply(skb); - -fail: - if (skb) - kfree_skb(skb); - - return -EINVAL; -} - -/** - * hdd_get_station_remote() - get remote peer's info - * @hdd_ctx: hdd context - * @adapter: hostapd interface - * @mac_addr: mac address of requested peer - * - * This function collect and indicate the remote peer's info - * - * Return: 0 on success, otherwise error value - */ -static int hdd_get_station_remote(struct hdd_context *hdd_ctx, - struct hdd_adapter *adapter, - struct qdf_mac_addr mac_addr) -{ - struct hdd_station_info *stainfo = hdd_get_stainfo(adapter->sta_info, - mac_addr); - int status = 0; - bool is_associated = false; - - if (!stainfo) { - status = hdd_get_cached_station_remote(hdd_ctx, adapter, - mac_addr); - return status; - } - - is_associated = hdd_is_peer_associated(adapter, &mac_addr); - if (!is_associated) { - status = hdd_get_cached_station_remote(hdd_ctx, adapter, - mac_addr); - return status; - } - - status = hdd_get_connected_station_info(hdd_ctx, adapter, - mac_addr, stainfo); - return status; -} - -/** - * __hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd - * @wiphy: corestack handler - * @wdev: wireless device - * @data: data - * @data_len: data length - * - * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. - * Validate cmd attributes and send the station info to upper layers. - * - * Return: Success(0) or reason code for failure - */ -static int -__hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + 1]; - int32_t status; - - hdd_enter_dev(dev); - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - status = -EPERM; - goto out; - } - - status = wlan_hdd_validate_context(hdd_ctx); - if (0 != status) - goto out; - - - status = wlan_cfg80211_nla_parse(tb, - QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX, - data, data_len, - hdd_get_station_policy); - if (status) { - hdd_err("Invalid ATTR"); - goto out; - } - - /* Parse and fetch Command Type*/ - if (tb[STATION_INFO]) { - status = hdd_get_station_info(hdd_ctx, adapter); - } else if (tb[STATION_ASSOC_FAIL_REASON]) { - status = hdd_get_station_assoc_fail(hdd_ctx, adapter); - } else if (tb[STATION_REMOTE]) { - struct qdf_mac_addr mac_addr; - - if (adapter->device_mode != QDF_SAP_MODE && - adapter->device_mode != QDF_P2P_GO_MODE) { - hdd_err("invalid device_mode:%d", adapter->device_mode); - status = -EINVAL; - goto out; - } - - nla_memcpy(mac_addr.bytes, tb[STATION_REMOTE], - QDF_MAC_ADDR_SIZE); - - hdd_debug("STATION_REMOTE " MAC_ADDRESS_STR, - MAC_ADDR_ARRAY(mac_addr.bytes)); - - status = hdd_get_station_remote(hdd_ctx, adapter, mac_addr); - } else { - hdd_err("get station info cmd type failed"); - status = -EINVAL; - goto out; - } - hdd_exit(); -out: - return status; -} - -/** - * wlan_hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd - * @wiphy: corestack handler - * @wdev: wireless device - * @data: data - * @data_len: data length - * - * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. - * Validate cmd attributes and send the station info to upper layers. - * - * Return: Success(0) or reason code for failure - */ -static int32_t -hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __hdd_cfg80211_get_station_cmd(wiphy, wdev, data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - /* * undef short names defined for get station command * used by __wlan_hdd_cfg80211_get_station_cmd() @@ -8342,202 +7088,6 @@ static int wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, } #endif -/* - * define short names for the global vendor params - * used by __wlan_hdd_cfg80211_monitor_rssi() - */ -#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX -#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID -#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL -#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI -#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI - -/** - * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Return: 0 on success, negative errno on failure - */ -static int -__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct nlattr *tb[PARAM_MAX + 1]; - struct rssi_monitor_req req; - QDF_STATUS status; - int ret; - uint32_t control; - mac_handle_t mac_handle; - static const struct nla_policy policy[PARAM_MAX + 1] = { - [PARAM_REQUEST_ID] = { .type = NLA_U32 }, - [PARAM_CONTROL] = { .type = NLA_U32 }, - [PARAM_MIN_RSSI] = { .type = NLA_S8 }, - [PARAM_MAX_RSSI] = { .type = NLA_S8 }, - }; - - hdd_enter_dev(dev); - - if (wlan_hdd_validate_session_id(adapter->session_id)) - return -EINVAL; - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret) - return ret; - - if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { - hdd_err("Not in Connected state!"); - return -ENOTSUPP; - } - - if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, policy)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - if (!tb[PARAM_REQUEST_ID]) { - hdd_err("attr request id failed"); - return -EINVAL; - } - - if (!tb[PARAM_CONTROL]) { - hdd_err("attr control failed"); - return -EINVAL; - } - - req.request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); - req.session_id = adapter->session_id; - control = nla_get_u32(tb[PARAM_CONTROL]); - - if (control == QCA_WLAN_RSSI_MONITORING_START) { - req.control = true; - if (!tb[PARAM_MIN_RSSI]) { - hdd_err("attr min rssi failed"); - return -EINVAL; - } - - if (!tb[PARAM_MAX_RSSI]) { - hdd_err("attr max rssi failed"); - return -EINVAL; - } - - req.min_rssi = nla_get_s8(tb[PARAM_MIN_RSSI]); - req.max_rssi = nla_get_s8(tb[PARAM_MAX_RSSI]); - - if (!(req.min_rssi < req.max_rssi)) { - hdd_warn("min_rssi: %d must be less than max_rssi: %d", - req.min_rssi, req.max_rssi); - return -EINVAL; - } - hdd_debug("Min_rssi: %d Max_rssi: %d", - req.min_rssi, req.max_rssi); - - } else if (control == QCA_WLAN_RSSI_MONITORING_STOP) - req.control = false; - else { - hdd_err("Invalid control cmd: %d", control); - return -EINVAL; - } - hdd_debug("Request Id: %u Session_id: %d Control: %d", - req.request_id, req.session_id, req.control); - - mac_handle = hdd_ctx->mac_handle; - status = sme_set_rssi_monitoring(mac_handle, &req); - if (!QDF_IS_STATUS_SUCCESS(status)) { - hdd_err("sme_set_rssi_monitoring failed(err=%d)", status); - return -EINVAL; - } - - return 0; -} - -/* - * done with short names for the global vendor params - * used by __wlan_hdd_cfg80211_monitor_rssi() - */ -#undef PARAM_MAX -#undef PARAM_CONTROL -#undef PARAM_REQUEST_ID -#undef PARAM_MAX_RSSI -#undef PARAM_MIN_RSSI - -/** - * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring - * @wiphy: wiphy structure pointer - * @wdev: Wireless device structure pointer - * @data: Pointer to the data received - * @data_len: Length of @data - * - * Return: 0 on success; errno on failure - */ -static int -wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, - const void *data, int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, - struct rssi_breach_event *data) -{ - struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); - struct sk_buff *skb; - - hdd_enter(); - - if (wlan_hdd_validate_context(hdd_ctx)) - return; - if (!data) { - hdd_err("data is null"); - return; - } - - skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, - NULL, - EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, - QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, - GFP_KERNEL); - - if (!skb) { - hdd_err("mem alloc failed"); - return; - } - - hdd_debug("Req Id: %u Current rssi: %d", - data->request_id, data->curr_rssi); - hdd_debug("Current BSSID: " MAC_ADDRESS_STR, - MAC_ADDR_ARRAY(data->curr_bssid.bytes)); - - if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, - data->request_id) || - nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, - sizeof(data->curr_bssid), data->curr_bssid.bytes) || - nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, - data->curr_rssi)) { - hdd_err("nla put fail"); - goto fail; - } - - cfg80211_vendor_event(skb, GFP_KERNEL); - return; - -fail: - kfree_skb(skb); -} - #ifdef WLAN_NS_OFFLOAD static const struct nla_policy ns_offload_set_policy[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX + 1] = { @@ -9070,1104 +7620,6 @@ static int wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy, return ret; } -static const struct -nla_policy -qca_wlan_vendor_ota_test_policy -[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE] = {.type = NLA_U8 }, -}; - -/** - * __wlan_hdd_cfg80211_set_ota_test () - enable/disable OTA test - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Return: 0 on success, negative errno on failure - */ -static int __wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1]; - uint8_t ota_enable = 0; - QDF_STATUS status; - uint32_t current_roam_state; - mac_handle_t mac_handle; - - hdd_enter_dev(dev); - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EPERM; - } - - if (0 != wlan_hdd_validate_context(hdd_ctx)) - return -EINVAL; - - if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX, - data, data_len, - qca_wlan_vendor_ota_test_policy)) { - hdd_err("invalid attr"); - return -EINVAL; - } - - if (!tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]) { - hdd_err("attr ota test failed"); - return -EINVAL; - } - - ota_enable = nla_get_u8( - tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]); - - hdd_debug(" OTA test enable = %d", ota_enable); - if (ota_enable != 1) { - hdd_err("Invalid value, only enable test mode is supported!"); - return -EINVAL; - } - - mac_handle = hdd_ctx->mac_handle; - current_roam_state = - sme_get_current_roam_state(mac_handle, adapter->session_id); - status = sme_stop_roaming(mac_handle, adapter->session_id, - eCsrHddIssued); - if (status != QDF_STATUS_SUCCESS) { - hdd_err("Enable/Disable roaming failed"); - return -EINVAL; - } - - status = sme_ps_enable_disable(mac_handle, adapter->session_id, - SME_PS_DISABLE); - if (status != QDF_STATUS_SUCCESS) { - hdd_err("Enable/Disable power save failed"); - /* restore previous roaming setting */ - if (current_roam_state == eCSR_ROAMING_STATE_JOINING || - current_roam_state == eCSR_ROAMING_STATE_JOINED) - status = sme_start_roaming(mac_handle, - adapter->session_id, - eCsrHddIssued); - else if (current_roam_state == eCSR_ROAMING_STATE_STOP || - current_roam_state == eCSR_ROAMING_STATE_IDLE) - status = sme_stop_roaming(mac_handle, - adapter->session_id, - eCsrHddIssued); - - if (status != QDF_STATUS_SUCCESS) - hdd_err("Restoring roaming state failed"); - - return -EINVAL; - } - - - return 0; -} - -/** - * wlan_hdd_cfg80211_set_ota_test () - Enable or disable OTA test - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Return: 0 on success, negative errno on failure - */ -static int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret = 0; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_set_ota_test(wiphy, wdev, data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -static const struct nla_policy -txpower_scale_policy[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE] = { .type = NLA_U8 }, -}; - -/** - * __wlan_hdd_cfg80211_txpower_scale () - txpower scaling - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Return: 0 on success, negative errno on failure - */ -static int __wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter; - int ret; - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1]; - uint8_t scale_value; - QDF_STATUS status; - - hdd_enter_dev(dev); - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret) - return ret; - - adapter = WLAN_HDD_GET_PRIV_PTR(dev); - - if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX, - data, data_len, txpower_scale_policy)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]) { - hdd_err("attr tx power scale failed"); - return -EINVAL; - } - - scale_value = nla_get_u8(tb - [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]); - - if (scale_value > MAX_TXPOWER_SCALE) { - hdd_err("Invalid tx power scale level"); - return -EINVAL; - } - - status = wma_set_tx_power_scale(adapter->session_id, scale_value); - - if (QDF_STATUS_SUCCESS != status) { - hdd_err("Set tx power scale failed"); - return -EINVAL; - } - - return 0; -} - -/** - * wlan_hdd_cfg80211_txpower_scale () - txpower scaling - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Return: 0 on success, negative errno on failure - */ -static int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_txpower_scale(wiphy, wdev, - data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -static const struct nla_policy txpower_scale_decr_db_policy -[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB] = { .type = NLA_U8 }, -}; - -/** - * __wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Return: 0 on success, negative errno on failure - */ -static int __wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter; - int ret; - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1]; - uint8_t scale_value; - QDF_STATUS status; - - hdd_enter_dev(dev); - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret) - return ret; - - adapter = WLAN_HDD_GET_PRIV_PTR(dev); - - if (wlan_cfg80211_nla_parse(tb, - QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX, - data, data_len, - txpower_scale_decr_db_policy)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]) { - hdd_err("attr tx power decrease db value failed"); - return -EINVAL; - } - - scale_value = nla_get_u8(tb - [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]); - - status = wma_set_tx_power_scale_decr_db(adapter->session_id, - scale_value); - - if (QDF_STATUS_SUCCESS != status) { - hdd_err("Set tx power decrease db failed"); - return -EINVAL; - } - - return 0; -} - -/** - * wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Return: 0 on success, negative errno on failure - */ -static int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_txpower_scale_decr_db(wiphy, wdev, - data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -/** - * __wlan_hdd_cfg80211_conditional_chan_switch() - Conditional channel switch - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Processes the conditional channel switch request and invokes the helper - * APIs to process the channel switch request. - * - * Return: 0 on success, negative errno on failure - */ -static int __wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter; - struct nlattr - *tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX + 1]; - uint32_t freq_len, i; - uint32_t *freq; - uint8_t chans[QDF_MAX_NUM_CHAN] = {0}; - - hdd_enter_dev(dev); - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret) - return ret; - - if (!hdd_ctx->config->enableDFSMasterCap) { - hdd_err("DFS master capability is not present in the driver"); - return -EINVAL; - } - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EPERM; - } - - adapter = WLAN_HDD_GET_PRIV_PTR(dev); - if (adapter->device_mode != QDF_SAP_MODE) { - hdd_err("Invalid device mode %d", adapter->device_mode); - return -EINVAL; - } - - /* - * audit note: it is ok to pass a NULL policy here since only - * one attribute is parsed which is array of frequencies and - * it is explicitly validated for both under read and over read - */ - if (wlan_cfg80211_nla_parse(tb, - QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX, - data, data_len, NULL)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - if (!tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]) { - hdd_err("Frequency list is missing"); - return -EINVAL; - } - - freq_len = nla_len( - tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST])/ - sizeof(uint32_t); - - if (freq_len > QDF_MAX_NUM_CHAN) { - hdd_err("insufficient space to hold channels"); - return -ENOMEM; - } - - hdd_debug("freq_len=%d", freq_len); - - freq = nla_data( - tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]); - - - for (i = 0; i < freq_len; i++) { - if (freq[i] == 0) - chans[i] = 0; - else - chans[i] = ieee80211_frequency_to_channel(freq[i]); - - hdd_debug("freq[%d]=%d", i, freq[i]); - } - - /* - * The input frequency list from user space is designed to be a - * priority based frequency list. This is only to accommodate any - * future request. But, current requirement is only to perform CAC - * on a single channel. So, the first entry from the list is picked. - * - * If channel is zero, any channel in the available outdoor regulatory - * domain will be selected. - */ - ret = wlan_hdd_request_pre_cac(chans[0]); - if (ret) { - hdd_err("pre cac request failed with reason:%d", ret); - return ret; - } - - return 0; -} - -/* P2P listen offload device types parameters length in bytes */ -#define P2P_LO_MAX_REQ_DEV_TYPE_COUNT (10) -#define P2P_LO_WPS_DEV_TYPE_LEN (8) -#define P2P_LO_DEV_TYPE_MAX_LEN \ - (P2P_LO_MAX_REQ_DEV_TYPE_COUNT * P2P_LO_WPS_DEV_TYPE_LEN) - -static const struct nla_policy -p2p_listen_offload_policy[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] = { - .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] = { - .type = NLA_BINARY, - .len = P2P_LO_DEV_TYPE_MAX_LEN }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE] = { - .type = NLA_BINARY, - .len = MAX_GENIE_LEN }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG] = { - .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON] = { - .type = NLA_U8 }, -}; - -/** - * __wlan_hdd_cfg80211_p2p_lo_start () - start P2P Listen Offload - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * This function is to process the p2p listen offload start vendor - * command. It parses the input parameters and invoke WMA API to - * send the command to firmware. - * - * Return: 0 on success, negative errno on failure - */ -static int __wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter; - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1]; - struct sir_p2p_lo_start params; - - hdd_enter_dev(dev); - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret) - return ret; - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EPERM; - } - - adapter = WLAN_HDD_GET_PRIV_PTR(dev); - if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && - (adapter->device_mode != QDF_P2P_CLIENT_MODE) && - (adapter->device_mode != QDF_P2P_GO_MODE)) { - hdd_err("Invalid device mode %d", adapter->device_mode); - return -EINVAL; - } - - if (wlan_cfg80211_nla_parse(tb, - QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX, - data, data_len, - p2p_listen_offload_policy)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - memset(¶ms, 0, sizeof(params)); - - if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]) - params.ctl_flags = 1; /* set to default value */ - else - params.ctl_flags = nla_get_u32(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]); - - if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] || - !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] || - !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] || - !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] || - !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] || - !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]) { - hdd_err("Attribute parsing failed"); - return -EINVAL; - } - - params.vdev_id = adapter->session_id; - params.freq = nla_get_u32(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL]); - if ((params.freq != 2412) && (params.freq != 2437) && - (params.freq != 2462)) { - hdd_err("Invalid listening channel: %d", params.freq); - return -EINVAL; - } - - params.period = nla_get_u32(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD]); - if (!((params.period > 0) && (params.period < UINT_MAX))) { - hdd_err("Invalid period: %d", params.period); - return -EINVAL; - } - - params.interval = nla_get_u32(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL]); - if (!((params.interval > 0) && (params.interval < UINT_MAX))) { - hdd_err("Invalid interval: %d", params.interval); - return -EINVAL; - } - - params.count = nla_get_u32(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT]); - if (!((params.count >= 0) && (params.count < UINT_MAX))) { - hdd_err("Invalid count: %d", params.count); - return -EINVAL; - } - - params.device_types = nla_data(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); - if (params.device_types == NULL) { - hdd_err("Invalid device types"); - return -EINVAL; - } - - params.dev_types_len = nla_len(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); - /* device type length has to be multiple of P2P_LO_WPS_DEV_TYPE_LEN */ - if (0 != (params.dev_types_len % P2P_LO_WPS_DEV_TYPE_LEN)) { - hdd_err("Invalid device type length: %d", params.dev_types_len); - return -EINVAL; - } - - params.probe_resp_tmplt = nla_data(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); - if (params.probe_resp_tmplt == NULL) { - hdd_err("Invalid probe response template"); - return -EINVAL; - } - - /* - * IEs minimum length should be 2 bytes: 1 byte for element id - * and 1 byte for element id length. - */ - params.probe_resp_len = nla_len(tb - [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); - if (params.probe_resp_len < MIN_GENIE_LEN) { - hdd_err("Invalid probe resp template length: %d", - params.probe_resp_len); - return -EINVAL; - } - - hdd_debug("P2P LO params: freq=%d, period=%d, interval=%d, count=%d", - params.freq, params.period, params.interval, params.count); - - return wlan_hdd_listen_offload_start(adapter, ¶ms); -} - - -/** - * wlan_hdd_cfg80211_p2p_lo_start () - start P2P Listen Offload - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * This function inovkes internal __wlan_hdd_cfg80211_p2p_lo_start() - * to process p2p listen offload start vendor command. - * - * Return: 0 on success, negative errno on failure - */ -static int wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret = 0; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_p2p_lo_start(wiphy, wdev, - data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -/** - * __wlan_hdd_cfg80211_p2p_lo_stop () - stop P2P Listen Offload - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * This function is to process the p2p listen offload stop vendor - * command. It invokes WMA API to send command to firmware. - * - * Return: 0 on success, negative errno on failure - */ -static int __wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - struct hdd_adapter *adapter; - struct net_device *dev = wdev->netdev; - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EPERM; - } - - adapter = WLAN_HDD_GET_PRIV_PTR(dev); - if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && - (adapter->device_mode != QDF_P2P_CLIENT_MODE) && - (adapter->device_mode != QDF_P2P_GO_MODE)) { - hdd_err("Invalid device mode"); - return -EINVAL; - } - - return wlan_hdd_listen_offload_stop(adapter); -} - -/** - * wlan_hdd_cfg80211_p2p_lo_stop () - stop P2P Listen Offload - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * This function inovkes internal __wlan_hdd_cfg80211_p2p_lo_stop() - * to process p2p listen offload stop vendor command. - * - * Return: 0 on success, negative errno on failure - */ -static int wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret = 0; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_p2p_lo_stop(wiphy, wdev, - data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -/** - * wlan_hdd_cfg80211_conditional_chan_switch() - SAP conditional channel switch - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Data length - * - * Inovkes internal API __wlan_hdd_cfg80211_conditional_chan_switch() - * to process the conditional channel switch request. - * - * Return: 0 on success, negative errno on failure - */ -static int wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_conditional_chan_switch(wiphy, wdev, - data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -/** - * 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) - * @handle: Global handle - * - * 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, mac_handle_t handle) -{ - QDF_STATUS ret; - - ret = wlan_sap_set_pre_cac_status( - WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter), status, handle); - if (QDF_IS_STATUS_ERROR(ret)) - return -EINVAL; - - return 0; -} - -/** - * wlan_hdd_set_chan_before_pre_cac() - Save the channel before pre cac - * @ap_adapter: AP adapter - * @chan_before_pre_cac: Channel - * - * Saves the channel 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_before_pre_cac(struct hdd_adapter *ap_adapter, - uint8_t chan_before_pre_cac) -{ - QDF_STATUS ret; - - ret = wlan_sap_set_chan_before_pre_cac( - WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), chan_before_pre_cac); - if (QDF_IS_STATUS_ERROR(ret)) - return -EINVAL; - - return 0; -} - -int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter, - uint32_t *channel_count, - uint8_t *channel_list, - enum band_info band) -{ - tsap_config_t *sap_config; - struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); - uint8_t tmp_chan_list[QDF_MAX_NUM_CHAN] = {0}; - uint32_t chan_count; - uint8_t i; - QDF_STATUS status; - struct wlan_objmgr_pdev *pdev = hdd_ctx->hdd_pdev; - uint8_t tmp_chan; - - sap_config = &adapter->session.ap.sap_config; - - status = - policy_mgr_get_valid_chans(hdd_ctx->hdd_psoc, - tmp_chan_list, - &chan_count); - if (QDF_IS_STATUS_ERROR(status)) { - hdd_err("Failed to get channel list"); - return -EINVAL; - } - - for (i = 0; i < chan_count; i++) { - tmp_chan = tmp_chan_list[i]; - if (*channel_count < QDF_MAX_NUM_CHAN) { - if ((BAND_2G == band) && - (WLAN_REG_IS_24GHZ_CH(tmp_chan)) && - (!wlan_reg_is_disable_ch(pdev, tmp_chan))) { - channel_list[*channel_count] = tmp_chan; - *channel_count += 1; - } else if ((BAND_5G == band) && - (WLAN_REG_IS_5GHZ_CH(tmp_chan)) && - (!wlan_reg_is_disable_ch(pdev, tmp_chan))) { - channel_list[*channel_count] = tmp_chan; - *channel_count += 1; - } - } else { - break; - } - } - - if (*channel_count == 0) { - hdd_err("no valid channel found"); - 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 - * @channel: Channel requested by userspace - * @pre_cac_chan: Pointer to the pre CAC channel - * - * 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, - uint8_t channel, - uint8_t *pre_cac_chan) -{ - uint32_t i; - QDF_STATUS status; - uint32_t weight_len = 0; - uint32_t len = WNI_CFG_VALID_CHANNEL_LIST_LEN; - uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0}; - uint8_t pcl_weights[QDF_MAX_NUM_CHAN] = {0}; - mac_handle_t mac_handle; - - if (0 == channel) { - /* 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->hdd_psoc, - channel_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->hdd_psoc, - channel_list, &len, pcl_weights, weight_len); - for (i = 0; i < len; i++) { - if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, - channel_list[i])) { - *pre_cac_chan = channel_list[i]; - break; - } - } - if (*pre_cac_chan == 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, channel) || - !wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, channel)) { - hdd_err("Invalid channel for pre cac:%d", channel); - return -EINVAL; - } - *pre_cac_chan = channel; - } - hdd_debug("selected pre cac channel:%d", *pre_cac_chan); - return 0; -} - -/** - * wlan_hdd_request_pre_cac() - Start pre CAC in the driver - * @channel: Channel 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(uint8_t channel) -{ - uint8_t pre_cac_chan = 0, *mac_addr; - struct hdd_context *hdd_ctx; - 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; - uint32_t freq; - struct ieee80211_channel *chan; - mac_handle_t mac_handle; - bool val; - - hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); - if (0 != wlan_hdd_validate_context(hdd_ctx)) - return -EINVAL; - - if (policy_mgr_get_connection_count(hdd_ctx->hdd_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; - } - - 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_ch(hdd_ctx->hdd_pdev, - hdd_ap_ctx->operating_channel)) { - hdd_err("SAP is already on DFS channel:%d", - hdd_ap_ctx->operating_channel); - return -EINVAL; - } - - if (!WLAN_REG_IS_24GHZ_CH(hdd_ap_ctx->operating_channel)) { - hdd_err("pre CAC alllowed only when SAP is in 2.4GHz:%d", - hdd_ap_ctx->operating_channel); - return -EINVAL; - } - - mac_addr = wlan_hdd_get_intf_addr(hdd_ctx); - if (!mac_addr) { - hdd_err("can't add virtual intf: Not getting valid mac addr"); - return -EINVAL; - } - - hdd_debug("channel:%d", channel); - - ret = wlan_hdd_validate_and_get_pre_cac_ch(hdd_ctx, ap_adapter, channel, - &pre_cac_chan); - 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"); - - /* 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. - */ - pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, "precac%d", - mac_addr, NET_NAME_UNKNOWN, true); - if (!pre_cac_adapter) { - hdd_err("error opening the pre cac adapter"); - goto release_intf_addr_and_return_failure; - } - - /* - * 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) { - hdd_err("failed to alloc mem for 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; - - /* 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. - */ - switch (ap_adapter->session.ap.sap_config.ch_width_orig) { - case CH_WIDTH_20MHZ: - channel_type = NL80211_CHAN_HT20; - break; - case CH_WIDTH_40MHZ: - if (ap_adapter->session.ap.sap_config.sec_ch > - ap_adapter->session.ap.sap_config.channel) - channel_type = NL80211_CHAN_HT40PLUS; - else - channel_type = NL80211_CHAN_HT40MINUS; - break; - default: - channel_type = NL80211_CHAN_NO_HT; - break; - } - - freq = cds_chan_to_freq(pre_cac_chan); - chan = ieee80211_get_channel(wiphy, freq); - if (!chan) { - hdd_err("channel converion failed"); - goto stop_close_pre_cac_adapter; - } - - cfg80211_chandef_create(&chandef, chan, channel_type); - - hdd_debug("orig width:%d channel_type:%d freq:%d", - ap_adapter->session.ap.sap_config.ch_width_orig, - channel_type, 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->hdd_psoc, - ap_adapter->session_id, - pre_cac_chan, - 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 (0 != ret) { - 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, mac_handle); - if (0 != ret) { - hdd_err("failed to set pre cac status"); - goto stop_close_pre_cac_adapter; - } - - ret = wlan_hdd_set_chan_before_pre_cac(ap_adapter, - hdd_ap_ctx->operating_channel); - if (0 != ret) { - hdd_err("failed to set channel before pre cac"); - goto stop_close_pre_cac_adapter; - } - - ap_adapter->pre_cac_chan = pre_cac_chan; - - 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 - */ - wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); - return -EINVAL; -} - static const struct nla_policy wlan_hdd_sap_config_policy[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL] = {.type = NLA_U8 }, @@ -10181,13 +7633,6 @@ wlan_hdd_set_acs_dfs_config_policy[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT] = {.type = NLA_U8 }, }; -static const struct nla_policy -wlan_hdd_set_limit_off_channel_param_policy -[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS] = {.type = NLA_U8 }, - [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START] = {.type = NLA_U8 }, -}; - /** * __wlan_hdd_cfg80211_acs_dfs_mode() - set ACS DFS mode and channel * @wiphy: Pointer to wireless phy @@ -11753,51 +9198,6 @@ static int wlan_hdd_cfg80211_sar_convert_modulation(u32 nl80211_value, return ret; } -static u32 hdd_sar_wmi_to_nl_enable(uint32_t wmi_value) -{ - switch (wmi_value) { - default: - case WMI_SAR_FEATURE_OFF: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE; - case WMI_SAR_FEATURE_ON_SET_0: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0; - case WMI_SAR_FEATURE_ON_SET_1: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1; - case WMI_SAR_FEATURE_ON_SET_2: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2; - case WMI_SAR_FEATURE_ON_SET_3: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3; - case WMI_SAR_FEATURE_ON_SET_4: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4; - case WMI_SAR_FEATURE_ON_USER_DEFINED: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER; - case WMI_SAR_FEATURE_ON_SAR_V2_0: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0; - } -} - -static u32 hdd_sar_wmi_to_nl_band(uint32_t wmi_value) -{ - switch (wmi_value) { - default: - case WMI_SAR_2G_ID: - return HDD_NL80211_BAND_2GHZ; - case WMI_SAR_5G_ID: - return HDD_NL80211_BAND_5GHZ; - } -} - -static u32 hdd_sar_wmi_to_nl_modulation(uint32_t wmi_value) -{ - switch (wmi_value) { - default: - case WMI_SAR_MOD_CCK: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK; - case WMI_SAR_MOD_OFDM: - return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM; - } -} - static const struct nla_policy sar_limits_policy[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE] = {.type = NLA_U32}, @@ -11809,260 +9209,6 @@ sar_limits_policy[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX] = {.type = NLA_U32}, }; -#define WLAN_WAIT_TIME_SAR 5000 - -/** - * hdd_sar_context - hdd sar context - * @event: sar limit event - */ -struct hdd_sar_context { - struct sar_limit_event event; -}; - -/** - * hdd_sar_cb () - sar response message handler - * @cookie: hdd request cookie - * @event: sar response event - * - * Return: none - */ -static void hdd_sar_cb(void *cookie, - struct sar_limit_event *event) -{ - struct osif_request *request; - struct hdd_sar_context *context; - - hdd_enter(); - - if (!event) { - hdd_err("response is NULL"); - return; - } - - request = osif_request_get(cookie); - if (!request) { - hdd_debug("Obsolete request"); - return; - } - - context = osif_request_priv(request); - context->event = *event; - osif_request_complete(request); - osif_request_put(request); - - hdd_exit(); -} - -static uint32_t hdd_sar_get_response_len(const struct sar_limit_event *event) -{ - uint32_t len; - uint32_t row_len; - - len = NLMSG_HDRLEN; - /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE */ - len += NLA_HDRLEN + sizeof(u32); - /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS */ - len += NLA_HDRLEN + sizeof(u32); - - /* nest */ - row_len = NLA_HDRLEN; - /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND */ - row_len += NLA_HDRLEN + sizeof(u32); - /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN */ - row_len += NLA_HDRLEN + sizeof(u32); - /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION */ - row_len += NLA_HDRLEN + sizeof(u32); - /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT */ - row_len += NLA_HDRLEN + sizeof(u32); - - /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC */ - len += NLA_HDRLEN + (row_len * event->num_limit_rows); - - return len; -} - -static int hdd_sar_fill_response(struct sk_buff *skb, - const struct sar_limit_event *event) -{ - int errno; - u32 value; - u32 attr; - struct nlattr *nla_spec_attr; - struct nlattr *nla_row_attr; - uint32_t row; - const struct sar_limit_event_row *event_row; - - attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE; - value = hdd_sar_wmi_to_nl_enable(event->sar_enable); - errno = nla_put_u32(skb, attr, value); - if (errno) - return errno; - - attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS; - value = event->num_limit_rows; - errno = nla_put_u32(skb, attr, value); - if (errno) - return errno; - - attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC; - nla_spec_attr = nla_nest_start(skb, attr); - if (!nla_spec_attr) - return -EINVAL; - - for (row = 0, event_row = event->sar_limit_row; - row < event->num_limit_rows; - row++, event_row++) { - nla_row_attr = nla_nest_start(skb, attr); - if (!nla_row_attr) - return -EINVAL; - - attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND; - value = hdd_sar_wmi_to_nl_band(event_row->band_id); - errno = nla_put_u32(skb, attr, value); - if (errno) - return errno; - - attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN; - value = event_row->chain_id; - errno = nla_put_u32(skb, attr, value); - if (errno) - return errno; - - attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION; - value = hdd_sar_wmi_to_nl_modulation(event_row->mod_id); - errno = nla_put_u32(skb, attr, value); - if (errno) - return errno; - - attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT; - value = event_row->limit_value; - errno = nla_put_u32(skb, attr, value); - if (errno) - return errno; - - nla_nest_end(skb, nla_row_attr); - } - nla_nest_end(skb, nla_spec_attr); - - return 0; -} - -static int hdd_sar_send_response(struct wiphy *wiphy, - const struct sar_limit_event *event) -{ - uint32_t len; - struct sk_buff *skb; - int errno; - - len = hdd_sar_get_response_len(event); - skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); - if (!skb) { - hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); - return -ENOMEM; - } - - errno = hdd_sar_fill_response(skb, event); - if (errno) { - kfree_skb(skb); - return errno; - } - - return cfg80211_vendor_cmd_reply(skb); -} - -/** - * __wlan_hdd_get_sar_power_limits() - Get SAR power limits - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Length of @data - * - * This function is used to retrieve Specific Absorption Rate limit specs. - * - * Return: 0 on success, negative errno on failure - */ -static int __wlan_hdd_get_sar_power_limits(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) -{ - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct osif_request *request; - struct hdd_sar_context *context; - mac_handle_t mac_handle; - void *cookie; - QDF_STATUS status; - int ret; - static const struct osif_request_params params = { - .priv_size = sizeof(*context), - .timeout_ms = WLAN_WAIT_TIME_SAR, - }; - - hdd_enter(); - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EPERM; - } - - if (wlan_hdd_validate_context(hdd_ctx)) - return -EINVAL; - - request = osif_request_alloc(¶ms); - if (!request) { - hdd_err("Request allocation failure"); - return -ENOMEM; - } - - cookie = osif_request_cookie(request); - - mac_handle = hdd_ctx->mac_handle; - status = sme_get_sar_power_limits(mac_handle, hdd_sar_cb, cookie); - if (!QDF_IS_STATUS_SUCCESS(status)) { - hdd_err("Unable to post sar message"); - ret = -EINVAL; - goto cleanup; - } - - ret = osif_request_wait_for_response(request); - if (ret) { - hdd_err("Target response timed out"); - goto cleanup; - } - - context = osif_request_priv(request); - ret = hdd_sar_send_response(wiphy, &context->event); - -cleanup: - osif_request_put(request); - - return ret; -} - -/** - * wlan_hdd_cfg80211_get_sar_power_limits() - Get SAR power limits - * @wiphy: Pointer to wireless phy - * @wdev: Pointer to wireless device - * @data: Pointer to data - * @data_len: Length of @data - * - * Wrapper function of __wlan_hdd_cfg80211_get_sar_power_limits() - * - * Return: 0 on success, negative errno on failure - */ -static int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, - int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_get_sar_power_limits(wiphy, wdev, data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - /** * __wlan_hdd_set_sar_power_limits() - Set SAR power limits * @wiphy: Pointer to wireless phy @@ -13527,21 +10673,6 @@ void hdd_bt_activity_cb(hdd_handle_t hdd_handle, uint32_t bt_activity) hdd_ctx->bt_vo_active); } - -/** - * wlan_hdd_is_bt_in_progress() - check if bt activity is in progress - * @hdd_ctx : HDD context - * - * Return: true if BT activity is in progress else false - */ -static inline bool wlan_hdd_is_bt_in_progress(struct hdd_context *hdd_ctx) -{ - if (hdd_ctx->bt_a2dp_active || hdd_ctx->bt_vo_active) - return true; - - return false; -} - struct chain_rssi_priv { struct chain_rssi_result chain_rssi; }; @@ -13733,331 +10864,6 @@ static int wlan_hdd_cfg80211_get_chain_rssi(struct wiphy *wiphy, return ret; } -/** - * __wlan_hdd_cfg80211_set_limit_offchan_param() - set limit off-channel cmd - * parameters - * @wiphy: pointer to wireless wiphy structure. - * @wdev: pointer to wireless_dev structure. - * @data: pointer to limit off-channel command parameters. - * @data_len: the length in byte of limit off-channel command parameters. - * - * This is called when application wants to limit the off channel time due to - * active voip traffic. - * - * Return: An error code or 0 on success. - */ -static int __wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, - struct wireless_dev *wdev, const void *data, int data_len) -{ - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1]; - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - int ret = 0; - uint8_t tos; - uint8_t tos_status; - - hdd_enter(); - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret < 0) - return ret; - - if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX, - data, data_len, - wlan_hdd_set_limit_off_channel_param_policy)) { - hdd_err("Invalid ATTR"); - return -EINVAL; - } - - if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]) { - hdd_err("attr tos failed"); - goto fail; - } - - tos = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]); - if (tos >= HDD_MAX_AC) { - hdd_err("tos value %d exceeded Max value %d", - tos, HDD_MAX_AC); - goto fail; - } - hdd_debug("tos %d", tos); - - if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]) { - hdd_err("attr tos active failed"); - goto fail; - } - tos_status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]); - - hdd_debug("tos status %d", tos_status); - ret = hdd_set_limit_off_chan_for_tos(adapter, tos, tos_status); - -fail: - return ret; -} - -/** - * wlan_hdd_cfg80211_set_limit_offchan_param() - set limit off-channel cmd - * parameters - * @wiphy: pointer to wireless wiphy structure. - * @wdev: pointer to wireless_dev structure. - * @data: pointer to limit off-channel command parameters. - * @data_len: the length in byte of limit off-channel command parameters. - * - * This is called when application wants to limit the off channel time due to - * active voip traffic. - * - * Return: An error code or 0 on success. - */ -static int wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) - -{ - int ret = 0; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_set_limit_offchan_param(wiphy, wdev, data, - data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - -/** - * wlan_hdd_fill_btm_resp() - Fill bss candidate response buffer - * @reply_skb : pointer to reply_skb - * @info : bss candidate information - * @index : attribute type index for nla_next_start() - * - * Return : 0 on success and errno on failure - */ -static int wlan_hdd_fill_btm_resp(struct sk_buff *reply_skb, - struct bss_candidate_info *info, - int index) -{ - struct nlattr *attr; - - attr = nla_nest_start(reply_skb, index); - if (!attr) { - hdd_err("nla_nest_start failed"); - kfree_skb(reply_skb); - return -EINVAL; - } - - if (nla_put(reply_skb, - QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID, - ETH_ALEN, info->bssid.bytes) || - nla_put_u32(reply_skb, - QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS, - info->status)) { - hdd_err("nla_put failed"); - kfree_skb(reply_skb); - return -EINVAL; - } - - nla_nest_end(reply_skb, attr); - - return 0; -} - -/** - * __wlan_hdd_cfg80211_fetch_bss_transition_status() - fetch bss transition - * status - * @wiphy : WIPHY structure pointer - * @wdev : Wireless device structure pointer - * @data : Pointer to the data received - * @data_len : Length of the data received - * - * This function is used to fetch transition status for candidate bss. The - * transition status is either accept or reason for reject. - * - * Return : 0 on success and errno on failure - */ -static int __wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) -{ - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; - struct nlattr *tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1]; - uint8_t transition_reason; - struct nlattr *attr; - struct sk_buff *reply_skb; - int rem, j; - int ret; - bool is_bt_in_progress; - struct bss_candidate_info candidate_info[MAX_CANDIDATE_INFO]; - uint16_t nof_candidates, i = 0; - struct hdd_context *hdd_ctx = wiphy_priv(wiphy); - struct net_device *dev = wdev->netdev; - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - struct hdd_station_ctx *hdd_sta_ctx = - WLAN_HDD_GET_STATION_CTX_PTR(adapter); - mac_handle_t mac_handle; - - const struct nla_policy - btm_params_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { - [QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] = { - .type = NLA_U8}, - [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO] = { - .type = NLA_NESTED}, - }; - const struct nla_policy - btm_cand_list_policy[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] - = {[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = { - .len = QDF_MAC_ADDR_SIZE}, - [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = { - .type = NLA_U32}, - }; - - hdd_enter(); - - if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { - hdd_err("Command not allowed in FTM mode"); - return -EINVAL; - } - - ret = wlan_hdd_validate_context(hdd_ctx); - if (ret) - return ret; - - if (adapter->device_mode != QDF_STA_MODE || - hdd_sta_ctx->conn_info.connState != eConnectionState_Associated) { - hdd_err("Command is either not invoked for STA mode (device mode: %d) or STA is not associated (Connection state: %d)", - adapter->device_mode, hdd_sta_ctx->conn_info.connState); - return -EINVAL; - } - - ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, - data_len, btm_params_policy); - if (ret) { - hdd_err("Attribute parse failed"); - return -EINVAL; - } - - if (!tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] || - !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO]) { - hdd_err("Missing attributes"); - return -EINVAL; - } - - transition_reason = nla_get_u8( - tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON]); - - nla_for_each_nested(attr, - tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO], - rem) { - ret = wlan_cfg80211_nla_parse_nested(tb_msg, - QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX, - attr, btm_cand_list_policy); - if (ret) { - hdd_err("Attribute parse failed"); - return -EINVAL; - } - - if (!tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]) { - hdd_err("Missing BSSID attribute"); - return -EINVAL; - } - - qdf_mem_copy((void *)candidate_info[i].bssid.bytes, - nla_data(tb_msg[ - QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]), - QDF_MAC_ADDR_SIZE); - i++; - if (i == MAX_CANDIDATE_INFO) - break; - } - - /* - * Determine status for each candidate and fill in the status field. - * Also arrange the candidates in the order of preference. - */ - nof_candidates = i; - - is_bt_in_progress = wlan_hdd_is_bt_in_progress(hdd_ctx); - - mac_handle = hdd_ctx->mac_handle; - ret = sme_get_bss_transition_status(mac_handle, transition_reason, - &hdd_sta_ctx->conn_info.bssId, - candidate_info, - nof_candidates, - is_bt_in_progress); - if (ret) - return -EINVAL; - - /* Prepare the reply and send it to userspace */ - reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, - ((QDF_MAC_ADDR_SIZE + sizeof(uint32_t)) * - nof_candidates) + NLMSG_HDRLEN); - if (!reply_skb) { - hdd_err("reply buffer alloc failed"); - return -ENOMEM; - } - - attr = nla_nest_start(reply_skb, - QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO); - if (!attr) { - hdd_err("nla_nest_start failed"); - kfree_skb(reply_skb); - return -EINVAL; - } - - /* - * Order candidates as - accepted candidate list followed by rejected - * candidate list - */ - for (i = 0, j = 0; i < nof_candidates; i++) { - /* copy accepted candidate list */ - if (candidate_info[i].status == QCA_STATUS_ACCEPT) { - if (wlan_hdd_fill_btm_resp(reply_skb, - &candidate_info[i], j)) - return -EINVAL; - j++; - } - } - for (i = 0; i < nof_candidates; i++) { - /* copy rejected candidate list */ - if (candidate_info[i].status != QCA_STATUS_ACCEPT) { - if (wlan_hdd_fill_btm_resp(reply_skb, - &candidate_info[i], j)) - return -EINVAL; - j++; - } - } - nla_nest_end(reply_skb, attr); - - hdd_exit(); - - return cfg80211_vendor_cmd_reply(reply_skb); -} - -/** - * wlan_hdd_cfg80211_fetch_bss_transition_status() - fetch bss transition status - * @wiphy : WIPHY structure pointer - * @wdev : Wireless device structure pointer - * @data : Pointer to the data received - * @data_len : Length of the data received - * - * This function is used to fetch transition status for candidate bss. The - * transition status is either accept or reason for reject. - * - * Return : 0 on success and errno on failure - */ -static int wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) -{ - int ret; - - cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_fetch_bss_transition_status(wiphy, wdev, - data, data_len); - cds_ssr_unprotect(__func__); - - return ret; -} - /** * wlan_hdd_fill_intf_info() - Fill skb buffer with interface info * @skb: Pointer to skb @@ -14388,12 +11194,9 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_set_scanning_mac_oui }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, - .doit = wlan_hdd_cfg80211_get_concurrency_matrix - }, + + FEATURE_CONCURRENCY_MATRIX_VENDOR_COMMANDS + { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG, @@ -14410,14 +11213,9 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_handle_wisa_cmd }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_STATION, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = hdd_cfg80211_get_station_cmd - }, + + FEATURE_STATION_INFO_VENDOR_COMMANDS + { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS, @@ -14561,14 +11359,8 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { .doit = wlan_hdd_cfg80211_offloaded_packets }, #endif - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_monitor_rssi - }, + FEATURE_RSSI_MONITOR_VENDOR_COMMANDS + #ifdef WLAN_NS_OFFLOAD { .info.vendor_id = QCA_NL80211_VENDOR_ID, @@ -14679,14 +11471,9 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_get_link_properties }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OTA_TEST, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_set_ota_test - }, + + FEATURE_OTA_TEST_VENDOR_COMMANDS + #ifdef FEATURE_LFR_SUBNET_DETECTION { .info.vendor_id = QCA_NL80211_VENDOR_ID, @@ -14697,23 +11484,9 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { .doit = wlan_hdd_cfg80211_set_gateway_params }, #endif /* FEATURE_LFR_SUBNET_DETECTION */ - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_txpower_scale - }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = - QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_txpower_scale_decr_db - }, + + FEATURE_TX_POWER_VENDOR_COMMANDS + #ifdef FEATURE_WLAN_APF { .info.vendor_id = QCA_NL80211_VENDOR_ID, @@ -14758,33 +11531,10 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_sap_configuration_set }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = - QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_p2p_lo_start - }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = - QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_p2p_lo_stop - }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = - QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_conditional_chan_switch - }, + + FEATURE_P2P_LISTEN_OFFLOAD_VENDOR_COMMANDS + + FEATURE_SAP_COND_CHAN_SWITCH_VENDOR_COMMANDS #ifdef WLAN_FEATURE_NAN_DATAPATH { .info.vendor_id = QCA_NL80211_VENDOR_ID, @@ -14857,13 +11607,8 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { .doit = wlan_hdd_cfg80211_configure_tdls_mode }, #endif - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_get_sar_power_limits - }, + FEATURE_SAR_LIMITS_VENDOR_COMMANDS + { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS, @@ -14904,15 +11649,8 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_get_nud_stats }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = - QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_fetch_bss_transition_status - }, + + FEATURE_BSS_TRANSITION_VENDOR_COMMANDS FEATURE_SPECTRAL_SCAN_VENDOR_COMMANDS #ifdef WLAN_UMAC_CONVERGENCE COMMON_VENDOR_COMMANDS @@ -14927,14 +11665,8 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_get_chain_rssi }, - { - .info.vendor_id = QCA_NL80211_VENDOR_ID, - .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS, - .flags = WIPHY_VENDOR_CMD_NEED_WDEV | - WIPHY_VENDOR_CMD_NEED_NETDEV | - WIPHY_VENDOR_CMD_NEED_RUNNING, - .doit = wlan_hdd_cfg80211_set_limit_offchan_param - }, + + FEATURE_ACTIVE_TOS_VENDOR_COMMANDS }; diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index bca41579c914..2eac435339c3 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -369,19 +369,6 @@ void wlan_hdd_cfg80211_extscan_callback(hdd_handle_t hdd_handle, void wlan_hdd_rso_cmd_status_cb(hdd_handle_t hdd_handle, struct rso_cmd_status *rso_status); -/** - * hdd_rssi_threshold_breached() - rssi breached NL event - * @hdd_handle: HDD handle - * @data: rssi breached event data - * - * This function reads the rssi breached event %data and fill in the skb with - * NL attributes and send up the NL event. - * - * Return: none - */ -void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, - struct rssi_breach_event *data); - struct cfg80211_bss * wlan_hdd_cfg80211_update_bss_list(struct hdd_adapter *adapter, tSirMacAddr bssid); diff --git a/core/hdd/src/wlan_hdd_concurrency_matrix.c b/core/hdd/src/wlan_hdd_concurrency_matrix.c new file mode 100644 index 000000000000..bb962085812a --- /dev/null +++ b/core/hdd/src/wlan_hdd_concurrency_matrix.c @@ -0,0 +1,144 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_concurrency_matrix.c + * + * WLAN concurrency matrix functions + * + */ + +#include +#include +#include +#include +#include +#include + +#define CDS_MAX_FEATURE_SET 8 +#define MAX_CONCURRENT_MATRIX \ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX +#define MATRIX_CONFIG_PARAM_SET_SIZE_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX +static const struct nla_policy +wlan_hdd_get_concurrency_matrix_policy[MAX_CONCURRENT_MATRIX + 1] = { + [MATRIX_CONFIG_PARAM_SET_SIZE_MAX] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_get_concurrency_matrix() - to retrieve concurrency matrix + * @wiphy: pointer phy adapter + * @wdev: pointer to wireless device structure + * @data: pointer to data buffer + * @data_len: length of data + * + * This routine will give concurrency matrix + * + * Return: int status code + */ +static int +__wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint32_t feature_set_matrix[CDS_MAX_FEATURE_SET] = {0}; + uint8_t i, feature_sets, max_feature_sets; + struct nlattr *tb[MAX_CONCURRENT_MATRIX + 1]; + struct sk_buff *reply_skb; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + + hdd_enter_dev(wdev->netdev); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (wlan_cfg80211_nla_parse(tb, MAX_CONCURRENT_MATRIX, data, data_len, + wlan_hdd_get_concurrency_matrix_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch max feature set */ + if (!tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]) { + hdd_err("Attr max feature set size failed"); + return -EINVAL; + } + max_feature_sets = nla_get_u32(tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]); + hdd_debug("Max feature set size: %d", max_feature_sets); + + /* Fill feature combination matrix */ + feature_sets = 0; + feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | + WIFI_FEATURE_P2P; + feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | + WIFI_FEATURE_NAN; + /* Add more feature combinations here */ + + feature_sets = QDF_MIN(feature_sets, max_feature_sets); + hdd_debug("Number of feature sets: %d", feature_sets); + hdd_debug("Feature set matrix"); + for (i = 0; i < feature_sets; i++) + hdd_debug("[%d] 0x%02X", i, feature_set_matrix[i]); + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * feature_sets + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("Feature set matrix: buffer alloc fail"); + return -ENOMEM; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE, + feature_sets) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET, + sizeof(u32) * feature_sets, + feature_set_matrix)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + return cfg80211_vendor_cmd_reply(reply_skb); +} + +#undef MAX_CONCURRENT_MATRIX +#undef MATRIX_CONFIG_PARAM_SET_SIZE_MAX + +int wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_concurrency_matrix(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_concurrency_matrix.h b/core/hdd/src/wlan_hdd_concurrency_matrix.h new file mode 100644 index 000000000000..1bdc6f75fd4e --- /dev/null +++ b/core/hdd/src/wlan_hdd_concurrency_matrix.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_CONCURRENCY_MATRIX_H +#define __WLAN_HDD_CONCURRENCY_MATRIX_H + +/** + * DOC: wlan_hdd_concurrency_matrix_h + * + * WLAN Host Device Driver concurrency matrix API specification + */ + +#ifdef FEATURE_CONCURRENCY_MATRIX +/** + * wlan_hdd_cfg80211_get_concurrency_matrix() - get concurrency matrix + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Retrieves the concurrency feature set matrix + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_CONCURRENCY_MATRIX_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX,\ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,\ + .doit = wlan_hdd_cfg80211_get_concurrency_matrix \ +}, +#else /* FEATURE_CONCURRENCY_MATRIX */ +#define FEATURE_CONCURRENCY_MATRIX_VENDOR_COMMANDS +#endif /* FEATURE_CONCURRENCY_MATRIX */ + +#endif /* __WLAN_HDD_CONCURRENCY_MATRIX_H */ + diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 6e860466aeb6..effbe3ae9d02 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -138,6 +138,7 @@ #include "wlan_mlme_main.h" #include "wlan_p2p_cfg_api.h" #include "wlan_tdls_cfg_api.h" +#include #ifdef CNSS_GENL #include @@ -300,13 +301,6 @@ static const struct category_info cinfo[MAX_SUPPORTED_CATEGORY] = { [QDF_MODULE_ID_CONFIG] = {QDF_TRACE_LEVEL_ALL}, }; -int limit_off_chan_tbl[HDD_MAX_AC][HDD_MAX_OFF_CHAN_ENTRIES] = { - { HDD_AC_BK_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BK }, - { HDD_AC_BE_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BE }, - { HDD_AC_VI_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VI }, - { HDD_AC_VO_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VO }, -}; - struct notifier_block hdd_netdev_notifier; struct notifier_block system_reboot_notifier; @@ -14129,76 +14123,6 @@ int hdd_get_rssi_snr_by_bssid(struct hdd_adapter *adapter, const uint8_t *bssid, return 0; } -/** - * hdd_set_limit_off_chan_for_tos() - set limit off-channel command parameters - * @adapter - HDD adapter - * @tos - type of service - * @status - status of the traffic - * - * Return: 0 on success and non zero value on failure - */ - -int hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, enum tos tos, - bool is_tos_active) -{ - int ac_bit; - struct hdd_context *hdd_ctx; - uint32_t max_off_chan_time = 0; - QDF_STATUS status; - int ret; - - hdd_ctx = WLAN_HDD_GET_CTX(adapter); - ret = wlan_hdd_validate_context(hdd_ctx); - - if (ret < 0) { - hdd_err("failed to set limit off chan params"); - return ret; - } - - ac_bit = limit_off_chan_tbl[tos][HDD_AC_BIT_INDX]; - - if (is_tos_active) - adapter->active_ac |= ac_bit; - else - adapter->active_ac &= ~ac_bit; - - if (adapter->active_ac) { - if (adapter->active_ac & HDD_AC_VO_BIT) { - max_off_chan_time = - limit_off_chan_tbl[TOS_VO][HDD_DWELL_TIME_INDX]; - policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, - PM_LATENCY); - } else if (adapter->active_ac & HDD_AC_VI_BIT) { - max_off_chan_time = - limit_off_chan_tbl[TOS_VI][HDD_DWELL_TIME_INDX]; - policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, - PM_LATENCY); - } else { - /*ignore this command if only BE/BK is active */ - is_tos_active = false; - policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, - hdd_ctx->config->conc_system_pref); - } - } else { - /* No active tos */ - policy_mgr_set_cur_conc_system_pref(hdd_ctx->hdd_psoc, - hdd_ctx->config->conc_system_pref); - } - - status = sme_send_limit_off_channel_params(hdd_ctx->mac_handle, - adapter->session_id, - is_tos_active, - max_off_chan_time, - hdd_ctx->config->nRestTimeConc, - true); - if (!QDF_IS_STATUS_SUCCESS(status)) { - hdd_err("failed to set limit off chan params"); - ret = -EINVAL; - } - - return ret; -} - /** * hdd_reset_limit_off_chan() - reset limit off-channel command parameters * @adapter - HDD adapter diff --git a/core/hdd/src/wlan_hdd_ota_test.c b/core/hdd/src/wlan_hdd_ota_test.c new file mode 100644 index 000000000000..ef54c99b1f89 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ota_test.c @@ -0,0 +1,142 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_ota_test.c + * + * WLAN OTA test functions + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct +nla_policy +qca_wlan_vendor_ota_test_policy +[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_set_ota_test() - enable/disable OTA test + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1]; + uint8_t ota_enable = 0; + QDF_STATUS status; + uint32_t current_roam_state; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx) != 0) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX, + data, data_len, + qca_wlan_vendor_ota_test_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]) { + hdd_err("attr ota test failed"); + return -EINVAL; + } + + ota_enable = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]); + + hdd_debug(" OTA test enable = %d", ota_enable); + if (ota_enable != 1) { + hdd_err("Invalid value, only enable test mode is supported!"); + return -EINVAL; + } + + mac_handle = hdd_ctx->mac_handle; + current_roam_state = + sme_get_current_roam_state(mac_handle, adapter->session_id); + status = sme_stop_roaming(mac_handle, adapter->session_id, + eCsrHddIssued); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Enable/Disable roaming failed"); + return -EINVAL; + } + + status = sme_ps_enable_disable(mac_handle, adapter->session_id, + SME_PS_DISABLE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Enable/Disable power save failed"); + /* restore previous roaming setting */ + if (current_roam_state == eCSR_ROAMING_STATE_JOINING || + current_roam_state == eCSR_ROAMING_STATE_JOINED) + status = sme_start_roaming(mac_handle, + adapter->session_id, + eCsrHddIssued); + else if (current_roam_state == eCSR_ROAMING_STATE_STOP || + current_roam_state == eCSR_ROAMING_STATE_IDLE) + status = sme_stop_roaming(mac_handle, + adapter->session_id, + eCsrHddIssued); + + if (status != QDF_STATUS_SUCCESS) + hdd_err("Restoring roaming state failed"); + + return -EINVAL; + } + return 0; +} + +int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ota_test(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_ota_test.h b/core/hdd/src/wlan_hdd_ota_test.h new file mode 100644 index 000000000000..9d950b808171 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ota_test.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_OTA_TEST_H +#define __WLAN_HDD_OTA_TEST_H + +/** + * DOC: wlan_hdd_ota_test_h + * + * WLAN Host Device Driver OTA test API specification + */ + +#ifdef FEATURE_OTA_TEST +/** + * wlan_hdd_cfg80211_set_ota_test () - Enable or disable OTA test + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_OTA_TEST_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OTA_TEST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_ota_test \ +}, +#else /* FEATURE_OTA_TEST */ +#define FEATURE_OTA_TEST_VENDOR_COMMANDS +#endif /* FEATURE_OTA_TEST */ + +#endif /* __WLAN_HDD_OTA_TEST_H */ + diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index 2027cc1f268a..580223a05307 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -1040,70 +1040,6 @@ int wlan_hdd_set_power_save(struct hdd_adapter *adapter, return qdf_status_to_os_return(status); } -int wlan_hdd_listen_offload_start(struct hdd_adapter *adapter, - struct sir_p2p_lo_start *params) -{ - struct wlan_objmgr_psoc *psoc; - struct p2p_lo_start lo_start; - struct hdd_context *hdd_ctx; - QDF_STATUS status; - - if (!adapter || !params) { - hdd_err("null param, adapter:%pK, params:%pK", - adapter, params); - return -EINVAL; - } - - hdd_ctx = WLAN_HDD_GET_CTX(adapter); - psoc = hdd_ctx->hdd_psoc; - if (!psoc) { - hdd_err("psoc is null"); - return -EINVAL; - } - - lo_start.vdev_id = params->vdev_id; - lo_start.ctl_flags = params->ctl_flags; - lo_start.freq = params->freq; - lo_start.period = params->period; - lo_start.interval = params->interval; - lo_start.count = params->count; - lo_start.device_types = params->device_types; - lo_start.dev_types_len = params->dev_types_len; - lo_start.probe_resp_tmplt = params->probe_resp_tmplt; - lo_start.probe_resp_len = params->probe_resp_len; - - status = ucfg_p2p_lo_start(psoc, &lo_start); - hdd_debug("p2p listen offload start, status:%d", status); - - return qdf_status_to_os_return(status); -} - -int wlan_hdd_listen_offload_stop(struct hdd_adapter *adapter) -{ - struct wlan_objmgr_psoc *psoc; - struct hdd_context *hdd_ctx; - uint32_t vdev_id; - QDF_STATUS status; - - if (!adapter) { - hdd_err("adapter is null, adapter:%pK", adapter); - return -EINVAL; - } - - vdev_id = (uint32_t)adapter->session_id; - hdd_ctx = WLAN_HDD_GET_CTX(adapter); - psoc = hdd_ctx->hdd_psoc; - if (!psoc) { - hdd_err("psoc is null"); - return -EINVAL; - } - - status = ucfg_p2p_lo_stop(psoc, vdev_id); - hdd_debug("p2p listen offload stop, status:%d", status); - - return qdf_status_to_os_return(status); -} - /** * wlan_hdd_update_mcc_adaptive_scheduler() - Function to update * MAS value to FW diff --git a/core/hdd/src/wlan_hdd_p2p_listen_offload.c b/core/hdd/src/wlan_hdd_p2p_listen_offload.c new file mode 100644 index 000000000000..fe5e843e70e2 --- /dev/null +++ b/core/hdd/src/wlan_hdd_p2p_listen_offload.c @@ -0,0 +1,347 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_vendor_p2p_listen_offload.c + * + * WLAN p2p listen offload functions + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* P2P listen offload device types parameters length in bytes */ +#define P2P_LO_MAX_REQ_DEV_TYPE_COUNT (10) +#define P2P_LO_WPS_DEV_TYPE_LEN (8) +#define P2P_LO_DEV_TYPE_MAX_LEN \ + (P2P_LO_MAX_REQ_DEV_TYPE_COUNT * P2P_LO_WPS_DEV_TYPE_LEN) + +static const struct nla_policy +p2p_listen_offload_policy[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] = { + .type = NLA_BINARY, + .len = P2P_LO_DEV_TYPE_MAX_LEN }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE] = { + .type = NLA_BINARY, + .len = MAX_GENIE_LEN }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON] = { + .type = NLA_U8 }, +}; + +/** + * wlan_hdd_listen_offload_start() - hdd set listen offload start + * @adapter: adapter context + * @params: listen offload parameters + * + * This function sets listen offload start parameters. + * + * Return: 0 on success, others on failure + */ +static int wlan_hdd_listen_offload_start(struct hdd_adapter *adapter, + struct sir_p2p_lo_start *params) +{ + struct wlan_objmgr_psoc *psoc; + struct p2p_lo_start lo_start; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + + if (!adapter || !params) { + hdd_err("null param, adapter:%pK, params:%pK", + adapter, params); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + psoc = hdd_ctx->hdd_psoc; + if (!psoc) { + hdd_err("psoc is null"); + return -EINVAL; + } + + lo_start.vdev_id = params->vdev_id; + lo_start.ctl_flags = params->ctl_flags; + lo_start.freq = params->freq; + lo_start.period = params->period; + lo_start.interval = params->interval; + lo_start.count = params->count; + lo_start.device_types = params->device_types; + lo_start.dev_types_len = params->dev_types_len; + lo_start.probe_resp_tmplt = params->probe_resp_tmplt; + lo_start.probe_resp_len = params->probe_resp_len; + + status = ucfg_p2p_lo_start(psoc, &lo_start); + hdd_debug("p2p listen offload start, status:%d", status); + + return qdf_status_to_os_return(status); +} + +/** + * __wlan_hdd_cfg80211_p2p_lo_start () - start P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload start vendor + * command. It parses the input parameters and invoke WMA API to + * send the command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1]; + struct sir_p2p_lo_start params; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && + (adapter->device_mode != QDF_P2P_CLIENT_MODE) && + (adapter->device_mode != QDF_P2P_GO_MODE)) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX, + data, data_len, + p2p_listen_offload_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(params)); + + if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]) + params.ctl_flags = 1; /* set to default value */ + else + params.ctl_flags = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]) { + hdd_err("Attribute parsing failed"); + return -EINVAL; + } + + params.vdev_id = adapter->session_id; + params.freq = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL]); + if ((params.freq != 2412) && (params.freq != 2437) && + (params.freq != 2462)) { + hdd_err("Invalid listening channel: %d", params.freq); + return -EINVAL; + } + + params.period = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD]); + if (!((params.period > 0) && (params.period < UINT_MAX))) { + hdd_err("Invalid period: %d", params.period); + return -EINVAL; + } + + params.interval = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL]); + if (!((params.interval > 0) && (params.interval < UINT_MAX))) { + hdd_err("Invalid interval: %d", params.interval); + return -EINVAL; + } + + params.count = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT]); + if (!((params.count >= 0) && (params.count < UINT_MAX))) { + hdd_err("Invalid count: %d", params.count); + return -EINVAL; + } + + params.device_types = nla_data(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); + if (!params.device_types) { + hdd_err("Invalid device types"); + return -EINVAL; + } + + params.dev_types_len = nla_len(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); + /* device type length has to be multiple of P2P_LO_WPS_DEV_TYPE_LEN */ + if (0 != (params.dev_types_len % P2P_LO_WPS_DEV_TYPE_LEN)) { + hdd_err("Invalid device type length: %d", params.dev_types_len); + return -EINVAL; + } + + params.probe_resp_tmplt = nla_data(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); + if (!params.probe_resp_tmplt) { + hdd_err("Invalid probe response template"); + return -EINVAL; + } + + /* + * IEs minimum length should be 2 bytes: 1 byte for element id + * and 1 byte for element id length. + */ + params.probe_resp_len = nla_len(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); + if (params.probe_resp_len < MIN_GENIE_LEN) { + hdd_err("Invalid probe resp template length: %d", + params.probe_resp_len); + return -EINVAL; + } + + hdd_debug("P2P LO params: freq=%d, period=%d, interval=%d, count=%d", + params.freq, params.period, params.interval, params.count); + + return wlan_hdd_listen_offload_start(adapter, ¶ms); +} + +int wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_p2p_lo_start(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_listen_offload_stop() - hdd set listen offload stop + * @adapter: adapter context + * + * This function sets listen offload stop parameters. + * + * Return: 0 on success, others on failure + */ +static int wlan_hdd_listen_offload_stop(struct hdd_adapter *adapter) +{ + struct wlan_objmgr_psoc *psoc; + struct hdd_context *hdd_ctx; + uint32_t vdev_id; + QDF_STATUS status; + + if (!adapter) { + hdd_err("adapter is null, adapter:%pK", adapter); + return -EINVAL; + } + + vdev_id = (uint32_t)adapter->session_id; + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + psoc = hdd_ctx->hdd_psoc; + if (!psoc) { + hdd_err("psoc is null"); + return -EINVAL; + } + + status = ucfg_p2p_lo_stop(psoc, vdev_id); + hdd_debug("p2p listen offload stop, status:%d", status); + + return qdf_status_to_os_return(status); +} + +/** + * __wlan_hdd_cfg80211_p2p_lo_stop () - stop P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload stop vendor + * command. It invokes WMA API to send command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_adapter *adapter; + struct net_device *dev = wdev->netdev; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && + (adapter->device_mode != QDF_P2P_CLIENT_MODE) && + (adapter->device_mode != QDF_P2P_GO_MODE)) { + hdd_err("Invalid device mode"); + return -EINVAL; + } + + return wlan_hdd_listen_offload_stop(adapter); +} + +int wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_p2p_lo_stop(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_p2p_listen_offload.h b/core/hdd/src/wlan_hdd_p2p_listen_offload.h new file mode 100644 index 000000000000..f039aca82a8e --- /dev/null +++ b/core/hdd/src/wlan_hdd_p2p_listen_offload.h @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_P2P_LISTEN_OFFLOAD_H +#define __WLAN_HDD_P2P_LISTEN_OFFLOAD_H + +/** + * DOC: wlan_hdd_p2p_listen_offload_h + * + * WLAN Host Device Driver p2p listen offload API specification + */ + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * __wlan_hdd_cfg80211_p2p_lo_start() - start P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload start vendor + * command. It parses the input parameters and invoke WMA API to + * send the command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_p2p_lo_stop() - stop P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function inovkes internal __wlan_hdd_cfg80211_p2p_lo_stop() + * to process p2p listen offload stop vendor command. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_P2P_LISTEN_OFFLOAD_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_p2p_lo_start \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_p2p_lo_stop \ +}, +#else /* FEATURE_P2P_LISTEN_OFFLOAD */ +#define FEATURE_P2P_LISTEN_OFFLOAD_VENDOR_COMMANDS +#endif /* FEATURE_P2P_LISTEN_OFFLOAD */ + +#endif /* __WLAN_HDD_P2P_LISTEN_OFFLOAD_H */ + diff --git a/core/hdd/src/wlan_hdd_rssi_monitor.c b/core/hdd/src/wlan_hdd_rssi_monitor.c new file mode 100644 index 000000000000..b78116f36534 --- /dev/null +++ b/core/hdd/src/wlan_hdd_rssi_monitor.c @@ -0,0 +1,222 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_rssi_monitor.c + * + * WLAN rssi monitoring functions + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX +#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID +#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL +#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI +#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI + +/** + * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct rssi_monitor_req req; + QDF_STATUS status; + int ret; + uint32_t control; + mac_handle_t mac_handle; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_MIN_RSSI] = { .type = NLA_S8 }, + [PARAM_MAX_RSSI] = { .type = NLA_S8 }, + }; + + hdd_enter_dev(dev); + + if (wlan_hdd_validate_session_id(adapter->session_id)) { + hdd_err("invalid session id: %d", adapter->session_id); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hdd_err("attr control failed"); + return -EINVAL; + } + + req.request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + req.session_id = adapter->session_id; + control = nla_get_u32(tb[PARAM_CONTROL]); + + if (control == QCA_WLAN_RSSI_MONITORING_START) { + req.control = true; + if (!tb[PARAM_MIN_RSSI]) { + hdd_err("attr min rssi failed"); + return -EINVAL; + } + + if (!tb[PARAM_MAX_RSSI]) { + hdd_err("attr max rssi failed"); + return -EINVAL; + } + + req.min_rssi = nla_get_s8(tb[PARAM_MIN_RSSI]); + req.max_rssi = nla_get_s8(tb[PARAM_MAX_RSSI]); + + if (!(req.min_rssi < req.max_rssi)) { + hdd_warn("min_rssi: %d must be less than max_rssi: %d", + req.min_rssi, req.max_rssi); + return -EINVAL; + } + hdd_debug("Min_rssi: %d Max_rssi: %d", + req.min_rssi, req.max_rssi); + + } else if (control == QCA_WLAN_RSSI_MONITORING_STOP) { + req.control = false; + } else { + hdd_err("Invalid control cmd: %d", control); + return -EINVAL; + } + hdd_debug("Request Id: %u Session_id: %d Control: %d", + req.request_id, req.session_id, req.control); + + mac_handle = hdd_ctx->mac_handle; + status = sme_set_rssi_monitoring(mac_handle, &req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_rssi_monitoring failed(err=%d)", status); + return -EINVAL; + } + + return 0; +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#undef PARAM_MAX +#undef PARAM_CONTROL +#undef PARAM_REQUEST_ID +#undef PARAM_MAX_RSSI +#undef PARAM_MIN_RSSI + +int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, + struct rssi_breach_event *data) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct sk_buff *skb; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, + GFP_KERNEL); + + if (!skb) { + hdd_err("mem alloc failed"); + return; + } + + hdd_debug("Req Id: %u Current rssi: %d", + data->request_id, data->curr_rssi); + hdd_debug("Current BSSID: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(data->curr_bssid.bytes)); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, + data->request_id) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, + sizeof(data->curr_bssid), data->curr_bssid.bytes) || + nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, + data->curr_rssi)) { + hdd_err("nla put fail"); + goto fail; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); +} + diff --git a/core/hdd/src/wlan_hdd_rssi_monitor.h b/core/hdd/src/wlan_hdd_rssi_monitor.h new file mode 100644 index 000000000000..ac621c477bf4 --- /dev/null +++ b/core/hdd/src/wlan_hdd_rssi_monitor.h @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_RSSI_MONITOR_H +#define __WLAN_HDD_RSSI_MONITOR_H + +/** + * DOC: wlan_hdd_rssi_monitor_h + * + * WLAN Host Device Driver RSSI monitoring API specification + */ + +#ifdef FEATURE_RSSI_MONITOR +/** + * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +/** + * hdd_rssi_threshold_breached() - rssi breached NL event + * @hdd_handle: HDD handle + * @data: rssi breached event data + * + * This function reads the rssi breached event %data and fill in the skb with + * NL attributes and send up the NL event. + * + * Return: none + */ +void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, + struct rssi_breach_event *data); + +#define FEATURE_RSSI_MONITOR_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI \ +}, + +#define FEATURE_RSSI_MONITOR_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_monitor_rssi \ +}, + +#else /* FEATURE_RSSI_MONITOR */ +static inline +void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, + struct rssi_breach_event *data) +{ +} + +#define FEATURE_RSSI_MONITOR_VENDOR_EVENTS +#define FEATURE_RSSI_MONITOR_VENDOR_COMMANDS +#endif /* FEATURE_RSSI_MONITOR */ + +#endif /* __WLAN_HDD_RSSI_MONITOR_H */ + diff --git a/core/hdd/src/wlan_hdd_sap_cond_chan_switch.c b/core/hdd/src/wlan_hdd_sap_cond_chan_switch.c new file mode 100644 index 000000000000..60274d27c8d8 --- /dev/null +++ b/core/hdd/src/wlan_hdd_sap_cond_chan_switch.c @@ -0,0 +1,518 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_sap_cond_chan_switch.c + * + * WLAN SAP conditional channel switch functions + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * 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) + * @handle: Global handle + * + * 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, mac_handle_t handle) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_pre_cac_status( + WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter), status, handle); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +/** + * wlan_hdd_set_chan_before_pre_cac() - Save the channel before pre cac + * @ap_adapter: AP adapter + * @chan_before_pre_cac: Channel + * + * Saves the channel 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_before_pre_cac(struct hdd_adapter *ap_adapter, + uint8_t chan_before_pre_cac) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_chan_before_pre_cac( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), chan_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 + * @channel: Channel requested by userspace + * @pre_cac_chan: Pointer to the pre CAC channel + * + * 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, + uint8_t channel, + uint8_t *pre_cac_chan) +{ + uint32_t i; + QDF_STATUS status; + uint32_t weight_len = 0; + uint32_t len = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0}; + uint8_t pcl_weights[QDF_MAX_NUM_CHAN] = {0}; + mac_handle_t mac_handle; + + if (channel == 0) { + /* 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->hdd_psoc, + channel_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->hdd_psoc, + channel_list, &len, + pcl_weights, + weight_len); + for (i = 0; i < len; i++) { + if (wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, + channel_list[i])) { + *pre_cac_chan = channel_list[i]; + break; + } + } + if (*pre_cac_chan == 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, channel) || + !wlan_reg_is_dfs_ch(hdd_ctx->hdd_pdev, channel)) { + hdd_err("Invalid channel for pre cac:%d", channel); + return -EINVAL; + } + *pre_cac_chan = channel; + } + hdd_debug("selected pre cac channel:%d", *pre_cac_chan); + return 0; +} + +/** + * wlan_hdd_request_pre_cac() - Start pre CAC in the driver + * @channel: Channel 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(uint8_t channel) +{ + uint8_t pre_cac_chan = 0, *mac_addr; + struct hdd_context *hdd_ctx; + 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; + uint32_t freq; + struct ieee80211_channel *chan; + mac_handle_t mac_handle; + bool val; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx) != 0) + return -EINVAL; + + if (policy_mgr_get_connection_count(hdd_ctx->hdd_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; + } + + 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_ch(hdd_ctx->hdd_pdev, + hdd_ap_ctx->operating_channel)) { + hdd_err("SAP is already on DFS channel:%d", + hdd_ap_ctx->operating_channel); + return -EINVAL; + } + + if (!WLAN_REG_IS_24GHZ_CH(hdd_ap_ctx->operating_channel)) { + hdd_err("pre CAC alllowed only when SAP is in 2.4GHz:%d", + hdd_ap_ctx->operating_channel); + return -EINVAL; + } + + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx); + if (!mac_addr) { + hdd_err("can't add virtual intf: Not getting valid mac addr"); + return -EINVAL; + } + + hdd_debug("channel:%d", channel); + + ret = wlan_hdd_validate_and_get_pre_cac_ch(hdd_ctx, ap_adapter, channel, + &pre_cac_chan); + 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"); + + /* 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. + */ + pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, "precac%d", + mac_addr, NET_NAME_UNKNOWN, true); + if (!pre_cac_adapter) { + hdd_err("error opening the pre cac adapter"); + goto release_intf_addr_and_return_failure; + } + + /* + * 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) { + hdd_err("failed to alloc mem for 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; + + /* 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. + */ + switch (ap_adapter->session.ap.sap_config.ch_width_orig) { + case CH_WIDTH_20MHZ: + channel_type = NL80211_CHAN_HT20; + break; + case CH_WIDTH_40MHZ: + if (ap_adapter->session.ap.sap_config.sec_ch > + ap_adapter->session.ap.sap_config.channel) + channel_type = NL80211_CHAN_HT40PLUS; + else + channel_type = NL80211_CHAN_HT40MINUS; + break; + default: + channel_type = NL80211_CHAN_NO_HT; + break; + } + + freq = cds_chan_to_freq(pre_cac_chan); + chan = ieee80211_get_channel(wiphy, freq); + if (!chan) { + hdd_err("channel converion failed"); + goto stop_close_pre_cac_adapter; + } + + cfg80211_chandef_create(&chandef, chan, channel_type); + + hdd_debug("orig width:%d channel_type:%d freq:%d", + ap_adapter->session.ap.sap_config.ch_width_orig, + channel_type, 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->hdd_psoc, + ap_adapter->session_id, + pre_cac_chan, + 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, mac_handle); + if (ret != 0) { + hdd_err("failed to set pre cac status"); + goto stop_close_pre_cac_adapter; + } + + ret = wlan_hdd_set_chan_before_pre_cac(ap_adapter, + hdd_ap_ctx->operating_channel); + if (ret != 0) { + hdd_err("failed to set channel before pre cac"); + goto stop_close_pre_cac_adapter; + } + + ap_adapter->pre_cac_chan = pre_cac_chan; + + 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 + */ + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_conditional_chan_switch() - Conditional channel switch + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Processes the conditional channel switch request and invokes the helper + * APIs to process the channel switch request. + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct nlattr + *tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX + 1]; + uint32_t freq_len, i; + uint32_t *freq; + uint8_t chans[QDF_MAX_NUM_CHAN] = {0}; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_ctx->config->enableDFSMasterCap) { + hdd_err("DFS master capability is not present in the driver"); + return -EINVAL; + } + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + + /* + * audit note: it is ok to pass a NULL policy here since only + * one attribute is parsed which is array of frequencies and + * it is explicitly validated for both under read and over read + */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]) { + hdd_err("Frequency list is missing"); + return -EINVAL; + } + + freq_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST])/ + sizeof(uint32_t); + + if (freq_len > QDF_MAX_NUM_CHAN) { + hdd_err("insufficient space to hold channels"); + return -ENOMEM; + } + + hdd_debug("freq_len=%d", freq_len); + + freq = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]); + + for (i = 0; i < freq_len; i++) { + if (freq[i] == 0) + chans[i] = 0; + else + chans[i] = ieee80211_frequency_to_channel(freq[i]); + + hdd_debug("freq[%d]=%d", i, freq[i]); + } + + /* + * The input frequency list from user space is designed to be a + * priority based frequency list. This is only to accommodate any + * future request. But, current requirement is only to perform CAC + * on a single channel. So, the first entry from the list is picked. + * + * If channel is zero, any channel in the available outdoor regulatory + * domain will be selected. + */ + ret = wlan_hdd_request_pre_cac(chans[0]); + if (ret) { + hdd_err("pre cac request failed with reason:%d", ret); + return ret; + } + + return 0; +} + +int wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_conditional_chan_switch(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_sap_cond_chan_switch.h b/core/hdd/src/wlan_hdd_sap_cond_chan_switch.h new file mode 100644 index 000000000000..1ea89eb1e00c --- /dev/null +++ b/core/hdd/src/wlan_hdd_sap_cond_chan_switch.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_SAP_COND_CHAN_SWITCH_H +#define __WLAN_HDD_SAP_COND_CHAN_SWITCH_H + +/** + * DOC: wlan_hdd_sap_cond_chan_switch_h + * + * WLAN Host Device Driver SAP conditional channel switch API specification + */ + +#ifdef FEATURE_SAP_COND_CHAN_SWITCH +/** + * wlan_hdd_cfg80211_conditional_chan_switch() - SAP conditional channel switch + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Invokes internal API __wlan_hdd_cfg80211_conditional_chan_switch() + * to process the conditional channel switch request. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_SAP_COND_CHAN_SWITCH_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_conditional_chan_switch \ +}, +#else /* FEATURE_SAP_COND_CHAN_SWITCH */ +#define FEATURE_SAP_COND_CHAN_SWITCH_VENDOR_COMMANDS +#endif /* FEATURE_SAP_COND_CHAN_SWITCH */ + +#endif /* __WLAN_HDD_SAP_COND_CHAN_SWITCH_H */ + diff --git a/core/hdd/src/wlan_hdd_sar_limits.c b/core/hdd/src/wlan_hdd_sar_limits.c new file mode 100644 index 000000000000..c500ddc6c798 --- /dev/null +++ b/core/hdd/src/wlan_hdd_sar_limits.c @@ -0,0 +1,320 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_vendor_sar_limits.c + * + * WLAN SAR limits functions + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define WLAN_WAIT_TIME_SAR 5000 +/** + * hdd_sar_context - hdd sar context + * @event: sar limit event + */ +struct hdd_sar_context { + struct sar_limit_event event; +}; + +static u32 hdd_sar_wmi_to_nl_enable(uint32_t wmi_value) +{ + switch (wmi_value) { + default: + case WMI_SAR_FEATURE_OFF: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE; + case WMI_SAR_FEATURE_ON_SET_0: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0; + case WMI_SAR_FEATURE_ON_SET_1: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1; + case WMI_SAR_FEATURE_ON_SET_2: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2; + case WMI_SAR_FEATURE_ON_SET_3: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3; + case WMI_SAR_FEATURE_ON_SET_4: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4; + case WMI_SAR_FEATURE_ON_USER_DEFINED: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER; + case WMI_SAR_FEATURE_ON_SAR_V2_0: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0; + } +} + +static u32 hdd_sar_wmi_to_nl_band(uint32_t wmi_value) +{ + switch (wmi_value) { + default: + case WMI_SAR_2G_ID: + return HDD_NL80211_BAND_2GHZ; + case WMI_SAR_5G_ID: + return HDD_NL80211_BAND_5GHZ; + } +} + +static u32 hdd_sar_wmi_to_nl_modulation(uint32_t wmi_value) +{ + switch (wmi_value) { + default: + case WMI_SAR_MOD_CCK: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK; + case WMI_SAR_MOD_OFDM: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM; + } +} + +/** + * hdd_sar_cb () - sar response message handler + * @cookie: hdd request cookie + * @event: sar response event + * + * Return: none + */ +static void hdd_sar_cb(void *cookie, + struct sar_limit_event *event) +{ + struct osif_request *request; + struct hdd_sar_context *context; + + hdd_enter(); + + if (!event) { + hdd_err("response is NULL"); + return; + } + + request = osif_request_get(cookie); + if (!request) { + hdd_debug("Obsolete request"); + return; + } + + context = osif_request_priv(request); + context->event = *event; + osif_request_complete(request); + osif_request_put(request); + + hdd_exit(); +} + +static uint32_t hdd_sar_get_response_len(const struct sar_limit_event *event) +{ + uint32_t len; + uint32_t row_len; + + len = NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE */ + len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS */ + len += NLA_HDRLEN + sizeof(u32); + + /* nest */ + row_len = NLA_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND */ + row_len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN */ + row_len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION */ + row_len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT */ + row_len += NLA_HDRLEN + sizeof(u32); + + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC */ + len += NLA_HDRLEN + (row_len * event->num_limit_rows); + + return len; +} + +static int hdd_sar_fill_response(struct sk_buff *skb, + const struct sar_limit_event *event) +{ + int errno; + u32 value; + u32 attr; + struct nlattr *nla_spec_attr; + struct nlattr *nla_row_attr; + uint32_t row; + const struct sar_limit_event_row *event_row; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE; + value = hdd_sar_wmi_to_nl_enable(event->sar_enable); + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS; + value = event->num_limit_rows; + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC; + nla_spec_attr = nla_nest_start(skb, attr); + if (!nla_spec_attr) + return -EINVAL; + + for (row = 0, event_row = event->sar_limit_row; + row < event->num_limit_rows; + row++, event_row++) { + nla_row_attr = nla_nest_start(skb, attr); + if (!nla_row_attr) + return -EINVAL; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND; + value = hdd_sar_wmi_to_nl_band(event_row->band_id); + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN; + value = event_row->chain_id; + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION; + value = hdd_sar_wmi_to_nl_modulation(event_row->mod_id); + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT; + value = event_row->limit_value; + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + nla_nest_end(skb, nla_row_attr); + } + nla_nest_end(skb, nla_spec_attr); + + return 0; +} + +static int hdd_sar_send_response(struct wiphy *wiphy, + const struct sar_limit_event *event) +{ + uint32_t len; + struct sk_buff *skb; + int errno; + + len = hdd_sar_get_response_len(event); + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + errno = hdd_sar_fill_response(skb, event); + if (errno) { + kfree_skb(skb); + return errno; + } + + return cfg80211_vendor_cmd_reply(skb); +} + +/** + * __wlan_hdd_get_sar_power_limits() - Get SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to retrieve Specific Absorption Rate limit specs. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_get_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct osif_request *request; + struct hdd_sar_context *context; + mac_handle_t mac_handle; + void *cookie; + QDF_STATUS status; + int ret; + static const struct osif_request_params params = { + .priv_size = sizeof(*context), + .timeout_ms = WLAN_WAIT_TIME_SAR, + }; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + + mac_handle = hdd_ctx->mac_handle; + status = sme_get_sar_power_limits(mac_handle, hdd_sar_cb, cookie); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to post sar message"); + ret = -EINVAL; + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Target response timed out"); + goto cleanup; + } + + context = osif_request_priv(request); + ret = hdd_sar_send_response(wiphy, &context->event); + +cleanup: + osif_request_put(request); + + return ret; +} + +int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_get_sar_power_limits(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_sar_limits.h b/core/hdd/src/wlan_hdd_sar_limits.h new file mode 100644 index 000000000000..2a49a46ef853 --- /dev/null +++ b/core/hdd/src/wlan_hdd_sar_limits.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_SAR_LIMITS_H +#define __WLAN_HDD_SAR_LIMITS_H + +/** + * DOC: wlan_hdd_sar_limits_h + * + * WLAN Host Device Driver SAR limits API specification + */ + +#ifdef FEATURE_SAR_LIMITS +/** + * wlan_hdd_cfg80211_get_sar_power_limits() - Get SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_get_sar_power_limits() + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_SAR_LIMITS_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_sar_power_limits \ +}, +#else /* FEATURE_SAR_LIMITS */ +#define FEATURE_SAR_LIMITS_VENDOR_COMMANDS +#endif /* FEATURE_SAR_LIMITS */ + +#endif /* __WLAN_HDD_SAR_LIMITS_H */ + diff --git a/core/hdd/src/wlan_hdd_station_info.c b/core/hdd/src/wlan_hdd_station_info.c new file mode 100644 index 000000000000..35af7f3e2d00 --- /dev/null +++ b/core/hdd/src/wlan_hdd_station_info.c @@ -0,0 +1,1222 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_station_info.c + * + * WLAN station info functions + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_get_station_cmd() + */ +#define STATION_INVALID \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INVALID +#define STATION_INFO \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO +#define STATION_ASSOC_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_ASSOC_FAIL_REASON +#define STATION_REMOTE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_REMOTE +#define STATION_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + +/* define short names for get station info attributes */ +#define LINK_INFO_STANDARD_NL80211_ATTR \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_LINK_STANDARD_NL80211_ATTR +#define AP_INFO_STANDARD_NL80211_ATTR \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_STANDARD_NL80211_ATTR +#define INFO_ROAM_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT +#define INFO_AKM \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM +#define WLAN802_11_MODE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE +#define AP_INFO_HS20_INDICATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION +#define HT_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HT_OPERATION +#define VHT_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_VHT_OPERATION +#define INFO_ASSOC_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_FAIL_REASON +#define REMOTE_MAX_PHY_RATE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_MAX_PHY_RATE +#define REMOTE_TX_PACKETS \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_PACKETS +#define REMOTE_TX_BYTES \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_BYTES +#define REMOTE_RX_PACKETS \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_PACKETS +#define REMOTE_RX_BYTES \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_BYTES +#define REMOTE_LAST_TX_RATE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_LAST_TX_RATE +#define REMOTE_LAST_RX_RATE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_LAST_RX_RATE +#define REMOTE_WMM \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_WMM +#define REMOTE_SUPPORTED_MODE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_SUPPORTED_MODE +#define REMOTE_AMPDU \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_AMPDU +#define REMOTE_TX_STBC \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_STBC +#define REMOTE_RX_STBC \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_STBC +#define REMOTE_CH_WIDTH\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_CH_WIDTH +#define REMOTE_SGI_ENABLE\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_SGI_ENABLE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) + #define REMOTE_PAD\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_PAD +#endif + +static const struct nla_policy +hdd_get_station_policy[STATION_MAX + 1] = { + [STATION_INFO] = {.type = NLA_FLAG}, + [STATION_ASSOC_FAIL_REASON] = {.type = NLA_FLAG}, + [STATION_REMOTE] = {.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE}, +}; + +#ifdef QCA_SUPPORT_CP_STATS +static int hdd_get_sta_congestion(struct hdd_adapter *adapter, + uint32_t *congestion) +{ + QDF_STATUS status; + struct cca_stats cca_stats; + + status = ucfg_mc_cp_stats_cca_stats_get(adapter->hdd_vdev, &cca_stats); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + *congestion = cca_stats.congestion; + return 0; +} +#else +static int hdd_get_sta_congestion(struct hdd_adapter *adapter, + uint32_t *congestion) +{ + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + *congestion = hdd_sta_ctx->conn_info.cca; + return 0; +} +#endif + +/** + * hdd_get_station_assoc_fail() - Handle get station assoc fail + * @hdd_ctx: HDD context within host driver + * @wdev: wireless device + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION_ASSOC_FAIL. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int hdd_get_station_assoc_fail(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len; + struct hdd_station_ctx *hdd_sta_ctx; + uint32_t congestion; + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += sizeof(uint32_t); + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (nla_put_u32(skb, INFO_ASSOC_FAIL_REASON, + hdd_sta_ctx->conn_info.assoc_status_code)) { + hdd_err("put fail"); + goto fail; + } + + if (hdd_get_sta_congestion(adapter, &congestion)) + congestion = 0; + + hdd_info("congestion:%d", congestion); + if (nla_put_u32(skb, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + congestion)) { + hdd_err("put fail"); + goto fail; + } + + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +/** + * hdd_map_auth_type() - transform auth type specific to + * vendor command + * @auth_type: csr auth type + * + * Return: Success(0) or reason code for failure + */ +static int hdd_convert_auth_type(uint32_t auth_type) +{ + uint32_t ret_val; + + switch (auth_type) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + ret_val = QCA_WLAN_AUTH_TYPE_OPEN; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + ret_val = QCA_WLAN_AUTH_TYPE_SHARED; + break; + case eCSR_AUTH_TYPE_WPA: + ret_val = QCA_WLAN_AUTH_TYPE_WPA; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_WPA_PSK; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + ret_val = QCA_WLAN_AUTH_TYPE_AUTOSWITCH; + break; + case eCSR_AUTH_TYPE_WPA_NONE: + ret_val = QCA_WLAN_AUTH_TYPE_WPA_NONE; + break; + case eCSR_AUTH_TYPE_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_RSN; + break; + case eCSR_AUTH_TYPE_RSN_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_RSN_PSK; + break; + case eCSR_AUTH_TYPE_FT_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_FT; + break; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_FT_PSK; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + ret_val = QCA_WLAN_AUTH_TYPE_WAI; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_WAI_PSK; + break; + case eCSR_AUTH_TYPE_CCKM_WPA: + ret_val = QCA_WLAN_AUTH_TYPE_CCKM_WPA; + break; + case eCSR_AUTH_TYPE_CCKM_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_CCKM_RSN; + break; + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_SHA256_PSK; + break; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_SHA256; + break; + case eCSR_NUM_OF_SUPPORT_AUTH_TYPE: + case eCSR_AUTH_TYPE_FAILED: + case eCSR_AUTH_TYPE_NONE: + default: + ret_val = QCA_WLAN_AUTH_TYPE_INVALID; + break; + } + return ret_val; +} + +/** + * hdd_map_dot_11_mode() - transform dot11mode type specific to + * vendor command + * @dot11mode: dot11mode + * + * Return: Success(0) or reason code for failure + */ +static int hdd_convert_dot11mode(uint32_t dot11mode) +{ + uint32_t ret_val; + + switch (dot11mode) { + case eCSR_CFG_DOT11_MODE_11A: + ret_val = QCA_WLAN_802_11_MODE_11A; + break; + case eCSR_CFG_DOT11_MODE_11B: + ret_val = QCA_WLAN_802_11_MODE_11B; + break; + case eCSR_CFG_DOT11_MODE_11G: + ret_val = QCA_WLAN_802_11_MODE_11G; + break; + case eCSR_CFG_DOT11_MODE_11N: + ret_val = QCA_WLAN_802_11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AC: + ret_val = QCA_WLAN_802_11_MODE_11AC; + break; + case eCSR_CFG_DOT11_MODE_AUTO: + case eCSR_CFG_DOT11_MODE_ABG: + default: + ret_val = QCA_WLAN_802_11_MODE_INVALID; + } + return ret_val; +} + +/** + * hdd_add_tx_bitrate() - add tx bitrate attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_tx_bitrate(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, + int idx) +{ + struct nlattr *nla_attr; + uint32_t bitrate, bitrate_compat; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) { + hdd_err("nla_nest_start failed"); + goto fail; + } + + /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ + bitrate = cfg80211_calculate_bitrate(&hdd_sta_ctx-> + cache_conn_info.txrate); + + /* report 16-bit bitrate only if we can */ + bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; + + if (bitrate > 0) { + if (nla_put_u32(skb, NL80211_RATE_INFO_BITRATE32, bitrate)) { + hdd_err("put fail bitrate: %u", bitrate); + goto fail; + } + } else { + hdd_err("Invalid bitrate: %u", bitrate); + } + + if (bitrate_compat > 0) { + if (nla_put_u16(skb, NL80211_RATE_INFO_BITRATE, + bitrate_compat)) { + hdd_err("put fail bitrate_compat: %u", bitrate_compat); + goto fail; + } + } else { + hdd_err("Invalid bitrate_compat: %u", bitrate_compat); + } + + if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS, + hdd_sta_ctx->cache_conn_info.txrate.nss)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_sta_info() - add station info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_sta_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) { + hdd_err("nla_nest_start failed"); + goto fail; + } + + if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, + (hdd_sta_ctx->cache_conn_info.signal + 100))) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_tx_bitrate(skb, hdd_sta_ctx, NL80211_STA_INFO_TX_BITRATE)) { + hdd_err("hdd_add_tx_bitrate failed"); + goto fail; + } + + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_survey_info() - add survey info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_survey_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY, + hdd_sta_ctx->cache_conn_info.freq) || + nla_put_u8(skb, NL80211_SURVEY_INFO_NOISE, + (hdd_sta_ctx->cache_conn_info.noise + 100))) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_link_standard_info() - add link info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_add_link_standard_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) { + hdd_err("nla_nest_start failed"); + goto fail; + } + + if (nla_put(skb, + NL80211_ATTR_SSID, + hdd_sta_ctx->cache_conn_info.last_ssid.SSID.length, + hdd_sta_ctx->cache_conn_info.last_ssid.SSID.ssId)) { + hdd_err("put fail"); + goto fail; + } + if (nla_put(skb, NL80211_ATTR_MAC, QDF_MAC_ADDR_SIZE, + hdd_sta_ctx->cache_conn_info.bssId.bytes)) { + hdd_err("put bssid failed"); + goto fail; + } + if (hdd_add_survey_info(skb, hdd_sta_ctx, NL80211_ATTR_SURVEY_INFO)) { + hdd_err("hdd_add_survey_info failed"); + goto fail; + } + + if (hdd_add_sta_info(skb, hdd_sta_ctx, NL80211_ATTR_STA_INFO)) { + hdd_err("hdd_add_sta_info failed"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_ap_standard_info() - add ap info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_add_ap_standard_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present) + if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, + sizeof(hdd_sta_ctx->cache_conn_info.vht_caps), + &hdd_sta_ctx->cache_conn_info.vht_caps)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present) + if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, + sizeof(hdd_sta_ctx->cache_conn_info.ht_caps), + &hdd_sta_ctx->cache_conn_info.ht_caps)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_get_station_info() - send BSS information to supplicant + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * + * Return: 0 if success else error status + */ +static int hdd_get_station_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct sk_buff *skb = NULL; + uint8_t *tmp_hs20 = NULL; + uint32_t nl_buf_len; + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += sizeof(hdd_sta_ctx-> + cache_conn_info.last_ssid.SSID.length) + + QDF_MAC_ADDR_SIZE + + sizeof(hdd_sta_ctx->cache_conn_info.freq) + + sizeof(hdd_sta_ctx->cache_conn_info.noise) + + sizeof(hdd_sta_ctx->cache_conn_info.signal) + + (sizeof(uint32_t) * 2) + + sizeof(hdd_sta_ctx->cache_conn_info.txrate.nss) + + sizeof(hdd_sta_ctx->cache_conn_info.roam_count) + + sizeof(hdd_sta_ctx->cache_conn_info.last_auth_type) + + sizeof(hdd_sta_ctx->cache_conn_info.dot11Mode); + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present) + nl_buf_len += sizeof(hdd_sta_ctx->cache_conn_info.vht_caps); + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present) + nl_buf_len += sizeof(hdd_sta_ctx->cache_conn_info.ht_caps); + if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) { + tmp_hs20 = (uint8_t *)&(hdd_sta_ctx-> + cache_conn_info.hs20vendor_ie); + nl_buf_len += (sizeof(hdd_sta_ctx-> + cache_conn_info.hs20vendor_ie) - 1); + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) + nl_buf_len += sizeof(hdd_sta_ctx-> + cache_conn_info.ht_operation); + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) + nl_buf_len += sizeof(hdd_sta_ctx-> + cache_conn_info.vht_operation); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (hdd_add_link_standard_info(skb, hdd_sta_ctx, + LINK_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_ap_standard_info(skb, hdd_sta_ctx, + AP_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("put fail"); + goto fail; + } + if (nla_put_u32(skb, INFO_ROAM_COUNT, + hdd_sta_ctx->cache_conn_info.roam_count) || + nla_put_u32(skb, INFO_AKM, + hdd_convert_auth_type( + hdd_sta_ctx->cache_conn_info.last_auth_type)) || + nla_put_u32(skb, WLAN802_11_MODE, + hdd_convert_dot11mode( + hdd_sta_ctx->cache_conn_info.dot11Mode))) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) + if (nla_put(skb, HT_OPERATION, + (sizeof(hdd_sta_ctx->cache_conn_info.ht_operation)), + &hdd_sta_ctx->cache_conn_info.ht_operation)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) + if (nla_put(skb, VHT_OPERATION, + (sizeof(hdd_sta_ctx-> + cache_conn_info.vht_operation)), + &hdd_sta_ctx->cache_conn_info.vht_operation)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) + if (nla_put(skb, AP_INFO_HS20_INDICATION, + (sizeof(hdd_sta_ctx->cache_conn_info.hs20vendor_ie) + - 1), + tmp_hs20 + 1)) { + hdd_err("put fail"); + goto fail; + } + + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +static inline int32_t remote_station_put_u64(struct sk_buff *skb, + int32_t attrtype, + uint64_t value) +{ + return nla_put_u64_64bit(skb, attrtype, value, REMOTE_PAD); +} +#else +static inline int32_t remote_station_put_u64(struct sk_buff *skb, + int32_t attrtype, + uint64_t value) +{ + return nla_put_u64(skb, attrtype, value); +} +#endif + +/** + * hdd_add_survey_info_sap_get_len - get data length used in + * hdd_add_survey_info_sap() + * + * This function calculates the data length used in hdd_add_survey_info_sap() + * + * Return: total data length used in hdd_add_survey_info_sap() + */ +static uint32_t hdd_add_survey_info_sap_get_len(void) +{ + return ((NLA_HDRLEN) + (sizeof(uint32_t) + NLA_HDRLEN)); +} + +/** + * hdd_add_survey_info - add survey info attribute + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds survey info attribute to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int32_t hdd_add_survey_info_sap(struct sk_buff *skb, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY, + stainfo->freq)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_tx_bitrate_sap_get_len - get data length used in + * hdd_add_tx_bitrate_sap() + * + * This function calculates the data length used in hdd_add_tx_bitrate_sap() + * + * Return: total data length used in hdd_add_tx_bitrate_sap() + */ +static uint32_t hdd_add_tx_bitrate_sap_get_len(void) +{ + return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN)); +} + +/** + * hdd_add_tx_bitrate_sap - add vhs nss info attribute + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds vht nss attribute to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int hdd_add_tx_bitrate_sap(struct sk_buff *skb, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS, + stainfo->nss)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_sta_info_sap_get_len - get data length used in + * hdd_add_sta_info_sap() + * + * This function calculates the data length used in hdd_add_sta_info_sap() + * + * Return: total data length used in hdd_add_sta_info_sap() + */ +static uint32_t hdd_add_sta_info_sap_get_len(void) +{ + return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN) + + hdd_add_tx_bitrate_sap_get_len()); +} + +/** + * hdd_add_sta_info_sap - add sta signal info attribute + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds sta signal attribute to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int32_t hdd_add_sta_info_sap(struct sk_buff *skb, int8_t rssi, + struct hdd_station_info *stainfo, int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, rssi)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_tx_bitrate_sap(skb, stainfo, NL80211_STA_INFO_TX_BITRATE)) + goto fail; + + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_link_standard_info_sap_get_len - get data length used in + * hdd_add_link_standard_info_sap() + * + * This function calculates the data length used in + * hdd_add_link_standard_info_sap() + * + * Return: total data length used in hdd_add_link_standard_info_sap() + */ +static uint32_t hdd_add_link_standard_info_sap_get_len(void) +{ + return ((NLA_HDRLEN) + + hdd_add_survey_info_sap_get_len() + + hdd_add_sta_info_sap_get_len() + + (sizeof(uint32_t) + NLA_HDRLEN)); +} + +/** + * hdd_add_link_standard_info_sap - add add link info attribut + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds link info attribut to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int hdd_add_link_standard_info_sap(struct sk_buff *skb, int8_t rssi, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (hdd_add_survey_info_sap(skb, stainfo, NL80211_ATTR_SURVEY_INFO)) + goto fail; + if (hdd_add_sta_info_sap(skb, rssi, stainfo, NL80211_ATTR_STA_INFO)) + goto fail; + + if (nla_put_u32(skb, NL80211_ATTR_REASON_CODE, stainfo->reason_code)) { + hdd_err("Reason code put fail"); + goto fail; + } + + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_ap_standard_info_sap_get_len - get data length used in + * hdd_add_ap_standard_info_sap() + * @stainfo: station information + * + * This function calculates the data length used in + * hdd_add_ap_standard_info_sap() + * + * Return: total data length used in hdd_add_ap_standard_info_sap() + */ +static uint32_t hdd_add_ap_standard_info_sap_get_len( + struct hdd_station_info *stainfo) +{ + uint32_t len; + + len = NLA_HDRLEN; + if (stainfo->vht_present) + len += (sizeof(stainfo->vht_caps) + NLA_HDRLEN); + if (stainfo->ht_present) + len += (sizeof(stainfo->ht_caps) + NLA_HDRLEN); + + return len; +} + +/** + * hdd_add_ap_standard_info_sap - add HT and VHT info attributes + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds HT and VHT info attributes to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int hdd_add_ap_standard_info_sap(struct sk_buff *skb, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + if (stainfo->vht_present) { + if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, + sizeof(stainfo->vht_caps), + &stainfo->vht_caps)) { + hdd_err("put fail"); + goto fail; + } + } + if (stainfo->ht_present) { + if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, + sizeof(stainfo->ht_caps), + &stainfo->ht_caps)) { + hdd_err("put fail"); + goto fail; + } + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_decode_ch_width - decode channel band width based + * @ch_width: encoded enum value holding channel band width + * + * This function decodes channel band width from the given encoded enum value. + * + * Returns: decoded channel band width. + */ +static uint8_t hdd_decode_ch_width(tSirMacHTChannelWidth ch_width) +{ + switch (ch_width) { + case 0: + return 20; + case 1: + return 40; + case 2: + return 80; + case 3: + case 4: + return 160; + default: + hdd_debug("invalid enum: %d", ch_width); + return 20; + } +} + +/** + * hdd_get_cached_station_remote() - get cached(deleted) peer's info + * @hdd_ctx: hdd context + * @adapter: hostapd interface + * @mac_addr: mac address of requested peer + * + * This function collect and indicate the cached(deleted) peer's info + * + * Return: 0 on success, otherwise error value + */ + +static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + struct hdd_station_info *stainfo = hdd_get_stainfo( + adapter->cache_sta_info, + mac_addr); + struct sk_buff *skb = NULL; + uint32_t nl_buf_len = NLMSG_HDRLEN; + uint8_t channel_width; + + if (!stainfo) { + hdd_err("peer " MAC_ADDRESS_STR " not found", + MAC_ADDR_ARRAY(mac_addr.bytes)); + return -EINVAL; + } + + nl_buf_len += hdd_add_link_standard_info_sap_get_len() + + hdd_add_ap_standard_info_sap_get_len(stainfo) + + (sizeof(stainfo->dot11_mode) + NLA_HDRLEN) + + (sizeof(stainfo->ch_width) + NLA_HDRLEN) + + (sizeof(stainfo->tx_rate) + NLA_HDRLEN) + + (sizeof(stainfo->rx_rate) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (hdd_add_link_standard_info_sap(skb, stainfo->rssi, stainfo, + LINK_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("link standard put fail"); + goto fail; + } + + if (hdd_add_ap_standard_info_sap(skb, stainfo, + AP_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("ap standard put fail"); + goto fail; + } + + /* upper layer expects decoded channel BW */ + channel_width = hdd_decode_ch_width(stainfo->ch_width); + + if (nla_put_u32(skb, REMOTE_SUPPORTED_MODE, + hdd_convert_dot11mode( + stainfo->mode)) || + nla_put_u8(skb, REMOTE_CH_WIDTH, channel_width)) { + hdd_err("remote ch put fail"); + goto fail; + } + if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate)) { + hdd_err("tx rate put fail"); + goto fail; + } + if (nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate)) { + hdd_err("rx rate put fail"); + goto fail; + } + + qdf_mem_zero(stainfo, sizeof(*stainfo)); + + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + + return -EINVAL; +} + +/** + * hdd_get_cached_station_remote() - get connected peer's info + * @hdd_ctx: hdd context + * @adapter: hostapd interface + * @mac_addr: mac address of requested peer + * + * This function collect and indicate the connected peer's info + * + * Return: 0 on success, otherwise error value + */ +static int hdd_get_connected_station_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr, + struct hdd_station_info *stainfo) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len; + struct sir_peer_info_ext peer_info; + bool txrx_rate = true; + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(stainfo->max_phy_rate) + NLA_HDRLEN) + + (sizeof(stainfo->tx_packets) + NLA_HDRLEN) + + (sizeof(stainfo->tx_bytes) + NLA_HDRLEN) + + (sizeof(stainfo->rx_packets) + NLA_HDRLEN) + + (sizeof(stainfo->rx_bytes) + NLA_HDRLEN) + + (sizeof(stainfo->is_qos_enabled) + NLA_HDRLEN) + + (sizeof(stainfo->mode) + NLA_HDRLEN); + + if (!hdd_ctx->config->sap_get_peer_info || + wlan_hdd_get_peer_info(adapter, mac_addr, &peer_info)) { + hdd_err("fail to get tx/rx rate"); + txrx_rate = false; + } else { + stainfo->tx_rate = peer_info.tx_rate; + stainfo->rx_rate = peer_info.rx_rate; + nl_buf_len += (sizeof(stainfo->tx_rate) + NLA_HDRLEN) + + (sizeof(stainfo->rx_rate) + NLA_HDRLEN); + } + + /* below info is only valid for HT/VHT mode */ + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) + nl_buf_len += (sizeof(stainfo->ampdu) + NLA_HDRLEN) + + (sizeof(stainfo->tx_stbc) + NLA_HDRLEN) + + (sizeof(stainfo->rx_stbc) + NLA_HDRLEN) + + (sizeof(stainfo->ch_width) + NLA_HDRLEN) + + (sizeof(stainfo->sgi_enable) + NLA_HDRLEN); + + hdd_info("buflen %d hdrlen %d", nl_buf_len, NLMSG_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + goto fail; + } + + hdd_info("stainfo"); + hdd_info("maxrate %x tx_pkts %x tx_bytes %llx", + stainfo->max_phy_rate, stainfo->tx_packets, + stainfo->tx_bytes); + hdd_info("rx_pkts %x rx_bytes %llx mode %x", + stainfo->rx_packets, stainfo->rx_bytes, + stainfo->mode); + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) { + hdd_info("ampdu %d tx_stbc %d rx_stbc %d", + stainfo->ampdu, stainfo->tx_stbc, + stainfo->rx_stbc); + hdd_info("wmm %d chwidth %d sgi %d", + stainfo->is_qos_enabled, + stainfo->ch_width, + stainfo->sgi_enable); + } + + if (nla_put_u32(skb, REMOTE_MAX_PHY_RATE, stainfo->max_phy_rate) || + nla_put_u32(skb, REMOTE_TX_PACKETS, stainfo->tx_packets) || + remote_station_put_u64(skb, REMOTE_TX_BYTES, stainfo->tx_bytes) || + nla_put_u32(skb, REMOTE_RX_PACKETS, stainfo->rx_packets) || + remote_station_put_u64(skb, REMOTE_RX_BYTES, stainfo->rx_bytes) || + nla_put_u8(skb, REMOTE_WMM, stainfo->is_qos_enabled) || + nla_put_u8(skb, REMOTE_SUPPORTED_MODE, stainfo->mode)) { + hdd_err("put fail"); + goto fail; + } + + if (txrx_rate) { + if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate) || + nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate)) { + hdd_err("put fail"); + goto fail; + } else { + hdd_info("tx_rate %x rx_rate %x", + stainfo->tx_rate, stainfo->rx_rate); + } + } + + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) { + if (nla_put_u8(skb, REMOTE_AMPDU, stainfo->ampdu) || + nla_put_u8(skb, REMOTE_TX_STBC, stainfo->tx_stbc) || + nla_put_u8(skb, REMOTE_RX_STBC, stainfo->rx_stbc) || + nla_put_u8(skb, REMOTE_CH_WIDTH, stainfo->ch_width) || + nla_put_u8(skb, REMOTE_SGI_ENABLE, stainfo->sgi_enable)) { + hdd_err("put fail"); + goto fail; + } + } + + return cfg80211_vendor_cmd_reply(skb); + +fail: + if (skb) + kfree_skb(skb); + + return -EINVAL; +} + +/** + * hdd_get_station_remote() - get remote peer's info + * @hdd_ctx: hdd context + * @adapter: hostapd interface + * @mac_addr: mac address of requested peer + * + * This function collect and indicate the remote peer's info + * + * Return: 0 on success, otherwise error value + */ +static int hdd_get_station_remote(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + struct hdd_station_info *stainfo = hdd_get_stainfo(adapter->sta_info, + mac_addr); + int status = 0; + bool is_associated = false; + + if (!stainfo) { + status = hdd_get_cached_station_remote(hdd_ctx, adapter, + mac_addr); + return status; + } + + is_associated = hdd_is_peer_associated(adapter, &mac_addr); + if (!is_associated) { + status = hdd_get_cached_station_remote(hdd_ctx, adapter, + mac_addr); + return status; + } + + status = hdd_get_connected_station_info(hdd_ctx, adapter, + mac_addr, stainfo); + return status; +} + +/** + * __hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int +__hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + 1]; + int32_t status; + + hdd_enter_dev(dev); + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + status = -EPERM; + goto out; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + goto out; + + status = wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX, + data, data_len, + hdd_get_station_policy); + if (status) { + hdd_err("Invalid ATTR"); + goto out; + } + + /* Parse and fetch Command Type*/ + if (tb[STATION_INFO]) { + status = hdd_get_station_info(hdd_ctx, adapter); + } else if (tb[STATION_ASSOC_FAIL_REASON]) { + status = hdd_get_station_assoc_fail(hdd_ctx, adapter); + } else if (tb[STATION_REMOTE]) { + struct qdf_mac_addr mac_addr; + + if (adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_GO_MODE) { + hdd_err("invalid device_mode:%d", adapter->device_mode); + status = -EINVAL; + goto out; + } + + nla_memcpy(mac_addr.bytes, tb[STATION_REMOTE], + QDF_MAC_ADDR_SIZE); + + hdd_debug("STATION_REMOTE " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac_addr.bytes)); + + status = hdd_get_station_remote(hdd_ctx, adapter, mac_addr); + } else { + hdd_err("get station info cmd type failed"); + status = -EINVAL; + goto out; + } + hdd_exit(); +out: + return status; +} + +int32_t hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_cfg80211_get_station_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_station_info.h b/core/hdd/src/wlan_hdd_station_info.h new file mode 100644 index 000000000000..84e2c8693015 --- /dev/null +++ b/core/hdd/src/wlan_hdd_station_info.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_STATION_INFO_H +#define __WLAN_HDD_STATION_INFO_H + +/** + * DOC: wlan_hdd_station_info_h + * + * WLAN Host Device Driver STATION info API specification + */ + +#ifdef FEATURE_STATION_INFO +/** + * wlan_hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +int32_t hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_STATION_INFO_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_STATION, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = hdd_cfg80211_get_station_cmd \ +}, +#else /* FEATURE_STATION_INFO */ +#define FEATURE_STATION_INFO_VENDOR_COMMANDS +#endif /* FEATURE_STATION_INFO */ + +#endif /* __WLAN_HDD_STATION_INFO_H */ + diff --git a/core/hdd/src/wlan_hdd_tx_power.c b/core/hdd/src/wlan_hdd_tx_power.c new file mode 100644 index 000000000000..5ed261a15939 --- /dev/null +++ b/core/hdd/src/wlan_hdd_tx_power.c @@ -0,0 +1,192 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_tx_power.c + * + * WLAN tx power setting functions + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_TXPOWER_SCALE 4 + +static const struct nla_policy +txpower_scale_policy[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE] = { .type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + int ret; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1]; + uint8_t scale_value; + QDF_STATUS status; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX, + data, data_len, txpower_scale_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]) { + hdd_err("attr tx power scale failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]); + + if (scale_value > MAX_TXPOWER_SCALE) { + hdd_err("Invalid tx power scale level"); + return -EINVAL; + } + + status = wma_set_tx_power_scale(adapter->session_id, scale_value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Set tx power scale failed"); + return -EINVAL; + } + + return 0; +} + +int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy txpower_scale_decr_db_policy +[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB] = { .type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + int ret; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1]; + uint8_t scale_value; + QDF_STATUS status; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX, + data, data_len, + txpower_scale_decr_db_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]) { + hdd_err("attr tx power decrease db value failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]); + + status = wma_set_tx_power_scale_decr_db(adapter->session_id, + scale_value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Set tx power decrease db failed"); + return -EINVAL; + } + + return 0; +} + +int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale_decr_db(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/core/hdd/src/wlan_hdd_tx_power.h b/core/hdd/src/wlan_hdd_tx_power.h new file mode 100644 index 000000000000..3ba2792b2300 --- /dev/null +++ b/core/hdd/src/wlan_hdd_tx_power.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#ifndef __WLAN_HDD_TX_POWER_H +#define __WLAN_HDD_TX_POWER_H + +/** + * DOC: wlan_hdd_tx_power_h + * + * WLAN Host Device Driver TX power setting API specification + */ + +#ifdef FEATURE_TX_POWER +/** + * wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_TX_POWER_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_txpower_scale \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_txpower_scale_decr_db \ +}, +#else /* FEATURE_TX_POWER */ +#define FEATURE_TX_POWER_VENDOR_COMMANDS +#endif /* FEATURE_TX_POWER */ + +#endif /* __WLAN_HDD_TX_POWER_H */ + diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c index 177144172a68..5938221448a0 100644 --- a/core/sap/src/sap_module.c +++ b/core/sap/src/sap_module.c @@ -1525,6 +1525,7 @@ QDF_STATUS wlan_sap_update_next_channel(struct sap_context *sap_ctx, return QDF_STATUS_SUCCESS; } +#ifdef FEATURE_SAP_COND_CHAN_SWITCH QDF_STATUS wlan_sap_set_pre_cac_status(struct sap_context *sap_ctx, bool status, tHalHandle handle) { @@ -1561,6 +1562,7 @@ QDF_STATUS wlan_sap_set_chan_before_pre_cac(struct sap_context *sap_ctx, sap_ctx->chan_before_pre_cac = chan_before_pre_cac; return QDF_STATUS_SUCCESS; } +#endif /* FEATURE_SAP_COND_CHAN_SWITCH */ QDF_STATUS wlan_sap_set_pre_cac_complete_status(struct sap_context *sap_ctx, bool status) diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index d72b73bb156e..19545bfc3171 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -910,12 +910,27 @@ QDF_STATUS sme_ap_disable_intra_bss_fwd(tHalHandle hHal, uint8_t sessionId, QDF_STATUS sme_get_channel_bonding_mode5_g(tHalHandle hHal, uint32_t *mode); QDF_STATUS sme_get_channel_bonding_mode24_g(tHalHandle hHal, uint32_t *mode); -#ifdef WLAN_FEATURE_STATS_EXT +/** + * sme_send_unit_test_cmd() - send unit test command to lower layer + * @session_id: sme session id to be filled while forming the command + * @module_id: module id given by user to be filled in the command + * @arg_count: number of argument count + * @arg: pointer to argument list + * + * This API exposed to HDD layer which takes the argument from user and sends + * down to lower layer for further processing + * + * Return: QDF_STATUS based on overall success + */ +QDF_STATUS sme_send_unit_test_cmd(uint32_t vdev_id, uint32_t module_id, + uint32_t arg_count, uint32_t *arg); + typedef struct sStatsExtRequestReq { uint32_t request_data_len; uint8_t *request_data; } tStatsExtRequestReq, *tpStatsExtRequestReq; +#ifdef WLAN_FEATURE_STATS_EXT /** * sme_stats_ext_register_callback() - Register stats ext callback * @mac_handle: Opaque handle to the MAC context @@ -951,23 +966,19 @@ void sme_stats_ext2_register_callback(tHalHandle hal_handle, QDF_STATUS sme_stats_ext_request(uint8_t session_id, tpStatsExtRequestReq input); +#else +static inline void +sme_stats_ext_register_callback(mac_handle_t mac_handle, + stats_ext_cb callback) +{ +} + +static inline void +sme_stats_ext2_register_callback(tHalHandle hal_handle, + stats_ext2_cb callback) +{ +} #endif /* WLAN_FEATURE_STATS_EXT */ - -/** - * sme_send_unit_test_cmd() - send unit test command to lower layer - * @session_id: sme session id to be filled while forming the command - * @module_id: module id given by user to be filled in the command - * @arg_count: number of argument count - * @arg: pointer to argument list - * - * This API exposed to HDD layer which takes the argument from user and sends - * down to lower layer for further processing - * - * Return: QDF_STATUS based on overall success - */ -QDF_STATUS sme_send_unit_test_cmd(uint32_t vdev_id, uint32_t module_id, - uint32_t arg_count, uint32_t *arg); - QDF_STATUS sme_update_dfs_scan_mode(tHalHandle hHal, uint8_t sessionId, uint8_t allowDFSChannelRoam); @@ -1182,6 +1193,7 @@ QDF_STATUS sme_disable_uapsd_for_ac(uint8_t sta_id, sme_ac_enum_type ac, uint32_t sessionId); +#ifdef FEATURE_RSSI_MONITOR QDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, struct rssi_monitor_req *input); @@ -1196,7 +1208,14 @@ QDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, */ QDF_STATUS sme_set_rssi_threshold_breached_cb(mac_handle_t mac_handle, rssi_threshold_breached_cb cb); - +#else /* FEATURE_RSSI_MONITOR */ +static inline +QDF_STATUS sme_set_rssi_threshold_breached_cb(mac_handle_t mac_handle, + rssi_threshold_breached_cb cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif /** * sme_reset_rssi_threshold_breached_cb() - Reset RSSI threshold breached * callback diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 8d374a177b3b..153e2034f8e7 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -12995,35 +12995,6 @@ QDF_STATUS sme_set_nud_debug_stats_cb(tHalHandle hal, return status; } -QDF_STATUS sme_set_rssi_threshold_breached_cb(mac_handle_t mac_handle, - rssi_threshold_breached_cb cb) -{ - QDF_STATUS status; - tpAniSirGlobal mac; - - mac = MAC_CONTEXT(mac_handle); - if (!mac) { - sme_err("Invalid mac context"); - return QDF_STATUS_E_INVAL; - } - - status = sme_acquire_global_lock(&mac->sme); - if (!QDF_IS_STATUS_SUCCESS(status)) { - sme_err("sme_acquire_global_lock failed!(status=%d)", - status); - return status; - } - - mac->sme.rssi_threshold_breached_cb = cb; - sme_release_global_lock(&mac->sme); - return status; -} - -QDF_STATUS sme_reset_rssi_threshold_breached_cb(mac_handle_t mac_handle) -{ - return sme_set_rssi_threshold_breached_cb(mac_handle, NULL); -} - /** * sme_is_any_session_in_connected_state() - SME wrapper API to * check if any session is in connected state or not. @@ -13066,6 +13037,7 @@ QDF_STATUS sme_set_chip_pwr_save_fail_cb(mac_handle_t mac_handle, return status; } +#ifdef FEATURE_RSSI_MONITOR /** * sme_set_rssi_monitoring() - set rssi monitoring * @hal: global hal handle @@ -13113,6 +13085,36 @@ QDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, return status; } +QDF_STATUS sme_set_rssi_threshold_breached_cb(mac_handle_t mac_handle, + rssi_threshold_breached_cb cb) +{ + QDF_STATUS status; + tpAniSirGlobal mac; + + mac = MAC_CONTEXT(mac_handle); + if (!mac) { + sme_err("Invalid mac context"); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + return status; + } + + mac->sme.rssi_threshold_breached_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} +#endif /* FEATURE_RSSI_MONITOR */ + +QDF_STATUS sme_reset_rssi_threshold_breached_cb(mac_handle_t mac_handle) +{ + return sme_set_rssi_threshold_breached_cb(mac_handle, NULL); +} + /* * sme_pdev_set_pcl() - Send WMI_PDEV_SET_PCL_CMDID to the WMA * @hal: Handle returned by macOpen @@ -15708,6 +15710,16 @@ QDF_STATUS sme_send_limit_off_channel_params(tHalHandle hal, uint8_t vdev_id, return QDF_STATUS_SUCCESS; } +uint32_t sme_unpack_rsn_ie(tHalHandle hal, uint8_t *buf, + uint8_t buf_len, tDot11fIERSN *rsn_ie, + bool append_ie) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + return dot11f_unpack_ie_rsn(mac_ctx, buf, buf_len, rsn_ie, append_ie); +} + +#ifdef FEATURE_BSS_TRANSITION /** * sme_get_status_for_candidate() - Get bss transition status for candidate * @hal: Handle for HAL @@ -15806,15 +15818,6 @@ static bool sme_get_status_for_candidate(tHalHandle hal, return false; } -uint32_t sme_unpack_rsn_ie(tHalHandle hal, uint8_t *buf, - uint8_t buf_len, tDot11fIERSN *rsn_ie, - bool append_ie) -{ - tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); - - return dot11f_unpack_ie_rsn(mac_ctx, buf, buf_len, rsn_ie, append_ie); -} - /** * wlan_hdd_get_bss_transition_status() - get bss transition status all cadidates * @adapter : Pointer to adapter @@ -15896,6 +15899,7 @@ free: return status; } +#endif /* FEATURE_BSS_TRANSITION */ void sme_enable_roaming_on_connected_sta(tHalHandle hal) { diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index a0055b8ee723..0dfa0185de49 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1729,8 +1729,17 @@ QDF_STATUS wma_update_vdev_tbl(tp_wma_handle wma_handle, uint8_t vdev_id, void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle); void wma_log_completion_timeout(void *data); +#ifdef FEATURE_RSSI_MONITOR QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, - struct rssi_monitor_req *req); + struct rssi_monitor_req *req); +#else /* FEATURE_RSSI_MONITOR */ +static inline +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_RSSI_MONITOR */ QDF_STATUS wma_send_pdev_set_pcl_cmd(tp_wma_handle wma_handle, struct wmi_pcl_chan_weights *msg); diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 59124c257a1c..bba583ef4940 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1094,8 +1094,17 @@ QDF_STATUS wma_set_tdls_offchan_mode(WMA_HANDLE wma_handle, void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id); void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id); +#ifdef FEATURE_RSSI_MONITOR int wma_rssi_breached_event_handler(void *handle, u_int8_t *cmd_param_info, u_int32_t len); +#else /* FEATURE_RSSI_MONITOR */ +static inline +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + return 0; +} +#endif /* FEATURE_RSSI_MONITOR */ QDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, struct vdev_ie_info *ie_info); diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c index 35e3abef808e..96e04a87f846 100644 --- a/core/wma/src/wma_power.c +++ b/core/wma/src/wma_power.c @@ -1690,6 +1690,7 @@ QDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id, return ret; } +#ifdef FEATURE_TX_POWER /** * wma_set_tx_power_scale() - set tx power scale * @vdev_id: vdev id @@ -1751,3 +1752,5 @@ QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value) return ret; } +#endif /* FEATURE_TX_POWER */ + diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index f988230c0d48..f4d7ca74edba 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -2853,6 +2853,37 @@ void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts) } #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef FEATURE_RSSI_MONITOR +/** + * wma_set_rssi_monitoring() - set rssi monitoring + * @handle: WMA handle + * @req: rssi monitoring request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the rssi monitoring configs down to the firmware + * + * Return: 0 on success; error number otherwise + */ +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req) +{ + struct rssi_monitor_param params = {0}; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + params.request_id = req->request_id; + params.session_id = req->session_id; + params.min_rssi = req->min_rssi; + params.max_rssi = req->max_rssi; + params.control = req->control; + + return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, + ¶ms); +} + /** * wma_rssi_breached_event_handler() - rssi breached event handler * @handle: wma handle @@ -2890,13 +2921,14 @@ int wma_rssi_breached_event_handler(void *handle, WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes); WMA_LOGD("%s: req_id: %u vdev_id: %d curr_rssi: %d", __func__, - rssi.request_id, rssi.session_id, rssi.curr_rssi); + rssi.request_id, rssi.session_id, rssi.curr_rssi); WMA_LOGI("%s: curr_bssid: %pM", __func__, rssi.curr_bssid.bytes); mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi); WMA_LOGD("%s: Invoke HDD rssi breached callback", __func__); return 0; } +#endif /* FEATURE_RSSI_MONITOR */ #ifdef WLAN_FEATURE_ROAM_OFFLOAD /** @@ -5268,37 +5300,6 @@ int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, return 0; } - -/** - * wma_set_rssi_monitoring() - set rssi monitoring - * @handle: WMA handle - * @req: rssi monitoring request structure - * - * This function reads the incoming @req and fill in the destination - * WMI structure and send down the rssi monitoring configs down to the firmware - * - * Return: 0 on success; error number otherwise - */ -QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, - struct rssi_monitor_req *req) -{ - struct rssi_monitor_param params = {0}; - - if (!wma) { - WMA_LOGE("%s: wma handle is NULL", __func__); - return QDF_STATUS_E_INVAL; - } - - params.request_id = req->request_id; - params.session_id = req->session_id; - params.min_rssi = req->min_rssi; - params.max_rssi = req->max_rssi; - params.control = req->control; - - return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, - ¶ms); -} - #ifdef FEATURE_LFR_SUBNET_DETECTION /** * wma_set_gateway_params() - set gateway parameters