From 37e3731d4ad9fb3a4b352453cef8721595ef8281 Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Sun, 30 Jun 2019 23:50:24 +0530 Subject: [PATCH] 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 --- components/mlme/core/inc/wlan_mlme_main.h | 30 ++++++++++ components/mlme/core/src/wlan_mlme_main.c | 57 +++++++++++++++++++ .../core/src/wlan_mlme_vdev_mgr_interface.c | 5 ++ core/hdd/src/wlan_hdd_cfg80211.c | 37 ++++++++++++ core/sme/inc/sme_api.h | 11 ++++ core/sme/src/common/sme_api.c | 30 ++++++++++ 6 files changed, 170 insertions(+) diff --git a/components/mlme/core/inc/wlan_mlme_main.h b/components/mlme/core/inc/wlan_mlme_main.h index b497c3205c0e..9f2e8c9d18e1 100644 --- a/components/mlme/core/inc/wlan_mlme_main.h +++ b/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 diff --git a/components/mlme/core/src/wlan_mlme_main.c b/components/mlme/core/src/wlan_mlme_main.c index a97fa69fc275..5f14a793d20e 100644 --- a/components/mlme/core/src/wlan_mlme_main.c +++ b/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; + } +} diff --git a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c b/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c index 59785a71121b..248086dd0f7c 100644 --- a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c +++ b/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; diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index b61cfe51c19b..67d3db821cc9 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/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}, }; /** diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 3d89090b4ee7..f6f0490100e9 100644 --- a/core/sme/inc/sme_api.h +++ b/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 ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 69772a6b6d78..9561f1701951 100644 --- a/core/sme/src/common/sme_api.c +++ b/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; +}