Pārlūkot izejas kodu

qcacld-3.0: Handle wifi config attribute RESTRICT_CHANNEL

Handle WIFI configuration vendor attribute
QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL.
This attribute is set by applications to restrict operations which
cause the AP/GO to go offchannel.

A counter is also added to hdd_adapter to track the number of times
this attribute is set by different applications.
This counter will be reset in the driver when the AP/GO interface is
brought down.
It is the responsibility of the application to remember(through
persistent storage) that it has applied the setting and in case the
application is killed it should be able to recall that it has made the
setting when it is re-started next time.

Change-Id: I45106c8515756d1a007514f1b3e9744bd6ce4834
CRs-Fixed: 2050999
Ajit Pal Singh 7 gadi atpakaļ
vecāks
revīzija
747b6807c1

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

@@ -1150,6 +1150,11 @@ struct hdd_adapter_s {
 	 */
 	uint8_t cfg80211_disconnect_reason;
 	struct lfr_firmware_status lfr_fw_status;
+	/*
+	 * Store the restrict_offchannel count
+	 * to cater to multiple application.
+	 */
+	u8 restrict_offchannel_cnt;
 };
 
 /*

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

@@ -4723,6 +4723,7 @@ wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
 	[ANT_DIV_MGMT_SNR_WEIGHT] = {.type = NLA_U32},
 	[ANT_DIV_DATA_SNR_WEIGHT] = {.type = NLA_U32},
 	[ANT_DIV_ACK_SNR_WEIGHT] = {.type = NLA_U32},
+	[QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL] = {.type = NLA_U8},
 };
 
 /**
@@ -4814,6 +4815,74 @@ static int wlan_hdd_save_default_scan_ies(hdd_context_t *hdd_ctx,
 	return 0;
 }
 
+/**
+ * wlan_hdd_handle_restrict_offchan_config() -
+ * Handle wifi configuration attribute :
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL
+ * @adapter: Pointer to HDD adapter
+ * @restrict_offchan: Restrict offchannel setting done by
+ * application
+ *
+ * Return: 0 on success; error number otherwise
+ */
+static int wlan_hdd_handle_restrict_offchan_config(hdd_adapter_t *adapter,
+						   u8 restrict_offchan)
+{
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	enum tQDF_ADAPTER_MODE dev_mode = adapter->device_mode;
+	int ret_val = 0;
+
+	if (!(dev_mode == QDF_SAP_MODE || dev_mode == QDF_P2P_GO_MODE)) {
+		hdd_err("Invalid interface type:%d", dev_mode);
+		return -EINVAL;
+	}
+	/*
+	 * To cater to multiple apps we maintain
+	 * a counter to check if restrict_offchannel
+	 * is enabled or disabled per AP/GO vdev.
+	 */
+	if (restrict_offchan == 1) {
+		enum policy_mgr_con_mode pmode =
+		policy_mgr_convert_device_mode_to_qdf_type(dev_mode);
+		int chan;
+
+		adapter->restrict_offchannel_cnt++;
+		if (adapter->restrict_offchannel_cnt == 1) {
+			u32 vdev_id = wlan_vdev_get_id(adapter->hdd_vdev);
+
+			wlan_vdev_obj_lock(adapter->hdd_vdev);
+			wlan_vdev_mlme_cap_set(adapter->hdd_vdev,
+					       WLAN_VDEV_C_RESTRICT_OFFCHAN);
+			wlan_vdev_obj_unlock(adapter->hdd_vdev);
+			chan = policy_mgr_get_channel(hdd_ctx->hdd_psoc, pmode,
+						      &vdev_id);
+			if (!chan ||
+			    wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, chan)) {
+				hdd_err("unable to send avoid_freq");
+				ret_val = -EINVAL;
+			}
+		}
+	} else if ((restrict_offchan == 0) &&
+			(adapter->restrict_offchannel_cnt > 0)) {
+		adapter->restrict_offchannel_cnt--;
+		if (adapter->restrict_offchannel_cnt == 0) {
+			wlan_vdev_obj_lock(adapter->hdd_vdev);
+			wlan_vdev_mlme_cap_clear(adapter->hdd_vdev,
+						 WLAN_VDEV_C_RESTRICT_OFFCHAN);
+			wlan_vdev_obj_unlock(adapter->hdd_vdev);
+			if (wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, 0)) {
+				hdd_err("unable to clear avoid_freq");
+				ret_val = -EINVAL;
+			}
+		}
+	} else {
+		ret_val = -EINVAL;
+		hdd_err("Invalid RESTRICT_OFFCHAN setting");
+	}
+
+	return ret_val;
+}
+
 /**
  * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration
  * vendor command
@@ -5235,6 +5304,20 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
 		}
 	}
 
+	if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL]) {
+		u8 restrict_offchan = nla_get_u8(
+			tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL]);
+
+		hdd_debug("Restrict offchannel:%d", restrict_offchan);
+		if (restrict_offchan <= 1)
+			ret_val =
+			wlan_hdd_handle_restrict_offchan_config(adapter,
+							restrict_offchan);
+		else {
+			ret_val = -EINVAL;
+			hdd_err("Invalid RESTRICT_OFFCHAN setting");
+		}
+	}
 	return ret_val;
 }
 

+ 11 - 1
core/hdd/src/wlan_hdd_hostapd.c

@@ -8454,6 +8454,8 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 	    ) {
 		beacon_data_t *old, *new;
 		enum nl80211_channel_type channel_type;
+		tsap_Config_t *sap_config =
+			&((WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->sapConfig);
 
 		old = pAdapter->sessionCtx.ap.beacon;
 
@@ -8503,7 +8505,15 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
 				&params->beacon,
 				params->ssid, params->ssid_len,
 				params->hidden_ssid, true, false);
-
+		/*
+		 * If Do_Not_Break_Stream enabled send avoid channel list
+		 * to application.
+		 */
+		if (policy_mgr_is_dnsc_set(pAdapter->hdd_vdev) &&
+		    sap_config->channel) {
+			wlan_hdd_send_avoid_freq_for_dnbs(pHddCtx,
+							  sap_config->channel);
+		}
 		if (pHddCtx->config->sap_max_inactivity_override) {
 			sta_inactivity_timer = qdf_mem_malloc(
 					sizeof(*sta_inactivity_timer));

+ 7 - 0
core/hdd/src/wlan_hdd_main.c

@@ -4100,6 +4100,13 @@ QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter,
 			qdf_mem_free(adapter->sessionCtx.ap.beacon);
 			adapter->sessionCtx.ap.beacon = NULL;
 		}
+
+		/*
+		 * If Do_Not_Break_Stream was enabled clear avoid channel list.
+		 */
+		if (policy_mgr_is_dnsc_set(adapter->hdd_vdev))
+			wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, 0);
+
 		if (true == bCloseSession)
 			hdd_vdev_destroy(adapter);
 		mutex_unlock(&hdd_ctx->sap_lock);