qcacld-3.0: Send disconnect IEs received in deauth/disassoc to kernel

AP may send IEs in deauth/disassoc frames as part of disconnection.
Extract the same and forward to kernel through
cfg80211_disconnected().

Change-Id: I4ef339dcd1ecff64d6bed1de35621ecce5d8030a
CRs-Fixed: 2481912
This commit is contained in:
Srinivas Dasari 2019-07-01 15:35:52 +05:30 • committed by nshrivas
commit d4e8725828
13 changed files with 193 additions and 15 deletions

View file

@ -88,6 +88,8 @@ enum vdev_assoc_type {
* @roam_invoke_params: Roam invoke params
* @self_disconnect_ies: Disconnect IEs to be sent in deauth/disassoc frames
* originated from driver
* @peer_disconnect_ies: Disconnect IEs received in deauth/disassoc frames
* from peer
*/
struct mlme_legacy_priv {
bool chan_switch_in_progress;
@ -101,6 +103,7 @@ struct mlme_legacy_priv {
uint8_t sta_dynamic_oce_value;
struct mlme_roam_after_data_stall roam_invoke_params;
struct wlan_ies self_disconnect_ies;
struct wlan_ies peer_disconnect_ies;
};
#ifndef CRYPTO_SET_KEY_CONVERGED
@ -308,4 +311,30 @@ void mlme_free_self_disconnect_ies(struct wlan_objmgr_vdev *vdev);
* Return: Returns a pointer to the self disconnect IEs present in vdev object
*/
struct wlan_ies *mlme_get_self_disconnect_ies(struct wlan_objmgr_vdev *vdev);
/**
* mlme_set_peer_disconnect_ies() - Cache disconnect IEs received from peer
* @vdev: vdev pointer
* @ie: pointer for disconnect IEs
*
* Return: None
*/
void mlme_set_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev,
struct wlan_ies *ie);
/**
* mlme_free_peer_disconnect_ies() - Free the peer diconnect IEs
* @vdev: vdev pointer
*
* Return: None
*/
void mlme_free_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev);
/**
* mlme_get_peer_disconnect_ies() - Get diconnect IEs from vdev object
* @vdev: vdev pointer
*
* Return: Returns a pointer to the peer disconnect IEs present in vdev object
*/
struct wlan_ies *mlme_get_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev);
#endif

View file

@ -2435,3 +2435,76 @@ struct wlan_ies *mlme_get_self_disconnect_ies(struct wlan_objmgr_vdev *vdev)
return &mlme_priv->self_disconnect_ies;
}
void mlme_set_peer_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->peer_disconnect_ies.data) {
qdf_mem_free(mlme_priv->peer_disconnect_ies.data);
mlme_priv->peer_disconnect_ies.len = 0;
}
mlme_priv->peer_disconnect_ies.data = qdf_mem_malloc(ie->len);
if (!mlme_priv->peer_disconnect_ies.data)
return;
qdf_mem_copy(mlme_priv->peer_disconnect_ies.data, ie->data, ie->len);
mlme_priv->peer_disconnect_ies.len = ie->len;
mlme_legacy_debug("peer disconnect IEs");
QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG,
mlme_priv->peer_disconnect_ies.data,
mlme_priv->peer_disconnect_ies.len);
}
void mlme_free_peer_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->peer_disconnect_ies.data) {
qdf_mem_free(mlme_priv->peer_disconnect_ies.data);
mlme_priv->peer_disconnect_ies.data = NULL;
mlme_priv->peer_disconnect_ies.len = 0;
}
}
struct wlan_ies *mlme_get_peer_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 NULL;
}
mlme_priv = vdev_mlme->ext_vdev_ptr;
return &mlme_priv->peer_disconnect_ies;
}

View file

@ -828,6 +828,7 @@ QDF_STATUS vdevmgr_mlme_ext_hdl_destroy(struct vdev_mlme_obj *vdev_mlme)
return QDF_STATUS_E_FAILURE;
mlme_free_self_disconnect_ies(vdev_mlme->vdev);
mlme_free_peer_disconnect_ies(vdev_mlme->vdev);
qdf_mem_free(vdev_mlme->ext_vdev_ptr);
vdev_mlme->ext_vdev_ptr = NULL;

View file

@ -1709,6 +1709,7 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
uint8_t sta_id;
bool sendDisconInd = true;
mac_handle_t mac_handle;
struct wlan_ies disconnect_ies = {0};
if (!dev) {
hdd_err("net_dev is released return");
@ -1771,6 +1772,12 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
* by kernel
*/
if (sendDisconInd) {
if (roam_info && roam_info->disconnect_ies) {
disconnect_ies.data =
roam_info->disconnect_ies->data;
disconnect_ies.len =
roam_info->disconnect_ies->len;
}
/*
* To avoid wpa_supplicant sending "HANGED" CMD
* to ICS UI.
@ -1782,12 +1789,15 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
roam_info->rxRssi);
wlan_hdd_cfg80211_indicate_disconnect(
dev, false,
roam_info->reasonCode);
roam_info->reasonCode,
disconnect_ies.data,
disconnect_ies.len);
} else {
wlan_hdd_cfg80211_indicate_disconnect(
dev, false,
WLAN_REASON_UNSPECIFIED
);
WLAN_REASON_UNSPECIFIED,
disconnect_ies.data,
disconnect_ies.len);
}
hdd_debug("sent disconnected event to nl80211, reason code %d",

View file

@ -18638,7 +18638,7 @@ disconnected:
*/
hdd_debug("Send disconnected event to userspace");
wlan_hdd_cfg80211_indicate_disconnect(adapter->dev, true,
WLAN_REASON_UNSPECIFIED);
WLAN_REASON_UNSPECIFIED, NULL, 0);
#endif
return result;

View file

@ -445,20 +445,26 @@ int wlan_hdd_try_disconnect(struct hdd_adapter *adapter);
#if defined(CFG80211_DISCONNECTED_V2) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
bool locally_generated,
int reason)
static inline void
wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
bool locally_generated,
int reason,
uint8_t *disconnect_ies,
uint16_t disconnect_ies_len)
{
cfg80211_disconnected(dev, reason, NULL, 0,
locally_generated, GFP_KERNEL);
cfg80211_disconnected(dev, reason, disconnect_ies, disconnect_ies_len,
locally_generated, GFP_KERNEL);
}
#else
static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
bool locally_generated,
int reason)
static inline void
wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev,
bool locally_generated,
int reason,
uint8_t *disconnect_ies,
uint16_t disconnect_ies_len)
{
cfg80211_disconnected(dev, reason, NULL, 0,
GFP_KERNEL);
cfg80211_disconnected(dev, reason, disconnect_ies, disconnect_ies_len,
GFP_KERNEL);
}
#endif

View file

@ -6750,7 +6750,8 @@ QDF_STATUS hdd_start_all_adapters(struct hdd_context *hdd_ctx)
/* indicate disconnected event to nl80211 */
wlan_hdd_cfg80211_indicate_disconnect(
adapter->dev, false,
WLAN_REASON_UNSPECIFIED);
WLAN_REASON_UNSPECIFIED,
NULL, 0);
} else if (eConnectionState_Connecting == conn_state) {
/*
* Indicate connect failure to supplicant if we

View file

@ -4827,3 +4827,28 @@ void lim_send_sme_tsm_ie_ind(struct mac_context *mac,
lim_sys_process_mmh_msg_api(mac, &msg);
}
#endif /* FEATURE_WLAN_ESE */
void lim_extract_ies_from_deauth_disassoc(struct pe_session *session,
uint8_t *deauth_disassoc_frame,
uint16_t deauth_disassoc_frame_len)
{
uint16_t reason_code, ie_offset;
struct wlan_ies ie;
if (!session) {
pe_err("NULL session");
return;
}
/* Get the offset of IEs */
ie_offset = sizeof(struct wlan_frame_hdr) + sizeof(reason_code);
if (!deauth_disassoc_frame || deauth_disassoc_frame_len <= ie_offset)
return;
ie.data = deauth_disassoc_frame + ie_offset;
ie.len = deauth_disassoc_frame_len - ie_offset;
mlme_set_peer_disconnect_ies(session->vdev, &ie);
}

View file

@ -281,4 +281,21 @@ QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx,
struct pe_session *session_entry,
uint8_t nss);
/**
* lim_extract_ies_from_deauth_disassoc() - Extract IEs from deauth/disassoc
*
* @session: PE session entry
* @deauth_disassoc_frame: A pointer to the deauth/disconnect frame buffer
* received from WMA.
* @deauth_disassoc_frame_leni: Length of the deauth/disconnect frame.
*
* This function receives deauth/disassoc frame from header. It extracts
* the IEs(tagged params) from the frame and caches in vdev object.
*
* Return: None
*/
void
lim_extract_ies_from_deauth_disassoc(struct pe_session *session,
uint8_t *deauth_disassoc_frame,
uint16_t deauth_disassoc_frame_len);
#endif /* __LIM_ASSOC_UTILS_H */

View file

@ -314,6 +314,8 @@ lim_process_deauth_frame(struct mac_context *mac, uint8_t *pRxPacketInfo,
}
}
lim_extract_ies_from_deauth_disassoc(pe_session, (uint8_t *)pHdr,
WMA_GET_RX_MPDU_LEN(pRxPacketInfo));
lim_perform_deauth(mac, pe_session, reasonCode, pHdr->sa,
frame_rssi);

View file

@ -310,6 +310,8 @@ lim_process_disassoc_frame(struct mac_context *mac, uint8_t *pRxPacketInfo,
} /* if (sta->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */
lim_extract_ies_from_deauth_disassoc(pe_session, (uint8_t *)pHdr,
WMA_GET_RX_MPDU_LEN(pRxPacketInfo));
lim_perform_disassoc(mac, frame_rssi, reasonCode,
pe_session, pHdr->sa);

View file

@ -1179,6 +1179,7 @@ struct csr_roam_info {
#endif
struct assoc_ind *owe_pending_assoc_ind;
uint16_t roam_reason;
struct wlan_ies *disconnect_ies;
};
typedef struct sSirSmeAssocIndToUpperLayerCnf {

View file

@ -9733,6 +9733,7 @@ csr_roam_send_disconnect_done_indication(struct mac_context *mac_ctx,
(struct sir_sme_discon_done_ind *)(msg_ptr);
struct csr_roam_info *roam_info;
struct csr_roam_session *session;
struct wlan_objmgr_vdev *vdev;
roam_info = qdf_mem_malloc(sizeof(*roam_info));
if (!roam_info)
@ -9751,10 +9752,20 @@ csr_roam_send_disconnect_done_indication(struct mac_context *mac_ctx,
roam_info->rx_rate = mac_ctx->peer_rxrate;
roam_info->disassoc_reason = discon_ind->reason_code;
roam_info->rx_mc_bc_cnt = mac_ctx->rx_mc_bc_cnt;
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc,
discon_ind->session_id,
WLAN_LEGACY_SME_ID);
if (vdev)
roam_info->disconnect_ies =
mlme_get_peer_disconnect_ies(vdev);
csr_roam_call_callback(mac_ctx, discon_ind->session_id,
roam_info, 0, eCSR_ROAM_LOSTLINK,
eCSR_ROAM_RESULT_DISASSOC_IND);
if (vdev) {
mlme_free_peer_disconnect_ies(vdev);
wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID);
}
session = CSR_GET_SESSION(mac_ctx, discon_ind->session_id);
if (session &&
!CSR_IS_INFRA_AP(&session->connectedProfile))