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
このコミットが含まれているのは:
@@ -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
|
* cleaning up the active connect request and thus only
|
||||||
* remove the pending connect.
|
* remove the pending connect.
|
||||||
*/
|
*/
|
||||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX);
|
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX, false);
|
||||||
break;
|
break;
|
||||||
case WLAN_CM_S_DISCONNECTING:
|
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 case of disconnecting state, there could be 2 scenarios:-
|
||||||
* In both case no state specific action is required.
|
* In both case no state specific action is required.
|
||||||
|
@@ -389,9 +389,16 @@ QDF_STATUS cm_disconnect_complete(struct cnx_mgr *cm_ctx,
|
|||||||
* complete.
|
* complete.
|
||||||
*/
|
*/
|
||||||
if (resp->req.cm_id == cm_ctx->active_cm_id)
|
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);
|
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;
|
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,
|
mlme_cm_osif_update_id_and_src(cm_ctx->vdev,
|
||||||
CM_SOURCE_INVALID,
|
CM_SOURCE_INVALID,
|
||||||
CM_ID_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;
|
break;
|
||||||
case WLAN_CM_SS_JOIN_ACTIVE:
|
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
|
* disconnect requests pending, so flush all the requests except
|
||||||
* the activated request.
|
* the activated request.
|
||||||
*/
|
*/
|
||||||
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX);
|
cm_flush_pending_request(cm_ctx, CONNECT_REQ_PREFIX, false);
|
||||||
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX);
|
cm_flush_pending_request(cm_ctx, DISCONNECT_REQ_PREFIX, false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mlme_err("Vdev %d disconnect req in invalid state %d",
|
mlme_err("Vdev %d disconnect req in invalid state %d",
|
||||||
|
@@ -131,12 +131,16 @@ struct cm_disconnect_req {
|
|||||||
* struct cm_req - connect manager req
|
* struct cm_req - connect manager req
|
||||||
* @node: connection manager req node
|
* @node: connection manager req node
|
||||||
* @cm_id: cm id
|
* @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
|
* @connect_req: connect req
|
||||||
* @disconnect_req: disconnect req
|
* @disconnect_req: disconnect req
|
||||||
*/
|
*/
|
||||||
struct cm_req {
|
struct cm_req {
|
||||||
qdf_list_node_t node;
|
qdf_list_node_t node;
|
||||||
wlan_cm_id cm_id;
|
wlan_cm_id cm_id;
|
||||||
|
bool failed_req;
|
||||||
union {
|
union {
|
||||||
struct cm_connect_req connect_req;
|
struct cm_connect_req connect_req;
|
||||||
struct cm_disconnect_req discon_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_flush_pending_request() - Flush all pending requests matching flush prefix
|
||||||
* @cm_ctx: connection manager context
|
* @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.
|
* Context: Can be called from any context.
|
||||||
*
|
*
|
||||||
* Return: void
|
* 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
|
* 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;
|
struct cnx_mgr *cm_ctx = ctx;
|
||||||
bool event_handled;
|
bool event_handled;
|
||||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
struct wlan_cm_connect_rsp *resp;
|
||||||
|
struct cm_req *cm_req;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case WLAN_CM_SM_EV_CONNECT_REQ:
|
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;
|
event_handled = false;
|
||||||
break;
|
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_transition_to(cm_ctx, WLAN_CM_S_INIT);
|
||||||
cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
|
cm_sm_deliver_event_sync(cm_ctx, event, data_len, data);
|
||||||
event_handled = true;
|
event_handled = true;
|
||||||
|
@@ -462,11 +462,12 @@ static void cm_remove_cmd_from_serialization(struct cnx_mgr *cm_ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
qdf_list_node_t *cur_node = NULL, *next_node = NULL;
|
||||||
struct cm_req *cm_req;
|
struct cm_req *cm_req;
|
||||||
uint32_t prefix;
|
uint32_t req_prefix;
|
||||||
|
|
||||||
cm_req_lock_acquire(cm_ctx);
|
cm_req_lock_acquire(cm_ctx);
|
||||||
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
|
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);
|
qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
|
||||||
cm_req = qdf_container_of(cur_node, struct cm_req, 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 */
|
/* Only remove the pending requests matching the flush prefix */
|
||||||
if (prefix != flush_prefix ||
|
if (req_prefix != prefix ||
|
||||||
cm_req->cm_id == cm_ctx->active_cm_id) {
|
cm_req->cm_id == cm_ctx->active_cm_id)
|
||||||
cur_node = next_node;
|
goto next;
|
||||||
next_node = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_handle_connect_flush(cm_ctx, cm_req);
|
||||||
cm_ctx->connect_count--;
|
cm_ctx->connect_count--;
|
||||||
cm_free_connect_req_mem(&cm_req->connect_req);
|
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);
|
cm_remove_cmd_from_serialization(cm_ctx, cm_req->cm_id);
|
||||||
qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
|
qdf_list_remove_node(&cm_ctx->req_list, &cm_req->node);
|
||||||
qdf_mem_free(cm_req);
|
qdf_mem_free(cm_req);
|
||||||
|
next:
|
||||||
cur_node = next_node;
|
cur_node = next_node;
|
||||||
next_node = NULL;
|
next_node = NULL;
|
||||||
}
|
}
|
||||||
|
新しいイシューから参照
ユーザーをブロックする