qcacld-3.0: Featurize some vendor commands
Featurize some vendor commands to compile out when not needed.
Change-Id: I6757b5764930efbd9cd1c7ab74e5990e96267421
CRs-Fixed: 2270461
diff --git a/Kbuild b/Kbuild
index ce0e1d0..1f803ef 100644
--- a/Kbuild
+++ b/Kbuild
@@ -166,6 +166,46 @@
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 @@
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 fa1166d..35368f9 100644
--- a/configs/default_defconfig
+++ b/configs/default_defconfig
@@ -573,6 +573,18 @@
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 7868788..6eed4ba 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_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 946cd13..8be54ed 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1632,36 +1632,6 @@
};
/**
- * 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
* @CFG_GRO_ENABLED: Generic Rx Offload
@@ -2932,22 +2902,6 @@
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
*
@@ -3212,19 +3166,6 @@
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 876ff19..9796b28 100644
--- a/core/hdd/inc/wlan_hdd_p2p.h
+++ b/core/hdd/inc/wlan_hdd_p2p.h
@@ -124,30 +124,6 @@
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
* @mas_value: 0-Disable, 1-Enable MAS
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 0000000..7884835
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wlan_hdd_active_tos.h>
+
+/**
+ * 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 0000000..80f39c4
--- /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 0000000..fd4b012
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wlan_hdd_bss_transition.h>
+
+/**
+ * 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 0000000..86ba247
--- /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 82e7538..e3d7bd2 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -107,6 +107,16 @@
#include <wlan_cfg80211_mc_cp_stats.h>
#include <wlan_cp_stats_mc_ucfg_api.h>
#include "wlan_tdls_cfg_api.h"
+#include <wlan_hdd_bss_transition.h>
+#include <wlan_hdd_concurrency_matrix.h>
+#include <wlan_hdd_p2p_listen_offload.h>
+#include <wlan_hdd_rssi_monitor.h>
+#include <wlan_hdd_sap_cond_chan_switch.h>
+#include <wlan_hdd_station_info.h>
+#include <wlan_hdd_tx_power.h>
+#include <wlan_hdd_active_tos.h>
+#include <wlan_hdd_sar_limits.h>
+#include <wlan_hdd_ota_test.h>
#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 @@
.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 @@
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 @@
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 @@
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 @@
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 @@
}
#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 @@
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 @@
[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 @@
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 @@
[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 @@
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;
};
@@ -13734,331 +10865,6 @@
}
/**
- * __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
* @info: mac mode info
@@ -14388,12 +11194,9 @@
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 @@
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 @@
.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 @@
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 @@
.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 @@
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 @@
.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 @@
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 @@
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 bca4157..2eac435 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.h
+++ b/core/hdd/src/wlan_hdd_cfg80211.h
@@ -369,19 +369,6 @@
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 0000000..bb96208
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wlan_hdd_concurrency_matrix.h>
+
+#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 0000000..1bdc6f7
--- /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 6e86046..effbe3a 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 <wlan_hdd_rssi_monitor.h>
#ifdef CNSS_GENL
#include <net/cnss_nl.h>
@@ -300,13 +301,6 @@
[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;
@@ -14130,76 +14124,6 @@
}
/**
- * 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 0000000..ef54c99
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <sme_power_save_api.h>
+#include <wlan_hdd_ota_test.h>
+
+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 0000000..9d950b8
--- /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 2027cc1..580223a 100644
--- a/core/hdd/src/wlan_hdd_p2p.c
+++ b/core/hdd/src/wlan_hdd_p2p.c
@@ -1040,70 +1040,6 @@
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 0000000..fe5e843
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wlan_hdd_p2p.h>
+#include <wlan_p2p_ucfg_api.h>
+#include <wlan_hdd_p2p_listen_offload.h>
+
+/* 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 0000000..f039aca
--- /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 0000000..b78116f
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wlan_hdd_ext_scan.h>
+#include <wlan_hdd_rssi_monitor.h>
+
+/*
+ * 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 0000000..ac621c4
--- /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 0000000..60274d2
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <cds_utils.h>
+#include <qdf_str.h>
+#include <wlan_hdd_sap_cond_chan_switch.h>
+
+/**
+ * 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 0000000..1ea89eb
--- /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 0000000..c500ddc
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wlan_osif_request_manager.h>
+#include <wlan_hdd_sar_limits.h>
+
+#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 0000000..2a49a46
--- /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 0000000..35af7f3
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wlan_cp_stats_mc_ucfg_api.h>
+#include <wlan_hdd_stats.h>
+#include <wlan_hdd_hostapd.h>
+#include <wlan_hdd_station_info.h>
+
+/*
+ * 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 0000000..84e2c86
--- /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 0000000..5ed261a
--- /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 <wlan_hdd_includes.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <wma_api.h>
+#include <wlan_hdd_tx_power.h>
+
+#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 0000000..3ba2792
--- /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 1771441..5938221 100644
--- a/core/sap/src/sap_module.c
+++ b/core/sap/src/sap_module.c
@@ -1525,6 +1525,7 @@
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 @@
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 d72b73b..19545bf 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -910,12 +910,27 @@
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 @@
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 @@
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_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 8d374a1..153e203 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -12995,35 +12995,6 @@
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 @@
return status;
}
+#ifdef FEATURE_RSSI_MONITOR
/**
* sme_set_rssi_monitoring() - set rssi monitoring
* @hal: global hal handle
@@ -13113,6 +13085,36 @@
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 @@
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 @@
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 @@
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 a0055b8..0dfa018 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -1729,8 +1729,17 @@
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 59124c2..bba583e 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1094,8 +1094,17 @@
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 35e3abe..96e04a8 100644
--- a/core/wma/src/wma_power.c
+++ b/core/wma/src/wma_power.c
@@ -1690,6 +1690,7 @@
return ret;
}
+#ifdef FEATURE_TX_POWER
/**
* wma_set_tx_power_scale() - set tx power scale
* @vdev_id: vdev id
@@ -1751,3 +1752,5 @@
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 f988230..f4d7ca7 100644
--- a/core/wma/src/wma_scan_roam.c
+++ b/core/wma/src/wma_scan_roam.c
@@ -2853,6 +2853,37 @@
}
#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 @@
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 @@
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