Browse Source

qcacld-3.0: Implement legacy commands of easy mesh

Provide below APIs for easy mesh.
API to get the current frequency of the given VDEV.
API to get acs status of the given VDEV.
API to get cac status of the given VDEV.
API to get/set bandwidth of the given VDEV.
API to get band information of the given VDEV.
API to get connected STA count of the given VDEV.
API to get BSSID of the given VDEV.
API to get SSID of the given VDEV.
API to set channel of the given VDEV.
API to get/set cac timeout of the given VDEV.
API to get/set country code of the given VDEV.

Change-Id: Ia0bd201ad8155a66a4a8c5517f6fa43f3f358505
CRs-Fixed: 3027192
bings 3 years ago
parent
commit
a44cf88b36

+ 31 - 0
Kbuild

@@ -201,6 +201,10 @@ ifeq ($(CONFIG_IPA_OFFLOAD), y)
 HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_ipa.o
 endif
 
+ifeq ($(CONFIG_QCACLD_FEATURE_SON), y)
+HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_son.o
+endif
+
 ifeq ($(CONFIG_QCACLD_FEATURE_NAN), y)
 HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_nan.o
 HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_nan_datapath.o
@@ -2312,6 +2316,27 @@ $(call add-wlan-objs,nan,$(WLAN_NAN_OBJS))
 
 #######################################################
 
+######################### SON #########################
+#SON_CORE_DIR := components/son/core/src
+#SON_CORE_INC := -I$(WLAN_ROOT)/components/son/core/inc
+SON_UCFG_DIR := components/son/dispatcher/src
+SON_UCFG_INC := -I$(WLAN_ROOT)/components/son/dispatcher/inc
+#SON_TGT_DIR  := components/target_if/son/src
+#SON_TGT_INC  := -I$(WLAN_ROOT)/components/target_if/son/inc
+
+SON_OS_IF_DIR  := os_if/son/src
+SON_OS_IF_INC  := -I$(WLAN_ROOT)/os_if/son/inc
+
+ifeq ($(CONFIG_QCACLD_FEATURE_SON), y)
+WLAN_SON_OBJS := $(SON_UCFG_DIR)/son_ucfg_api.o \
+		 $(SON_UCFG_DIR)/son_api.o \
+		 $(SON_OS_IF_DIR)/os_if_son.o
+endif
+
+$(call add-wlan-objs,son,$(WLAN_SON_OBJS))
+
+#######################################################
+
 ###### COEX ########
 COEX_OS_IF_SRC      := os_if/coex/src
 COEX_TGT_SRC        := components/target_if/coex/src
@@ -2787,6 +2812,11 @@ INCS +=		$(NAN_CORE_INC)
 INCS +=		$(NAN_UCFG_INC)
 INCS +=		$(NAN_TGT_INC)
 INCS +=		$(NAN_OS_IF_INC)
+################ SON ################
+INCS +=		$(SON_CORE_INC)
+INCS +=		$(SON_UCFG_INC)
+INCS +=		$(SON_TGT_INC)
+INCS +=		$(SON_OS_IF_INC)
 ##########################################
 INCS +=		$(UMAC_OBJMGR_INC)
 INCS +=		$(UMAC_MGMT_TXRX_INC)
@@ -3196,6 +3226,7 @@ cppflags-$(CONFIG_WLAN_LOG_EXIT) += -DWLAN_LOG_EXIT
 cppflags-$(WLAN_OPEN_SOURCE) += -DWLAN_OPEN_SOURCE
 cppflags-$(CONFIG_FEATURE_STATS_EXT) += -DWLAN_FEATURE_STATS_EXT
 cppflags-$(CONFIG_QCACLD_FEATURE_NAN) += -DWLAN_FEATURE_NAN
+cppflags-$(CONFIG_QCACLD_FEATURE_SON) += -DWLAN_FEATURE_SON
 cppflags-$(CONFIG_NDP_SAP_CONCURRENCY_ENABLE) += -DNDP_SAP_CONCURRENCY_ENABLE
 
 ifeq ($(CONFIG_DFS_FCC_TYPE4_DURATION_CHECK), y)

+ 7 - 0
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -3377,4 +3377,11 @@ wlan_mlme_get_p2p_p2p_conc_support(struct wlan_objmgr_psoc *psoc)
 	return false;
 }
 #endif
+
+/**
+ * mlme_get_vht_ch_width() - get vht channel width of fw capability
+ *
+ * Return: vht channel width
+ */
+enum phy_ch_width mlme_get_vht_ch_width(void);
 #endif /* _WLAN_MLME_API_H_ */

+ 15 - 0
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -5251,3 +5251,18 @@ wlan_mlme_get_p2p_p2p_conc_support(struct wlan_objmgr_psoc *psoc)
 					    WLAN_SOC_EXT_P2P_P2P_CONC_SUPPORT);
 }
 #endif
+
+enum phy_ch_width mlme_get_vht_ch_width(void)
+{
+	enum phy_ch_width bandwidth = CH_WIDTH_INVALID;
+	uint32_t fw_ch_wd = wma_get_vht_ch_width();
+
+	if (fw_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ)
+		bandwidth = CH_WIDTH_80P80MHZ;
+	else if (fw_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ)
+		bandwidth = CH_WIDTH_160MHZ;
+	else
+		bandwidth = CH_WIDTH_80MHZ;
+
+	return bandwidth;
+}

+ 41 - 0
components/son/dispatcher/inc/son_api.h

@@ -0,0 +1,41 @@
+/*
+ * 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 : contains interface prototypes for son api
+ */
+#ifndef _SON_API_H_
+#define _SON_API_H_
+
+#include <qdf_types.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <reg_services_public_struct.h>
+
+/**
+ * wlan_son_get_chan_flag() - get chan flag
+ * @pdev: pointer to pdev
+ * @freq: qdf_freq_t
+ * @flag_160: If true, 160 channel info will be obtained;
+ *            otherwise 80+80, 80 channel info will be obtained
+ * @chan_params: chan parameters
+ *
+ * Return: combination of enum qca_wlan_vendor_channel_prop_flags and
+ *         enum qca_wlan_vendor_channel_prop_flags_2
+ */
+uint32_t wlan_son_get_chan_flag(struct wlan_objmgr_pdev *pdev,
+				qdf_freq_t freq, bool flag_160,
+				struct ch_params *chan_params);
+#endif

+ 79 - 0
components/son/dispatcher/inc/son_ucfg_api.h

@@ -0,0 +1,79 @@
+/*
+ * 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 : contains interface prototypes for OS_IF layer
+ */
+#ifndef _SON_UCFG_API_H_
+#define _SON_UCFG_API_H_
+
+#include <qdf_trace.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_mlme_ucfg_api.h>
+
+/**
+ * ucfg_son_get_operation_chan_freq_vdev_id() - get operating chan freq of
+ *                                              given vdev id
+ * @pdev: Pointer to pdev
+ * @vdev_id: vdev id
+ *
+ * Return: chan freq of given vdev id
+ */
+qdf_freq_t
+ucfg_son_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev,
+					 uint8_t vdev_id);
+
+/**
+ * ucfg_son_get_min_and_max_power() - get min and max power
+ * @psoc: pointer to psoc
+ * @max_tx_power: max tx power(dBm units) to get.
+ * @min_tx_power: min tx power(dBm units) to get.
+ *
+ * Return: Void
+ */
+void ucfg_son_get_min_and_max_power(struct wlan_objmgr_psoc *psoc,
+				    int8_t *max_tx_power,
+				    int8_t *min_tx_power);
+
+/**
+ * ucfg_son_is_cac_in_progress() - whether cac in progress or not
+ * @vdev: Pointer to vdev
+ *
+ * Return: whether vdev in cac or not
+ */
+bool ucfg_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_son_get_sta_count() - get sta count
+ * @vdev: Pointer to vdev
+ *
+ * Return: sta count
+ */
+uint32_t ucfg_son_get_sta_count(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_son_get_chan_flag() - get chan flag
+ * @pdev: pointer to pdev
+ * @freq: qdf_freq_t
+ * @flag_160: whether 160 band width is enabled or not
+ * @chan_params: chan parameters
+ *
+ * Return: chan flag
+ */
+uint32_t ucfg_son_get_chan_flag(struct wlan_objmgr_pdev *pdev,
+				qdf_freq_t freq, bool flag_160,
+				struct ch_params *chan_params);
+#endif

+ 205 - 0
components/son/dispatcher/src/son_api.c

@@ -0,0 +1,205 @@
+/*
+ * 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 : contains interface prototypes for son api
+ */
+
+#include <son_api.h>
+#include <wlan_reg_services_api.h>
+#include <wlan_mlme_api.h>
+#include <ieee80211_external.h>
+
+/**
+ * wlan_son_is_he_supported() - is he supported or not
+ * @psoc: pointer to psoc
+ * @he_supported: he supported or not
+ *
+ * Return: void
+ */
+#ifdef WLAN_FEATURE_11AX
+static void wlan_son_is_he_supported(struct wlan_objmgr_psoc *psoc,
+				     bool *he_supported)
+{
+	tDot11fIEhe_cap *he_cap = NULL;
+
+	*he_supported = false;
+	mlme_cfg_get_he_caps(psoc, he_cap);
+	if (he_cap && he_cap->present)
+		*he_supported = true;
+}
+#else
+static void wlan_son_is_he_supported(struct wlan_objmgr_psoc *psoc,
+				     bool *he_supported)
+{
+	*he_supported = false;
+}
+#endif /*WLAN_FEATURE_11AX*/
+
+uint32_t wlan_son_get_chan_flag(struct wlan_objmgr_pdev *pdev,
+				qdf_freq_t freq, bool flag_160,
+				struct ch_params *chan_params)
+{
+	uint32_t flags = 0;
+	qdf_freq_t sec_freq;
+	struct ch_params ch_width40_ch_params;
+	uint8_t sub_20_channel_width = 0;
+	enum phy_ch_width bandwidth = mlme_get_vht_ch_width();
+	struct wlan_objmgr_psoc *psoc;
+	bool is_he_enabled;
+
+	if (!pdev) {
+		qdf_err("invalid pdev");
+		return flags;
+	}
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		qdf_err("invalid psoc");
+		return flags;
+	}
+
+	wlan_son_is_he_supported(psoc, &is_he_enabled);
+
+	wlan_mlme_get_sub_20_chan_width(wlan_pdev_get_psoc(pdev),
+					&sub_20_channel_width);
+
+	qdf_mem_zero(chan_params, sizeof(*chan_params));
+	qdf_mem_zero(&ch_width40_ch_params, sizeof(ch_width40_ch_params));
+	if (wlan_reg_is_24ghz_ch_freq(freq)) {
+		if (bandwidth == CH_WIDTH_80P80MHZ ||
+		    bandwidth == CH_WIDTH_160MHZ ||
+		    bandwidth == CH_WIDTH_80MHZ)
+			bandwidth = CH_WIDTH_40MHZ;
+	}
+
+	switch (bandwidth) {
+	case CH_WIDTH_80P80MHZ:
+		if (wlan_reg_get_5g_bonded_channel_state_for_freq(pdev, freq,
+								  bandwidth) !=
+		    CHANNEL_STATE_INVALID) {
+			if (!flag_160) {
+				chan_params->ch_width = CH_WIDTH_80P80MHZ;
+				wlan_reg_set_channel_params_for_freq(
+					pdev, freq, 0, chan_params);
+			}
+			if (is_he_enabled)
+				flags |= VENDOR_CHAN_FLAG2(
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80_80);
+			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80_80;
+		}
+		bandwidth = CH_WIDTH_160MHZ;
+	/* FALLTHROUGH */
+	case CH_WIDTH_160MHZ:
+		if (wlan_reg_get_5g_bonded_channel_state_for_freq(pdev, freq,
+								  bandwidth) !=
+		    CHANNEL_STATE_INVALID) {
+			if (flag_160) {
+				chan_params->ch_width = CH_WIDTH_160MHZ;
+				wlan_reg_set_channel_params_for_freq(
+					pdev, freq, 0, chan_params);
+			}
+			if (is_he_enabled)
+				flags |= VENDOR_CHAN_FLAG2(
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE160);
+			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT160;
+		}
+		bandwidth = CH_WIDTH_80MHZ;
+	/* FALLTHROUGH */
+	case CH_WIDTH_80MHZ:
+		if (wlan_reg_get_5g_bonded_channel_state_for_freq(pdev, freq,
+								  bandwidth) !=
+		    CHANNEL_STATE_INVALID) {
+			if (!flag_160 &&
+			    chan_params->ch_width != CH_WIDTH_80P80MHZ) {
+				chan_params->ch_width = CH_WIDTH_80MHZ;
+				wlan_reg_set_channel_params_for_freq(
+					pdev, freq, 0, chan_params);
+			}
+			if (is_he_enabled)
+				flags |= VENDOR_CHAN_FLAG2(
+					QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80);
+			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80;
+		}
+		bandwidth = CH_WIDTH_40MHZ;
+	/* FALLTHROUGH */
+	case CH_WIDTH_40MHZ:
+		ch_width40_ch_params.ch_width = bandwidth;
+		wlan_reg_set_channel_params_for_freq(pdev, freq, 0,
+						     &ch_width40_ch_params);
+
+		if (ch_width40_ch_params.sec_ch_offset == LOW_PRIMARY_CH)
+			sec_freq = freq + 20;
+		else if (ch_width40_ch_params.sec_ch_offset == HIGH_PRIMARY_CH)
+			sec_freq = freq - 20;
+		else
+			sec_freq = 0;
+
+		if (wlan_reg_get_bonded_channel_state_for_freq(pdev, freq,
+							       bandwidth,
+							       sec_freq) !=
+		    CHANNEL_STATE_INVALID) {
+			if (ch_width40_ch_params.sec_ch_offset ==
+			    LOW_PRIMARY_CH) {
+				if (is_he_enabled)
+				  flags |=
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40PLUS;
+				flags |=
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40PLUS;
+				flags |=
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS;
+			} else if (ch_width40_ch_params.sec_ch_offset ==
+				   HIGH_PRIMARY_CH) {
+				if (is_he_enabled)
+				  flags |=
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40MINUS;
+				flags |=
+				   QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40MINUS;
+				flags |=
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS;
+			}
+		}
+		bandwidth = CH_WIDTH_20MHZ;
+	/* FALLTHROUGH */
+	case CH_WIDTH_20MHZ:
+		flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT20;
+		flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT20;
+		if (is_he_enabled)
+			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE20;
+		bandwidth = CH_WIDTH_10MHZ;
+	/* FALLTHROUGH */
+	case CH_WIDTH_10MHZ:
+		if (wlan_reg_get_bonded_channel_state_for_freq(pdev, freq,
+							       bandwidth,
+							       0) !=
+		     CHANNEL_STATE_INVALID &&
+		     sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_10)
+			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HALF;
+		bandwidth = CH_WIDTH_5MHZ;
+	/* FALLTHROUGH */
+	case CH_WIDTH_5MHZ:
+		if (wlan_reg_get_bonded_channel_state_for_freq(pdev, freq,
+							       bandwidth,
+							       0) !=
+		    CHANNEL_STATE_INVALID &&
+		    sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_5)
+			flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_QUARTER;
+		break;
+	default:
+		qdf_info("invalid channel width value %d", bandwidth);
+	}
+
+	return flags;
+}

+ 72 - 0
components/son/dispatcher/src/son_ucfg_api.c

@@ -0,0 +1,72 @@
+/*
+ * 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 : contains interface prototypes for OS_IF layer
+ */
+
+#include <qdf_trace.h>
+#include <son_ucfg_api.h>
+#include <wlan_mlme_main.h>
+#include <init_deinit_lmac.h>
+#include <son_api.h>
+
+qdf_freq_t
+ucfg_son_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev,
+					 uint8_t vdev_id)
+{
+	return wlan_get_operation_chan_freq_vdev_id(pdev, vdev_id);
+}
+
+void ucfg_son_get_min_and_max_power(struct wlan_objmgr_psoc *psoc,
+				    int8_t *max_tx_power,
+				    int8_t *min_tx_power)
+{
+	struct wlan_psoc_target_capability_info *target_cap =
+					lmac_get_target_cap(psoc);
+
+	*max_tx_power = 0;
+	*min_tx_power = 0;
+
+	if (target_cap) {
+		*max_tx_power = target_cap->hw_max_tx_power;
+		*min_tx_power = target_cap->hw_min_tx_power;
+	}
+}
+
+bool ucfg_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_IS_STATUS_SUCCESS(wlan_vdev_is_dfs_cac_wait(vdev));
+}
+
+uint32_t ucfg_son_get_sta_count(struct wlan_objmgr_vdev *vdev)
+{
+	uint32_t sta_count = wlan_vdev_get_peer_count(vdev);
+
+	/* Don't include self peer in the count */
+	if (sta_count > 0)
+		--sta_count;
+
+	return sta_count;
+}
+
+uint32_t ucfg_son_get_chan_flag(struct wlan_objmgr_pdev *pdev,
+				qdf_freq_t freq, bool flag_160,
+				struct ch_params *chan_params)
+{
+	return wlan_son_get_chan_flag(pdev, freq, flag_160,
+				      chan_params);
+}

+ 7 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -4621,6 +4621,13 @@ int hdd_psoc_idle_shutdown(struct device *dev);
  */
 int hdd_psoc_idle_restart(struct device *dev);
 
+/**
+ * hdd_adapter_is_ap() - whether adapter is ap or not
+ * @adapter: adapter to check
+ * Return: true if it is AP
+ */
+bool hdd_adapter_is_ap(struct hdd_adapter *adapter);
+
 /**
  * hdd_common_roam_callback() - common sme roam callback
  * @psoc: Object Manager Psoc

+ 14 - 6
core/hdd/src/wlan_hdd_main.c

@@ -210,6 +210,7 @@
 #include "wlan_hdd_eht.h"
 #include <linux/bitfield.h>
 #include "wlan_hdd_mlo.h"
+#include <wlan_hdd_son.h>
 
 #ifdef MODULE
 #define WLAN_MODULE_NAME  module_name(THIS_MODULE)
@@ -407,6 +408,17 @@ struct sock *cesium_nl_srv_sock;
 static void wlan_hdd_auto_shutdown_cb(void);
 #endif
 
+bool hdd_adapter_is_ap(struct hdd_adapter *adapter)
+{
+	if (!adapter) {
+		hdd_err("null adapter");
+		return false;
+	}
+
+	return adapter->device_mode == QDF_SAP_MODE ||
+		adapter->device_mode == QDF_P2P_GO_MODE;
+}
+
 QDF_STATUS hdd_common_roam_callback(struct wlan_objmgr_psoc *psoc,
 				     uint8_t session_id,
 				    struct csr_roam_info *roam_info,
@@ -4418,6 +4430,8 @@ int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit)
 		 */
 		hdd_nan_register_callbacks(hdd_ctx);
 
+		hdd_son_register_callbacks(hdd_ctx);
+
 		wlan_hdd_register_btc_chain_mode_handler(hdd_ctx->psoc);
 
 		status = cds_pre_enable();
@@ -15614,12 +15628,6 @@ static inline bool hdd_adapter_is_sta(struct hdd_adapter *adapter)
 		adapter->device_mode == QDF_P2P_CLIENT_MODE;
 }
 
-static inline bool hdd_adapter_is_ap(struct hdd_adapter *adapter)
-{
-	return adapter->device_mode == QDF_SAP_MODE ||
-		adapter->device_mode == QDF_P2P_GO_MODE;
-}
-
 bool hdd_is_any_adapter_connected(struct hdd_context *hdd_ctx)
 {
 	struct hdd_adapter *adapter, *next_adapter = NULL;

+ 405 - 0
core/hdd/src/wlan_hdd_son.c

@@ -0,0 +1,405 @@
+/*
+ * 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 : contains son hdd API implementation
+ */
+
+#include <qdf_types.h>
+#include <wlan_hdd_main.h>
+#include <wlan_hdd_sta_info.h>
+#include <wlan_hdd_regulatory.h>
+#include <os_if_son.h>
+#include <sap_internal.h>
+#include <wma_api.h>
+#include <wlan_hdd_hostapd.h>
+#include <wlan_reg_services_api.h>
+#include <son_ucfg_api.h>
+#include <wlan_hdd_son.h>
+
+/**
+ * hdd_son_is_acs_in_progress() - whether acs is in progress or not
+ * @vdev: vdev
+ *
+ * Return: true if acs is in progress
+ */
+static uint32_t hdd_son_is_acs_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	struct hdd_adapter *adapter;
+	bool in_progress = false;
+
+	if (!vdev) {
+		hdd_err("null vdev");
+		return in_progress;
+	}
+	adapter = wlan_hdd_get_adapter_from_objmgr(vdev);
+	if (!adapter) {
+		hdd_err("null adapter");
+		return in_progress;
+	}
+
+	if (!hdd_adapter_is_ap(adapter)) {
+		hdd_err("vdev id %d is not AP", adapter->vdev_id);
+		return in_progress;
+	}
+
+	in_progress = qdf_atomic_read(&adapter->session.ap.acs_in_progress);
+
+	return in_progress;
+}
+
+/**
+ * hdd_son_bandwidth_to_phymode() - get new eCsrPhyMode according
+ *                                  to son band width
+ * @son_bandwidth: son band width
+ * @old_phymode: old eCsrPhyMode
+ * @phymode: new eCsrPhyMode to get
+ *
+ * Return: void
+ */
+static void hdd_son_bandwidth_to_phymode(uint32_t son_bandwidth,
+					 eCsrPhyMode old_phymode,
+					 eCsrPhyMode *phymode)
+{
+	*phymode = old_phymode;
+
+	switch (son_bandwidth) {
+	case HT20:
+	case HT40:
+		*phymode = eCSR_DOT11_MODE_11n;
+		break;
+	case VHT20:
+	case VHT40:
+	case VHT80:
+	case VHT160:
+	case VHT80_80:
+		*phymode = eCSR_DOT11_MODE_11ac;
+		break;
+	case HE20:
+	case HE40:
+	case HE80:
+	case HE160:
+	case HE80_80:
+		*phymode = eCSR_DOT11_MODE_11ax;
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * hdd_son_bandwidth_to_bonding_mode() - son band with to bonding mode
+ * @son_bandwidth: son band width
+ * @bonding_mode: bonding mode to get
+ *
+ * Return: void
+ */
+static void hdd_son_bandwidth_to_bonding_mode(uint32_t son_bandwidth,
+					      uint32_t *bonding_mode)
+{
+	switch (son_bandwidth) {
+	case HT40:
+	case VHT40:
+	case VHT80:
+	case VHT160:
+	case VHT80_80:
+	case HE40:
+	case HE80:
+	case HE160:
+	case HE80_80:
+		*bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE;
+		break;
+	default:
+		*bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
+	}
+}
+
+/**
+ * hdd_son_set_bandwidth() - set band width
+ * @vdev: vdev
+ * @son_bandwidth: son band width
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int hdd_son_set_bandwidth(struct wlan_objmgr_vdev *vdev,
+				 uint32_t son_bandwidth)
+{
+	eCsrPhyMode phymode;
+	eCsrPhyMode old_phymode;
+	uint8_t supported_band;
+	uint32_t bonding_mode;
+	struct hdd_adapter *adapter;
+	struct hdd_context *hdd_ctx;
+
+	if (!vdev) {
+		hdd_err("null vdev");
+		return -EINVAL;
+	}
+	adapter = wlan_hdd_get_adapter_from_objmgr(vdev);
+	if (!adapter) {
+		hdd_err("null adapter");
+		return -EINVAL;
+	}
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (!hdd_ctx) {
+		hdd_err("null hdd ctx");
+		return -EINVAL;
+	}
+	old_phymode = sme_get_phy_mode(hdd_ctx->mac_handle);
+
+	hdd_son_bandwidth_to_phymode(son_bandwidth, old_phymode, &phymode);
+
+	if (wlan_reg_is_6ghz_supported(hdd_ctx->psoc))
+		supported_band = REG_BAND_MASK_ALL;
+	else
+		supported_band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
+
+	hdd_son_bandwidth_to_bonding_mode(son_bandwidth, &bonding_mode);
+
+	return hdd_update_phymode(adapter, phymode, supported_band,
+				  bonding_mode);
+}
+
+/**
+ * hdd_phymode_chwidth_to_son_bandwidth() - get son bandwidth from
+ *                                          phymode and chwidth
+ * @phymode: eCsrPhyMode
+ * @chwidth: eSirMacHTChannelWidth
+ *
+ * Return: son bandwidth
+ */
+static uint32_t hdd_phymode_chwidth_to_son_bandwidth(
+					eCsrPhyMode phymode,
+					enum eSirMacHTChannelWidth chwidth)
+{
+	uint32_t son_bandwidth = NONHT;
+
+	switch (phymode) {
+	case eCSR_DOT11_MODE_abg:
+	case eCSR_DOT11_MODE_11a:
+	case eCSR_DOT11_MODE_11b:
+	case eCSR_DOT11_MODE_11g:
+	case eCSR_DOT11_MODE_11g_ONLY:
+	case eCSR_DOT11_MODE_11b_ONLY:
+		son_bandwidth = NONHT;
+		break;
+	case eCSR_DOT11_MODE_11n:
+	case eCSR_DOT11_MODE_11n_ONLY:
+		son_bandwidth = HT20;
+		if (chwidth == eHT_CHANNEL_WIDTH_40MHZ)
+			son_bandwidth = HT40;
+		break;
+	case eCSR_DOT11_MODE_11ac:
+	case eCSR_DOT11_MODE_11ac_ONLY:
+		son_bandwidth = VHT20;
+		if (chwidth == eHT_CHANNEL_WIDTH_40MHZ)
+			son_bandwidth = VHT40;
+		else if (chwidth == eHT_CHANNEL_WIDTH_80MHZ)
+			son_bandwidth = VHT80;
+		else if (chwidth == eHT_CHANNEL_WIDTH_160MHZ)
+			son_bandwidth = VHT160;
+		else if (chwidth == eHT_CHANNEL_WIDTH_80P80MHZ)
+			son_bandwidth = VHT80_80;
+		break;
+	case eCSR_DOT11_MODE_11ax:
+	case eCSR_DOT11_MODE_11ax_ONLY:
+	case eCSR_DOT11_MODE_AUTO:
+		son_bandwidth = HE20;
+		if (chwidth == eHT_CHANNEL_WIDTH_40MHZ)
+			son_bandwidth = HE40;
+		else if (chwidth == eHT_CHANNEL_WIDTH_80MHZ)
+			son_bandwidth = HE80;
+		else if (chwidth == eHT_CHANNEL_WIDTH_160MHZ)
+			son_bandwidth = HE160;
+		else if (chwidth == eHT_CHANNEL_WIDTH_80P80MHZ)
+			son_bandwidth = HE80_80;
+		break;
+	default:
+		break;
+	}
+
+	return son_bandwidth;
+}
+
+/**
+ * hdd_son_get_bandwidth() - get band width
+ * @vdev: vdev
+ *
+ * Return: band width
+ */
+static uint32_t hdd_son_get_bandwidth(struct wlan_objmgr_vdev *vdev)
+{
+	enum eSirMacHTChannelWidth chwidth;
+	eCsrPhyMode phymode;
+	struct hdd_adapter *adapter;
+	struct hdd_context *hdd_ctx;
+
+	if (!vdev) {
+		hdd_err("null vdev");
+		return NONHT;
+	}
+	adapter = wlan_hdd_get_adapter_from_objmgr(vdev);
+	if (!adapter) {
+		hdd_err("null adapter");
+		return NONHT;
+	}
+
+	chwidth = wma_cli_get_command(adapter->vdev_id, WMI_VDEV_PARAM_CHWIDTH,
+				      VDEV_CMD);
+
+	if (chwidth < 0) {
+		hdd_err("Failed to get chwidth");
+		return NONHT;
+	}
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (!hdd_ctx) {
+		hdd_err("null hdd ctx");
+		return -NONHT;
+	}
+	phymode = sme_get_phy_mode(hdd_ctx->mac_handle);
+
+	return hdd_phymode_chwidth_to_son_bandwidth(phymode, chwidth);
+}
+
+/**
+ * hdd_son_band_to_band() - translate SON band mode to reg_wifi_band
+ * @band: given enum wlan_band_id
+ *
+ * Return: reg_wifi_band
+ */
+static enum reg_wifi_band hdd_son_band_to_band(enum wlan_band_id band)
+{
+	enum reg_wifi_band reg_band = REG_BAND_UNKNOWN;
+
+	switch (band) {
+	case WLAN_BAND_2GHZ:
+		reg_band = REG_BAND_2G;
+		break;
+	case WLAN_BAND_5GHZ:
+		reg_band = REG_BAND_5G;
+		break;
+	case WLAN_BAND_6GHZ:
+		reg_band = REG_BAND_6G;
+		break;
+	default:
+		break;
+	}
+
+	return reg_band;
+}
+
+/**
+ * hdd_son_set_chan() - set chan
+ * @vdev: vdev
+ * @chan: given chan
+ * @son_band: given enum wlan_band_id
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int hdd_son_set_chan(struct wlan_objmgr_vdev *vdev, int chan,
+			    enum wlan_band_id son_band)
+{
+	struct hdd_adapter *adapter;
+	enum reg_wifi_band band = hdd_son_band_to_band(son_band);
+	bool status;
+	qdf_freq_t freq;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev) {
+		hdd_err("null vdev");
+		return -EINVAL;
+	}
+	adapter = wlan_hdd_get_adapter_from_objmgr(vdev);
+	if (!adapter) {
+		hdd_err("null adapter");
+		return -EINVAL;
+	}
+	if (!hdd_adapter_is_ap(adapter)) {
+		hdd_err("vdev id %d is not AP", adapter->vdev_id);
+		return -ENOTSUPP;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		hdd_err("null pdev");
+		return -EINVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		hdd_err("null psoc");
+		return -EINVAL;
+	}
+
+	freq = wlan_reg_chan_band_to_freq(pdev, chan, BIT(band));
+	status = policy_mgr_is_sap_allowed_on_dfs_freq(pdev, adapter->vdev_id,
+						       freq);
+	if (!status) {
+		hdd_err("sap_allowed_on_dfs_freq check fails");
+		return -EINVAL;
+	}
+	wlan_hdd_set_sap_csa_reason(psoc, adapter->vdev_id,
+				    CSA_REASON_USER_INITIATED);
+
+	return hdd_softap_set_channel_change(adapter->dev, freq, CH_WIDTH_MAX,
+					     false);
+}
+
+/**
+ * hdd_son_set_country() - set country code
+ * @vdev: vdev
+ * @country_code:pointer to country code
+ *
+ * Return: 0 if country code is set successfully
+ */
+static int hdd_son_set_country(struct wlan_objmgr_vdev *vdev,
+			       char *country_code)
+{
+	struct hdd_adapter *adapter;
+	struct hdd_context *hdd_ctx;
+
+	if (!vdev) {
+		hdd_err("null vdev");
+		return -EINVAL;
+	}
+	adapter = wlan_hdd_get_adapter_from_objmgr(vdev);
+	if (!adapter) {
+		hdd_err("null adapter");
+		return -EINVAL;
+	}
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (!hdd_ctx) {
+		hdd_err("null hdd ctx");
+		return -EINVAL;
+	}
+
+	return hdd_reg_set_country(hdd_ctx, country_code);
+}
+
+void hdd_son_register_callbacks(struct hdd_context *hdd_ctx)
+{
+	struct son_callbacks cb_obj = {0};
+
+	cb_obj.os_if_is_acs_in_progress = hdd_son_is_acs_in_progress;
+	cb_obj.os_if_set_bandwidth = hdd_son_set_bandwidth;
+	cb_obj.os_if_get_bandwidth = hdd_son_get_bandwidth;
+	cb_obj.os_if_set_chan = hdd_son_set_chan;
+	cb_obj.os_if_set_country_code = hdd_son_set_country;
+
+	os_if_son_register_hdd_callbacks(hdd_ctx->psoc, &cb_obj);
+}

+ 42 - 0
core/hdd/src/wlan_hdd_son.h

@@ -0,0 +1,42 @@
+/*
+ * 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 : contains son hdd API implementation
+ */
+
+#ifndef WLAN_HDD_SON_H
+#define WLAN_HDD_SON_H
+
+#include <qdf_types.h>
+#include <wlan_hdd_main.h>
+
+#ifdef WLAN_FEATURE_SON
+
+/**
+ * hdd_son_register_callbacks() - register hdd callback for son
+ * @hdd_ctx: hdd context
+ *
+ * Return: void
+ */
+void hdd_son_register_callbacks(struct hdd_context *hdd_ctx);
+#else
+
+static inline void hdd_son_register_callbacks(struct hdd_context *hdd_ctx)
+{
+}
+#endif /* WLAN_FEATURE_SON */
+#endif

+ 210 - 0
os_if/son/inc/os_if_son.h

@@ -0,0 +1,210 @@
+
+/*
+ * 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 : os_if_son.h
+ *
+ * WLAN Host Device Driver file for son (Self Organizing Network)
+ * support.
+ *
+ */
+#ifndef _OS_IF_SON_H_
+#define _OS_IF_SON_H_
+
+#include <qdf_types.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_reg_ucfg_api.h>
+#include <ieee80211_external.h>
+
+/**
+ * struct son_callbacks - struct containing callback to non-converged driver
+ * @os_if_is_acs_in_progress: whether acs is in progress or not
+ * @os_if_set_bandwidth: set band width
+ * @os_if_get_bandwidth: get band width
+ * @os_if_set_chan: set chan
+ * @os_if_set_country_code: set country code
+ */
+struct son_callbacks {
+	uint32_t (*os_if_is_acs_in_progress)(struct wlan_objmgr_vdev *vdev);
+	int (*os_if_set_bandwidth)(struct wlan_objmgr_vdev *vdev,
+				   uint32_t son_bandwidth);
+	uint32_t (*os_if_get_bandwidth)(struct wlan_objmgr_vdev *vdev);
+	int (*os_if_set_chan)(struct wlan_objmgr_vdev *vdev, int chan,
+			      enum wlan_band_id son_band);
+	uint32_t (*os_if_get_sta_count)(struct wlan_objmgr_vdev *vdev);
+	int (*os_if_set_country_code)(struct wlan_objmgr_vdev *vdev,
+				      char *country_code);
+};
+
+/**
+ * os_if_son_register_hdd_callbacks() - register son hdd callback
+ * @psoc: psoc
+ * @cb_obj: pointer to callback
+ *
+ * Return: void
+ */
+void os_if_son_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
+				      struct son_callbacks *cb_obj);
+
+/**
+ * os_if_son_get_freq() - get freq
+ * @vdev: vdev
+ *
+ * Return: freq of given vdev
+ */
+qdf_freq_t os_if_son_get_freq(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * os_if_son_is_acs_in_progress() - whether ACS in progress or not
+ * @vdev: vdev
+ *
+ * Return: true if ACS is in progress
+ */
+uint32_t os_if_son_is_acs_in_progress(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * os_if_son_is_cac_in_progress() - whether CAC is in progress or not
+ * @vdev: vdev
+ *
+ * Return: true if CAC is in progress
+ */
+uint32_t os_if_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * os_if_son_set_bandwidth() - set band width
+ * @vdev: vdev
+ * @son_bandwidth: band width
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int os_if_son_set_bandwidth(struct wlan_objmgr_vdev *vdev,
+			    uint32_t son_bandwidth);
+
+/**
+ * os_if_son_get_bandwidth() - get band width
+ * @vdev: vdev
+ *
+ * Return: band width
+ */
+uint32_t os_if_son_get_bandwidth(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * os_if_son_get_band_info() - get band info
+ * @vdev: vdev
+ *
+ * Return: band info
+ */
+uint32_t os_if_son_get_band_info(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * os_if_son_get_chan_list() - get a list of chan information
+ * @vdev: vdev
+ * @ic_chans: chan information array to get
+ * @chan_info: pointer to ieee80211_channel_info to get
+ * @ic_nchans: number of chan information it gets
+ * @flag_160: flag indicating the API to fill the center frequencies of 160MHz.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int os_if_son_get_chan_list(struct wlan_objmgr_vdev *vdev,
+			    struct ieee80211_ath_channel *ic_chans,
+			    struct ieee80211_channel_info *chan_info,
+			    uint8_t *ic_nchans, bool flag_160);
+
+/**
+ * os_if_son_get_sta_count() - get connected STA count
+ * @vdev: vdev
+ *
+ * Return: connected STA count
+ */
+uint32_t os_if_son_get_sta_count(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * os_if_son_get_bssid() - get bssid of given vdev
+ * @vdev: vdev
+ * @bssid: pointer to BSSID
+ *
+ * Return: 0 if BSSID is gotten successfully
+ */
+int os_if_son_get_bssid(struct wlan_objmgr_vdev *vdev,
+			uint8_t bssid[QDF_MAC_ADDR_SIZE]);
+
+/**
+ * os_if_son_get_ssid() - get ssid of given vdev
+ * @vdev: vdev
+ * @ssid: pointer to SSID
+ * @ssid_len: ssid length
+ *
+ * Return: 0 if SSID is gotten successfully
+ */
+int os_if_son_get_ssid(struct wlan_objmgr_vdev *vdev,
+		       char ssid[WLAN_SSID_MAX_LEN + 1],
+		       uint8_t *ssid_len);
+
+/**
+ * os_if_son_set_chan() - set chan
+ * @vdev: vdev
+ * @chan: given chan
+ * @son_band: given band
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int os_if_son_set_chan(struct wlan_objmgr_vdev *vdev,
+		       int chan, enum wlan_band_id son_band);
+
+/**
+ * os_if_son_set_cac_timeout() - set cac timeout
+ * @vdev: vdev
+ * @cac_timeout: cac timeount to set
+ *
+ * Return: 0 if cac time out is set successfully
+ */
+int os_if_son_set_cac_timeout(struct wlan_objmgr_vdev *vdev,
+			      int cac_timeout);
+
+/**
+ * os_if_son_get_cac_timeout() - get cac timeout
+ * @vdev: vdev
+ * @cac_timeout: cac timeout to get
+ *
+ * Return 0 if cac time out is get successfully
+ */
+int os_if_son_get_cac_timeout(struct wlan_objmgr_vdev *vdev,
+			      int *cac_timeout);
+
+/**
+ * os_if_son_set_country_code() - set country code
+ * @vdev: vdev
+ * @country_code: country code to set
+ *
+ * Return: 0 if country code is set successfully
+ */
+int os_if_son_set_country_code(struct wlan_objmgr_vdev *vdev,
+			       char *country_code);
+
+/**
+ * os_if_son_get_country_code() - get country code
+ * @vdev: vdev
+ * @country_code: country code to get
+ *
+ * Return: 0 if country code is get successfully
+ */
+int os_if_son_get_country_code(struct wlan_objmgr_vdev *vdev,
+			       char *country_code);
+#endif

+ 553 - 0
os_if/son/src/os_if_son.c

@@ -0,0 +1,553 @@
+/*
+ * 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 : os_if_son.c
+ *
+ * WLAN Host Device Driver file for son (Self Organizing Network)
+ * support.
+ *
+ */
+
+#include <os_if_son.h>
+#include <qdf_trace.h>
+#include <qdf_module.h>
+#include <wlan_cfg80211.h>
+#include <son_ucfg_api.h>
+#include <wlan_dfs_ucfg_api.h>
+#include <wlan_reg_ucfg_api.h>
+#include <wlan_vdev_mgr_ucfg_api.h>
+#include <wlan_mlme_ucfg_api.h>
+#include <wlan_reg_services_api.h>
+
+static struct son_callbacks g_son_os_if_cb;
+
+void os_if_son_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc,
+				      struct son_callbacks *cb_obj)
+{
+	g_son_os_if_cb = *cb_obj;
+}
+
+qdf_freq_t os_if_son_get_freq(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_pdev *pdev;
+	qdf_freq_t freq;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return 0;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		osif_err("null pdev");
+		return 0;
+	}
+
+	freq = ucfg_son_get_operation_chan_freq_vdev_id(pdev,
+							wlan_vdev_get_id(vdev));
+	osif_debug("vdev %d get freq %d", wlan_vdev_get_id(vdev), freq);
+
+	return freq;
+}
+qdf_export_symbol(os_if_son_get_freq);
+
+uint32_t os_if_son_is_acs_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	uint32_t acs_in_progress;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return 0;
+	}
+
+	acs_in_progress = g_son_os_if_cb.os_if_is_acs_in_progress(vdev);
+	osif_debug("vdev %d acs_in_progress %d",
+		   wlan_vdev_get_id(vdev), acs_in_progress);
+
+	return acs_in_progress;
+}
+qdf_export_symbol(os_if_son_is_acs_in_progress);
+
+uint32_t os_if_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev)
+{
+	uint32_t cac_in_progress;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return 0;
+	}
+
+	cac_in_progress = ucfg_son_is_cac_in_progress(vdev);
+	osif_debug("vdev %d cac_in_progress %d",
+		   wlan_vdev_get_id(vdev), cac_in_progress);
+
+	return cac_in_progress;
+}
+qdf_export_symbol(os_if_son_is_cac_in_progress);
+
+int os_if_son_set_bandwidth(struct wlan_objmgr_vdev *vdev,
+			    uint32_t son_bandwidth)
+{
+	int ret;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+
+	ret = g_son_os_if_cb.os_if_set_bandwidth(vdev, son_bandwidth);
+	osif_debug("vdev %d son_bandwidth %d ret %d",
+		   wlan_vdev_get_id(vdev), son_bandwidth, ret);
+
+	return ret;
+}
+qdf_export_symbol(os_if_son_set_bandwidth);
+
+uint32_t os_if_son_get_bandwidth(struct wlan_objmgr_vdev *vdev)
+{
+	uint32_t bandwidth;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return NONHT;
+	}
+
+	bandwidth = g_son_os_if_cb.os_if_get_bandwidth(vdev);
+	osif_debug("vdev %d son_bandwidth %d",
+		   wlan_vdev_get_id(vdev), bandwidth);
+
+	return bandwidth;
+}
+qdf_export_symbol(os_if_son_get_bandwidth);
+
+static uint32_t os_if_band_bitmap_to_son_band_info(
+					uint32_t reg_wifi_band_bitmap)
+{
+	uint32_t son_band_info = FULL_BAND_RADIO;
+
+	if (!(reg_wifi_band_bitmap & BIT(REG_BAND_5G)) &&
+	    !(reg_wifi_band_bitmap & BIT(REG_BAND_6G)))
+		return NON_5G_RADIO;
+	if (reg_wifi_band_bitmap & BIT(REG_BAND_6G) &&
+	    !(reg_wifi_band_bitmap & BIT(REG_BAND_2G)) &&
+	    !(reg_wifi_band_bitmap & BIT(REG_BAND_5G)))
+		return BAND_6G_RADIO;
+
+	return son_band_info;
+}
+
+uint32_t os_if_son_get_band_info(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_objmgr_pdev *pdev;
+	uint32_t reg_wifi_band_bitmap;
+	uint32_t band_info;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return NO_BAND_INFORMATION_AVAILABLE;
+	}
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		osif_err("null pdev");
+		return NO_BAND_INFORMATION_AVAILABLE;
+	}
+
+	status = ucfg_reg_get_band(pdev, &reg_wifi_band_bitmap);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		osif_err("failed to get band");
+		return NO_BAND_INFORMATION_AVAILABLE;
+	}
+
+	band_info = os_if_band_bitmap_to_son_band_info(reg_wifi_band_bitmap);
+	osif_debug("vdev %d band_info %d",
+		   wlan_vdev_get_id(vdev), band_info);
+
+	return band_info;
+}
+qdf_export_symbol(os_if_son_get_band_info);
+
+#define BW_WITHIN(min, bw, max) ((min) <= (bw) && (bw) <= (max))
+/**
+ * os_if_son_fill_chan_info() - fill chan info
+ * @chan_info: chan info to fill
+ * @chan_num: chan number
+ * @primary_freq: chan frequency
+ * @ch_num_seg1: channel number for segment 1
+ * @ch_num_seg2: channel number for segment 2
+ *
+ * Return: void
+ */
+static void os_if_son_fill_chan_info(struct ieee80211_channel_info *chan_info,
+				     uint8_t chan_num, qdf_freq_t primary_freq,
+				     uint8_t ch_num_seg1, uint8_t ch_num_seg2)
+{
+	chan_info->ieee = chan_num;
+	chan_info->freq = primary_freq;
+	chan_info->vhtop_ch_num_seg1 = ch_num_seg1;
+	chan_info->vhtop_ch_num_seg2 = ch_num_seg2;
+}
+
+/**
+ * os_if_son_update_chan_info() - update chan info
+ * @pdev: pdev
+ * @flag_160: flag indicating the API to fill the center frequencies of 160MHz.
+ * @cur_chan_list: pointer to regulatory_channel
+ * @chan_info: chan info to fill
+ * @half_and_quarter_rate_flags: half and quarter rate flags
+ *
+ * Return: void
+ */
+static void os_if_son_update_chan_info(
+			struct wlan_objmgr_pdev *pdev, bool flag_160,
+			struct regulatory_channel *cur_chan_list,
+			struct ieee80211_channel_info *chan_info,
+			uint64_t half_and_quarter_rate_flags)
+{
+	qdf_freq_t primary_freq = cur_chan_list->center_freq;
+	struct ch_params chan_params = {0};
+
+	if (!chan_info) {
+		osif_err("null chan info");
+		return;
+	}
+	if (cur_chan_list->chan_flags & REGULATORY_CHAN_NO_OFDM)
+		chan_info->flags |=
+			VENDOR_CHAN_FLAG2(QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_B);
+	else
+		chan_info->flags |= ucfg_son_get_chan_flag(pdev, primary_freq,
+							   flag_160,
+							   &chan_params);
+	if (cur_chan_list->chan_flags & REGULATORY_CHAN_RADAR) {
+		chan_info->flags_ext |=
+			QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS;
+		chan_info->flags_ext |=
+			QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_ADHOC;
+		chan_info->flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_PASSIVE;
+	} else if (cur_chan_list->chan_flags & REGULATORY_CHAN_NO_IR) {
+		/* For 2Ghz passive channels. */
+		chan_info->flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_PASSIVE;
+	}
+
+	if (WLAN_REG_IS_6GHZ_PSC_CHAN_FREQ(primary_freq))
+		chan_info->flags_ext |=
+			QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_PSC;
+
+	os_if_son_fill_chan_info(chan_info, cur_chan_list->chan_num,
+				 primary_freq,
+				 chan_params.center_freq_seg0,
+				 chan_params.center_freq_seg1);
+}
+
+int os_if_son_get_chan_list(struct wlan_objmgr_vdev *vdev,
+			    struct ieee80211_ath_channel *chan_list,
+			    struct ieee80211_channel_info *chan_info,
+			    uint8_t *nchans, bool flag_160)
+{
+	struct regulatory_channel *cur_chan_list;
+	int i;
+	uint32_t phybitmap;
+	uint32_t reg_wifi_band_bitmap;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct regulatory_channel *chan;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+
+	if (!chan_info) {
+		osif_err("null chan info");
+		return -EINVAL;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		osif_err("null pdev");
+		return -EINVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		osif_err("null psoc");
+		return -EINVAL;
+	}
+
+	status = ucfg_reg_get_band(pdev, &reg_wifi_band_bitmap);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		osif_err("failed to get band");
+		return -EINVAL;
+	}
+
+	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS *
+			sizeof(struct regulatory_channel));
+	if (!cur_chan_list) {
+		osif_err("cur_chan_list allocation fails");
+		return -EINVAL;
+	}
+
+	if (wlan_reg_get_current_chan_list(
+	    pdev, cur_chan_list) != QDF_STATUS_SUCCESS) {
+		qdf_mem_free(cur_chan_list);
+		osif_err("fail to get current chan list");
+		return -EINVAL;
+	}
+
+	ucfg_reg_get_band(pdev, &phybitmap);
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		uint64_t band_flags;
+		qdf_freq_t primary_freq = cur_chan_list[i].center_freq;
+		uint64_t half_and_quarter_rate_flags = 0;
+
+		chan = &cur_chan_list[i];
+		if ((chan->chan_flags & REGULATORY_CHAN_DISABLED) &&
+		    chan->state == CHANNEL_STATE_DISABLE &&
+		    !chan->nol_chan && !chan->nol_history)
+			continue;
+		if (WLAN_REG_IS_6GHZ_CHAN_FREQ(primary_freq)) {
+			if (!(reg_wifi_band_bitmap & BIT(REG_BAND_6G)))
+				continue;
+			band_flags = VENDOR_CHAN_FLAG2(
+				QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_6GHZ);
+		} else if (WLAN_REG_IS_24GHZ_CH_FREQ(primary_freq)) {
+			if (!(reg_wifi_band_bitmap & BIT(REG_BAND_2G)))
+				continue;
+			band_flags = QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_2GHZ;
+		} else if (WLAN_REG_IS_5GHZ_CH_FREQ(primary_freq)) {
+			if (!(reg_wifi_band_bitmap & BIT(REG_BAND_5G)))
+				continue;
+			band_flags = QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_5GHZ;
+		} else if (WLAN_REG_IS_49GHZ_FREQ(primary_freq)) {
+			if (!(reg_wifi_band_bitmap & BIT(REG_BAND_5G)))
+				continue;
+			band_flags = QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_5GHZ;
+			/**
+			 * If 4.9G Half and Quarter rates are supported
+			 * by the channel, update them as separate entries
+			 * to the list
+			 */
+			if (BW_WITHIN(chan->min_bw, BW_10_MHZ, chan->max_bw)) {
+				os_if_son_fill_chan_info(&chan_info[*nchans],
+							 chan->chan_num,
+							 primary_freq, 0, 0);
+				chan_info[*nchans].flags |=
+					QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HALF;
+				chan_info[*nchans].flags |=
+					VENDOR_CHAN_FLAG2(
+					QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_A);
+				half_and_quarter_rate_flags =
+					chan_info[*nchans].flags;
+				if (++(*nchans) >= IEEE80211_CHAN_MAX)
+					break;
+			}
+			if (BW_WITHIN(chan->min_bw, BW_5_MHZ, chan->max_bw)) {
+				os_if_son_fill_chan_info(&chan_info[*nchans],
+							 chan->chan_num,
+							 primary_freq, 0, 0);
+				chan_info[*nchans].flags |=
+				    QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_QUARTER;
+				chan_info[*nchans].flags |=
+					VENDOR_CHAN_FLAG2(
+					QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_A);
+				half_and_quarter_rate_flags =
+					chan_info[*nchans].flags;
+				if (++(*nchans) >= IEEE80211_CHAN_MAX)
+					break;
+			}
+		} else {
+			continue;
+		}
+
+		os_if_son_update_chan_info(pdev, flag_160, chan,
+					   &chan_info[*nchans],
+					   half_and_quarter_rate_flags);
+
+		if (++(*nchans) >= IEEE80211_CHAN_MAX)
+			break;
+	}
+
+	qdf_mem_free(cur_chan_list);
+	osif_debug("vdev %d channel_info exit", wlan_vdev_get_id(vdev));
+
+	return 0;
+}
+qdf_export_symbol(os_if_son_get_chan_list);
+
+uint32_t os_if_son_get_sta_count(struct wlan_objmgr_vdev *vdev)
+{
+	uint32_t sta_count;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return 0;
+	}
+
+	sta_count = ucfg_son_get_sta_count(vdev);
+	osif_debug("vdev %d sta count %d", wlan_vdev_get_id(vdev), sta_count);
+
+	return sta_count;
+}
+qdf_export_symbol(os_if_son_get_sta_count);
+
+int os_if_son_get_bssid(struct wlan_objmgr_vdev *vdev,
+			uint8_t bssid[QDF_MAC_ADDR_SIZE])
+{
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+
+	ucfg_wlan_vdev_mgr_get_param_bssid(vdev, bssid);
+	osif_debug("vdev %d bssid " QDF_MAC_ADDR_FMT,
+		   wlan_vdev_get_id(vdev), QDF_MAC_ADDR_REF(bssid));
+
+	return 0;
+}
+qdf_export_symbol(os_if_son_get_bssid);
+
+int os_if_son_get_ssid(struct wlan_objmgr_vdev *vdev,
+		       char ssid[WLAN_SSID_MAX_LEN + 1],
+		       uint8_t *ssid_len)
+{
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+
+	ucfg_wlan_vdev_mgr_get_param_ssid(vdev, ssid, ssid_len);
+	osif_debug("vdev %d ssid %s", wlan_vdev_get_id(vdev), ssid);
+
+	return 0;
+}
+qdf_export_symbol(os_if_son_get_ssid);
+
+int os_if_son_set_chan(struct wlan_objmgr_vdev *vdev,
+		       int chan, enum wlan_band_id son_band)
+{
+	int ret;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+
+	ret = g_son_os_if_cb.os_if_set_chan(vdev, chan, son_band);
+	osif_debug("vdev %d chan %d son_band %d", wlan_vdev_get_id(vdev),
+		   chan, son_band);
+
+	return ret;
+}
+qdf_export_symbol(os_if_son_set_chan);
+
+int os_if_son_set_cac_timeout(struct wlan_objmgr_vdev *vdev,
+			      int cac_timeout)
+{
+	struct wlan_objmgr_pdev *pdev;
+	int status;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		osif_err("null pdev");
+		return -EINVAL;
+	}
+
+	if (QDF_IS_STATUS_ERROR(ucfg_dfs_override_cac_timeout(
+		pdev, cac_timeout, &status))) {
+		osif_err("cac timeout override fails");
+		return -EINVAL;
+	}
+	osif_debug("vdev %d cac_timeout %d status %d",
+		   wlan_vdev_get_id(vdev), cac_timeout, status);
+
+	return status;
+}
+qdf_export_symbol(os_if_son_set_cac_timeout);
+
+int os_if_son_get_cac_timeout(struct wlan_objmgr_vdev *vdev,
+			      int *cac_timeout)
+{
+	struct wlan_objmgr_pdev *pdev;
+	int status;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		osif_err("null pdev");
+		return -EINVAL;
+	}
+
+	if (QDF_IS_STATUS_ERROR(ucfg_dfs_get_override_cac_timeout(
+		pdev, cac_timeout, &status))) {
+		osif_err("fails to get cac timeout");
+		return -EINVAL;
+	}
+	osif_debug("vdev %d cac_timeout %d status %d",
+		   wlan_vdev_get_id(vdev), *cac_timeout, status);
+
+	return status;
+}
+qdf_export_symbol(os_if_son_get_cac_timeout);
+
+int os_if_son_set_country_code(struct wlan_objmgr_vdev *vdev,
+			       char *country_code)
+{
+	int ret;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+	ret = g_son_os_if_cb.os_if_set_country_code(vdev, country_code);
+	osif_debug("vdev %d country_code %s ret %d",
+		   wlan_vdev_get_id(vdev), country_code, ret);
+
+	return ret;
+}
+qdf_export_symbol(os_if_son_set_country_code);
+
+int os_if_son_get_country_code(struct wlan_objmgr_vdev *vdev,
+			       char *country_code)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev) {
+		osif_err("null vdev");
+		return -EINVAL;
+	}
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		osif_err("null psoc");
+		return -EINVAL;
+	}
+	status = ucfg_reg_get_current_country(psoc, country_code);
+	osif_debug("vdev %d country_code %s status %d",
+		   wlan_vdev_get_id(vdev), country_code, status);
+
+	return qdf_status_to_os_return(status);
+}
+qdf_export_symbol(os_if_son_get_country_code);