qcacmn: Modify MLO disconnect handling

Modify MLO disconnect handling to issue disconnect on all links in
parallel
Also modify connect resp to accommodate ml info in connect resp

Change-Id: I57575c6ce7c8ebff7770f862dc81e7dfd20aa42d
This commit is contained in:
Himanshu Batra
2021-10-21 11:25:52 +05:30
committato da Madan Koyyalamudi
parent 7581cd6d12
commit b21d96305e
4 ha cambiato i file con 295 aggiunte e 214 eliminazioni

Vedi File

@@ -26,6 +26,7 @@
#include <wlan_cm_api.h>
#include <wlan_mlo_mgr_cmn.h>
#include <wlan_scan_api.h>
#include <scheduler_api.h>
#ifdef WLAN_FEATURE_11BE_MLO
/**
@@ -195,6 +196,29 @@ bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev)
return mlo_is_mld_disconnected(vdev);
}
static inline
void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
uint8_t i = 0;
if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev))
return;
for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
if (!mlo_dev_ctx->wlan_vdev_list[i])
continue;
wlan_vdev_mlme_feat_ext2_cap_clear(
mlo_dev_ctx->wlan_vdev_list[i],
WLAN_VDEV_FEXT2_MLO);
}
}
void ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev)
{
mlo_mld_clear_mlo_cap(vdev);
}
static void
mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev,
struct wlan_cm_connect_req *req)
@@ -500,39 +524,117 @@ mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx,
}
}
static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg)
{
struct wlan_objmgr_vdev *vdev = msg->bodyptr;
if (!vdev) {
mlme_err("Null input vdev");
return QDF_STATUS_E_INVAL;
}
mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
REASON_UNSPEC_FAILURE, NULL);
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg)
{
struct wlan_objmgr_vdev *vdev = msg->bodyptr;
if (!vdev) {
mlme_err("Null input vdev");
return QDF_STATUS_E_INVAL;
}
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
static inline
QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
{
return scheduler_post_message(
QDF_MODULE_ID_SYS,
QDF_MODULE_ID_SYS,
QDF_MODULE_ID_SYS,
msg);
}
#else
static inline
QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
{
return scheduler_post_message(
QDF_MODULE_ID_MLME,
QDF_MODULE_ID_MLME,
QDF_MODULE_ID_MLME,
msg);
}
#endif
static inline
void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev,
struct wlan_cm_connect_resp *rsp)
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
struct wlan_mlo_sta *sta_ctx = NULL;
struct scheduler_msg msg = {0};
QDF_STATUS ret;
if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
sta_ctx = mlo_dev_ctx->sta_ctx;
if (sta_ctx->orig_conn_req) {
mlo_free_connect_ies(
sta_ctx->orig_conn_req);
qdf_mem_free(sta_ctx->orig_conn_req);
sta_ctx->orig_conn_req = NULL;
}
} else {
mlo_update_connected_links(vdev, 0);
if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
rsp->reason == CM_HW_MODE_FAILURE ||
rsp->reason == CM_SER_FAILURE) {
ret = wlan_objmgr_vdev_try_get_ref(
vdev, WLAN_MLO_MGR_ID);
if (QDF_IS_STATUS_ERROR(ret)) {
mlo_err("Failed to get ref vdev_id %d",
wlan_vdev_get_id(vdev));
return;
}
/* Since these failures happen in same context. use
* scheduler to avoid deadlock by deferring context
*/
msg.bodyptr = vdev;
msg.callback = ml_activate_disconnect_req_sched_cb;
msg.flush_callback =
ml_activate_disconnect_req_flush_cb;
mlo_post_disconnect_msg(&msg);
if (QDF_IS_STATUS_ERROR(ret)) {
wlan_objmgr_vdev_release_ref(
vdev,
WLAN_MLO_MGR_ID);
return;
}
} else {
mlo_disconnect(vdev, CM_OSIF_DISCONNECT,
REASON_UNSPEC_FAILURE, NULL);
}
}
}
void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
struct wlan_cm_connect_resp *rsp)
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
struct wlan_mlo_sta *sta_ctx = NULL;
if (mlo_dev_ctx) {
mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev));
if (wlan_cm_is_vdev_disconnected(vdev)) {
// Connect Failure
if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
sta_ctx = mlo_dev_ctx->sta_ctx;
if (sta_ctx->orig_conn_req) {
mlo_free_connect_ies(
sta_ctx->orig_conn_req);
qdf_mem_free(sta_ctx->orig_conn_req);
sta_ctx->orig_conn_req = NULL;
}
return;
} else {
mlo_update_connected_links(vdev, 0);
if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
rsp->reason == CM_HW_MODE_FAILURE ||
rsp->reason == CM_SER_FAILURE)
mlo_disconnect_no_lock(
vdev, CM_OSIF_DISCONNECT,
REASON_UNSPEC_FAILURE, NULL);
else
mlo_disconnect(
vdev, CM_OSIF_DISCONNECT,
REASON_UNSPEC_FAILURE, NULL);
return;
}
mlo_handle_sta_link_connect_failure(vdev, rsp);
return;
} else if (!wlan_cm_is_vdev_connected(vdev)) {
/* If vdev is not in disconnected or connected state,
* then the event is received due to connect req being
@@ -569,32 +671,6 @@ void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev,
}
}
/*
* mlo_get_connected_link_vdev - API to get 1st connected link vdev
*
* @mlo_dev_ctx: mlo dev ctx
*
* Return: 1st connected link vdev in ML dev, NULL if none of the link vdev
* is connected
*/
static struct wlan_objmgr_vdev
*mlo_get_connected_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx)
{
uint8_t i = 0;
for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
if (!mlo_dev_ctx->wlan_vdev_list[i])
continue;
if ((mlo_dev_ctx->wlan_vdev_list[i] !=
mlo_get_assoc_link_vdev(mlo_dev_ctx)) &&
wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]))
return mlo_dev_ctx->wlan_vdev_list[i];
}
return NULL;
}
/**
* mlo_send_link_disconnect- Issue the disconnect request on MLD links
*
@@ -605,7 +681,6 @@ static struct wlan_objmgr_vdev
*
* Return: QDF_STATUS
*/
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
static QDF_STATUS
mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
enum wlan_cm_source source,
@@ -630,6 +705,16 @@ mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
return QDF_STATUS_SUCCESS;
}
/**
* mlo_send_link_disconnect- Issue sync the disconnect request on MLD links
*
* @mlo_dev_ctx: pointer to mlo dev context
* @source: disconnect source
* @reason_code: disconnect reason
* @bssid: bssid of AP to disconnect, can be null if not known
*
* Return: QDF_STATUS
*/
static QDF_STATUS
mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
enum wlan_cm_source source,
@@ -652,68 +737,6 @@ mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
source, reason_code);
return QDF_STATUS_SUCCESS;
}
#else
static QDF_STATUS
mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx,
enum wlan_cm_source source,
enum wlan_reason_code reason_code,
struct qdf_mac_addr *bssid)
{
uint8_t i = 0;
QDF_STATUS status = QDF_STATUS_E_ALREADY;
for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
if (!mlo_dev_ctx->wlan_vdev_list[i])
continue;
if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
if (wlan_cm_is_vdev_connecting(
mlo_dev_ctx->wlan_vdev_list[i]) ||
wlan_cm_is_vdev_disconnecting(
mlo_dev_ctx->wlan_vdev_list[i]) ||
wlan_cm_is_vdev_roaming(
mlo_dev_ctx->wlan_vdev_list[i])) {
wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
source, reason_code, NULL);
return QDF_STATUS_SUCCESS;
}
}
}
return status;
}
static QDF_STATUS
mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx,
enum wlan_cm_source source,
enum wlan_reason_code reason_code,
struct qdf_mac_addr *bssid)
{
uint8_t i = 0;
QDF_STATUS status = QDF_STATUS_E_ALREADY;
for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
if (!mlo_dev_ctx->wlan_vdev_list[i])
continue;
if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
if (wlan_cm_is_vdev_connecting(
mlo_dev_ctx->wlan_vdev_list[i]) ||
wlan_cm_is_vdev_disconnecting(
mlo_dev_ctx->wlan_vdev_list[i]) ||
wlan_cm_is_vdev_roaming(
mlo_dev_ctx->wlan_vdev_list[i])) {
wlan_cm_disconnect_sync(
mlo_dev_ctx->wlan_vdev_list[i],
source, reason_code);
return QDF_STATUS_SUCCESS;
}
}
}
return status;
}
#endif
static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
enum wlan_cm_source source,
@@ -721,7 +744,6 @@ static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
struct qdf_mac_addr *bssid)
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
struct wlan_objmgr_vdev *tmp_vdev = vdev;
struct wlan_mlo_sta *sta_ctx = NULL;
QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -744,22 +766,6 @@ static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev,
status = mlo_send_link_disconnect(mlo_dev_ctx, source,
reason_code, bssid);
if (QDF_IS_STATUS_SUCCESS(status))
return status;
tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
if (tmp_vdev) {
status = wlan_cm_disconnect(tmp_vdev, source,
reason_code, NULL);
return status;
}
tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
if (tmp_vdev) {
status = wlan_cm_disconnect(tmp_vdev, source,
reason_code, NULL);
return status;
}
}
return status;
@@ -770,11 +776,14 @@ QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
enum wlan_reason_code reason_code,
struct qdf_mac_addr *bssid)
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
struct wlan_objmgr_vdev *tmp_vdev = NULL;
struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
struct wlan_mlo_sta *sta_ctx = NULL;
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!vdev)
return QDF_STATUS_E_FAILURE;
mlo_dev_ctx = vdev->mlo_dev_ctx;
if (mlo_dev_ctx)
sta_ctx = mlo_dev_ctx->sta_ctx;
if (sta_ctx && sta_ctx->orig_conn_req) {
@@ -793,26 +802,6 @@ QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev,
status = mlo_send_link_disconnect(mlo_dev_ctx, source,
reason_code, bssid);
if (QDF_IS_STATUS_SUCCESS(status)) {
mlo_dev_lock_release(mlo_dev_ctx);
return status;
}
tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
if (tmp_vdev) {
status = wlan_cm_disconnect(tmp_vdev, source,
reason_code, NULL);
mlo_dev_lock_release(mlo_dev_ctx);
return status;
}
tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
if (tmp_vdev) {
status = wlan_cm_disconnect(tmp_vdev, source,
reason_code, NULL);
mlo_dev_lock_release(mlo_dev_ctx);
return status;
}
mlo_dev_lock_release(mlo_dev_ctx);
return status;
}
@@ -825,11 +814,14 @@ QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
enum wlan_reason_code reason_code,
struct qdf_mac_addr *bssid)
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
struct wlan_objmgr_vdev *tmp_vdev = NULL;
struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
struct wlan_mlo_sta *sta_ctx = NULL;
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!vdev)
return QDF_STATUS_E_FAILURE;
mlo_dev_ctx = vdev->mlo_dev_ctx;
if (mlo_dev_ctx)
sta_ctx = mlo_dev_ctx->sta_ctx;
if (sta_ctx && sta_ctx->orig_conn_req) {
@@ -848,21 +840,6 @@ QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev,
status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source,
reason_code, bssid);
if (QDF_IS_STATUS_SUCCESS(status))
return status;
tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx);
if (tmp_vdev) {
status = wlan_cm_disconnect_sync(tmp_vdev, source,
reason_code);
return status;
}
tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
if (tmp_vdev) {
status = wlan_cm_disconnect_sync(tmp_vdev, source,
reason_code);
return status;
}
return status;
}
return wlan_cm_disconnect_sync(vdev, source,
@@ -911,42 +888,120 @@ void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
static
void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx,
struct wlan_cm_discon_rsp *resp)
{ }
#endif
static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg)
{
struct wlan_objmgr_vdev *assoc_vdev = NULL;
enum wlan_cm_source source;
enum wlan_reason_code reason_code;
struct wlan_objmgr_vdev *vdev = msg->bodyptr;
struct wlan_mlo_dev_context *mlo_dev_ctx = NULL;
struct wlan_mlo_sta *sta_ctx = NULL;
if (!vdev) {
mlme_err("Null input vdev");
return QDF_STATUS_E_INVAL;
}
mlo_dev_ctx = vdev->mlo_dev_ctx;
if (!mlo_dev_ctx) {
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
return QDF_STATUS_E_INVAL;
}
sta_ctx = mlo_dev_ctx->sta_ctx;
if (!sta_ctx) {
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
return QDF_STATUS_E_INVAL;
}
mlo_connect(vdev, sta_ctx->connect_req);
mlo_free_connect_ies(sta_ctx->connect_req);
qdf_mem_free(sta_ctx->connect_req);
sta_ctx->connect_req = NULL;
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
return QDF_STATUS_SUCCESS;
}
static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg)
{
struct wlan_objmgr_vdev *vdev = msg->bodyptr;
if (!vdev) {
mlme_err("Null input vdev");
return QDF_STATUS_E_INVAL;
}
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID);
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
static inline
void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
{ }
#else
static inline
void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev)
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
struct wlan_objmgr_vdev *tmp_vdev;
struct scheduler_msg msg = {0};
QDF_STATUS ret;
struct wlan_mlo_sta *sta_ctx = NULL;
uint8_t i = 0;
struct mlo_partner_info partner_info;
struct mlo_link_info partner_link_info;
mlo_dev_lock_acquire(mlo_dev_ctx);
for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
if (!mlo_dev_ctx->wlan_vdev_list[i])
continue;
sta_ctx = mlo_dev_ctx->sta_ctx;
ret = wlan_objmgr_vdev_try_get_ref(
vdev,
WLAN_MLO_MGR_ID);
if (QDF_IS_STATUS_ERROR(ret)) {
mlo_free_connect_ies(sta_ctx->connect_req);
qdf_mem_free(sta_ctx->connect_req);
sta_ctx->connect_req = NULL;
return;
}
msg.bodyptr = vdev;
msg.callback = ml_activate_connect_req_sched_cb;
msg.flush_callback = ml_activate_connect_req_flush_cb;
if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) {
if (wlan_cm_is_vdev_connected(
mlo_dev_ctx->wlan_vdev_list[i])) {
if (wlan_vdev_mlme_is_mlo_link_vdev(
mlo_dev_ctx->wlan_vdev_list[i])) {
source = resp->req.req.source;
reason_code = resp->req.req.reason_code;
wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i],
source, reason_code, NULL);
mlo_dev_lock_release(mlo_dev_ctx);
return;
}
ret = scheduler_post_message(QDF_MODULE_ID_MLME,
QDF_MODULE_ID_MLME,
QDF_MODULE_ID_MLME, &msg);
if (QDF_IS_STATUS_ERROR(ret)) {
mlo_free_connect_ies(sta_ctx->connect_req);
qdf_mem_free(sta_ctx->connect_req);
sta_ctx->connect_req = NULL;
wlan_objmgr_vdev_release_ref(vdev,
WLAN_MLO_MGR_ID);
return;
}
if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) {
partner_info = sta_ctx->connect_req->ml_parnter_info;
wlan_vdev_mlme_feat_ext2_cap_set(vdev, WLAN_VDEV_FEXT2_MLO);
mlo_clear_connect_req_links_bmap(vdev);
mlo_update_connect_req_links(vdev, 1);
for (i = 0; i < partner_info.num_partner_links; i++) {
partner_link_info = partner_info.partner_link_info[i];
tmp_vdev = mlo_get_ml_vdev_by_mac(
vdev,
&partner_link_info.link_addr);
if (tmp_vdev) {
mlo_update_connect_req_links(tmp_vdev, 1);
wlan_vdev_mlme_feat_ext2_cap_set(
tmp_vdev, WLAN_VDEV_FEXT2_MLO);
wlan_vdev_mlme_feat_ext2_cap_set(
tmp_vdev,
WLAN_VDEV_FEXT2_MLO_STA_LINK);
wlan_vdev_set_link_id(
tmp_vdev,
partner_link_info.link_id);
}
}
}
assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
if (assoc_vdev && wlan_cm_is_vdev_connected(assoc_vdev)) {
source = resp->req.req.source;
reason_code = resp->req.req.reason_code;
wlan_cm_disconnect(assoc_vdev,
source, reason_code, NULL);
mlo_dev_lock_release(mlo_dev_ctx);
return;
}
mlo_dev_lock_release(mlo_dev_ctx);
}
#endif
@@ -955,6 +1010,7 @@ void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev,
{
struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
struct wlan_mlo_sta *sta_ctx = NULL;
struct wlan_objmgr_vdev *assoc_vdev = NULL;
if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev)))
return;
@@ -967,15 +1023,11 @@ void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev,
return;
mlo_update_connected_links(vdev, 0);
if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
if (mlo_is_mld_disconnected(vdev)) {
if (sta_ctx->connect_req) {
mlo_connect(mlo_get_assoc_link_vdev(mlo_dev_ctx),
sta_ctx->connect_req);
mlo_free_connect_ies(sta_ctx->connect_req);
qdf_mem_free(sta_ctx->connect_req);
sta_ctx->connect_req = NULL;
assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
mlo_sta_link_handle_pending_connect(assoc_vdev);
}
return;
}
mlo_handle_disconnect_resp(mlo_dev_ctx, resp);