qcacmn: Avoid moving the SM to INIT state if disconnect is pending
If a connect req fails before serialization, with a disconnect req Already queued. Indicating the failed connect req and moving the SM to INIT state will lead to a invalid disconnected state Even when, disconnect is in progress. Thus in this case wait for disconnect to complete before indicating connect failure and moving SM to INIT state. Change-Id: Ib25ed43276410cd3e1bb717f64742d691bb17568 CRs-Fixed: 2802137
This commit is contained in:

gecommit door
snandini

bovenliggende
4ded73bfcf
commit
55929f5239
@@ -920,9 +920,16 @@ cm_handle_connect_req_in_non_init_state(struct cnx_mgr *cm_ctx,
|
||||
* cleaning up the active connect request and thus only
|
||||
* remove the pending connect.
|
||||
*/
|
||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX);
|
||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX, false);
|
||||
break;
|
||||
case WLAN_CM_S_DISCONNECTING:
|
||||
/*
|
||||
* Flush failed pending connect req as new req is received
|
||||
* and its no longer the latest one.
|
||||
*/
|
||||
if (cm_ctx->connect_count)
|
||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX,
|
||||
true);
|
||||
/*
|
||||
* In case of disconnecting state, there could be 2 scenarios:-
|
||||
* In both case no state specific action is required.
|
||||
|
@@ -389,9 +389,16 @@ QDF_STATUS cm_disconnect_complete(struct cnx_mgr *cm_ctx,
|
||||
* complete.
|
||||
*/
|
||||
if (resp->req.cm_id == cm_ctx->active_cm_id)
|
||||
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX);
|
||||
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX, false);
|
||||
|
||||
cm_remove_cmd(cm_ctx, resp->req.cm_id);
|
||||
mlme_debug(CM_PREFIX_FMT "disconnect count %d connect count %d",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
|
||||
resp->req.cm_id),
|
||||
cm_ctx->disconnect_count, cm_ctx->connect_count);
|
||||
/* Flush failed connect req as pending disconnect is completed */
|
||||
if (!cm_ctx->disconnect_count && cm_ctx->connect_count)
|
||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX, true);
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -429,7 +436,14 @@ cm_handle_discon_req_in_non_connected_state(struct cnx_mgr *cm_ctx,
|
||||
mlme_cm_osif_update_id_and_src(cm_ctx->vdev,
|
||||
CM_SOURCE_INVALID,
|
||||
CM_ID_INVALID);
|
||||
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX);
|
||||
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX, false);
|
||||
/*
|
||||
* Flush failed pending connect req as new req is received
|
||||
* and its no longer the latest one.
|
||||
*/
|
||||
if (cm_ctx->connect_count)
|
||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX,
|
||||
true);
|
||||
break;
|
||||
case WLAN_CM_SS_JOIN_ACTIVE:
|
||||
/*
|
||||
@@ -462,8 +476,8 @@ cm_handle_discon_req_in_non_connected_state(struct cnx_mgr *cm_ctx,
|
||||
* disconnect requests pending, so flush all the requests except
|
||||
* the activated request.
|
||||
*/
|
||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX);
|
||||
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX);
|
||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX, false);
|
||||
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX, false);
|
||||
break;
|
||||
default:
|
||||
mlme_err("Vdev %d disconnect req in invalid state %d",
|
||||
|
@@ -131,12 +131,16 @@ struct cm_disconnect_req {
|
||||
* struct cm_req - connect manager req
|
||||
* @node: connection manager req node
|
||||
* @cm_id: cm id
|
||||
* @failed_req: set if req failed before serialization,
|
||||
* with a commands pending before it, ie this is the latest command which failed
|
||||
* but still some operation(req) is pending.
|
||||
* @connect_req: connect req
|
||||
* @disconnect_req: disconnect req
|
||||
*/
|
||||
struct cm_req {
|
||||
qdf_list_node_t node;
|
||||
wlan_cm_id cm_id;
|
||||
bool failed_req;
|
||||
union {
|
||||
struct cm_connect_req connect_req;
|
||||
struct cm_disconnect_req discon_req;
|
||||
|
@@ -617,13 +617,15 @@ bool cm_is_cm_id_current_candidate_single_pmk(struct cnx_mgr *cm_ctx,
|
||||
/**
|
||||
* cm_flush_pending_request() - Flush all pending requests matching flush prefix
|
||||
* @cm_ctx: connection manager context
|
||||
* @flush_prefix: prefix for the type of command to flush
|
||||
* @prefix: prefix for the type of command to flush
|
||||
* @only_failed_req: flush only the failed pending req
|
||||
*
|
||||
* Context: Can be called from any context.
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t flush_prefix);
|
||||
void cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix,
|
||||
bool only_failed_req);
|
||||
|
||||
/**
|
||||
* cm_remove_cmd() - Remove cmd from req list and serialization
|
||||
|
@@ -422,6 +422,8 @@ static bool cm_subst_join_pending_event(void *ctx, uint16_t event,
|
||||
struct cnx_mgr *cm_ctx = ctx;
|
||||
bool event_handled;
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
struct wlan_cm_connect_rsp *resp;
|
||||
struct cm_req *cm_req;
|
||||
|
||||
switch (event) {
|
||||
case WLAN_CM_SM_EV_CONNECT_REQ:
|
||||
@@ -480,6 +482,30 @@ static bool cm_subst_join_pending_event(void *ctx, uint16_t event,
|
||||
event_handled = false;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* On connect req failure (before serialization), if there is a
|
||||
* pending disconnect req then move to disconnecting state and
|
||||
* wait for disconnect to complete before moving to INIT state.
|
||||
* Else directly transition to INIT state.
|
||||
*
|
||||
* On disconnect completion or a new connect/disconnect req in
|
||||
* disconnnecting state, the failed connect req will be flushed.
|
||||
* This will ensure SM moves to INIT state after completion of
|
||||
* all operation.
|
||||
*/
|
||||
if (cm_ctx->disconnect_count) {
|
||||
resp = data;
|
||||
|
||||
mlme_debug(CM_PREFIX_FMT "disconnect_count %d",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev),
|
||||
resp->cm_id),
|
||||
cm_ctx->disconnect_count);
|
||||
cm_req = cm_get_req_by_cm_id(cm_ctx, resp->cm_id);
|
||||
cm_req->failed_req = true;
|
||||
cm_sm_transition_to(cm_ctx, WLAN_CM_S_DISCONNECTING);
|
||||
event_handled = true;
|
||||
break;
|
||||
}
|
||||
cm_sm_transition_to(cm_ctx, WLAN_CM_S_INIT);
|
||||
cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
|
||||
event_handled = true;
|
||||
|
@@ -462,11 +462,12 @@ static void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx,
|
||||
}
|
||||
|
||||
void
|
||||
cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t flush_prefix)
|
||||
cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t prefix,
|
||||
bool only_failed_req)
|
||||
{
|
||||
qdf_list_node_t *cur_node = NULL, *next_node = NULL;
|
||||
struct cm_req *cm_req;
|
||||
uint32_t prefix;
|
||||
uint32_t req_prefix;
|
||||
|
||||
cm_req_lock_acquire(cm_ctx);
|
||||
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
|
||||
@@ -474,17 +475,18 @@ cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t flush_prefix)
|
||||
qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
|
||||
cm_req = qdf_container_of(cur_node, struct cm_req, node);
|
||||
|
||||
prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
|
||||
req_prefix = CM_ID_GET_PREFIX(cm_req->cm_id);
|
||||
|
||||
/* Only remove the pending requests matching the flush prefix */
|
||||
if (prefix != flush_prefix ||
|
||||
cm_req->cm_id == cm_ctx->active_cm_id) {
|
||||
cur_node = next_node;
|
||||
next_node = NULL;
|
||||
continue;
|
||||
}
|
||||
if (req_prefix != prefix ||
|
||||
cm_req->cm_id == cm_ctx->active_cm_id)
|
||||
goto next;
|
||||
|
||||
if (prefix == CONNECT_REQ_PREFIX) {
|
||||
/* If only_failed_req is set flush only failed req */
|
||||
if (only_failed_req && !cm_req->failed_req)
|
||||
goto next;
|
||||
|
||||
if (req_prefix == CONNECT_REQ_PREFIX) {
|
||||
cm_handle_connect_flush(cm_ctx, cm_req);
|
||||
cm_ctx->connect_count--;
|
||||
cm_free_connect_req_mem(&cm_req->connect_req);
|
||||
@@ -498,7 +500,7 @@ cm_flush_pending_request(struct cnx_mgr *cm_ctx, uint32_t flush_prefix)
|
||||
cm_remove_cmd_from_serialization(cm_ctx, cm_req->cm_id);
|
||||
qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
|
||||
qdf_mem_free(cm_req);
|
||||
|
||||
next:
|
||||
cur_node = next_node;
|
||||
next_node = NULL;
|
||||
}
|
||||
|
Verwijs in nieuw issue
Block a user