Sfoglia il codice sorgente

qcacld-3.0: Get disconnect IEs and cache in vdev mgr object

Application sends disconnect IEs to driver through vendor command
SET_WIFI_CONFIGURATION by embeding in the attribute
QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES. Extract the same and validate
to make sure it's not more than maximum IE length that can be
accomodated in deauth/disassoc frame. Cache the extracted IEs
in mlme vdev object.

Change-Id: I6c95aa1d4d8ef7d8ed3ad5be8832ef1f45c26a2f
CRs-Fixed: 2481908
Srinivas Dasari 5 anni fa
parent
commit
37e3731d4a

+ 30 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -43,6 +43,16 @@ struct wlan_mlme_psoc_obj {
 	struct wlan_mlme_cfg cfg;
 };
 
+/**
+ * struct wlan_ies - Generic WLAN Information Element(s) format
+ * @len: Total length of the IEs
+ * @data: IE data
+ */
+struct wlan_ies {
+	uint16_t len;
+	uint8_t *data;
+};
+
 /**
  * struct peer_mlme_priv_obj - peer MLME component object
  * @ucast_key_cipher: unicast crypto type.
@@ -76,6 +86,8 @@ enum vdev_assoc_type {
  * @ini_cfg: Max configuration of nss, chains supported for vdev.
  * @sta_dynamic_oce_value: Dyanmic oce flags value for sta
  * @roam_invoke_params: Roam invoke params
+ * @self_disconnect_ies: Disconnect IEs to be sent in deauth/disassoc frames
+ *			 originated from driver
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -88,6 +100,7 @@ struct mlme_legacy_priv {
 	struct wlan_mlme_nss_chains ini_cfg;
 	uint8_t sta_dynamic_oce_value;
 	struct mlme_roam_after_data_stall roam_invoke_params;
+	struct wlan_ies self_disconnect_ies;
 };
 
 #ifndef CRYPTO_SET_KEY_CONVERGED
@@ -270,4 +283,21 @@ struct wlan_mlme_psoc_obj *mlme_get_psoc_obj_fl(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS mlme_init_ibss_cfg(struct wlan_objmgr_psoc *psoc,
 			      struct wlan_mlme_ibss_cfg *ibss_cfg);
 
+/**
+ * mlme_set_self_disconnect_ies() - Set diconnect IEs configured from userspace
+ * @vdev: vdev pointer
+ * @ie: pointer for disconnect IEs
+ *
+ * Return: None
+ */
+void mlme_set_self_disconnect_ies(struct wlan_objmgr_vdev *vdev,
+				  struct wlan_ies *ie);
+
+/**
+ * mlme_free_self_disconnect_ies() - Free the self diconnect IEs
+ * @vdev: vdev pointer
+ *
+ * Return: None
+ */
+void mlme_free_self_disconnect_ies(struct wlan_objmgr_vdev *vdev);
 #endif

+ 57 - 0
components/mlme/core/src/wlan_mlme_main.c

@@ -2362,3 +2362,60 @@ QDF_STATUS mlme_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc)
 
 	return status;
 }
+
+void mlme_set_self_disconnect_ies(struct wlan_objmgr_vdev *vdev,
+				  struct wlan_ies *ie)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct mlme_legacy_priv *mlme_priv;
+
+	if (!ie || !ie->len || !ie->data) {
+		mlme_legacy_debug("disocnnect IEs are NULL");
+		return;
+	}
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_legacy_err("vdev component object is NULL");
+		return;
+	}
+
+	mlme_priv = vdev_mlme->ext_vdev_ptr;
+
+	if (mlme_priv->self_disconnect_ies.data) {
+		qdf_mem_free(mlme_priv->self_disconnect_ies.data);
+		mlme_priv->self_disconnect_ies.len = 0;
+	}
+
+	mlme_priv->self_disconnect_ies.data = qdf_mem_malloc(ie->len);
+	if (!mlme_priv->self_disconnect_ies.data)
+		return;
+
+	qdf_mem_copy(mlme_priv->self_disconnect_ies.data, ie->data, ie->len);
+	mlme_priv->self_disconnect_ies.len = ie->len;
+
+	mlme_legacy_debug("Self disconnect IEs");
+	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG,
+			   mlme_priv->self_disconnect_ies.data,
+			   mlme_priv->self_disconnect_ies.len);
+}
+
+void mlme_free_self_disconnect_ies(struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_mlme_obj *vdev_mlme;
+	struct mlme_legacy_priv *mlme_priv;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_legacy_err("vdev component object is NULL");
+		return;
+	}
+
+	mlme_priv = vdev_mlme->ext_vdev_ptr;
+
+	if (mlme_priv->self_disconnect_ies.data) {
+		qdf_mem_free(mlme_priv->self_disconnect_ies.data);
+		mlme_priv->self_disconnect_ies.data = NULL;
+		mlme_priv->self_disconnect_ies.len = 0;
+	}
+}

+ 5 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -823,6 +823,11 @@ QDF_STATUS vdevmgr_mlme_ext_hdl_destroy(struct vdev_mlme_obj *vdev_mlme)
 {
 	mlme_legacy_debug("vdev id = %d ",
 			  vdev_mlme->vdev->vdev_objmgr.vdev_id);
+
+	if (!vdev_mlme->ext_vdev_ptr)
+		return QDF_STATUS_E_FAILURE;
+
+	mlme_free_self_disconnect_ies(vdev_mlme->vdev);
 	qdf_mem_free(vdev_mlme->ext_vdev_ptr);
 	vdev_mlme->ext_vdev_ptr = NULL;
 

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

@@ -5450,6 +5450,9 @@ wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST] = {
 		.type = NLA_BINARY,
 		.len = WLAN_MAX_IE_LEN + 2},
+	[QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES] = {
+		.type = NLA_BINARY,
+		.len = SIR_MAC_MAX_ADD_IE_LENGTH + 2},
 
 };
 
@@ -6612,6 +6615,38 @@ static int hdd_config_gtx(struct hdd_adapter *adapter,
 	return errno;
 }
 
+/**
+ * hdd_config_disconnect_ies() - Configure disconnect IEs
+ * @adapter: Pointer to HDD adapter
+ * @attr: array of pointer to struct nlattr
+ *
+ * Return: 0 on success; error number otherwise
+ */
+static int hdd_config_disconnect_ies(struct hdd_adapter *adapter,
+				     const struct nlattr *attr)
+{
+	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	QDF_STATUS status;
+
+	hdd_debug("IE len %u session %u device mode %u",
+		  nla_len(attr), adapter->vdev_id, adapter->device_mode);
+	if (!nla_len(attr) ||
+	    nla_len(attr) > SIR_MAC_MAX_ADD_IE_LENGTH + 2 ||
+	    !wlan_is_ie_valid(nla_data(attr), nla_len(attr))) {
+		hdd_err("Invalid disconnect IEs");
+		return -EINVAL;
+	}
+
+	status = sme_set_disconnect_ies(hdd_ctx->mac_handle,
+					adapter->vdev_id,
+					nla_data(attr),
+					nla_len(attr));
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Failed to set disconnect_ies");
+
+	return qdf_status_to_os_return(status);
+}
+
 /**
  * typedef independent_setter_fn - independent attribute handler
  * @adapter: The adapter being configured
@@ -6696,6 +6731,8 @@ static const struct independent_setters independent_setters[] = {
 	 hdd_config_rsn_ie},
 	{QCA_WLAN_VENDOR_ATTR_CONFIG_GTX,
 	 hdd_config_gtx},
+	{QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES,
+	 hdd_config_disconnect_ies},
 };
 
 /**

+ 11 - 0
core/sme/inc/sme_api.h

@@ -3547,4 +3547,15 @@ QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
 }
 #endif
 
+/**
+ * sme_set_disconnect_ies() - set disconnect IEs
+ * @mac_handle: handle returned by mac_open
+ * @vdev_id: vdev id
+ * @ie_data: Disconnect IE data
+ * @ie_len: Disconnect IE length
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_set_disconnect_ies(mac_handle_t mac_handle, uint8_t vdev_id,
+				  uint8_t *ie_data, uint16_t ie_len);
 #endif /* #if !defined( __SME_API_H ) */

+ 30 - 0
core/sme/src/common/sme_api.c

@@ -15675,3 +15675,33 @@ QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle,
 	return status;
 }
 #endif
+
+QDF_STATUS sme_set_disconnect_ies(mac_handle_t mac_handle, uint8_t vdev_id,
+				  uint8_t *ie_data, uint16_t ie_len)
+{
+	struct mac_context *mac_ctx;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_ies ie;
+
+	if (!ie_data || !ie_len) {
+		sme_debug("Got NULL disconnect IEs");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mac_ctx = MAC_CONTEXT(mac_handle);
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc,
+						    vdev_id,
+						    WLAN_LEGACY_SME_ID);
+	if (!vdev) {
+		sme_err("Got NULL vdev obj, returning");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ie.data = ie_data;
+	ie.len = ie_len;
+
+	mlme_set_self_disconnect_ies(vdev, &ie);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID);
+	return QDF_STATUS_SUCCESS;
+}