qcacmn: Allow disconnect req in INIT state for link switch
VDEV is moved to INIT state as part of link switch disconnect, before set MAC address response is received, any disconnect request on this VDEV will not be handled as VDEV is in INIT state, if link switch is in progress then it will abort link switch and starts link switch dequeue process. If the new disconnect request is from userspace it will increment the OSIF ops, but if link switch is on assoc VDEV OSIF is notified to restore the adapter deflink as part of link switch complete where it wait for all OSIF ops to complete. This is a deadlock case where driver is waiting for ops completion on same thread where ops is initiated. To fix this issue, do not handle link switch dequeue on the same thread, instead move the link switch state to abort and when actual link switch thread comes it will flush from serialization. If userspace disconnect is not queued as VDEV is in INIT state due to link switch, kernel won't be notified about the disconnect as this notification is only done on assoc VDEV and any further connect requests from supplicant gets dropped in kernel saying already connected and supplicant will immediately try disconnect which driver will again drop as VDEV is in INIT state. To avoid this kernel-driver out of sync, forcefully move VDEV to disconnecting state and queue the disconnect request. Change-Id: I116859601ebba21d44797e74e160b56532ef833c CRs-Fixed: 3588936
Este cometimento está contido em:

cometido por
Rahul Choudhary

ascendente
78d988e666
cometimento
9e3a7ecb78
@@ -1682,7 +1682,7 @@ cm_handle_connect_req_in_non_init_state(struct cnx_mgr *cm_ctx,
|
||||
|
||||
/* Reject any link switch connect request while in non-init state */
|
||||
if (cm_req->req.source == CM_MLO_LINK_SWITCH_CONNECT) {
|
||||
mlme_info(CM_PREFIX_FMT "Ignore disconnect req from source %d state %d",
|
||||
mlme_info(CM_PREFIX_FMT "Ignore connect req from source %d state %d",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id),
|
||||
cm_req->req.source, cm_state_substate);
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
@@ -639,7 +639,8 @@ QDF_STATUS cm_disconnect_complete(struct cnx_mgr *cm_ctx,
|
||||
if (is_link_switch_cmd) {
|
||||
cm_reset_active_cm_id(cm_ctx->vdev, resp->req.cm_id);
|
||||
mlo_mgr_link_switch_disconnect_done(cm_ctx->vdev,
|
||||
link_switch_status);
|
||||
link_switch_status,
|
||||
is_link_switch_cmd);
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
@@ -760,13 +761,27 @@ cm_handle_discon_req_in_non_connected_state(struct cnx_mgr *cm_ctx,
|
||||
*
|
||||
* So no need to do anything here, just return failure and drop
|
||||
* disconnect.
|
||||
*
|
||||
* Notification to userspace is done on non-LINK VDEV in case of
|
||||
* MLO connection, and if assoc VDEV is in INIT state due to
|
||||
* link switch disconnect and dropping userspace disconnect here
|
||||
* might lead to not notifying kernel and any further connect
|
||||
* requests from supplicant will be dropped by kernel saying
|
||||
* already connected and supplicant will immediately attempt
|
||||
* disconnect which will again gets dropped.
|
||||
* Notify MLO manager to terminate link switch operation and
|
||||
* instead of dropping the disconnect forcefully move VDEV state
|
||||
* to disconnecting and add disconnect request to queue so that
|
||||
* kernel and driver will be in sync.
|
||||
*/
|
||||
if (cm_req->req.source != CM_MLO_LINK_SWITCH_DISCONNECT &&
|
||||
wlan_vdev_mlme_is_mlo_link_switch_in_progress(cm_ctx->vdev)) {
|
||||
mlme_info(CM_PREFIX_FMT "Notfiy MLO MGR to abort link switch",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id));
|
||||
mlo_mgr_link_switch_disconnect_done(cm_ctx->vdev,
|
||||
QDF_STATUS_E_ABORTED);
|
||||
QDF_STATUS_E_ABORTED,
|
||||
false);
|
||||
break;
|
||||
|
||||
} else {
|
||||
mlme_info(CM_PREFIX_FMT "dropping disconnect req from source %d in INIT state",
|
||||
|
@@ -116,13 +116,24 @@ static bool cm_state_init_event(void *ctx, uint16_t event,
|
||||
cm_disconnect_complete(cm_ctx, data);
|
||||
break;
|
||||
case WLAN_CM_SM_EV_DISCONNECT_REQ:
|
||||
cm_handle_discon_req_in_non_connected_state(cm_ctx, data,
|
||||
WLAN_CM_S_INIT);
|
||||
status = cm_handle_discon_req_in_non_connected_state(cm_ctx, data,
|
||||
WLAN_CM_S_INIT);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
/*
|
||||
* Return not handled as this req need to be
|
||||
* dropped and return failure to the requester
|
||||
*/
|
||||
event_handled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return not handled as this req need to be dropped and return
|
||||
* failure to the requester
|
||||
* If status is success, then forcefully queue
|
||||
* disconnect req and move VDEV state to disconnecting.
|
||||
*/
|
||||
event_handled = false;
|
||||
cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
|
||||
cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_START,
|
||||
data_len, data);
|
||||
break;
|
||||
case WLAN_CM_SM_EV_ROAM_SYNC:
|
||||
/**
|
||||
|
@@ -640,7 +640,8 @@ cm_handle_disconnect_flush(struct cnx_mgr *cm_ctx, struct cm_req *cm_req)
|
||||
if (resp.req.cm_id & CM_ID_LSWITCH_BIT) {
|
||||
cm_reset_active_cm_id(cm_ctx->vdev, resp.req.cm_id);
|
||||
mlo_mgr_link_switch_disconnect_done(cm_ctx->vdev,
|
||||
QDF_STATUS_E_ABORTED);
|
||||
QDF_STATUS_E_ABORTED,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
|
Criar uma nova questão referindo esta
Bloquear um utilizador