qcacmn: Add reassoc changes related to host roaming
Support reassoc request for host roaming Change-Id: Iacb2950e314561c22ed1900de6522dd192cda12e CRs-Fixed: 2845076
This commit is contained in:
866
umac/mlme/connection_mgr/core/src/wlan_cm_host_roam.c
Normal file
866
umac/mlme/connection_mgr/core/src/wlan_cm_host_roam.c
Normal file
@@ -0,0 +1,866 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "wlan_cm_main.h"
|
||||
#include "wlan_cm_roam_sm.h"
|
||||
#include "wlan_cm_sm.h"
|
||||
#include <wlan_mlme_cmn.h>
|
||||
#include "wlan_cm_main_api.h"
|
||||
#include <wlan_scan_api.h>
|
||||
#include <wlan_serialization_api.h>
|
||||
#include <wlan_utility.h>
|
||||
#include <wlan_cm_api.h>
|
||||
|
||||
static void
|
||||
cm_fill_roam_fail_resp_from_cm_id(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp,
|
||||
wlan_cm_id cm_id,
|
||||
enum wlan_cm_connect_fail_reason reason)
|
||||
{
|
||||
resp->reassoc_status = QDF_STATUS_E_FAILURE;
|
||||
resp->cm_id = cm_id;
|
||||
resp->vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
resp->reason = reason;
|
||||
cm_fill_bss_info_in_roam_rsp_by_cm_id(cm_ctx, cm_id, resp);
|
||||
}
|
||||
|
||||
static QDF_STATUS
|
||||
cm_reassoc_fail_disconnect(struct wlan_objmgr_vdev *vdev,
|
||||
enum wlan_cm_source source,
|
||||
enum wlan_reason_code reason_code,
|
||||
struct qdf_mac_addr *bssid)
|
||||
{
|
||||
struct cnx_mgr *cm_ctx;
|
||||
struct cm_req *cm_req;
|
||||
struct cm_disconnect_req *disconnect_req;
|
||||
struct wlan_cm_disconnect_req req = {0};
|
||||
QDF_STATUS status;
|
||||
|
||||
cm_ctx = cm_get_cm_ctx(vdev);
|
||||
if (!cm_ctx)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
/*
|
||||
* This would be freed as part of removal from cm req list if adding
|
||||
* to list is success after posting WLAN_CM_SM_EV_DISCONNECT_REQ.
|
||||
*/
|
||||
cm_req = qdf_mem_malloc(sizeof(*cm_req));
|
||||
|
||||
if (!cm_req)
|
||||
return QDF_STATUS_E_NOMEM;
|
||||
|
||||
req.vdev_id = wlan_vdev_get_id(vdev);
|
||||
req.source = source;
|
||||
req.reason_code = reason_code;
|
||||
if (bssid)
|
||||
qdf_copy_macaddr(&req.bssid, bssid);
|
||||
|
||||
disconnect_req = &cm_req->discon_req;
|
||||
disconnect_req->req = req;
|
||||
|
||||
status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_DISCONNECT_REQ,
|
||||
sizeof(*disconnect_req),
|
||||
disconnect_req);
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
qdf_mem_free(cm_req);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS
|
||||
cm_send_reassoc_start_fail(struct cnx_mgr *cm_ctx,
|
||||
wlan_cm_id cm_id,
|
||||
enum wlan_cm_connect_fail_reason reason)
|
||||
{
|
||||
struct wlan_cm_roam_resp *resp;
|
||||
QDF_STATUS status;
|
||||
|
||||
resp = qdf_mem_malloc(sizeof(*resp));
|
||||
if (!resp)
|
||||
return QDF_STATUS_E_NOMEM;
|
||||
|
||||
cm_fill_roam_fail_resp_from_cm_id(cm_ctx, resp, cm_id, reason);
|
||||
status = cm_sm_deliver_event(cm_ctx->vdev,
|
||||
WLAN_CM_SM_EV_REASSOC_FAILURE,
|
||||
sizeof(*resp), resp);
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
cm_reassoc_complete(cm_ctx, resp);
|
||||
|
||||
qdf_mem_free(resp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void cm_connect_prepare_scan_filter_for_roam(
|
||||
struct wlan_objmgr_pdev *pdev,
|
||||
struct cnx_mgr *cm_ctx, struct cm_roam_req *cm_req,
|
||||
struct scan_filter *filter, bool security_valid_for_6ghz)
|
||||
{
|
||||
uint16_t rsn_caps;
|
||||
struct wlan_objmgr_vdev *vdev = cm_ctx->vdev;
|
||||
|
||||
if (!qdf_is_macaddr_zero(&cm_req->req.bssid)) {
|
||||
filter->num_of_bssid = 1;
|
||||
qdf_copy_macaddr(&filter->bssid_list[0], &cm_req->req.bssid);
|
||||
}
|
||||
|
||||
filter->num_of_ssid = 1;
|
||||
wlan_vdev_mlme_get_ssid(vdev, filter->ssid_list[0].ssid,
|
||||
&filter->ssid_list[0].length);
|
||||
|
||||
if (cm_req->req.chan_freq) {
|
||||
filter->num_of_channels = 1;
|
||||
filter->chan_freq_list[0] = cm_req->req.chan_freq;
|
||||
}
|
||||
|
||||
/* Security is not valid for 6Ghz so ignore 6Ghz APs */
|
||||
if (!security_valid_for_6ghz)
|
||||
filter->ignore_6ghz_channel = true;
|
||||
|
||||
filter->authmodeset =
|
||||
wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_AUTH_MODE);
|
||||
|
||||
filter->ucastcipherset =
|
||||
wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER);
|
||||
|
||||
filter->mcastcipherset =
|
||||
wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MCAST_CIPHER);
|
||||
|
||||
filter->key_mgmt =
|
||||
wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT);
|
||||
|
||||
filter->mgmtcipherset =
|
||||
wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MGMT_CIPHER);
|
||||
|
||||
if (!QDF_HAS_PARAM(filter->authmodeset, WLAN_CRYPTO_AUTH_WAPI) &&
|
||||
!QDF_HAS_PARAM(filter->authmodeset, WLAN_CRYPTO_AUTH_RSNA) &&
|
||||
!QDF_HAS_PARAM(filter->authmodeset, WLAN_CRYPTO_AUTH_WPA)) {
|
||||
filter->ignore_auth_enc_type = 1;
|
||||
}
|
||||
|
||||
rsn_caps =
|
||||
wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_RSN_CAP);
|
||||
|
||||
if (rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)
|
||||
filter->pmf_cap = WLAN_PMF_REQUIRED;
|
||||
else if (rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)
|
||||
filter->pmf_cap = WLAN_PMF_CAPABLE;
|
||||
else
|
||||
filter->pmf_cap = WLAN_PMF_DISABLED;
|
||||
}
|
||||
|
||||
QDF_STATUS cm_roam_get_candidates(
|
||||
struct wlan_objmgr_pdev *pdev,
|
||||
struct cnx_mgr *cm_ctx,
|
||||
struct cm_roam_req *cm_req)
|
||||
{
|
||||
struct scan_filter *filter;
|
||||
uint32_t num_bss = 0;
|
||||
enum QDF_OPMODE op_mode;
|
||||
qdf_list_t *candidate_list;
|
||||
uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
qdf_list_node_t *cur_node = NULL;
|
||||
bool security_valid_for_6ghz = true;
|
||||
|
||||
filter = qdf_mem_malloc(sizeof(*filter));
|
||||
if (!filter)
|
||||
return QDF_STATUS_E_NOMEM;
|
||||
|
||||
cm_connect_prepare_scan_filter_for_roam(pdev, cm_ctx, cm_req, filter,
|
||||
security_valid_for_6ghz);
|
||||
|
||||
candidate_list = wlan_scan_get_result(pdev, filter);
|
||||
if (candidate_list) {
|
||||
num_bss = qdf_list_size(candidate_list);
|
||||
mlme_debug(CM_PREFIX_FMT "num_entries found %d",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
|
||||
}
|
||||
|
||||
op_mode = wlan_vdev_mlme_get_opmode(cm_ctx->vdev);
|
||||
if (num_bss && op_mode == QDF_STA_MODE)
|
||||
cm_calculate_scores(pdev, filter, candidate_list);
|
||||
|
||||
qdf_mem_free(filter);
|
||||
|
||||
if (!candidate_list || !qdf_list_size(candidate_list)) {
|
||||
if (candidate_list)
|
||||
wlan_scan_purge_results(candidate_list);
|
||||
|
||||
mlme_info(CM_PREFIX_FMT "no valid candidate found, num_bss %d",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id), num_bss);
|
||||
cm_req->candidate_list = NULL;
|
||||
return QDF_STATUS_E_EMPTY;
|
||||
}
|
||||
|
||||
qdf_list_peek_front(candidate_list, &cur_node);
|
||||
cm_req->candidate_list = candidate_list;
|
||||
cm_req->cur_candidate = qdf_container_of(cur_node,
|
||||
struct scan_cache_node,
|
||||
node);
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS cm_start_roam_req(struct cnx_mgr *cm_ctx,
|
||||
struct cm_req *cm_req)
|
||||
{
|
||||
cm_req->roam_req.cm_id =
|
||||
cm_get_cm_id(cm_ctx, cm_req->roam_req.req.source);
|
||||
cm_req->cm_id = cm_req->roam_req.cm_id;
|
||||
cm_req->roam_req.req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
cm_add_req_to_list_and_indicate_osif(cm_ctx, cm_req,
|
||||
cm_req->roam_req.req.source);
|
||||
|
||||
cm_sm_transition_to(cm_ctx, WLAN_CM_SS_PREAUTH);
|
||||
|
||||
return cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_ROAM_START,
|
||||
sizeof(*cm_req), cm_req);
|
||||
}
|
||||
|
||||
QDF_STATUS cm_host_roam_start_req(struct cnx_mgr *cm_ctx,
|
||||
struct cm_req *cm_req)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
struct wlan_objmgr_pdev *pdev;
|
||||
enum wlan_cm_connect_fail_reason reason = CM_GENERIC_FAILURE;
|
||||
uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
|
||||
mlme_cm_roam_start_ind(cm_ctx->vdev, &cm_req->roam_req.req);
|
||||
|
||||
pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
|
||||
if (!pdev) {
|
||||
mlme_err(CM_PREFIX_FMT "Failed to find pdev",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id));
|
||||
reason = CM_GENERIC_FAILURE;
|
||||
goto roam_err;
|
||||
}
|
||||
|
||||
status = cm_roam_get_candidates(pdev, cm_ctx,
|
||||
&cm_req->roam_req);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
reason = CM_NO_CANDIDATE_FOUND;
|
||||
goto roam_err;
|
||||
}
|
||||
|
||||
status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_START_REASSOC,
|
||||
sizeof(cm_req->roam_req),
|
||||
&cm_req->roam_req);
|
||||
if (QDF_IS_STATUS_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
roam_err:
|
||||
return cm_send_reassoc_start_fail(cm_ctx, cm_req->cm_id, reason);
|
||||
}
|
||||
|
||||
bool cm_roam_resp_cmid_match_list_head(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{
|
||||
return cm_check_cmid_match_list_head(cm_ctx, &resp->cm_id);
|
||||
}
|
||||
|
||||
static QDF_STATUS
|
||||
cm_inform_if_mgr_reassoc_complete(struct wlan_objmgr_vdev *vdev,
|
||||
QDF_STATUS status)
|
||||
{
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static inline QDF_STATUS
|
||||
cm_inform_blm_reassoc_complete(struct wlan_objmgr_vdev *vdev,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS cm_reassoc_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
|
||||
{
|
||||
struct cm_req *cm_req;
|
||||
struct wlan_cm_vdev_discon_req req;
|
||||
|
||||
cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
|
||||
if (!cm_req)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
cm_ctx->active_cm_id = *cm_id;
|
||||
qdf_mem_zero(&req, sizeof(req));
|
||||
req.cm_id = *cm_id;
|
||||
req.req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
req.req.source = CM_ROAM_DISCONNECT;
|
||||
wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &req.req.bssid);
|
||||
|
||||
return mlme_cm_disconnect_req(cm_ctx->vdev, &req);
|
||||
}
|
||||
|
||||
QDF_STATUS cm_reassoc_disconnect_complete(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_discon_rsp *resp)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
struct cm_req *cm_req;
|
||||
struct qdf_mac_addr *bssid;
|
||||
struct cm_disconnect_req discon_req;
|
||||
uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
wlan_cm_id cm_id = cm_ctx->active_cm_id;
|
||||
|
||||
cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id);
|
||||
if (!cm_req)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
qdf_mem_zero(&discon_req, sizeof(discon_req));
|
||||
|
||||
discon_req.cm_id = cm_id;
|
||||
discon_req.req.vdev_id = vdev_id;
|
||||
qdf_copy_macaddr(&discon_req.req.bssid,
|
||||
&resp->req.req.bssid);
|
||||
cm_update_scan_mlme_on_disconnect(cm_ctx->vdev, &discon_req);
|
||||
mlme_cm_disconnect_complete_ind(cm_ctx->vdev, resp);
|
||||
|
||||
bssid = &cm_req->roam_req.cur_candidate->entry->bssid;
|
||||
status = mlme_cm_bss_peer_create_req(cm_ctx->vdev, bssid);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err(CM_PREFIX_FMT "Peer create request failed",
|
||||
CM_PREFIX_REF(vdev_id, cm_id));
|
||||
status = cm_send_reassoc_start_fail(cm_ctx, cm_id,
|
||||
CM_PEER_CREATE_FAILED);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS
|
||||
cm_resume_reassoc_after_peer_create(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id)
|
||||
{
|
||||
struct wlan_cm_vdev_reassoc_req req;
|
||||
struct cm_req *cm_req;
|
||||
QDF_STATUS status;
|
||||
|
||||
cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id);
|
||||
if (!cm_req)
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
|
||||
req.vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
req.cm_id = *cm_id;
|
||||
req.bss = cm_req->roam_req.cur_candidate;
|
||||
|
||||
status = mlme_cm_reassoc_req(cm_ctx->vdev, &req);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err(CM_PREFIX_FMT "Reassoc request failed",
|
||||
CM_PREFIX_REF(req.vdev_id, req.cm_id));
|
||||
mlme_cm_bss_peer_delete_req(cm_ctx->vdev);
|
||||
status = cm_send_reassoc_start_fail(cm_ctx, *cm_id,
|
||||
CM_JOIN_FAILED);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
cm_update_scan_db_on_reassoc_success(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{
|
||||
struct element_info *bcn_probe_rsp;
|
||||
struct cm_req *cm_req;
|
||||
int32_t rssi;
|
||||
|
||||
if (!cm_is_vdev_connected(cm_ctx->vdev))
|
||||
return;
|
||||
|
||||
cm_req = cm_get_req_by_cm_id(cm_ctx, resp->cm_id);
|
||||
if (!cm_req)
|
||||
return;
|
||||
|
||||
if (!cm_req->roam_req.cur_candidate)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Get beacon or probe resp from connect response, and if not present
|
||||
* use cur candidate to get beacon or probe resp
|
||||
*/
|
||||
if (resp->connect_ies.bcn_probe_rsp.ptr)
|
||||
bcn_probe_rsp = &resp->connect_ies.bcn_probe_rsp;
|
||||
else
|
||||
bcn_probe_rsp =
|
||||
&cm_req->roam_req.cur_candidate->entry->raw_frame;
|
||||
|
||||
rssi = cm_req->roam_req.cur_candidate->entry->rssi_raw;
|
||||
|
||||
cm_inform_bcn_probe(cm_ctx, bcn_probe_rsp->ptr, bcn_probe_rsp->len,
|
||||
resp->freq, rssi, resp->cm_id);
|
||||
}
|
||||
|
||||
inline void cm_set_fils_wep_key_on_reassoc(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{
|
||||
}
|
||||
|
||||
QDF_STATUS cm_reassoc_complete(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{
|
||||
enum wlan_cm_sm_state sm_state;
|
||||
struct bss_info bss_info;
|
||||
struct mlme_info mlme_info;
|
||||
struct wlan_objmgr_vdev *vdev = cm_ctx->vdev;
|
||||
|
||||
/*
|
||||
* If the entry is not present in the list, it must have been cleared
|
||||
* already.
|
||||
*/
|
||||
if (!cm_get_req_by_cm_id(cm_ctx, resp->cm_id))
|
||||
return QDF_STATUS_SUCCESS;
|
||||
|
||||
sm_state = cm_get_state(cm_ctx);
|
||||
if (QDF_IS_STATUS_ERROR(resp->reassoc_status))
|
||||
goto reassoc_fail;
|
||||
|
||||
if (QDF_IS_STATUS_SUCCESS(resp->reassoc_status) &&
|
||||
sm_state == WLAN_CM_S_CONNECTED) {
|
||||
cm_update_scan_db_on_reassoc_success(cm_ctx, resp);
|
||||
cm_set_fils_wep_key_on_reassoc(cm_ctx, resp);
|
||||
}
|
||||
|
||||
mlme_cm_reassoc_complete_ind(vdev, resp);
|
||||
mlme_cm_osif_reassoc_complete(vdev, resp);
|
||||
cm_inform_if_mgr_reassoc_complete(vdev, resp->reassoc_status);
|
||||
cm_inform_blm_reassoc_complete(vdev, resp);
|
||||
|
||||
reassoc_fail:
|
||||
/* Update scan entry in case connect is success or fails with bssid */
|
||||
if (!qdf_is_macaddr_zero(&resp->bssid)) {
|
||||
if (QDF_IS_STATUS_SUCCESS(resp->reassoc_status))
|
||||
mlme_info.assoc_state = SCAN_ENTRY_CON_STATE_ASSOC;
|
||||
else
|
||||
mlme_info.assoc_state = SCAN_ENTRY_CON_STATE_NONE;
|
||||
qdf_copy_macaddr(&bss_info.bssid, &resp->bssid);
|
||||
bss_info.freq = resp->freq;
|
||||
bss_info.ssid.length = resp->ssid.length;
|
||||
qdf_mem_copy(&bss_info.ssid.ssid, resp->ssid.ssid,
|
||||
bss_info.ssid.length);
|
||||
wlan_scan_update_mlme_by_bssinfo(
|
||||
wlan_vdev_get_pdev(vdev),
|
||||
&bss_info, &mlme_info);
|
||||
}
|
||||
|
||||
mlme_debug(CM_PREFIX_FMT,
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(vdev),
|
||||
resp->cm_id));
|
||||
cm_remove_cmd(cm_ctx, resp->cm_id);
|
||||
|
||||
/*
|
||||
* If roaming fails and conn_sm is in ROAMING state, then
|
||||
* initiate disconnect to cleanup and move conn_sm to INIT state
|
||||
*/
|
||||
if (QDF_IS_STATUS_ERROR(resp->reassoc_status) &&
|
||||
sm_state == WLAN_CM_S_ROAMING) {
|
||||
cm_reassoc_fail_disconnect(cm_ctx->vdev, CM_ROAM_DISCONNECT,
|
||||
REASON_UNSPEC_FAILURE,
|
||||
&resp->bssid);
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
cm_reassoc_handle_event_post_fail(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id)
|
||||
{
|
||||
struct wlan_cm_roam_resp *resp;
|
||||
|
||||
resp = qdf_mem_malloc(sizeof(*resp));
|
||||
if (!resp)
|
||||
return;
|
||||
|
||||
cm_fill_roam_fail_resp_from_cm_id(cm_ctx, resp, cm_id,
|
||||
CM_GENERIC_FAILURE);
|
||||
cm_reassoc_complete(cm_ctx, resp);
|
||||
qdf_mem_free(resp);
|
||||
}
|
||||
|
||||
static QDF_STATUS cm_reassoc_cmd_timeout(struct cnx_mgr *cm_ctx,
|
||||
wlan_cm_id cm_id)
|
||||
{
|
||||
struct wlan_cm_roam_resp *resp;
|
||||
QDF_STATUS status;
|
||||
|
||||
resp = qdf_mem_malloc(sizeof(*resp));
|
||||
if (!resp)
|
||||
return QDF_STATUS_E_NOMEM;
|
||||
|
||||
cm_fill_roam_fail_resp_from_cm_id(cm_ctx, resp, cm_id, CM_SER_TIMEOUT);
|
||||
status = cm_sm_deliver_event(cm_ctx->vdev,
|
||||
WLAN_CM_SM_EV_REASSOC_FAILURE,
|
||||
sizeof(*resp), resp);
|
||||
if (QDF_IS_STATUS_ERROR(status))
|
||||
cm_reassoc_complete(cm_ctx, resp);
|
||||
|
||||
qdf_mem_free(resp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef WLAN_CM_USE_SPINLOCK
|
||||
static QDF_STATUS cm_activate_reassoc_req_flush_cb(struct scheduler_msg *msg)
|
||||
{
|
||||
struct wlan_serialization_command *cmd = msg->bodyptr;
|
||||
|
||||
if (!cmd || !cmd->vdev) {
|
||||
mlme_err("Null input cmd:%pK", cmd);
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
wlan_objmgr_vdev_release_ref(cmd->vdev, WLAN_MLME_CM_ID);
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static QDF_STATUS cm_activate_reassoc_req_sched_cb(struct scheduler_msg *msg)
|
||||
{
|
||||
struct wlan_serialization_command *cmd = msg->bodyptr;
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
struct cnx_mgr *cm_ctx;
|
||||
QDF_STATUS ret = QDF_STATUS_E_FAILURE;
|
||||
|
||||
if (!cmd) {
|
||||
mlme_err("cmd is null");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
vdev = cmd->vdev;
|
||||
if (!vdev) {
|
||||
mlme_err("vdev is null");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
cm_ctx = cm_get_cm_ctx(vdev);
|
||||
if (!cm_ctx)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
ret = cm_sm_deliver_event(vdev,
|
||||
WLAN_CM_SM_EV_REASSOC_ACTIVE,
|
||||
sizeof(wlan_cm_id),
|
||||
&cmd->cmd_id);
|
||||
|
||||
/*
|
||||
* Called from scheduler context hence posting failure
|
||||
*/
|
||||
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||
mlme_err(CM_PREFIX_FMT "Activation failed for cmd:%d",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id),
|
||||
cmd->cmd_type);
|
||||
cm_reassoc_handle_event_post_fail(cm_ctx, cmd->cmd_id);
|
||||
}
|
||||
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QDF_STATUS
|
||||
cm_activate_reassoc_req(struct wlan_serialization_command *cmd)
|
||||
{
|
||||
struct wlan_objmgr_vdev *vdev = cmd->vdev;
|
||||
struct scheduler_msg msg = {0};
|
||||
QDF_STATUS ret;
|
||||
|
||||
msg.bodyptr = cmd;
|
||||
msg.callback = cm_activate_reassoc_req_sched_cb;
|
||||
msg.flush_callback = cm_activate_reassoc_req_flush_cb;
|
||||
|
||||
ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_MLME_CM_ID);
|
||||
if (QDF_IS_STATUS_ERROR(ret))
|
||||
return ret;
|
||||
|
||||
ret = scheduler_post_message(QDF_MODULE_ID_MLME,
|
||||
QDF_MODULE_ID_MLME,
|
||||
QDF_MODULE_ID_MLME, &msg);
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||
mlme_err(CM_PREFIX_FMT "Failed to post scheduler_msg",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id));
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
|
||||
return ret;
|
||||
}
|
||||
mlme_debug(CM_PREFIX_FMT "Cmd act in sched cmd type:%d",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id),
|
||||
cmd->cmd_type);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static QDF_STATUS
|
||||
cm_activate_reassoc_req(struct wlan_serialization_command *cmd)
|
||||
{
|
||||
return cm_sm_deliver_event(cmd->vdev,
|
||||
WLAN_CM_SM_EV_REASSOC_ACTIVE,
|
||||
sizeof(wlan_cm_id),
|
||||
&cmd->cmd_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
static QDF_STATUS
|
||||
cm_ser_reassoc_cb(struct wlan_serialization_command *cmd,
|
||||
enum wlan_serialization_cb_reason reason)
|
||||
{
|
||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
struct cnx_mgr *cm_ctx;
|
||||
|
||||
if (!cmd) {
|
||||
mlme_err("cmd is NULL, reason: %d", reason);
|
||||
QDF_ASSERT(0);
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
vdev = cmd->vdev;
|
||||
|
||||
cm_ctx = cm_get_cm_ctx(vdev);
|
||||
if (!cm_ctx)
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
|
||||
switch (reason) {
|
||||
case WLAN_SER_CB_ACTIVATE_CMD:
|
||||
/*
|
||||
* For pending to active reason, use async api to take lock.
|
||||
* For direct activation use sync api to avoid taking lock
|
||||
* as lock is already acquired by the requester.
|
||||
*/
|
||||
if (cmd->activation_reason == SER_PENDING_TO_ACTIVE)
|
||||
status = cm_activate_reassoc_req(cmd);
|
||||
else
|
||||
status = cm_sm_deliver_event_sync(
|
||||
cm_ctx, WLAN_CM_SM_EV_REASSOC_ACTIVE,
|
||||
sizeof(wlan_cm_id), &cmd->cmd_id);
|
||||
|
||||
if (QDF_IS_STATUS_SUCCESS(status))
|
||||
break;
|
||||
/*
|
||||
* Handle failure if posting fails, i.e. the SM state has
|
||||
* changed or head cm_id doesn't match the active cm_id.
|
||||
* connect active should be handled only in JOIN_PENDING. If
|
||||
* new command has been received connect activation should be
|
||||
* aborted from here with connect req cleanup.
|
||||
*/
|
||||
cm_reassoc_handle_event_post_fail(cm_ctx, cmd->cmd_id);
|
||||
break;
|
||||
case WLAN_SER_CB_CANCEL_CMD:
|
||||
/* command removed from pending list. */
|
||||
break;
|
||||
case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
|
||||
mlme_err(CM_PREFIX_FMT "Active command timeout",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id));
|
||||
QDF_ASSERT(0);
|
||||
|
||||
cm_reassoc_cmd_timeout(cm_ctx, cmd->cmd_id);
|
||||
break;
|
||||
case WLAN_SER_CB_RELEASE_MEM_CMD:
|
||||
cm_reset_active_cm_id(vdev, cmd->cmd_id);
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID);
|
||||
break;
|
||||
default:
|
||||
QDF_ASSERT(0);
|
||||
status = QDF_STATUS_E_INVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#define REASSOC_TIMEOUT 10000
|
||||
static QDF_STATUS cm_ser_reassoc_req(struct cnx_mgr *cm_ctx,
|
||||
struct cm_roam_req *cm_req)
|
||||
{
|
||||
struct wlan_serialization_command cmd = {0, };
|
||||
enum wlan_serialization_status ser_cmd_status;
|
||||
QDF_STATUS status;
|
||||
uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
|
||||
status = wlan_objmgr_vdev_try_get_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err(CM_PREFIX_FMT "unable to get reference",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id));
|
||||
return status;
|
||||
}
|
||||
|
||||
cmd.cmd_type = WLAN_SER_CMD_VDEV_REASSOC;
|
||||
cmd.cmd_id = cm_req->cm_id;
|
||||
cmd.cmd_cb = cm_ser_reassoc_cb;
|
||||
cmd.source = WLAN_UMAC_COMP_MLME;
|
||||
cmd.is_high_priority = false;
|
||||
cmd.cmd_timeout_duration = REASSOC_TIMEOUT;
|
||||
cmd.vdev = cm_ctx->vdev;
|
||||
cmd.is_blocking = cm_ser_get_blocking_cmd();
|
||||
|
||||
ser_cmd_status = wlan_serialization_request(&cmd);
|
||||
switch (ser_cmd_status) {
|
||||
case WLAN_SER_CMD_PENDING:
|
||||
/* command moved to pending list.Do nothing */
|
||||
break;
|
||||
case WLAN_SER_CMD_ACTIVE:
|
||||
/* command moved to active list. Do nothing */
|
||||
break;
|
||||
default:
|
||||
mlme_err(CM_PREFIX_FMT "ser cmd status %d",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id), ser_cmd_status);
|
||||
wlan_objmgr_vdev_release_ref(cm_ctx->vdev, WLAN_MLME_CM_ID);
|
||||
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS cm_reassoc_start(struct cnx_mgr *cm_ctx,
|
||||
struct cm_roam_req *cm_req)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
|
||||
|
||||
status = cm_ser_reassoc_req(cm_ctx, cm_req);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err(CM_PREFIX_FMT "Serialization of reassoc failed",
|
||||
CM_PREFIX_REF(vdev_id, cm_req->cm_id));
|
||||
return cm_send_reassoc_start_fail(cm_ctx, cm_req->cm_id,
|
||||
CM_SER_FAILURE);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS cm_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{
|
||||
struct cnx_mgr *cm_ctx;
|
||||
QDF_STATUS qdf_status;
|
||||
wlan_cm_id cm_id;
|
||||
uint32_t prefix;
|
||||
|
||||
cm_ctx = cm_get_cm_ctx(vdev);
|
||||
if (!cm_ctx)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
cm_id = cm_ctx->active_cm_id;
|
||||
prefix = CM_ID_GET_PREFIX(cm_id);
|
||||
|
||||
if (prefix != ROAM_REQ_PREFIX ||
|
||||
cm_id != resp->cm_id) {
|
||||
mlme_err(CM_PREFIX_FMT " Active cm_id 0x%x is different",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(vdev), resp->cm_id),
|
||||
cm_id);
|
||||
qdf_status = QDF_STATUS_E_FAILURE;
|
||||
goto post_err;
|
||||
}
|
||||
|
||||
if (QDF_IS_STATUS_SUCCESS(resp->reassoc_status)) {
|
||||
/*
|
||||
* On successful connection to sae single pmk AP,
|
||||
* clear all the single pmk AP.
|
||||
*/
|
||||
if (cm_is_cm_id_current_candidate_single_pmk(cm_ctx, cm_id))
|
||||
wlan_crypto_selective_clear_sae_single_pmk_entries(
|
||||
vdev, &resp->bssid);
|
||||
qdf_status = cm_sm_deliver_event(vdev,
|
||||
WLAN_CM_SM_EV_REASSOC_DONE,
|
||||
sizeof(*resp), resp);
|
||||
if (QDF_IS_STATUS_SUCCESS(qdf_status))
|
||||
return qdf_status;
|
||||
}
|
||||
post_err:
|
||||
cm_reassoc_complete(cm_ctx, resp);
|
||||
|
||||
return qdf_status;
|
||||
}
|
||||
|
||||
QDF_STATUS cm_roam_bss_peer_create_rsp(struct wlan_objmgr_vdev *vdev,
|
||||
QDF_STATUS status,
|
||||
struct qdf_mac_addr *peer_mac)
|
||||
{
|
||||
struct cnx_mgr *cm_ctx;
|
||||
QDF_STATUS qdf_status;
|
||||
wlan_cm_id cm_id;
|
||||
uint32_t prefix;
|
||||
struct cm_req *cm_req;
|
||||
|
||||
cm_ctx = cm_get_cm_ctx(vdev);
|
||||
if (!cm_ctx)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
cm_id = cm_ctx->active_cm_id;
|
||||
prefix = CM_ID_GET_PREFIX(cm_id);
|
||||
|
||||
if (prefix != ROAM_REQ_PREFIX) {
|
||||
mlme_err(CM_PREFIX_FMT "Active req is not roam req",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id));
|
||||
mlme_cm_bss_peer_delete_req(vdev);
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id);
|
||||
if (!cm_req)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
return cm_send_reassoc_start_fail(
|
||||
cm_ctx, cm_id,
|
||||
CM_PEER_CREATE_FAILED);
|
||||
}
|
||||
|
||||
qdf_status = cm_sm_deliver_event(
|
||||
vdev, WLAN_CM_SM_EV_BSS_CREATE_PEER_SUCCESS,
|
||||
sizeof(wlan_cm_id), &cm_id);
|
||||
if (QDF_IS_STATUS_SUCCESS(qdf_status))
|
||||
return qdf_status;
|
||||
|
||||
mlme_cm_bss_peer_delete_req(vdev);
|
||||
cm_reassoc_handle_event_post_fail(cm_ctx, cm_id);
|
||||
|
||||
return qdf_status;
|
||||
}
|
||||
|
||||
QDF_STATUS cm_roam_disconnect_rsp(struct wlan_objmgr_vdev *vdev,
|
||||
struct wlan_cm_discon_rsp *resp)
|
||||
{
|
||||
struct cnx_mgr *cm_ctx;
|
||||
QDF_STATUS qdf_status;
|
||||
wlan_cm_id cm_id;
|
||||
uint32_t prefix;
|
||||
|
||||
cm_ctx = cm_get_cm_ctx(vdev);
|
||||
if (!cm_ctx)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
cm_id = cm_ctx->active_cm_id;
|
||||
prefix = CM_ID_GET_PREFIX(cm_id);
|
||||
|
||||
if (prefix != ROAM_REQ_PREFIX || cm_id != resp->req.cm_id) {
|
||||
mlme_err(CM_PREFIX_FMT "Active cm_id 0x%x is different",
|
||||
CM_PREFIX_REF(wlan_vdev_get_id(vdev), resp->req.cm_id),
|
||||
cm_id);
|
||||
qdf_status = QDF_STATUS_E_FAILURE;
|
||||
goto disconnect_complete;
|
||||
}
|
||||
qdf_status =
|
||||
cm_sm_deliver_event(vdev,
|
||||
WLAN_CM_SM_EV_DISCONNECT_DONE,
|
||||
sizeof(*resp), resp);
|
||||
if (QDF_IS_STATUS_SUCCESS(qdf_status))
|
||||
return qdf_status;
|
||||
|
||||
disconnect_complete:
|
||||
cm_reassoc_handle_event_post_fail(cm_ctx, cm_id);
|
||||
return qdf_status;
|
||||
}
|
||||
|
||||
void cm_start_roam_invoke(struct cnx_mgr *cm_ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void cm_fw_roam_start(struct cnx_mgr *cm_ctx)
|
||||
{
|
||||
}
|
236
umac/mlme/connection_mgr/core/src/wlan_cm_roam.h
Normal file
236
umac/mlme/connection_mgr/core/src/wlan_cm_roam.h
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: wlan_cm_roam.h
|
||||
*
|
||||
* This header file maintain APIs required for connection mgr roam functions
|
||||
*/
|
||||
|
||||
#ifndef __WLAN_CM_ROAM_H__
|
||||
#define __WLAN_CM_ROAM_H__
|
||||
|
||||
/**
|
||||
* cm_check_and_prepare_roam_req() - Initiate roam request
|
||||
* @cm_ctx: connection manager context
|
||||
* @connect_req: connection manager request
|
||||
* @roam_req: Roam request
|
||||
*
|
||||
* Context: Can be called only while handling connection manager event
|
||||
* ie holding state machine lock
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS
|
||||
cm_check_and_prepare_roam_req(struct cnx_mgr *cm_ctx,
|
||||
struct cm_connect_req *connect_req,
|
||||
struct cm_req **roam_req);
|
||||
|
||||
/**
|
||||
* cm_roam_bss_peer_create_rsp() - handle bss peer create response for roam
|
||||
* @vdev: vdev
|
||||
* @status: bss peer create status
|
||||
* @peer_mac: peer mac
|
||||
*
|
||||
* Return: QDF status
|
||||
*/
|
||||
QDF_STATUS cm_roam_bss_peer_create_rsp(struct wlan_objmgr_vdev *vdev,
|
||||
QDF_STATUS status,
|
||||
struct qdf_mac_addr *peer_mac);
|
||||
|
||||
/**
|
||||
* cm_reassoc_rsp() - Connection manager reassoc response
|
||||
* @vdev: vdev pointer
|
||||
* @resp: Reassoc response
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS cm_reassoc_rsp(struct wlan_objmgr_vdev *vdev,
|
||||
struct wlan_cm_roam_resp *resp);
|
||||
|
||||
/**
|
||||
* cm_roam_disconnect_rsp() - Connection manager api to post connect event
|
||||
* @vdev: VDEV object
|
||||
* @cm_discon_rsp: Disconnect response
|
||||
*
|
||||
* Context: Any context.
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS cm_roam_disconnect_rsp(struct wlan_objmgr_vdev *vdev,
|
||||
struct wlan_cm_discon_rsp *resp);
|
||||
|
||||
/**
|
||||
* cm_reassoc_complete() - This API would be called after reassoc complete
|
||||
* request from the serialization.
|
||||
* @cm_ctx: connection manager context
|
||||
* @resp: Roam complete resp.
|
||||
*
|
||||
* This API would be called after roam completion resp from VDEV mgr
|
||||
*
|
||||
* Return: QDF status
|
||||
*/
|
||||
#ifdef WLAN_FEATURE_HOST_ROAM
|
||||
QDF_STATUS cm_reassoc_complete(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp);
|
||||
#else
|
||||
static inline QDF_STATUS cm_reassoc_complete(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cm_free_roam_req_mem() - free croam req internal memory, to be called
|
||||
* before cm_req is freed
|
||||
* @roam_req: roam req
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void cm_free_roam_req_mem(struct cm_roam_req *roam_req);
|
||||
|
||||
/**
|
||||
* cm_get_active_reassoc_req() - Get copy of active reassoc request
|
||||
* @vdev: vdev pointer
|
||||
* @req: pointer to the copy of the active reassoc request
|
||||
* *
|
||||
* Context: Should be called only in the conext of the
|
||||
* cm request activation
|
||||
*
|
||||
* Return: true and reassoc req if any request is active
|
||||
*/
|
||||
bool cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
|
||||
struct wlan_cm_vdev_reassoc_req *req);
|
||||
|
||||
/**
|
||||
* cm_start_roam_req() - Initiate roam request
|
||||
* @cm_ctx: Connection manager context
|
||||
* @cm_req: Struct containing the roam request
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS if roam initiation delivers the event
|
||||
* to connection state machine else error value.
|
||||
*/
|
||||
QDF_STATUS cm_start_roam_req(struct cnx_mgr *cm_ctx,
|
||||
struct cm_req *cm_req);
|
||||
|
||||
/**
|
||||
* cm_host_roam_start_req() - Start host roam request
|
||||
* @cm_ctx: Connection manager context
|
||||
* @cm_req: Struct containing the roam request
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS on delivering the event
|
||||
* to connection state machine else error value.
|
||||
*/
|
||||
QDF_STATUS cm_host_roam_start_req(struct cnx_mgr *cm_ctx,
|
||||
struct cm_req *cm_req);
|
||||
|
||||
/**
|
||||
* cm_start_roam_invoke() - Start roam request
|
||||
* @cm_ctx: Connection manager context
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void cm_start_roam_invoke(struct cnx_mgr *cm_ctx);
|
||||
|
||||
/**
|
||||
* cm_fw_roam_start() - Initiate FW roam request
|
||||
* @cm_ctx: Connection manager context
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void cm_fw_roam_start(struct cnx_mgr *cm_ctx);
|
||||
|
||||
/**
|
||||
* cm_reassoc_start() - This API will be called to initiate the reassoc
|
||||
* process
|
||||
* @cm_ctx: connection manager context
|
||||
* @req: roam request.
|
||||
*
|
||||
* Return: QDF status
|
||||
*/
|
||||
QDF_STATUS cm_reassoc_start(struct cnx_mgr *cm_ctx, struct cm_roam_req *req);
|
||||
|
||||
/**
|
||||
* cm_reassoc_active() - This API would be called after the reassoc
|
||||
* request gets activated in serialization.
|
||||
* @cm_ctx: connection manager context
|
||||
* @cm_id: Connection mgr ID assigned to this reassoc request.
|
||||
*
|
||||
* Return: QDF status
|
||||
*/
|
||||
QDF_STATUS cm_reassoc_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id);
|
||||
|
||||
/**
|
||||
* cm_reassoc_disconnect_complete() - This API would be called after
|
||||
* disconnect complete due to reassoc request.
|
||||
* @cm_ctx: connection manager context
|
||||
* @resp: disconnection complete resp.
|
||||
*
|
||||
* This API would be called after disconnection completion resp from VDEV mgr
|
||||
*
|
||||
* Return: QDF status
|
||||
*/
|
||||
|
||||
QDF_STATUS cm_reassoc_disconnect_complete(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_discon_rsp *resp);
|
||||
|
||||
/**
|
||||
* cm_resume_reassoc_after_peer_create() - Called after bss create rsp
|
||||
* @cm_ctx: connection manager context
|
||||
* @cm_id: Connection mgr ID assigned to this reassoc request.
|
||||
*
|
||||
* Return: QDF status
|
||||
*/
|
||||
QDF_STATUS
|
||||
cm_resume_reassoc_after_peer_create(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id);
|
||||
|
||||
/**
|
||||
* cm_roam_resp_cmid_match_list_head() - Check if resp cmid is same as list
|
||||
* head
|
||||
* @cm_ctx: connection manager context
|
||||
* @resp: roam resp
|
||||
*
|
||||
* Return: bool
|
||||
*/
|
||||
bool cm_roam_resp_cmid_match_list_head(struct cnx_mgr *cm_ctx,
|
||||
struct wlan_cm_roam_resp *resp);
|
||||
|
||||
/**
|
||||
* cm_send_reassoc_start_fail() - initiate reassoc failure
|
||||
* @cm_ctx: connection manager context
|
||||
* @cm_id: active command id
|
||||
* @reason: failure reason
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS
|
||||
cm_send_reassoc_start_fail(struct cnx_mgr *cm_ctx,
|
||||
wlan_cm_id cm_id,
|
||||
enum wlan_cm_connect_fail_reason reason);
|
||||
|
||||
/**
|
||||
* cm_fill_bss_info_in_roam_rsp_by_cm_id() - fill bss info for the cm id
|
||||
* @cm_ctx: connection manager context
|
||||
* @cm_id: cm id of connect/disconnect req
|
||||
* @resp: resp to copy bss info like ssid/bssid and freq
|
||||
*
|
||||
* Return: Success if entry was found else failure
|
||||
*/
|
||||
QDF_STATUS
|
||||
cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
|
||||
wlan_cm_id cm_id,
|
||||
struct wlan_cm_roam_resp *resp);
|
||||
|
||||
#endif /* __WLAN_CM_ROAM_H__ */
|
168
umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.c
Normal file
168
umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Implements general Roam utils for connection manager
|
||||
*/
|
||||
|
||||
#include "wlan_cm_main.h"
|
||||
#include "wlan_cm_roam_sm.h"
|
||||
#include "wlan_cm_sm.h"
|
||||
#include "wlan_cm_main_api.h"
|
||||
#include "wlan_cm_roam.h"
|
||||
#include <wlan_scan_api.h>
|
||||
|
||||
QDF_STATUS cm_check_and_prepare_roam_req(struct cnx_mgr *cm_ctx,
|
||||
struct cm_connect_req *connect_req,
|
||||
struct cm_req **roam_req)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
struct wlan_cm_connect_req *req;
|
||||
struct qdf_mac_addr bssid;
|
||||
struct wlan_ssid ssid;
|
||||
struct cm_req *cm_req, *req_ptr;
|
||||
|
||||
cm_req = qdf_container_of(connect_req, struct cm_req, connect_req);
|
||||
req = &connect_req->req;
|
||||
/*
|
||||
* Reject re-assoc unless freq along with prev bssid and one
|
||||
* of bssid or bssid hint is present.
|
||||
*/
|
||||
if (!req->chan_freq || qdf_is_macaddr_zero(&req->prev_bssid) ||
|
||||
(qdf_is_macaddr_zero(&req->bssid) &&
|
||||
qdf_is_macaddr_zero(&req->bssid_hint)))
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
|
||||
wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &bssid);
|
||||
|
||||
/* Reject re-assoc unless prev_bssid matches the current BSSID. */
|
||||
if (!qdf_is_macaddr_equal(&req->prev_bssid, &bssid))
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
|
||||
status = wlan_vdev_mlme_get_ssid(cm_ctx->vdev, ssid.ssid, &ssid.length);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
mlme_err("failed to get ssid");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
/* Reject re-assoc unless ssid matches. */
|
||||
if (ssid.length != req->ssid.length ||
|
||||
qdf_mem_cmp(ssid.ssid, req->ssid.ssid, ssid.length))
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
|
||||
/* fill roam_req for roaming and free cm_req */
|
||||
*roam_req = qdf_mem_malloc(sizeof(**roam_req));
|
||||
if (!*roam_req)
|
||||
return QDF_STATUS_E_NOMEM;
|
||||
|
||||
req_ptr = *roam_req;
|
||||
if (!qdf_is_macaddr_zero(&req->bssid))
|
||||
qdf_copy_macaddr(&req_ptr->roam_req.req.bssid, &req->bssid);
|
||||
else
|
||||
qdf_copy_macaddr(&req_ptr->roam_req.req.bssid,
|
||||
&req->bssid_hint);
|
||||
|
||||
qdf_copy_macaddr(&req_ptr->roam_req.req.prev_bssid, &req->prev_bssid);
|
||||
req_ptr->roam_req.req.chan_freq = req->chan_freq;
|
||||
req_ptr->roam_req.req.source = CM_ROAMING_HOST;
|
||||
|
||||
/* Free the connect req, as reassoc is tried */
|
||||
cm_free_connect_req_mem(connect_req);
|
||||
qdf_mem_free(cm_req);
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_HOST_ROAM
|
||||
bool cm_get_active_reassoc_req(struct wlan_objmgr_vdev *vdev,
|
||||
struct wlan_cm_vdev_reassoc_req *req)
|
||||
{
|
||||
struct cnx_mgr *cm_ctx;
|
||||
qdf_list_node_t *cur_node = NULL, *next_node = NULL;
|
||||
struct cm_req *cm_req = NULL;
|
||||
bool status = false;
|
||||
uint32_t cm_id_prefix;
|
||||
|
||||
cm_ctx = cm_get_cm_ctx(vdev);
|
||||
|
||||
cm_req_lock_acquire(cm_ctx);
|
||||
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
|
||||
while (cur_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_id_prefix = CM_ID_GET_PREFIX((cm_req->cm_id));
|
||||
|
||||
if (cm_req->cm_id == cm_ctx->active_cm_id &&
|
||||
cm_id_prefix == ROAM_REQ_PREFIX) {
|
||||
req->vdev_id = wlan_vdev_get_id(vdev);
|
||||
req->cm_id = cm_req->roam_req.cm_id;
|
||||
qdf_copy_macaddr(&req->prev_bssid,
|
||||
&cm_req->roam_req.req.prev_bssid);
|
||||
req->bss = cm_req->roam_req.cur_candidate;
|
||||
status = true;
|
||||
cm_req_lock_release(cm_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
cur_node = next_node;
|
||||
next_node = NULL;
|
||||
}
|
||||
cm_req_lock_release(cm_ctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
QDF_STATUS
|
||||
cm_fill_bss_info_in_roam_rsp_by_cm_id(struct cnx_mgr *cm_ctx,
|
||||
wlan_cm_id cm_id,
|
||||
struct wlan_cm_roam_resp *resp)
|
||||
{
|
||||
qdf_list_node_t *cur_node = NULL, *next_node = NULL;
|
||||
struct cm_req *cm_req;
|
||||
uint32_t prefix = CM_ID_GET_PREFIX(cm_id);
|
||||
struct wlan_cm_roam_req *req;
|
||||
|
||||
if (prefix != ROAM_REQ_PREFIX)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
cm_req_lock_acquire(cm_ctx);
|
||||
qdf_list_peek_front(&cm_ctx->req_list, &cur_node);
|
||||
while (cur_node) {
|
||||
qdf_list_peek_next(&cm_ctx->req_list, cur_node, &next_node);
|
||||
cm_req = qdf_container_of(cur_node, struct cm_req, node);
|
||||
|
||||
if (cm_req->cm_id == cm_id) {
|
||||
req = &cm_req->roam_req.req;
|
||||
resp->freq = req->chan_freq;
|
||||
wlan_vdev_mlme_get_ssid(cm_ctx->vdev, resp->ssid.ssid,
|
||||
&resp->ssid.length);
|
||||
|
||||
if (!qdf_is_macaddr_zero(&req->bssid))
|
||||
qdf_copy_macaddr(&resp->bssid, &req->bssid);
|
||||
|
||||
cm_req_lock_release(cm_ctx);
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cur_node = next_node;
|
||||
next_node = NULL;
|
||||
}
|
||||
cm_req_lock_release(cm_ctx);
|
||||
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
Reference in New Issue
Block a user