浏览代码

qcacld-3.0: Support extended avoid frequency list updating

Add sub vendor command support for extended avoid frequency
list(QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT). It will
exclude the channels that application doesn't prefer and
update to regulatory component.

Change-Id: I5164a0b2c4769e9749ef0e8140bded3f530087d4
CRs-Fixed: 2974529
Chaoli Zhou 3 年之前
父节点
当前提交
6610d8c5dd
共有 4 个文件被更改,包括 272 次插入0 次删除
  1. 5 0
      Kbuild
  2. 57 0
      core/hdd/inc/wlan_hdd_avoid_freq_ext.h
  3. 207 0
      core/hdd/src/wlan_hdd_avoid_freq_ext.c
  4. 3 0
      core/hdd/src/wlan_hdd_cfg80211.c

+ 5 - 0
Kbuild

@@ -473,6 +473,10 @@ ifeq ($(CONFIG_FEATURE_BUS_BANDWIDTH_MGR),y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_bus_bandwidth.o
 endif
 
+ifeq ($(CONFIG_FEATURE_WLAN_CH_AVOID_EXT),y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_avoid_freq_ext.o
+endif
+
 $(call add-wlan-objs,hdd,$(HDD_OBJS))
 
 ###### OSIF_SYNC ########
@@ -3589,6 +3593,7 @@ 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_WLAN_CH_AVOID_EXT) += -DFEATURE_WLAN_CH_AVOID_EXT
 
 #if converged p2p is enabled
 ifeq ($(CONFIG_CONVERGED_P2P_ENABLE), y)

+ 57 - 0
core/hdd/inc/wlan_hdd_avoid_freq_ext.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, 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_avoid_freq_ext.h
+ *
+ * WLAN Host Device Driver extended avoid frequency interface implementation.
+ */
+
+#if !defined(__WLAN_HDD_AVOID_FREQ_EXT_H)
+#define __WLAN_HDD_AVOID_FREQ_EXT_H
+
+#include <linux/netdevice.h>
+#include <net/netlink.h>
+#include <net/cfg80211.h>
+#include <qca_vendor.h>
+#include "wlan_hdd_main.h"
+
+#ifdef FEATURE_WLAN_CH_AVOID_EXT
+extern const struct nla_policy
+avoid_freq_ext_policy[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1];
+
+#define FEATURE_AVOID_FREQ_EXT_VENDOR_COMMANDS                          \
+{                                                                       \
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,                        \
+	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT,   \
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |                           \
+		WIPHY_VENDOR_CMD_NEED_NETDEV |                          \
+		WIPHY_VENDOR_CMD_NEED_RUNNING,                          \
+	.doit = wlan_hdd_cfg80211_avoid_freq_ext,                       \
+	vendor_command_policy(avoid_freq_ext_policy,                    \
+			      QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX) \
+},
+
+int wlan_hdd_cfg80211_avoid_freq_ext(struct wiphy *wiphy,
+				     struct wireless_dev *wdev,
+				     const void *data, int data_len);
+
+#else
+#define FEATURE_AVOID_FREQ_EXT_VENDOR_COMMANDS
+static inline void wlan_hdd_cfg80211_avoid_freq_ext(void) {}
+#endif
+#endif
+

+ 207 - 0
core/hdd/src/wlan_hdd_avoid_freq_ext.c

@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2021, 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_avoid_freq_ext.c
+ *
+ * WLAN Host Device Driver extended avoid frequency interface implementation.
+ */
+
+/* Include Files */
+
+#include <osif_psoc_sync.h>
+#include "wlan_hdd_avoid_freq_ext.h"
+#include "wlan_reg_ucfg_api.h"
+#include "wlan_reg_services_api.h"
+
+#define AVOID_FREQ_EXT_MAX QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX
+
+const struct nla_policy
+avoid_freq_ext_policy [QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE] = { .type = NLA_NESTED },
+	[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START] = {.type = NLA_U32},
+	[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END] = {.type = NLA_U32},
+};
+
+/**
+ * __wlan_hdd_cfg80211_avoid_freq_ext() - exclude channels from upper layer.
+ * @wiphy: wiphy structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of @data
+ *
+ * __wlan_hdd_cfg80211_avoid_freq_ext() extract the valid avoid frequency
+ * list from upper layer and prepared one extended avoid frequency list for
+ * regulatory component.
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int
+__wlan_hdd_cfg80211_avoid_freq_ext(struct wiphy *wiphy,
+				   struct wireless_dev *wdev,
+		const void *data, int data_len)
+{
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	int ret = 0;
+	struct ch_avoid_ind_type avoid_freq_list;
+	enum QDF_GLOBAL_MODE curr_mode;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1];
+	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1];
+	struct nlattr *freq_ext;
+	int id, rem, i, sub_id;
+	struct ch_avoid_freq_type *avoid_freq_range;
+
+	hdd_enter_dev(wdev->netdev);
+
+	curr_mode = hdd_get_conparam();
+	if (curr_mode == QDF_GLOBAL_FTM_MODE ||
+	    curr_mode == QDF_GLOBAL_MONITOR_MODE) {
+		hdd_debug("Command not allowed in FTM/MONITOR mode");
+		return -EINVAL;
+	}
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	if (hdd_is_connection_in_progress(NULL, NULL)) {
+		hdd_debug("Update chan list refused: conn in progress");
+		ret = -EPERM;
+		goto out;
+	}
+
+	qdf_mem_zero(&avoid_freq_list, sizeof(struct ch_avoid_ind_type));
+
+	if (!data && data_len == 0) {
+		hdd_debug("Clear extended avoid frequency list");
+		goto process_avoid_channel_ext;
+	}
+
+	ret = wlan_cfg80211_nla_parse(tb,
+				      QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX,
+				      data,
+				      data_len,
+				      avoid_freq_ext_policy);
+	if (ret) {
+		hdd_err("Invalid avoid freq ext ATTR");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE;
+
+	if (!tb[id]) {
+		hdd_err("Attr avoid frequency ext range failed");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	i = 0;
+	avoid_freq_list.ch_avoid_range_cnt = CH_AVOID_MAX_RANGE;
+
+	nla_for_each_nested(freq_ext, tb[id], rem) {
+		if (i == CH_AVOID_MAX_RANGE) {
+			hdd_warn("Ignoring excess range number");
+			break;
+		}
+
+		if (wlan_cfg80211_nla_parse(tb2, AVOID_FREQ_EXT_MAX,
+					    nla_data(freq_ext),
+					    nla_len(freq_ext),
+					    avoid_freq_ext_policy)) {
+			hdd_err("nla_parse failed");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		avoid_freq_range = &avoid_freq_list.avoid_freq_range[i];
+
+		/* ext avoid freq start */
+		sub_id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START;
+		if (!tb2[sub_id]) {
+			ret = -EINVAL;
+			goto out;
+		}
+		avoid_freq_range->start_freq = nla_get_u32(tb2[sub_id]);
+
+		/* ext avoid freq end */
+		sub_id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END;
+		if (!tb2[sub_id]) {
+			ret = -EINVAL;
+			goto out;
+		}
+		avoid_freq_range->end_freq = nla_get_u32(tb2[sub_id]);
+
+		if (!wlan_reg_is_same_band_freqs(avoid_freq_range->start_freq,
+						 avoid_freq_range->end_freq)) {
+			hdd_debug("Not in same band");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (avoid_freq_range->end_freq <
+		    avoid_freq_range->start_freq) {
+			ret = -EINVAL;
+			goto out;
+		}
+		hdd_debug("ext avoid freq start: %u end: %u",
+			  avoid_freq_range->start_freq,
+			  avoid_freq_range->end_freq);
+		i++;
+	}
+
+	if (i < CH_AVOID_MAX_RANGE) {
+		hdd_warn("Number of freq range %u less than expected %u",
+			 i, CH_AVOID_MAX_RANGE);
+		avoid_freq_list.ch_avoid_range_cnt = i;
+	}
+
+process_avoid_channel_ext:
+	ucfg_reg_ch_avoid_ext(hdd_ctx->psoc, &avoid_freq_list);
+out:
+	return ret;
+}
+
+/**
+ * wlan_hdd_cfg80211_avoid_freq_ext() - exclude channels from upper layer.
+ * @wiphy: wiphy structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of @data
+ *
+ * wlan_hdd_cfg80211_avoid_freq_ext() will pass the extended avoid frequency
+ * list from upper layer to regulatory component to compute one new channel
+ * list.
+ *
+ * Return: 0 on success; errno on failure
+ */
+int wlan_hdd_cfg80211_avoid_freq_ext(struct wiphy *wiphy,
+				     struct wireless_dev *wdev,
+				     const void *data, int data_len)
+{
+	struct osif_psoc_sync *psoc_sync;
+	int errno;
+
+	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_avoid_freq_ext(wiphy, wdev, data, data_len);
+
+	osif_psoc_sync_op_stop(psoc_sync);
+
+	return errno;
+}

+ 3 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -169,6 +169,8 @@
 #include "wlan_hdd_bootup_marker.h"
 #include "wlan_hdd_cm_api.h"
 #include "wlan_roam_debug.h"
+#include "wlan_hdd_avoid_freq_ext.h"
+
 #define g_mode_rates_size (12)
 #define a_mode_rates_size (8)
 
@@ -16531,6 +16533,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	FEATURE_GPIO_CFG_VENDOR_COMMANDS
 	FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS
 	FEATURE_RADAR_HISTORY_VENDOR_COMMANDS
+	FEATURE_AVOID_FREQ_EXT_VENDOR_COMMANDS
 };
 
 struct hdd_context *hdd_cfg80211_wiphy_alloc(void)