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:
gaurank kathpalia
2020-10-21 16:27:44 +05:30
gecommit door snandini
bovenliggende 4ded73bfcf
commit 55929f5239
6 gewijzigde bestanden met toevoegingen van 73 en 18 verwijderingen

Bestand weergeven

@@ -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.

Bestand weergeven

@@ -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",

Bestand weergeven

@@ -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;

Bestand weergeven

@@ -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

Bestand weergeven

@@ -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;

Bestand weergeven

@@ -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;
}