qcacmn: Fix scan with random address failed since wdev is connected
Reproduce steps: 1. Connect from OSIF success, wdev->connected = true; 2. Disconnect from target if and reassoc from OSIF happens back to back. 3. Disconnect event is not sent to kernel, wdev->connected keeps true, isn't cleared. 4. Connect from OSIF failed too, wdev->connected keeps true, isn't cleared. 5. Scan with random address failed since wdev->connected is true. To fix it, if connect req was a reassoc req and received in not connected state for race between disconnect from target if and reassoc connect from OSIF, set reassoc_in_non_connected to send disconnect instead of connect rsp to kernel to cleanup kernel flags like: wdev->connected. change-Id: Ibbe38da14e9339b49589216250453b76c7387b57 CRs-Fixed: 3290496
This commit is contained in:

committad av
Madan Koyyalamudi

förälder
1f49ac1d70
incheckning
fb43cc12b8
@@ -1080,13 +1080,14 @@ QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev,
|
|||||||
struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
|
struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev);
|
||||||
QDF_STATUS status;
|
QDF_STATUS status;
|
||||||
|
|
||||||
osif_nofl_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Connect with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" is %s cm_id 0x%x cm_reason %d status_code %d is_reassoc %d",
|
osif_nofl_info("%s(vdevid-%d): " QDF_MAC_ADDR_FMT " Connect with " QDF_MAC_ADDR_FMT " SSID \"%.*s\" is %s cm_id 0x%x cm_reason %d status_code %d is_reassoc %d send discon %d",
|
||||||
osif_priv->wdev->netdev->name, rsp->vdev_id,
|
osif_priv->wdev->netdev->name, rsp->vdev_id,
|
||||||
QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
|
QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)),
|
||||||
QDF_MAC_ADDR_REF(rsp->bssid.bytes),
|
QDF_MAC_ADDR_REF(rsp->bssid.bytes),
|
||||||
rsp->ssid.length, rsp->ssid.ssid,
|
rsp->ssid.length, rsp->ssid.ssid,
|
||||||
rsp->connect_status ? "FAILURE" : "SUCCESS", rsp->cm_id,
|
rsp->connect_status ? "FAILURE" : "SUCCESS", rsp->cm_id,
|
||||||
rsp->reason, rsp->status_code, rsp->is_reassoc);
|
rsp->reason, rsp->status_code, rsp->is_reassoc,
|
||||||
|
rsp->send_disconnect);
|
||||||
|
|
||||||
osif_check_and_unlink_bss(vdev, osif_priv, rsp);
|
osif_check_and_unlink_bss(vdev, osif_priv, rsp);
|
||||||
|
|
||||||
@@ -1097,8 +1098,34 @@ QDF_STATUS osif_connect_handler(struct wlan_objmgr_vdev *vdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
osif_cm_connect_comp_ind(vdev, rsp, OSIF_PRE_USERSPACE_UPDATE);
|
osif_cm_connect_comp_ind(vdev, rsp, OSIF_PRE_USERSPACE_UPDATE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To fix issue that scan with random address failed since wdev keeps
|
||||||
|
* connected, rsp->send_disconnect is added.
|
||||||
|
* Reproduce steps:
|
||||||
|
* 1. Connect from OSIF success, wdev->connected = true;
|
||||||
|
* 2. Disconnect from target if and reassoc from OSIF happens back to
|
||||||
|
* back.
|
||||||
|
* 3. Disconnect event is not sent to kernel, wdev->connected keeps
|
||||||
|
* true, isn't cleared.
|
||||||
|
* 4. Connect from OSIF failed too, wdev->connected keeps true, isn't
|
||||||
|
* cleared.
|
||||||
|
* 5. Scan with random address failed since wdev->connected is true.
|
||||||
|
*
|
||||||
|
* To fix it, if connect req was a reassoc req and received in not
|
||||||
|
* connected state for race between disconnect from target if and
|
||||||
|
* reassoc connect from OSIF, set reassoc_in_non_connected to send
|
||||||
|
* disconnect instead of connect rsp to kernel to cleanup kernel flags
|
||||||
|
* like: wdev->connected.
|
||||||
|
*/
|
||||||
if (rsp->is_reassoc)
|
if (rsp->is_reassoc)
|
||||||
osif_indicate_reassoc_results(vdev, osif_priv, rsp);
|
osif_indicate_reassoc_results(vdev, osif_priv, rsp);
|
||||||
|
else if (rsp->send_disconnect &&
|
||||||
|
QDF_IS_STATUS_ERROR(rsp->connect_status))
|
||||||
|
osif_cm_indicate_disconnect(vdev, osif_priv->wdev->netdev,
|
||||||
|
WLAN_REASON_UNSPECIFIED,
|
||||||
|
false, NULL, 0,
|
||||||
|
qdf_mem_malloc_flags());
|
||||||
else
|
else
|
||||||
osif_indcate_connect_results(vdev, osif_priv, rsp);
|
osif_indcate_connect_results(vdev, osif_priv, rsp);
|
||||||
osif_cm_connect_comp_ind(vdev, rsp, OSIF_POST_USERSPACE_UPDATE);
|
osif_cm_connect_comp_ind(vdev, rsp, OSIF_POST_USERSPACE_UPDATE);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015, 2020-2021 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2012-2015, 2020-2021 The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -81,7 +82,7 @@ rel_lock:
|
|||||||
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
|
||||||
#ifdef WLAN_FEATURE_11BE_MLO
|
#ifdef WLAN_FEATURE_11BE_MLO
|
||||||
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
|
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
|
||||||
static void
|
void
|
||||||
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
enum ieee80211_reasoncode reason,
|
enum ieee80211_reasoncode reason,
|
||||||
@@ -98,7 +99,7 @@ osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
|
#else /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
|
||||||
static void
|
void
|
||||||
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
enum ieee80211_reasoncode reason,
|
enum ieee80211_reasoncode reason,
|
||||||
@@ -128,7 +129,7 @@ osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
|||||||
}
|
}
|
||||||
#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
|
#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */
|
||||||
#else /* WLAN_FEATURE_11BE_MLO */
|
#else /* WLAN_FEATURE_11BE_MLO */
|
||||||
static void
|
void
|
||||||
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
enum ieee80211_reasoncode reason,
|
enum ieee80211_reasoncode reason,
|
||||||
@@ -139,7 +140,7 @@ osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
|||||||
}
|
}
|
||||||
#endif /* WLAN_FEATURE_11BE_MLO */
|
#endif /* WLAN_FEATURE_11BE_MLO */
|
||||||
#else
|
#else
|
||||||
static void
|
void
|
||||||
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
enum ieee80211_reasoncode reason,
|
enum ieee80211_reasoncode reason,
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
|
* Copyright (c) 2012-2015,2020-2021 The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -134,4 +135,25 @@ osif_indicate_reassoc_results(struct wlan_objmgr_vdev *vdev,
|
|||||||
QDF_STATUS osif_failed_candidate_handler(struct wlan_objmgr_vdev *vdev,
|
QDF_STATUS osif_failed_candidate_handler(struct wlan_objmgr_vdev *vdev,
|
||||||
struct wlan_cm_connect_resp *rsp);
|
struct wlan_cm_connect_resp *rsp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* osif_cm_indicate_disconnect - notify osif that connection was dropped
|
||||||
|
*
|
||||||
|
* @vdev: pointer to vdev
|
||||||
|
* @dev: network device
|
||||||
|
* @reason: reason code for the disconnection, set it to 0 if unknown
|
||||||
|
* @locally_generated: disconnection was requested locally
|
||||||
|
* @ie: information elements of the deauth/disassoc frame (may be %NULL)
|
||||||
|
* @ie_len: length of IEs
|
||||||
|
* @gfp: allocation flags
|
||||||
|
*
|
||||||
|
* After it calls this function, the driver should enter an idle state
|
||||||
|
* and not try to connect to any AP any more.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
osif_cm_indicate_disconnect(struct wlan_objmgr_vdev *vdev,
|
||||||
|
struct net_device *dev,
|
||||||
|
enum ieee80211_reasoncode reason,
|
||||||
|
bool locally_generated, const u8 *ie,
|
||||||
|
size_t ie_len, gfp_t gfp);
|
||||||
|
|
||||||
#endif /* __OSIF_CM_RSP_H */
|
#endif /* __OSIF_CM_RSP_H */
|
||||||
|
@@ -1340,6 +1340,15 @@ cm_handle_connect_req_in_non_init_state(struct cnx_mgr *cm_ctx,
|
|||||||
struct cm_connect_req *cm_req,
|
struct cm_connect_req *cm_req,
|
||||||
enum wlan_cm_sm_state cm_state_substate)
|
enum wlan_cm_sm_state cm_state_substate)
|
||||||
{
|
{
|
||||||
|
if (cm_state_substate != WLAN_CM_S_CONNECTED &&
|
||||||
|
cm_is_connect_req_reassoc(&cm_req->req)) {
|
||||||
|
cm_req->req.reassoc_in_non_connected = true;
|
||||||
|
mlme_debug(CM_PREFIX_FMT "Reassoc received in %d state",
|
||||||
|
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
|
||||||
|
cm_req->cm_id),
|
||||||
|
cm_state_substate);
|
||||||
|
}
|
||||||
|
|
||||||
switch (cm_state_substate) {
|
switch (cm_state_substate) {
|
||||||
case WLAN_CM_S_ROAMING:
|
case WLAN_CM_S_ROAMING:
|
||||||
/* for FW roam/LFR3 remove the req from the list */
|
/* for FW roam/LFR3 remove the req from the list */
|
||||||
@@ -2236,11 +2245,69 @@ cm_clear_vdev_mlo_cap(struct wlan_objmgr_vdev *vdev)
|
|||||||
{ }
|
{ }
|
||||||
#endif /*WLAN_FEATURE_11BE_MLO*/
|
#endif /*WLAN_FEATURE_11BE_MLO*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cm_is_connect_id_reassoc_in_non_connected()
|
||||||
|
* @cm_ctx: connection manager context
|
||||||
|
* @cm_id: cm id
|
||||||
|
*
|
||||||
|
* If connect req is a reassoc req and received in not connected state
|
||||||
|
*
|
||||||
|
* Return: bool
|
||||||
|
*/
|
||||||
|
static bool cm_is_connect_id_reassoc_in_non_connected(struct cnx_mgr *cm_ctx,
|
||||||
|
wlan_cm_id cm_id)
|
||||||
|
{
|
||||||
|
qdf_list_node_t *cur_node = NULL, *next_node = NULL;
|
||||||
|
struct cm_req *cm_req;
|
||||||
|
uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
|
||||||
|
bool is_reassoc = false;
|
||||||
|
|
||||||
|
if (prefix != CONNECT_REQ_PREFIX)
|
||||||
|
return is_reassoc;
|
||||||
|
|
||||||
|
cm_req_lock_acquire(cm_ctx);
|
||||||
|
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
|
||||||
|
while (cur_node) {
|
||||||
|
qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
|
||||||
|
cm_req = qdf_container_of(cur_node, struct cm_req, node);
|
||||||
|
|
||||||
|
if (cm_req->cm_id == cm_id) {
|
||||||
|
if (cm_req->connect_req.req.reassoc_in_non_connected)
|
||||||
|
is_reassoc = true;
|
||||||
|
cm_req_lock_release(cm_ctx);
|
||||||
|
return is_reassoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_node = next_node;
|
||||||
|
next_node = NULL;
|
||||||
|
}
|
||||||
|
cm_req_lock_release(cm_ctx);
|
||||||
|
|
||||||
|
return is_reassoc;
|
||||||
|
}
|
||||||
|
|
||||||
QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
|
QDF_STATUS cm_notify_connect_complete(struct cnx_mgr *cm_ctx,
|
||||||
struct wlan_cm_connect_resp *resp)
|
struct wlan_cm_connect_resp *resp)
|
||||||
{
|
{
|
||||||
|
enum wlan_cm_sm_state sm_state;
|
||||||
|
|
||||||
|
sm_state = cm_get_state(cm_ctx);
|
||||||
|
|
||||||
mlme_cm_connect_complete_ind(cm_ctx->vdev, resp);
|
mlme_cm_connect_complete_ind(cm_ctx->vdev, resp);
|
||||||
mlo_sta_link_connect_notify(cm_ctx->vdev, resp);
|
mlo_sta_link_connect_notify(cm_ctx->vdev, resp);
|
||||||
|
/*
|
||||||
|
* If connect req was a reassoc req and was received in not connected
|
||||||
|
* state send disconnect instead of connect resp to kernel to cleanup
|
||||||
|
* kernel flags
|
||||||
|
*/
|
||||||
|
if (QDF_IS_STATUS_ERROR(resp->connect_status) &&
|
||||||
|
sm_state == WLAN_CM_S_INIT &&
|
||||||
|
cm_is_connect_id_reassoc_in_non_connected(cm_ctx, resp->cm_id)) {
|
||||||
|
resp->send_disconnect = true;
|
||||||
|
mlme_debug(CM_PREFIX_FMT "Set send disconnect to true to indicate disconnect instaed of connect resp",
|
||||||
|
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
|
||||||
|
resp->cm_id));
|
||||||
|
}
|
||||||
mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
|
mlme_cm_osif_connect_complete(cm_ctx->vdev, resp);
|
||||||
cm_if_mgr_inform_connect_complete(cm_ctx->vdev,
|
cm_if_mgr_inform_connect_complete(cm_ctx->vdev,
|
||||||
resp->connect_status);
|
resp->connect_status);
|
||||||
|
@@ -1193,4 +1193,12 @@ void cm_set_candidate_custom_sort_cb(
|
|||||||
qdf_list_t *list));
|
qdf_list_t *list));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cm_is_connect_req_reassoc() - Is connect req for reassoc
|
||||||
|
* @req: connect req
|
||||||
|
*
|
||||||
|
* Return: void
|
||||||
|
*/
|
||||||
|
bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req);
|
||||||
#endif /* __WLAN_CM_MAIN_API_H__ */
|
#endif /* __WLAN_CM_MAIN_API_H__ */
|
||||||
|
@@ -72,9 +72,7 @@ QDF_STATUS cm_check_and_prepare_roam_req(struct cnx_mgr *cm_ctx,
|
|||||||
* Reject re-assoc unless freq along with prev bssid and one
|
* Reject re-assoc unless freq along with prev bssid and one
|
||||||
* of bssid or bssid hint is present.
|
* of bssid or bssid hint is present.
|
||||||
*/
|
*/
|
||||||
if (!freq || qdf_is_macaddr_zero(&req->prev_bssid) ||
|
if (!cm_is_connect_req_reassoc(req))
|
||||||
(qdf_is_macaddr_zero(&req->bssid) &&
|
|
||||||
qdf_is_macaddr_zero(&req->bssid_hint)))
|
|
||||||
return QDF_STATUS_E_FAILURE;
|
return QDF_STATUS_E_FAILURE;
|
||||||
|
|
||||||
wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid);
|
wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid);
|
||||||
|
@@ -1256,6 +1256,17 @@ void cm_fill_ml_partner_info(struct wlan_cm_connect_req *req,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool cm_is_connect_req_reassoc(struct wlan_cm_connect_req *req)
|
||||||
|
{
|
||||||
|
if (!qdf_is_macaddr_zero(&req->prev_bssid) &&
|
||||||
|
(!qdf_is_macaddr_zero(&req->bssid) ||
|
||||||
|
!qdf_is_macaddr_zero(&req->bssid_hint)) &&
|
||||||
|
(req->chan_freq || req->chan_freq_hint))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev,
|
bool cm_get_active_connect_req(struct wlan_objmgr_vdev *vdev,
|
||||||
struct wlan_cm_vdev_connect_req *req)
|
struct wlan_cm_vdev_connect_req *req)
|
||||||
{
|
{
|
||||||
|
@@ -188,6 +188,7 @@ enum wlan_cm_source {
|
|||||||
* for production.
|
* for production.
|
||||||
* @is_wps_connection: if its wps connection
|
* @is_wps_connection: if its wps connection
|
||||||
* @is_osen_connection: if its osen connection
|
* @is_osen_connection: if its osen connection
|
||||||
|
* @reassoc_in_non_connected: if reassoc received in non connected
|
||||||
* @dot11mode_filter: dot11mode filter used to restrict connection to
|
* @dot11mode_filter: dot11mode filter used to restrict connection to
|
||||||
* 11n/11ac/11ax.
|
* 11n/11ac/11ax.
|
||||||
* @sae_pwe: SAE mechanism for PWE derivation
|
* @sae_pwe: SAE mechanism for PWE derivation
|
||||||
@@ -216,7 +217,8 @@ struct wlan_cm_connect_req {
|
|||||||
struct element_info scan_ie;
|
struct element_info scan_ie;
|
||||||
uint8_t force_rsne_override:1,
|
uint8_t force_rsne_override:1,
|
||||||
is_wps_connection:1,
|
is_wps_connection:1,
|
||||||
is_osen_connection:1;
|
is_osen_connection:1,
|
||||||
|
reassoc_in_non_connected:1;
|
||||||
enum dot11_mode_filter dot11mode_filter;
|
enum dot11_mode_filter dot11mode_filter;
|
||||||
uint8_t sae_pwe;
|
uint8_t sae_pwe;
|
||||||
uint16_t ht_caps;
|
uint16_t ht_caps;
|
||||||
@@ -483,6 +485,8 @@ struct wlan_roam_sync_info {
|
|||||||
* @is_reassoc: if response is for reassoc/roam
|
* @is_reassoc: if response is for reassoc/roam
|
||||||
* @is_ft: is FT reassoc
|
* @is_ft: is FT reassoc
|
||||||
* @is_assoc: if response is for assoc
|
* @is_assoc: if response is for assoc
|
||||||
|
* @send_disconnect: if disconnect needed to sent to kernel, for reassoc
|
||||||
|
* received in non connected state, this is to cleanup kernel
|
||||||
* @cm_id: Connect manager id
|
* @cm_id: Connect manager id
|
||||||
* @bssid: BSSID of the ap
|
* @bssid: BSSID of the ap
|
||||||
* @ssid: SSID of the connection
|
* @ssid: SSID of the connection
|
||||||
@@ -502,7 +506,8 @@ struct wlan_cm_connect_resp {
|
|||||||
is_osen_connection:1,
|
is_osen_connection:1,
|
||||||
is_reassoc:1,
|
is_reassoc:1,
|
||||||
is_ft:1,
|
is_ft:1,
|
||||||
is_assoc:1;
|
is_assoc:1,
|
||||||
|
send_disconnect:1;
|
||||||
wlan_cm_id cm_id;
|
wlan_cm_id cm_id;
|
||||||
struct qdf_mac_addr bssid;
|
struct qdf_mac_addr bssid;
|
||||||
struct wlan_ssid ssid;
|
struct wlan_ssid ssid;
|
||||||
|
Referens i nytt ärende
Block a user