Browse Source

qcacmn: Add API to check Do Not Break Stream eligibility

1) Adds new policy mgr API 'policy_mgr_is_chan_ok_for_dnbs' to check
if a channel is OK for "Do Not Break Stream".
It means that if Do_Not_Switch_Channel is set for AP/GO vdev,
the channel passed should be either the AP/GO channel or a channel
from the other band.
2) Adds a new function policy_mgr_get_mode_specific_conn_info() to get
the mode specific connection count.

Change-Id: I4da6f7d56d01b01761a5f3557b8acbb84226a6fd
CRs-Fixed: 2037302
Ajit Pal Singh 8 years ago
parent
commit
ec973b0aa7

+ 26 - 1
os_if/linux/scan/src/wlan_cfg80211_scan.c

@@ -34,6 +34,7 @@
 #include <wlan_cfg80211_scan.h>
 #include <qdf_mem.h>
 #include <wlan_utility.h>
+#include <wlan_policy_mgr_api.h>
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
 static uint32_t hdd_config_sched_scan_start_delay(
@@ -945,10 +946,35 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev,
 	if (request->n_channels) {
 		char chl[(request->n_channels * 5) + 1];
 		int len = 0;
+		bool ap_or_go_present =
+			policy_mgr_mode_specific_connection_count(
+			     psoc, QDF_SAP_MODE, NULL) ||
+			     policy_mgr_mode_specific_connection_count(
+			     psoc, QDF_P2P_GO_MODE, NULL);
+
 		for (i = 0; i < request->n_channels; i++) {
 			channel = request->channels[i]->hw_value;
 			if (wlan_is_dsrc_channel(wlan_chan_to_freq(channel)))
 				continue;
+
+			if (ap_or_go_present) {
+				bool ok;
+				int ret;
+
+				ret = policy_mgr_is_chan_ok_for_dnbs(psoc,
+								channel,
+								&ok);
+
+				if (QDF_IS_STATUS_ERROR(ret)) {
+					cfg80211_err("DNBS check failed");
+					qdf_mem_free(req);
+					status = -EINVAL;
+					goto end;
+				}
+				if (!ok)
+					continue;
+			}
+
 			len += snprintf(chl + len, 5, "%d ", channel);
 			req->scan_req.chan_list[i] = wlan_chan_to_freq(channel);
 			num_chan++;
@@ -1296,4 +1322,3 @@ void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev,
 		frame_len, rssi, GFP_KERNEL);
 	qdf_mem_free(mgmt);
 }
-

+ 14 - 0
umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -1845,4 +1845,18 @@ void policy_mgr_update_old_hw_mode_index(struct wlan_objmgr_psoc *psoc,
  */
 void policy_mgr_update_new_hw_mode_index(struct wlan_objmgr_psoc *psoc,
 		uint32_t new_hw_mode_index);
+
+/**
+ * policy_mgr_is_chan_ok_for_dnbs() - Function to check if a channel
+ * is OK for "Do Not Break Stream"
+ * @psoc: PSOC object information
+ * @channel: Channel to check.
+ * @ok: Pointer to flag in which status will be stored
+ * This function checks if a channel is OK for
+ * "Do Not Break Stream"
+ * Return: SUCCESS or FAILURE
+ */
+QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc,
+			uint8_t channel, bool *ok);
+
 #endif /* __WLAN_POLICY_MGR_API_H */

+ 82 - 5
umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -39,6 +39,8 @@
 #include "qdf_types.h"
 #include "qdf_trace.h"
 #include "wlan_objmgr_global_obj.h"
+#include "wlan_objmgr_pdev_obj.h"
+#include "wlan_objmgr_vdev_obj.h"
 
 /* invalid channel id. */
 #define INVALID_CHANNEL_ID 0
@@ -1355,9 +1357,11 @@ bool policy_mgr_is_ibss_conn_exist(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
-bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc,
-				  uint8_t *channel, uint8_t *vdev_id)
+bool policy_mgr_get_mode_specific_conn_info(struct wlan_objmgr_psoc *psoc,
+				  uint8_t *channel, uint8_t *vdev_id,
+				  enum policy_mgr_con_mode mode)
 {
+
 	uint32_t count, index = 0;
 	uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
 	bool status = false;
@@ -1374,10 +1378,10 @@ bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc,
 	}
 
 	count = policy_mgr_mode_specific_connection_count(
-				psoc, PM_SAP_MODE, list);
+				psoc, mode, list);
 	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
 	if (count == 0) {
-		policy_mgr_err("No SAP connection");
+		policy_mgr_err("No mode:[%d] connection", mode);
 		status = false;
 	} else if (count == 1) {
 		*channel = pm_conc_connection_list[list[index]].chan;
@@ -1393,7 +1397,8 @@ bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc,
 		*channel = pm_conc_connection_list[list[index]].chan;
 		*vdev_id =
 			pm_conc_connection_list[list[index]].vdev_id;
-		policy_mgr_notice("Multiple SAP connections, picking first one");
+		policy_mgr_notice("Multiple mode:[%d] connections, picking first one",
+				mode);
 		status = true;
 	}
 	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
@@ -1401,6 +1406,15 @@ bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
+bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc,
+				  uint8_t *channel, uint8_t *vdev_id)
+{
+	return policy_mgr_get_mode_specific_conn_info(psoc,
+					  channel,
+					  vdev_id,
+					  PM_SAP_MODE);
+}
+
 bool policy_mgr_max_concurrent_connections_reached(
 		struct wlan_objmgr_psoc *psoc)
 {
@@ -2358,3 +2372,66 @@ bool policy_mgr_is_hw_mode_change_after_vdev_up(struct wlan_objmgr_psoc *psoc)
 
 	return flag;
 }
+
+bool policy_mgr_vdev_mlme_is_dnsc_set(struct wlan_objmgr_vdev *vdev)
+{
+	/* TODO : Check Dont_Switch_Channel status from vdev mlme caps*/
+	return false;
+}
+
+QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc,
+			uint8_t channel, bool *ok)
+{
+	uint8_t operating_channel = 0, vdev_id = 0;
+	struct wlan_objmgr_vdev *vdev;
+
+	if (!channel || !ok) {
+		policy_mgr_err("Invalid parameter");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (policy_mgr_get_mode_specific_conn_info(psoc,
+				  &operating_channel,
+				  &vdev_id,
+				  PM_SAP_MODE))
+		policy_mgr_debug("SAP mode active");
+	else if (policy_mgr_get_mode_specific_conn_info(psoc,
+				  &operating_channel,
+				  &vdev_id,
+				  PM_P2P_GO_MODE))
+		policy_mgr_debug("P2P_GO_MODE mode active");
+	else {
+		*ok = true;
+		return QDF_STATUS_SUCCESS;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						WLAN_POLICY_MGR_ID);
+	if (!vdev) {
+		policy_mgr_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/**
+	 * If channel passed is same as AP/GO operating channel, then
+	 *   return true.
+	 * If channel is different from operating channel but in same band.
+	 *   return false.
+	 * If operating channel in different band.
+	 *   return true.
+	 */
+	/* TODO: To be enhanced for SBS */
+	if (policy_mgr_vdev_mlme_is_dnsc_set(vdev)) {
+		if (operating_channel == channel)
+			*ok = true;
+		else if (WLAN_REG_IS_SAME_BAND_CHANNELS(operating_channel,
+							channel))
+			*ok = false;
+		else
+			*ok = true;
+	} else {
+		*ok = true;
+	}
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+	return QDF_STATUS_SUCCESS;
+}

+ 28 - 0
umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h

@@ -398,4 +398,32 @@ QDF_STATUS policy_mgr_reset_sap_mandatory_channels(
  */
 bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc,
 				uint8_t *channel, uint8_t *vdev_id);
+
+/**
+ * policy_mgr_get_mode_specific_conn_info() - Get active mode specific
+ * channel and vdev id
+ * @psoc: PSOC object information
+ * @channel: Mode specific channel
+ * @vdev_id: Mode specific vdev id
+ * @mode: Connection Mode
+ *
+ * Get active mode specific channel and vdev id
+ *
+ * Return: true for success, else false
+ */
+bool policy_mgr_get_mode_specific_conn_info(struct wlan_objmgr_psoc *psoc,
+				  uint8_t *channel, uint8_t *vdev_id,
+				  enum policy_mgr_con_mode mode);
+
+/**
+ * policy_mgr_vdev_mlme_is_dnsc_set - Check if user has set
+ * "Do_Not_Switch_Channel" for this vdev
+ * @vdev: vdev pointer
+ *
+ * Get "Do_Not_Switch_Channel" setting for this vdev
+ *
+ * Return: true for success, else false
+ */
+bool policy_mgr_vdev_mlme_is_dnsc_set(struct wlan_objmgr_vdev *vdev);
+
 #endif

+ 42 - 0
umac/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -166,6 +166,41 @@ static QDF_STATUS policy_mgr_modify_pcl_based_on_enabled_channels(
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS policy_mgr_modify_pcl_based_on_dnbs(
+						struct wlan_objmgr_psoc *psoc,
+						uint8_t *pcl_list_org,
+						uint8_t *weight_list_org,
+						uint32_t *pcl_len_org)
+{
+	uint32_t i, pcl_len = 0;
+	uint8_t pcl_list[QDF_MAX_NUM_CHAN];
+	uint8_t weight_list[QDF_MAX_NUM_CHAN];
+	bool ok;
+	int ret;
+
+	for (i = 0; i < *pcl_len_org; i++) {
+		ret = policy_mgr_is_chan_ok_for_dnbs(psoc, pcl_list_org[i],
+						&ok);
+
+		if (QDF_IS_STATUS_ERROR(ret)) {
+			policy_mgr_err("Not able to check DNBS eligibility");
+			return ret;
+		}
+		if (ok) {
+			pcl_list[pcl_len] = pcl_list_org[i];
+			weight_list[pcl_len++] = weight_list_org[i];
+		}
+	}
+
+	qdf_mem_zero(pcl_list_org, QDF_ARRAY_SIZE(pcl_list_org));
+	qdf_mem_zero(weight_list_org, QDF_ARRAY_SIZE(weight_list_org));
+	qdf_mem_copy(pcl_list_org, pcl_list, pcl_len);
+	qdf_mem_copy(weight_list_org, weight_list, pcl_len);
+	*pcl_len_org = pcl_len;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 uint8_t policy_mgr_get_channel(struct wlan_objmgr_psoc *psoc,
 			enum policy_mgr_con_mode mode, uint32_t *vdev_id)
 {
@@ -333,6 +368,13 @@ QDF_STATUS policy_mgr_get_pcl(struct wlan_objmgr_psoc *psoc,
 			pcl_channels[i], pcl_weight[i]);
 	}
 
+	status = policy_mgr_modify_pcl_based_on_dnbs(psoc, pcl_channels,
+						pcl_weight, len);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get modified pcl based on DNBS");
+		return status;
+	}
 	return QDF_STATUS_SUCCESS;
 }