|
@@ -1,2431 +0,0 @@
|
|
|
-/*
|
|
|
- * Copyright (c) 2017-2018 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_tdls_cmds_process.c
|
|
|
- *
|
|
|
- * TDLS north bound commands implementation
|
|
|
- */
|
|
|
-#include <wlan_reg_services_api.h>
|
|
|
-#include <wlan_serialization_api.h>
|
|
|
-#include "wlan_tdls_main.h"
|
|
|
-#include "wlan_tdls_peer.h"
|
|
|
-#include "wlan_tdls_ct.h"
|
|
|
-#include "wlan_tdls_mgmt.h"
|
|
|
-#include "wlan_tdls_cmds_process.h"
|
|
|
-#include "wlan_tdls_tgt_api.h"
|
|
|
-#include "wlan_policy_mgr_api.h"
|
|
|
-
|
|
|
-static uint16_t tdls_get_connected_peer(struct tdls_soc_priv_obj *soc_obj)
|
|
|
-{
|
|
|
- return soc_obj->connected_peer_count;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_decrement_peer_count() - decrement connected TDLS peer counter
|
|
|
- * @soc_obj: TDLS soc object
|
|
|
- *
|
|
|
- * Used in scheduler thread context, no lock needed.
|
|
|
- *
|
|
|
- * Return: None.
|
|
|
- */
|
|
|
-void tdls_decrement_peer_count(struct tdls_soc_priv_obj *soc_obj)
|
|
|
-{
|
|
|
- if (soc_obj->connected_peer_count)
|
|
|
- soc_obj->connected_peer_count--;
|
|
|
-
|
|
|
- tdls_debug("Connected peer count %d", soc_obj->connected_peer_count);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_increment_peer_count() - increment connected TDLS peer counter
|
|
|
- * @soc_obj: TDLS soc object
|
|
|
- *
|
|
|
- * Used in scheduler thread context, no lock needed.
|
|
|
- *
|
|
|
- * Return: None.
|
|
|
- */
|
|
|
-static void tdls_increment_peer_count(struct tdls_soc_priv_obj *soc_obj)
|
|
|
-{
|
|
|
- soc_obj->connected_peer_count++;
|
|
|
- tdls_debug("Connected peer count %d", soc_obj->connected_peer_count);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_validate_current_mode() - check current TDL mode
|
|
|
- * @soc_obj: TDLS soc object
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS if TDLS enabled, other for disabled
|
|
|
- */
|
|
|
-static QDF_STATUS tdls_validate_current_mode(struct tdls_soc_priv_obj *soc_obj)
|
|
|
-{
|
|
|
- if (soc_obj->tdls_current_mode == TDLS_SUPPORT_DISABLED ||
|
|
|
- soc_obj->tdls_current_mode == TDLS_SUPPORT_SUSPENDED) {
|
|
|
- tdls_err("TDLS mode disabled OR not enabled, current mode %d",
|
|
|
- soc_obj->tdls_current_mode);
|
|
|
- return QDF_STATUS_E_NOSUPPORT;
|
|
|
- }
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-static char *tdls_get_ser_cmd_str(enum wlan_serialization_cmd_type type)
|
|
|
-{
|
|
|
- switch (type) {
|
|
|
- case WLAN_SER_CMD_TDLS_ADD_PEER:
|
|
|
- return "TDLS_ADD_PEER_CMD";
|
|
|
- case WLAN_SER_CMD_TDLS_DEL_PEER:
|
|
|
- return "TDLS_DEL_PEER_CMD";
|
|
|
- case WLAN_SER_CMD_TDLS_SEND_MGMT:
|
|
|
- return "TDLS_SEND_MGMT_CMD";
|
|
|
- default:
|
|
|
- return "UNKNOWN";
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-tdls_release_serialization_command(struct wlan_objmgr_vdev *vdev,
|
|
|
- enum wlan_serialization_cmd_type type)
|
|
|
-{
|
|
|
- struct wlan_serialization_queued_cmd_info cmd = {0};
|
|
|
-
|
|
|
- cmd.cmd_type = type;
|
|
|
- cmd.cmd_id = 0;
|
|
|
- cmd.vdev = vdev;
|
|
|
-
|
|
|
- tdls_debug("release %s", tdls_get_ser_cmd_str(type));
|
|
|
- /* Inform serialization for command completion */
|
|
|
- wlan_serialization_remove_cmd(&cmd);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_pe_add_peer() - send TDLS add peer request to PE
|
|
|
- * @req: TDL add peer request
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS for success; other values if failed
|
|
|
- */
|
|
|
-static QDF_STATUS tdls_pe_add_peer(struct tdls_add_peer_request *req)
|
|
|
-{
|
|
|
- struct tdls_add_sta_req *addstareq;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_peer *peer;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct scheduler_msg msg = {0,};
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- addstareq = qdf_mem_malloc(sizeof(*addstareq));
|
|
|
- if (!addstareq) {
|
|
|
- tdls_err("allocate failed");
|
|
|
- return QDF_STATUS_E_NOMEM;
|
|
|
- }
|
|
|
- vdev = req->vdev;
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- if (!soc_obj) {
|
|
|
- tdls_err("NULL tdls soc object");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- addstareq->tdls_oper = TDLS_OPER_ADD;
|
|
|
- addstareq->transaction_id = 0;
|
|
|
-
|
|
|
- addstareq->session_id = wlan_vdev_get_id(vdev);
|
|
|
- peer = wlan_vdev_get_bsspeer(vdev);
|
|
|
- if (!peer) {
|
|
|
- tdls_err("bss peer is NULL");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("can't get bss peer");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- wlan_peer_obj_lock(peer);
|
|
|
- qdf_mem_copy(addstareq->bssid.bytes,
|
|
|
- wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
|
|
|
- wlan_peer_obj_unlock(peer);
|
|
|
- wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_copy(addstareq->peermac.bytes, req->add_peer_req.peer_addr,
|
|
|
- QDF_MAC_ADDR_SIZE);
|
|
|
-
|
|
|
- tdls_debug("for " QDF_MAC_ADDR_STR,
|
|
|
- QDF_MAC_ADDR_ARRAY(addstareq->peermac.bytes));
|
|
|
- msg.type = soc_obj->tdls_add_sta_req;
|
|
|
- msg.bodyptr = addstareq;
|
|
|
- status = scheduler_post_message(QDF_MODULE_ID_TDLS,
|
|
|
- QDF_MODULE_ID_PE,
|
|
|
- QDF_MODULE_ID_PE, &msg);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("fail to post pe msg to add peer");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- return status;
|
|
|
-error:
|
|
|
- qdf_mem_free(addstareq);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_pe_del_peer() - send TDLS delete peer request to PE
|
|
|
- * @req: TDLS delete peer request
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS for success; other values if failed
|
|
|
- */
|
|
|
-QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req)
|
|
|
-{
|
|
|
- struct tdls_del_sta_req *delstareq;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_peer *peer;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct scheduler_msg msg = {0,};
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- delstareq = qdf_mem_malloc(sizeof(*delstareq));
|
|
|
- if (!delstareq) {
|
|
|
- tdls_err("allocate failed");
|
|
|
- return QDF_STATUS_E_NOMEM;
|
|
|
- }
|
|
|
- vdev = req->vdev;
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- if (!soc_obj) {
|
|
|
- tdls_err("NULL tdls soc object");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- delstareq->transaction_id = 0;
|
|
|
-
|
|
|
- delstareq->session_id = wlan_vdev_get_id(vdev);
|
|
|
- peer = wlan_vdev_get_bsspeer(vdev);
|
|
|
- if (!peer) {
|
|
|
- tdls_err("bss peer is NULL");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("can't get bss peer");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- wlan_peer_obj_lock(peer);
|
|
|
- qdf_mem_copy(delstareq->bssid.bytes,
|
|
|
- wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
|
|
|
- wlan_peer_obj_unlock(peer);
|
|
|
- wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_copy(delstareq->peermac.bytes, req->del_peer_req.peer_addr,
|
|
|
- QDF_MAC_ADDR_SIZE);
|
|
|
-
|
|
|
- tdls_debug("for " QDF_MAC_ADDR_STR,
|
|
|
- QDF_MAC_ADDR_ARRAY(delstareq->peermac.bytes));
|
|
|
- msg.type = soc_obj->tdls_del_sta_req;
|
|
|
- msg.bodyptr = delstareq;
|
|
|
- status = scheduler_post_message(QDF_MODULE_ID_TDLS,
|
|
|
- QDF_MODULE_ID_PE,
|
|
|
- QDF_MODULE_ID_PE, &msg);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("fail to post pe msg to del peer");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- return status;
|
|
|
-error:
|
|
|
- qdf_mem_free(delstareq);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_pe_update_peer() - send TDLS update peer request to PE
|
|
|
- * @req: TDLS update peer request
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS for success; other values if failed
|
|
|
- */
|
|
|
-static QDF_STATUS tdls_pe_update_peer(struct tdls_update_peer_request *req)
|
|
|
-{
|
|
|
- struct tdls_add_sta_req *addstareq;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_peer *peer;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct scheduler_msg msg = {0,};
|
|
|
- struct tdls_update_peer_params *update_peer;
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- addstareq = qdf_mem_malloc(sizeof(*addstareq));
|
|
|
- if (!addstareq) {
|
|
|
- tdls_err("allocate failed");
|
|
|
- return QDF_STATUS_E_NOMEM;
|
|
|
- }
|
|
|
- vdev = req->vdev;
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- if (!soc_obj) {
|
|
|
- tdls_err("NULL tdls soc object");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- update_peer = &req->update_peer_req;
|
|
|
-
|
|
|
- addstareq->tdls_oper = TDLS_OPER_UPDATE;
|
|
|
- addstareq->transaction_id = 0;
|
|
|
-
|
|
|
- addstareq->session_id = wlan_vdev_get_id(vdev);
|
|
|
- peer = wlan_vdev_get_bsspeer(vdev);
|
|
|
- if (!peer) {
|
|
|
- tdls_err("bss peer is NULL");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("can't get bss peer");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- wlan_peer_obj_lock(peer);
|
|
|
- qdf_mem_copy(addstareq->bssid.bytes,
|
|
|
- wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
|
|
|
- wlan_peer_obj_unlock(peer);
|
|
|
- wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_copy(addstareq->peermac.bytes, update_peer->peer_addr,
|
|
|
- QDF_MAC_ADDR_SIZE);
|
|
|
- addstareq->capability = update_peer->capability;
|
|
|
- addstareq->uapsd_queues = update_peer->uapsd_queues;
|
|
|
- addstareq->max_sp = update_peer->max_sp;
|
|
|
-
|
|
|
- qdf_mem_copy(addstareq->extn_capability,
|
|
|
- update_peer->extn_capability, WLAN_MAC_MAX_EXTN_CAP);
|
|
|
- addstareq->htcap_present = update_peer->htcap_present;
|
|
|
- qdf_mem_copy(&addstareq->ht_cap,
|
|
|
- &update_peer->ht_cap,
|
|
|
- sizeof(update_peer->ht_cap));
|
|
|
- addstareq->vhtcap_present = update_peer->vhtcap_present;
|
|
|
- qdf_mem_copy(&addstareq->vht_cap,
|
|
|
- &update_peer->vht_cap,
|
|
|
- sizeof(update_peer->vht_cap));
|
|
|
- addstareq->supported_rates_length = update_peer->supported_rates_len;
|
|
|
- qdf_mem_copy(&addstareq->supported_rates,
|
|
|
- update_peer->supported_rates,
|
|
|
- update_peer->supported_rates_len);
|
|
|
- tdls_debug("for " QDF_MAC_ADDR_STR,
|
|
|
- QDF_MAC_ADDR_ARRAY(addstareq->peermac.bytes));
|
|
|
-
|
|
|
- msg.type = soc_obj->tdls_add_sta_req;
|
|
|
- msg.bodyptr = addstareq;
|
|
|
- status = scheduler_post_message(QDF_MODULE_ID_TDLS,
|
|
|
- QDF_MODULE_ID_PE,
|
|
|
- QDF_MODULE_ID_PE, &msg);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("fail to post pe msg to update peer");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- return status;
|
|
|
-error:
|
|
|
- qdf_mem_free(addstareq);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_internal_add_peer_rsp(struct tdls_add_peer_request *req,
|
|
|
- QDF_STATUS status)
|
|
|
-{
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
- QDF_STATUS ret;
|
|
|
-
|
|
|
- if (!req || !req->vdev) {
|
|
|
- tdls_err("req: %pK", req);
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
- vdev = req->vdev;
|
|
|
- ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
- if (QDF_IS_STATUS_ERROR(ret)) {
|
|
|
- tdls_err("can't get vdev object");
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- if (soc_obj && soc_obj->tdls_event_cb) {
|
|
|
- ind.vdev = vdev;
|
|
|
- ind.status = status;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_ADD_PEER, &ind);
|
|
|
- }
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_internal_update_peer_rsp(struct tdls_update_peer_request *req,
|
|
|
- QDF_STATUS status)
|
|
|
-{
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- QDF_STATUS ret;
|
|
|
-
|
|
|
- if (!req || !req->vdev) {
|
|
|
- tdls_err("req: %pK", req);
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
- vdev = req->vdev;
|
|
|
- ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
- if (QDF_IS_STATUS_ERROR(ret)) {
|
|
|
- tdls_err("can't get vdev object");
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- if (soc_obj && soc_obj->tdls_event_cb) {
|
|
|
- ind.vdev = vdev;
|
|
|
- ind.status = status;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_ADD_PEER, &ind);
|
|
|
- }
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS tdls_internal_del_peer_rsp(struct tdls_oper_request *req)
|
|
|
-{
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- if (!req || !req->vdev) {
|
|
|
- tdls_err("req: %pK", req);
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
- vdev = req->vdev;
|
|
|
- status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("can't get vdev object");
|
|
|
- return status;
|
|
|
- }
|
|
|
-
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
|
|
|
- if (soc_obj && soc_obj->tdls_event_cb) {
|
|
|
- ind.vdev = req->vdev;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_DEL_PEER, &ind);
|
|
|
- }
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS tdls_activate_add_peer(struct tdls_add_peer_request *req)
|
|
|
-{
|
|
|
- QDF_STATUS status;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct tdls_peer *peer;
|
|
|
- uint16_t curr_tdls_peers;
|
|
|
- const uint8_t *mac;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- if (!req->vdev) {
|
|
|
- tdls_err("vdev null when add tdls peer");
|
|
|
- QDF_ASSERT(0);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- mac = req->add_peer_req.peer_addr;
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(req->vdev);
|
|
|
-
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj);
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
- status = tdls_validate_current_mode(soc_obj);
|
|
|
- if (QDF_IS_STATUS_ERROR(status))
|
|
|
- goto addrsp;
|
|
|
-
|
|
|
- peer = tdls_get_peer(vdev_obj, mac);
|
|
|
- if (!peer) {
|
|
|
- tdls_err("peer: " QDF_MAC_ADDR_STR " not exist. invalid",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac));
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto addrsp;
|
|
|
- }
|
|
|
-
|
|
|
- /* in add station, we accept existing valid sta_id if there is */
|
|
|
- if ((peer->link_status > TDLS_LINK_CONNECTING) ||
|
|
|
- (TDLS_STA_INDEX_CHECK((peer->sta_id)))) {
|
|
|
- tdls_notice("link_status %d sta_id %d add peer ignored",
|
|
|
- peer->link_status, peer->sta_id);
|
|
|
- status = QDF_STATUS_SUCCESS;
|
|
|
- goto addrsp;
|
|
|
- }
|
|
|
-
|
|
|
- /* when others are on-going, we want to change link_status to idle */
|
|
|
- if (tdls_is_progress(vdev_obj, mac, true)) {
|
|
|
- tdls_notice(QDF_MAC_ADDR_STR " TDLS setuping. Req declined.",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac));
|
|
|
- status = QDF_STATUS_E_PERM;
|
|
|
- goto setlink;
|
|
|
- }
|
|
|
-
|
|
|
- /* first to check if we reached to maximum supported TDLS peer. */
|
|
|
- curr_tdls_peers = tdls_get_connected_peer(soc_obj);
|
|
|
- if (soc_obj->max_num_tdls_sta <= curr_tdls_peers) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR
|
|
|
- " Request declined. Current %d, Max allowed %d.",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac), curr_tdls_peers,
|
|
|
- soc_obj->max_num_tdls_sta);
|
|
|
- status = QDF_STATUS_E_PERM;
|
|
|
- goto setlink;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_set_peer_link_status(peer,
|
|
|
- TDLS_LINK_CONNECTING, TDLS_LINK_SUCCESS);
|
|
|
-
|
|
|
- status = tdls_pe_add_peer(req);
|
|
|
- if (QDF_IS_STATUS_ERROR(status))
|
|
|
- goto setlink;
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
-setlink:
|
|
|
- tdls_set_link_status(vdev_obj, mac, TDLS_LINK_IDLE,
|
|
|
- TDLS_LINK_UNSPECIFIED);
|
|
|
-addrsp:
|
|
|
- if (soc_obj->tdls_event_cb) {
|
|
|
- ind.status = status;
|
|
|
- ind.vdev = req->vdev;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_ADD_PEER, &ind);
|
|
|
- }
|
|
|
-
|
|
|
- return QDF_STATUS_E_PERM;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_add_peer_serialize_callback(struct wlan_serialization_command *cmd,
|
|
|
- enum wlan_serialization_cb_reason reason)
|
|
|
-{
|
|
|
- struct tdls_add_peer_request *req;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
- if (!cmd || !cmd->umac_cmd) {
|
|
|
- tdls_err("cmd: %pK, reason: %d", cmd, reason);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- req = cmd->umac_cmd;
|
|
|
- tdls_debug("reason: %d, req %pK", reason, req);
|
|
|
-
|
|
|
- switch (reason) {
|
|
|
- case WLAN_SER_CB_ACTIVATE_CMD:
|
|
|
- /* command moved to active list
|
|
|
- */
|
|
|
- status = tdls_activate_add_peer(req);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_CANCEL_CMD:
|
|
|
- /* command removed from pending list.
|
|
|
- * notify os interface the status
|
|
|
- */
|
|
|
- status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
|
|
|
- /* active command time out. */
|
|
|
- status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_RELEASE_MEM_CMD:
|
|
|
- /* command successfully completed.
|
|
|
- * release memory & vdev reference count
|
|
|
- */
|
|
|
- wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(req);
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- /* Do nothing but logging */
|
|
|
- QDF_ASSERT(0);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc,
|
|
|
- uint8_t action_code)
|
|
|
-{
|
|
|
- if (!tdls_soc)
|
|
|
- return;
|
|
|
-
|
|
|
- if (TDLS_TEARDOWN != action_code ||
|
|
|
- !tdls_soc->tdls_nss_switch_in_progress)
|
|
|
- return;
|
|
|
-
|
|
|
- if (tdls_soc->tdls_teardown_peers_cnt != 0)
|
|
|
- tdls_soc->tdls_teardown_peers_cnt--;
|
|
|
- if (tdls_soc->tdls_teardown_peers_cnt == 0) {
|
|
|
- if (tdls_soc->tdls_nss_transition_mode ==
|
|
|
- TDLS_NSS_TRANSITION_S_1x1_to_2x2) {
|
|
|
- /* TDLS NSS switch is fully completed, so
|
|
|
- * reset the flags.
|
|
|
- */
|
|
|
- tdls_notice("TDLS NSS switch is fully completed");
|
|
|
- tdls_soc->tdls_nss_switch_in_progress = false;
|
|
|
- tdls_soc->tdls_nss_teardown_complete = false;
|
|
|
- } else {
|
|
|
- /* TDLS NSS switch is not yet completed, but
|
|
|
- * tdls teardown is completed for all the
|
|
|
- * peers.
|
|
|
- */
|
|
|
- tdls_notice("teardown done & NSS switch in progress");
|
|
|
- tdls_soc->tdls_nss_teardown_complete = true;
|
|
|
- }
|
|
|
- tdls_soc->tdls_nss_transition_mode =
|
|
|
- TDLS_NSS_TRANSITION_S_UNKNOWN;
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_set_cap() - set TDLS capability type
|
|
|
- * @tdls_vdev: tdls vdev object
|
|
|
- * @mac: peer mac address
|
|
|
- * @cap: TDLS capability type
|
|
|
- *
|
|
|
- * Return: 0 if successful or negative errno otherwise
|
|
|
- */
|
|
|
-int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac,
|
|
|
- enum tdls_peer_capab cap)
|
|
|
-{
|
|
|
- struct tdls_peer *curr_peer;
|
|
|
-
|
|
|
- curr_peer = tdls_get_peer(tdls_vdev, mac);
|
|
|
- if (curr_peer == NULL) {
|
|
|
- tdls_err("curr_peer is NULL");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- curr_peer->tdls_support = cap;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int tdls_validate_setup_frames(struct tdls_soc_priv_obj *tdls_soc,
|
|
|
- struct tdls_validate_action_req *tdls_validate)
|
|
|
-{
|
|
|
- /* supplicant still sends tdls_mgmt(SETUP_REQ)
|
|
|
- * even after we return error code at
|
|
|
- * 'add_station()'. Hence we have this check
|
|
|
- * again in addition to add_station(). Anyway,
|
|
|
- * there is no harm to double-check.
|
|
|
- */
|
|
|
- if (TDLS_SETUP_REQUEST == tdls_validate->action_code) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).",
|
|
|
- QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
|
|
|
- tdls_validate->action_code,
|
|
|
- tdls_soc->connected_peer_count,
|
|
|
- tdls_soc->max_num_tdls_sta);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- /* maximum reached. tweak to send
|
|
|
- * error code to peer and return error
|
|
|
- * code to supplicant
|
|
|
- */
|
|
|
- tdls_validate->status_code = QDF_STATUS_E_RESOURCES;
|
|
|
- tdls_err(QDF_MAC_ADDR_STR " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).",
|
|
|
- QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
|
|
|
- tdls_validate->action_code,
|
|
|
- tdls_soc->connected_peer_count,
|
|
|
- tdls_soc->max_num_tdls_sta);
|
|
|
-
|
|
|
- tdls_validate->max_sta_failed = -EPERM;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-int tdls_validate_mgmt_request(struct tdls_action_frame_request *tdls_mgmt_req)
|
|
|
-{
|
|
|
- struct tdls_vdev_priv_obj *tdls_vdev;
|
|
|
- struct tdls_soc_priv_obj *tdls_soc;
|
|
|
- struct tdls_peer *curr_peer;
|
|
|
- struct tdls_peer *temp_peer;
|
|
|
- QDF_STATUS status;
|
|
|
- uint8_t vdev_id;
|
|
|
-
|
|
|
- struct tdls_validate_action_req *tdls_validate =
|
|
|
- tdls_mgmt_req->chk_frame;
|
|
|
-
|
|
|
- if (!tdls_validate || !tdls_validate->vdev)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(tdls_validate->vdev,
|
|
|
- &tdls_vdev,
|
|
|
- &tdls_soc))
|
|
|
- return -ENOTSUPP;
|
|
|
-
|
|
|
- /*
|
|
|
- * STA or P2P client should be connected and authenticated before
|
|
|
- * sending any TDLS frames
|
|
|
- */
|
|
|
- if (!tdls_is_vdev_connected(tdls_validate->vdev) ||
|
|
|
- !tdls_is_vdev_authenticated(tdls_validate->vdev)) {
|
|
|
- tdls_err("STA is not connected or not authenticated.");
|
|
|
- return -EAGAIN;
|
|
|
- }
|
|
|
-
|
|
|
- /* other than teardown frame, mgmt frames are not sent if disabled */
|
|
|
- if (TDLS_TEARDOWN != tdls_validate->action_code) {
|
|
|
- if (!tdls_check_is_tdls_allowed(tdls_validate->vdev)) {
|
|
|
- tdls_err("TDLS not allowed, reject MGMT, action = %d",
|
|
|
- tdls_validate->action_code);
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
- /* if tdls_mode is disabled, then decline the peer's request */
|
|
|
- if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode ||
|
|
|
- TDLS_SUPPORT_SUSPENDED == tdls_soc->tdls_current_mode) {
|
|
|
- tdls_notice(QDF_MAC_ADDR_STR
|
|
|
- " TDLS mode is disabled. action %d declined.",
|
|
|
- QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
|
|
|
- tdls_validate->action_code);
|
|
|
- return -ENOTSUPP;
|
|
|
- }
|
|
|
- if (tdls_soc->tdls_nss_switch_in_progress) {
|
|
|
- tdls_err("nss switch in progress, action %d declined "
|
|
|
- QDF_MAC_ADDR_STR,
|
|
|
- tdls_validate->action_code,
|
|
|
- QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac));
|
|
|
- return -EAGAIN;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (TDLS_IS_SETUP_ACTION(tdls_validate->action_code)) {
|
|
|
- if (NULL != tdls_is_progress(tdls_vdev,
|
|
|
- tdls_validate->peer_mac, true)) {
|
|
|
- tdls_err("setup is ongoing. action %d declined for "
|
|
|
- QDF_MAC_ADDR_STR,
|
|
|
- tdls_validate->action_code,
|
|
|
- QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac));
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* call hdd_wmm_is_acm_allowed() */
|
|
|
- vdev_id = wlan_vdev_get_id(tdls_validate->vdev);
|
|
|
- if (!tdls_soc->tdls_wmm_cb(vdev_id)) {
|
|
|
- tdls_debug("admission ctrl set to VI, send the frame with least AC (BK) for action %d",
|
|
|
- tdls_validate->action_code);
|
|
|
- tdls_mgmt_req->use_default_ac = false;
|
|
|
- } else {
|
|
|
- tdls_mgmt_req->use_default_ac = true;
|
|
|
- }
|
|
|
-
|
|
|
- if (TDLS_SETUP_REQUEST == tdls_validate->action_code ||
|
|
|
- TDLS_SETUP_RESPONSE == tdls_validate->action_code) {
|
|
|
- if (tdls_soc->max_num_tdls_sta <=
|
|
|
- tdls_soc->connected_peer_count) {
|
|
|
- status = tdls_validate_setup_frames(tdls_soc,
|
|
|
- tdls_validate);
|
|
|
- if (QDF_STATUS_SUCCESS != status)
|
|
|
- return status;
|
|
|
- /* fall through to send setup resp
|
|
|
- * with failure status code
|
|
|
- */
|
|
|
- } else {
|
|
|
- curr_peer =
|
|
|
- tdls_find_peer(tdls_vdev,
|
|
|
- tdls_validate->peer_mac);
|
|
|
- if (curr_peer) {
|
|
|
- if (TDLS_IS_LINK_CONNECTED(curr_peer)) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR " already connected action %d declined.",
|
|
|
- QDF_MAC_ADDR_ARRAY(
|
|
|
- tdls_validate->peer_mac),
|
|
|
- tdls_validate->action_code);
|
|
|
-
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- tdls_notice("tdls_mgmt" QDF_MAC_ADDR_STR " action %d, dialog_token %d status %d, len = %zu",
|
|
|
- QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
|
|
|
- tdls_validate->action_code, tdls_validate->dialog_token,
|
|
|
- tdls_validate->status_code, tdls_validate->len);
|
|
|
-
|
|
|
- /*Except teardown responder will not be used so just make 0 */
|
|
|
- tdls_validate->responder = 0;
|
|
|
- if (TDLS_TEARDOWN == tdls_validate->action_code) {
|
|
|
- temp_peer = tdls_find_peer(tdls_vdev, tdls_validate->peer_mac);
|
|
|
- if (!temp_peer) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR " peer doesn't exist",
|
|
|
- QDF_MAC_ADDR_ARRAY(
|
|
|
- tdls_validate->peer_mac));
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
-
|
|
|
- if (TDLS_IS_LINK_CONNECTED(temp_peer))
|
|
|
- tdls_validate->responder = temp_peer->is_responder;
|
|
|
- else {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR " peer doesn't exist or not connected %d dialog_token %d status %d, tdls_validate->len = %zu",
|
|
|
- QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
|
|
|
- temp_peer->link_status,
|
|
|
- tdls_validate->dialog_token,
|
|
|
- tdls_validate->status_code,
|
|
|
- tdls_validate->len);
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* For explicit trigger of DIS_REQ come out of BMPS for
|
|
|
- * successfully receiving DIS_RSP from peer.
|
|
|
- */
|
|
|
- if ((TDLS_SETUP_RESPONSE == tdls_validate->action_code) ||
|
|
|
- (TDLS_SETUP_CONFIRM == tdls_validate->action_code) ||
|
|
|
- (TDLS_DISCOVERY_RESPONSE == tdls_validate->action_code) ||
|
|
|
- (TDLS_DISCOVERY_REQUEST == tdls_validate->action_code)) {
|
|
|
- /* Fw will take care if PS offload is enabled. */
|
|
|
- if (TDLS_DISCOVERY_REQUEST != tdls_validate->action_code)
|
|
|
- tdls_set_cap(tdls_vdev, tdls_validate->peer_mac,
|
|
|
- TDLS_CAP_SUPPORTED);
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req)
|
|
|
-{
|
|
|
- struct wlan_serialization_command cmd = {0,};
|
|
|
- enum wlan_serialization_status ser_cmd_status;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
- if (!req || !req->vdev) {
|
|
|
- tdls_err("req: %pK", req);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- vdev = req->vdev;
|
|
|
- cmd.cmd_type = WLAN_SER_CMD_TDLS_ADD_PEER;
|
|
|
- cmd.cmd_id = 0;
|
|
|
- cmd.cmd_cb = (wlan_serialization_cmd_callback)
|
|
|
- tdls_add_peer_serialize_callback;
|
|
|
- cmd.umac_cmd = req;
|
|
|
- cmd.source = WLAN_UMAC_COMP_TDLS;
|
|
|
- cmd.is_high_priority = false;
|
|
|
- cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
|
|
|
- cmd.vdev = vdev;
|
|
|
- cmd.is_blocking = true;
|
|
|
-
|
|
|
- ser_cmd_status = wlan_serialization_request(&cmd);
|
|
|
- tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req,
|
|
|
- ser_cmd_status);
|
|
|
-
|
|
|
- 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;
|
|
|
- case WLAN_SER_CMD_DENIED_LIST_FULL:
|
|
|
- case WLAN_SER_CMD_DENIED_RULES_FAILED:
|
|
|
- case WLAN_SER_CMD_DENIED_UNSPECIFIED:
|
|
|
- /* notify os interface about internal error*/
|
|
|
- status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
- /* cmd can't be serviced.
|
|
|
- * release tdls_add_peer_request memory
|
|
|
- */
|
|
|
- qdf_mem_free(req);
|
|
|
- break;
|
|
|
- default:
|
|
|
- QDF_ASSERT(0);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-error:
|
|
|
- status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
|
|
|
- qdf_mem_free(req);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_activate_update_peer(struct tdls_update_peer_request *req)
|
|
|
-{
|
|
|
- QDF_STATUS status;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct tdls_peer *curr_peer;
|
|
|
- uint16_t curr_tdls_peers;
|
|
|
- const uint8_t *mac;
|
|
|
- struct tdls_update_peer_params *update_peer;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- if (!req->vdev) {
|
|
|
- tdls_err("vdev object NULL when add TDLS peer");
|
|
|
- QDF_ASSERT(0);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- mac = req->update_peer_req.peer_addr;
|
|
|
- vdev = req->vdev;
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj);
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
-
|
|
|
- status = tdls_validate_current_mode(soc_obj);
|
|
|
- if (QDF_IS_STATUS_ERROR(status))
|
|
|
- goto updatersp;
|
|
|
-
|
|
|
- curr_peer = tdls_get_peer(vdev_obj, mac);
|
|
|
- if (!curr_peer) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR " not exist. return invalid",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac));
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto updatersp;
|
|
|
- }
|
|
|
-
|
|
|
- /* in change station, we accept only when sta_id is valid */
|
|
|
- if (curr_peer->link_status > TDLS_LINK_CONNECTING ||
|
|
|
- !(TDLS_STA_INDEX_CHECK(curr_peer->sta_id))) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR " link %d. sta %d. update peer %s",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac), curr_peer->link_status,
|
|
|
- curr_peer->sta_id,
|
|
|
- (TDLS_STA_INDEX_CHECK(curr_peer->sta_id)) ? "ignored"
|
|
|
- : "declined");
|
|
|
- status = (TDLS_STA_INDEX_CHECK(curr_peer->sta_id)) ?
|
|
|
- QDF_STATUS_SUCCESS : QDF_STATUS_E_PERM;
|
|
|
- goto updatersp;
|
|
|
- }
|
|
|
-
|
|
|
- /* when others are on-going, we want to change link_status to idle */
|
|
|
- if (tdls_is_progress(vdev_obj, mac, true)) {
|
|
|
- tdls_notice(QDF_MAC_ADDR_STR " TDLS setuping. Req declined.",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac));
|
|
|
- status = QDF_STATUS_E_PERM;
|
|
|
- goto setlink;
|
|
|
- }
|
|
|
-
|
|
|
- curr_tdls_peers = tdls_get_connected_peer(soc_obj);
|
|
|
- if (soc_obj->max_num_tdls_sta <= curr_tdls_peers) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR
|
|
|
- " Request declined. Current: %d, Max allowed: %d.",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac), curr_tdls_peers,
|
|
|
- soc_obj->max_num_tdls_sta);
|
|
|
- status = QDF_STATUS_E_PERM;
|
|
|
- goto setlink;
|
|
|
- }
|
|
|
- update_peer = &req->update_peer_req;
|
|
|
-
|
|
|
- if (update_peer->htcap_present)
|
|
|
- curr_peer->spatial_streams = update_peer->ht_cap.mcsset[1];
|
|
|
-
|
|
|
- tdls_set_peer_caps(vdev_obj, mac, &req->update_peer_req);
|
|
|
- status = tdls_pe_update_peer(req);
|
|
|
- if (QDF_IS_STATUS_ERROR(status))
|
|
|
- goto setlink;
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
-setlink:
|
|
|
- tdls_set_link_status(vdev_obj, mac, TDLS_LINK_IDLE,
|
|
|
- TDLS_LINK_UNSPECIFIED);
|
|
|
-updatersp:
|
|
|
- if (soc_obj->tdls_event_cb) {
|
|
|
- ind.status = status;
|
|
|
- ind.vdev = vdev;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_ADD_PEER, &ind);
|
|
|
- }
|
|
|
-
|
|
|
- return QDF_STATUS_E_PERM;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_update_peer_serialize_callback(struct wlan_serialization_command *cmd,
|
|
|
- enum wlan_serialization_cb_reason reason)
|
|
|
-{
|
|
|
- struct tdls_update_peer_request *req;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
- if (!cmd || !cmd->umac_cmd) {
|
|
|
- tdls_err("cmd: %pK, reason: %d", cmd, reason);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- req = cmd->umac_cmd;
|
|
|
- tdls_debug("reason: %d, req %pK", reason, req);
|
|
|
-
|
|
|
- switch (reason) {
|
|
|
- case WLAN_SER_CB_ACTIVATE_CMD:
|
|
|
- /* command moved to active list
|
|
|
- */
|
|
|
- status = tdls_activate_update_peer(req);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_CANCEL_CMD:
|
|
|
- /* command removed from pending list.
|
|
|
- * notify os interface the status
|
|
|
- */
|
|
|
- status = tdls_internal_update_peer_rsp(req,
|
|
|
- QDF_STATUS_E_FAILURE);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
|
|
|
- /* active command time out. */
|
|
|
- status = tdls_internal_update_peer_rsp(req,
|
|
|
- QDF_STATUS_E_FAILURE);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_RELEASE_MEM_CMD:
|
|
|
- /* command successfully completed.
|
|
|
- * release memory & release reference count
|
|
|
- */
|
|
|
- wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(req);
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- /* Do nothing but logging */
|
|
|
- QDF_ASSERT(0);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_update_peer(struct tdls_update_peer_request *req)
|
|
|
-{
|
|
|
- struct wlan_serialization_command cmd = {0,};
|
|
|
- enum wlan_serialization_status ser_cmd_status;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
- if (!req || !req->vdev) {
|
|
|
- tdls_err("req: %pK", req);
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- vdev = req->vdev;
|
|
|
- cmd.cmd_type = WLAN_SER_CMD_TDLS_ADD_PEER;
|
|
|
- cmd.cmd_id = 0;
|
|
|
- cmd.cmd_cb = (wlan_serialization_cmd_callback)
|
|
|
- tdls_update_peer_serialize_callback;
|
|
|
- cmd.umac_cmd = req;
|
|
|
- cmd.source = WLAN_UMAC_COMP_TDLS;
|
|
|
- cmd.is_high_priority = false;
|
|
|
- cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
|
|
|
- cmd.vdev = req->vdev;
|
|
|
- cmd.is_blocking = true;
|
|
|
-
|
|
|
- ser_cmd_status = wlan_serialization_request(&cmd);
|
|
|
- tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req,
|
|
|
- ser_cmd_status);
|
|
|
-
|
|
|
- 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;
|
|
|
- case WLAN_SER_CMD_DENIED_LIST_FULL:
|
|
|
- case WLAN_SER_CMD_DENIED_RULES_FAILED:
|
|
|
- case WLAN_SER_CMD_DENIED_UNSPECIFIED:
|
|
|
- /* notify os interface about internal error*/
|
|
|
- status = tdls_internal_update_peer_rsp(req,
|
|
|
- QDF_STATUS_E_FAILURE);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
- /* cmd can't be serviced.
|
|
|
- * release tdls_add_peer_request memory
|
|
|
- */
|
|
|
- qdf_mem_free(req);
|
|
|
- break;
|
|
|
- default:
|
|
|
- QDF_ASSERT(0);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-error:
|
|
|
- status = tdls_internal_update_peer_rsp(req, QDF_STATUS_E_FAILURE);
|
|
|
- qdf_mem_free(req);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS tdls_activate_del_peer(struct tdls_oper_request *req)
|
|
|
-{
|
|
|
- struct tdls_del_peer_request request = {0,};
|
|
|
-
|
|
|
- request.vdev = req->vdev;
|
|
|
- request.del_peer_req.peer_addr = req->peer_addr;
|
|
|
-
|
|
|
- return tdls_pe_del_peer(&request);
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_del_peer_serialize_callback(struct wlan_serialization_command *cmd,
|
|
|
- enum wlan_serialization_cb_reason reason)
|
|
|
-{
|
|
|
- struct tdls_oper_request *req;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
- if (!cmd || !cmd->umac_cmd) {
|
|
|
- tdls_err("cmd: %pK, reason: %d", cmd, reason);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- req = cmd->umac_cmd;
|
|
|
- tdls_debug("reason: %d, req %pK", reason, req);
|
|
|
-
|
|
|
- switch (reason) {
|
|
|
- case WLAN_SER_CB_ACTIVATE_CMD:
|
|
|
- /* command moved to active list
|
|
|
- */
|
|
|
- status = tdls_activate_del_peer(req);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_CANCEL_CMD:
|
|
|
- /* command removed from pending list.
|
|
|
- * notify os interface the status
|
|
|
- */
|
|
|
- status = tdls_internal_del_peer_rsp(req);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
|
|
|
- /* active command time out. */
|
|
|
- status = tdls_internal_del_peer_rsp(req);
|
|
|
- break;
|
|
|
-
|
|
|
- case WLAN_SER_CB_RELEASE_MEM_CMD:
|
|
|
- /* command successfully completed.
|
|
|
- * release memory & vdev reference count
|
|
|
- */
|
|
|
- wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(req);
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- /* Do nothing but logging */
|
|
|
- QDF_ASSERT(0);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req)
|
|
|
-{
|
|
|
- struct wlan_serialization_command cmd = {0,};
|
|
|
- enum wlan_serialization_status ser_cmd_status;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- uint8_t *mac;
|
|
|
- struct tdls_peer *peer;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
-
|
|
|
- if (!req || !req->vdev) {
|
|
|
- tdls_err("req: %pK", req);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto free_req;
|
|
|
- }
|
|
|
-
|
|
|
- vdev = req->vdev;
|
|
|
-
|
|
|
- /* vdev reference cnt is acquired in ucfg_tdls_oper */
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
-
|
|
|
- if (!vdev_obj || !soc_obj) {
|
|
|
- tdls_err("tdls vdev_obj: %pK soc_obj: %pK", vdev_obj, soc_obj);
|
|
|
- status = QDF_STATUS_E_NULL_VALUE;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- mac = req->peer_addr;
|
|
|
- peer = tdls_find_peer(vdev_obj, mac);
|
|
|
- if (!peer) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR
|
|
|
- " not found, ignore NL80211_TDLS_ENABLE_LINK",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac));
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- if (soc_obj->tdls_dp_vdev_update)
|
|
|
- soc_obj->tdls_dp_vdev_update(&soc_obj->soc,
|
|
|
- peer->sta_id,
|
|
|
- soc_obj->tdls_update_dp_vdev_flags,
|
|
|
- false);
|
|
|
-
|
|
|
- cmd.cmd_type = WLAN_SER_CMD_TDLS_DEL_PEER;
|
|
|
- cmd.cmd_id = 0;
|
|
|
- cmd.cmd_cb = (wlan_serialization_cmd_callback)
|
|
|
- tdls_del_peer_serialize_callback;
|
|
|
- cmd.umac_cmd = req;
|
|
|
- cmd.source = WLAN_UMAC_COMP_TDLS;
|
|
|
- cmd.is_high_priority = false;
|
|
|
- cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
|
|
|
- cmd.vdev = vdev;
|
|
|
- cmd.is_blocking = true;
|
|
|
-
|
|
|
- ser_cmd_status = wlan_serialization_request(&cmd);
|
|
|
- tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req,
|
|
|
- ser_cmd_status);
|
|
|
-
|
|
|
- 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;
|
|
|
- case WLAN_SER_CMD_DENIED_LIST_FULL:
|
|
|
- case WLAN_SER_CMD_DENIED_RULES_FAILED:
|
|
|
- case WLAN_SER_CMD_DENIED_UNSPECIFIED:
|
|
|
- /* notify os interface about internal error*/
|
|
|
- status = tdls_internal_del_peer_rsp(req);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
- /* cmd can't be serviced.
|
|
|
- * release tdls_add_peer_request memory
|
|
|
- */
|
|
|
- qdf_mem_free(req);
|
|
|
- break;
|
|
|
- default:
|
|
|
- QDF_ASSERT(0);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-error:
|
|
|
- status = tdls_internal_del_peer_rsp(req);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
-free_req:
|
|
|
- qdf_mem_free(req);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_process_add_peer_rsp() - handle response for update TDLS peer
|
|
|
- * @rsp: TDLS add peer response
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS for success; other values if failed
|
|
|
- */
|
|
|
-static QDF_STATUS tdls_update_peer_rsp(struct tdls_add_sta_rsp *rsp)
|
|
|
-{
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_psoc *psoc;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- psoc = rsp->psoc;
|
|
|
- if (!psoc) {
|
|
|
- tdls_err("psoc is NULL");
|
|
|
- QDF_ASSERT(0);
|
|
|
- return QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
- vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
|
|
|
- WLAN_TDLS_SB_ID);
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("invalid vdev: %d", rsp->session_id);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_ADD_PEER);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
-error:
|
|
|
- soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
|
|
|
- if (soc_obj && soc_obj->tdls_event_cb) {
|
|
|
- ind.status = rsp->status_code;
|
|
|
- ind.vdev = vdev;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_ADD_PEER, &ind);
|
|
|
- }
|
|
|
- qdf_mem_free(rsp);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_process_send_mgmt_rsp() - handle response for send mgmt
|
|
|
- * @rsp: TDLS send mgmt response
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS for success; other values if failed
|
|
|
- */
|
|
|
-QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp)
|
|
|
-{
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_psoc *psoc;
|
|
|
- struct tdls_vdev_priv_obj *tdls_vdev;
|
|
|
- struct tdls_soc_priv_obj *tdls_soc = NULL;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- psoc = rsp->psoc;
|
|
|
- vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
|
|
|
- WLAN_TDLS_SB_ID);
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("invalid vdev");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- qdf_mem_free(rsp);
|
|
|
- return status;
|
|
|
- }
|
|
|
- tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc);
|
|
|
- tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- if (!tdls_soc || !tdls_vdev) {
|
|
|
- tdls_err("soc object:%pK, vdev object:%pK", tdls_soc, tdls_vdev);
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_SEND_MGMT);
|
|
|
-
|
|
|
- if (legacy_result_success == rsp->status_code)
|
|
|
- goto free_rsp;
|
|
|
- tdls_err("send mgmt failed. status code(=%d)", rsp->status_code);
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
-
|
|
|
- if (tdls_soc && tdls_soc->tdls_event_cb) {
|
|
|
- ind.vdev = vdev;
|
|
|
- ind.status = status;
|
|
|
- tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_MGMT_TX_ACK_CNF, &ind);
|
|
|
- }
|
|
|
-
|
|
|
-free_rsp:
|
|
|
- qdf_mem_free(rsp);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_send_mgmt_tx_completion() - process tx completion
|
|
|
- * @tx_complete: TDLS mgmt completion info
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS for success; other values if failed
|
|
|
- */
|
|
|
-QDF_STATUS tdls_send_mgmt_tx_completion(
|
|
|
- struct tdls_mgmt_tx_completion_ind *tx_complete)
|
|
|
-{
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_psoc *psoc;
|
|
|
- struct tdls_vdev_priv_obj *tdls_vdev;
|
|
|
- struct tdls_soc_priv_obj *tdls_soc = NULL;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- psoc = tx_complete->psoc;
|
|
|
- vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
|
|
|
- tx_complete->session_id,
|
|
|
- WLAN_TDLS_SB_ID);
|
|
|
-
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("invalid vdev");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto free_tx_complete;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc);
|
|
|
- tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
-
|
|
|
- if (!tdls_soc || !tdls_vdev) {
|
|
|
- tdls_err("soc object:%pK, vdev object:%pK", tdls_soc, tdls_vdev);
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
-
|
|
|
- if (tdls_soc && tdls_soc->tdls_event_cb) {
|
|
|
- ind.vdev = vdev;
|
|
|
- ind.status = tx_complete->tx_complete_status;
|
|
|
- tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_MGMT_TX_ACK_CNF, &ind);
|
|
|
- }
|
|
|
-
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
-free_tx_complete:
|
|
|
- qdf_mem_free(tx_complete);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_add_peer_rsp() - handle response for add TDLS peer
|
|
|
- * @rsp: TDLS add peer response
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS for success; other values if failed
|
|
|
- */
|
|
|
-static QDF_STATUS tdls_add_peer_rsp(struct tdls_add_sta_rsp *rsp)
|
|
|
-{
|
|
|
- uint8_t sta_idx;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_psoc *psoc;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct tdls_soc_priv_obj *soc_obj = NULL;
|
|
|
- struct tdls_conn_info *conn_rec;
|
|
|
- QDF_STATUS status = QDF_STATUS_SUCCESS;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- psoc = rsp->psoc;
|
|
|
- vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
|
|
|
- WLAN_TDLS_SB_ID);
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("invalid vdev: %d", rsp->session_id);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc object:%pK, vdev object:%pK", soc_obj, vdev_obj);
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- goto cmddone;
|
|
|
- }
|
|
|
- if (rsp->status_code) {
|
|
|
- tdls_err("add sta failed. status code(=%d)", rsp->status_code);
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- } else {
|
|
|
- conn_rec = soc_obj->tdls_conn_info;
|
|
|
- for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta;
|
|
|
- sta_idx++) {
|
|
|
- if (INVALID_TDLS_PEER_ID == conn_rec[sta_idx].sta_id) {
|
|
|
- conn_rec[sta_idx].session_id = rsp->session_id;
|
|
|
- conn_rec[sta_idx].sta_id = rsp->sta_id;
|
|
|
- qdf_copy_macaddr(&conn_rec[sta_idx].peer_mac,
|
|
|
- &rsp->peermac);
|
|
|
- tdls_warn("TDLS: STA IDX at %d is %d of mac "
|
|
|
- QDF_MAC_ADDR_STR, sta_idx,
|
|
|
- rsp->sta_id, QDF_MAC_ADDR_ARRAY
|
|
|
- (rsp->peermac.bytes));
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (sta_idx < soc_obj->max_num_tdls_sta) {
|
|
|
- status = tdls_set_sta_id(vdev_obj, rsp->peermac.bytes,
|
|
|
- rsp->sta_id);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("set staid failed");
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
- } else {
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-cmddone:
|
|
|
- tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_ADD_PEER);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
-error:
|
|
|
- if (soc_obj && soc_obj->tdls_event_cb) {
|
|
|
- ind.vdev = vdev;
|
|
|
- ind.status = rsp->status_code;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_ADD_PEER, &ind);
|
|
|
- }
|
|
|
- qdf_mem_free(rsp);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp)
|
|
|
-{
|
|
|
- tdls_debug("peer oper %d", rsp->tdls_oper);
|
|
|
-
|
|
|
- if (rsp->tdls_oper == TDLS_OPER_ADD)
|
|
|
- return tdls_add_peer_rsp(rsp);
|
|
|
- else if (rsp->tdls_oper == TDLS_OPER_UPDATE)
|
|
|
- return tdls_update_peer_rsp(rsp);
|
|
|
-
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp)
|
|
|
-{
|
|
|
- uint8_t sta_idx, id;
|
|
|
- QDF_STATUS status = QDF_STATUS_E_FAILURE;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- struct wlan_objmgr_psoc *psoc;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct tdls_soc_priv_obj *soc_obj = NULL;
|
|
|
- struct tdls_conn_info *conn_rec;
|
|
|
- struct tdls_peer *curr_peer = NULL;
|
|
|
- const uint8_t *macaddr;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- tdls_debug("del peer rsp: vdev %d peer " QDF_MAC_ADDR_STR,
|
|
|
- rsp->session_id, QDF_MAC_ADDR_ARRAY(rsp->peermac.bytes));
|
|
|
- psoc = rsp->psoc;
|
|
|
- vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
|
|
|
- WLAN_TDLS_SB_ID);
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("invalid vdev: %d", rsp->session_id);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc object:%pK, vdev object:%pK", soc_obj, vdev_obj);
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- goto cmddone;
|
|
|
- }
|
|
|
-
|
|
|
- conn_rec = soc_obj->tdls_conn_info;
|
|
|
- for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; sta_idx++) {
|
|
|
- if (conn_rec[sta_idx].session_id != rsp->session_id ||
|
|
|
- conn_rec[sta_idx].sta_id != rsp->sta_id)
|
|
|
- continue;
|
|
|
-
|
|
|
- macaddr = rsp->peermac.bytes;
|
|
|
- tdls_warn("TDLS: del STA IDX = %x", rsp->sta_id);
|
|
|
- curr_peer = tdls_find_peer(vdev_obj, macaddr);
|
|
|
- if (curr_peer) {
|
|
|
- tdls_debug(QDF_MAC_ADDR_STR " status is %d",
|
|
|
- QDF_MAC_ADDR_ARRAY(macaddr),
|
|
|
- curr_peer->link_status);
|
|
|
-
|
|
|
- id = wlan_vdev_get_id(vdev);
|
|
|
-
|
|
|
- if (TDLS_IS_LINK_CONNECTED(curr_peer)) {
|
|
|
- soc_obj->tdls_dereg_peer(
|
|
|
- soc_obj->tdls_peer_context,
|
|
|
- id, curr_peer->sta_id);
|
|
|
- tdls_decrement_peer_count(soc_obj);
|
|
|
- } else if (TDLS_LINK_CONNECTING ==
|
|
|
- curr_peer->link_status) {
|
|
|
- soc_obj->tdls_dereg_peer(
|
|
|
- soc_obj->tdls_peer_context,
|
|
|
- id, curr_peer->sta_id);
|
|
|
- }
|
|
|
- }
|
|
|
- tdls_reset_peer(vdev_obj, macaddr);
|
|
|
- conn_rec[sta_idx].sta_id = INVALID_TDLS_PEER_ID;
|
|
|
- conn_rec[sta_idx].session_id = 0xff;
|
|
|
- qdf_mem_zero(&conn_rec[sta_idx].peer_mac,
|
|
|
- QDF_MAC_ADDR_SIZE);
|
|
|
-
|
|
|
- status = QDF_STATUS_SUCCESS;
|
|
|
- break;
|
|
|
- }
|
|
|
- macaddr = rsp->peermac.bytes;
|
|
|
- if (!curr_peer) {
|
|
|
- curr_peer = tdls_find_peer(vdev_obj, macaddr);
|
|
|
-
|
|
|
- if (curr_peer)
|
|
|
- tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE,
|
|
|
- (curr_peer->link_status ==
|
|
|
- TDLS_LINK_TEARING) ?
|
|
|
- TDLS_LINK_UNSPECIFIED :
|
|
|
- TDLS_LINK_DROPPED_BY_REMOTE);
|
|
|
- }
|
|
|
-
|
|
|
-cmddone:
|
|
|
- tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_DEL_PEER);
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
|
|
-error:
|
|
|
-
|
|
|
- if (soc_obj && soc_obj->tdls_event_cb) {
|
|
|
- ind.vdev = vdev;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_DEL_PEER, &ind);
|
|
|
- }
|
|
|
- qdf_mem_free(rsp);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_wma_update_peer_state(struct tdls_soc_priv_obj *soc_obj,
|
|
|
- struct tdls_peer_update_state *peer_state)
|
|
|
-{
|
|
|
- struct scheduler_msg msg = {0,};
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- tdls_debug("update TDLS peer " QDF_MAC_ADDR_STR " vdev %d, state %d",
|
|
|
- QDF_MAC_ADDR_ARRAY(peer_state->peer_macaddr),
|
|
|
- peer_state->vdev_id, peer_state->peer_state);
|
|
|
- msg.type = soc_obj->tdls_update_peer_state;
|
|
|
- msg.reserved = 0;
|
|
|
- msg.bodyptr = peer_state;
|
|
|
-
|
|
|
- status = scheduler_post_message(QDF_MODULE_ID_TDLS,
|
|
|
- QDF_MODULE_ID_WMA,
|
|
|
- QDF_MODULE_ID_WMA, &msg);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("scheduler_post_msg failed");
|
|
|
- status = QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static QDF_STATUS
|
|
|
-tdls_update_uapsd(struct wlan_objmgr_psoc *psoc, struct wlan_objmgr_vdev *vdev,
|
|
|
- uint8_t sta_id, uint32_t srvc_int, uint32_t sus_int,
|
|
|
- uint8_t dir, uint8_t psb, uint32_t delay_interval)
|
|
|
-{
|
|
|
- uint8_t i;
|
|
|
- static const uint8_t ac[AC_PRIORITY_NUM] = {UAPSD_AC_VO, UAPSD_AC_VI,
|
|
|
- UAPSD_AC_BK, UAPSD_AC_BE};
|
|
|
- static const uint8_t tid[AC_PRIORITY_NUM] = {7, 5, 2, 3};
|
|
|
- uint32_t vdev_id;
|
|
|
-
|
|
|
- struct sta_uapsd_params tdls_uapsd_params;
|
|
|
- struct sta_uapsd_trig_params tdls_trig_params;
|
|
|
- struct wlan_objmgr_peer *bsspeer;
|
|
|
- uint8_t macaddr[QDF_MAC_ADDR_SIZE];
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- if (!psb) {
|
|
|
- tdls_debug("No need to configure auto trigger:psb is 0");
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
- }
|
|
|
- vdev_id = wlan_vdev_get_id(vdev);
|
|
|
- bsspeer = wlan_vdev_get_bsspeer(vdev);
|
|
|
- if (!bsspeer) {
|
|
|
- tdls_err("bss peer is NULL");
|
|
|
- return QDF_STATUS_E_FAILURE;
|
|
|
- }
|
|
|
- wlan_vdev_obj_lock(vdev);
|
|
|
- qdf_mem_copy(macaddr,
|
|
|
- wlan_peer_get_macaddr(bsspeer), QDF_MAC_ADDR_SIZE);
|
|
|
- wlan_vdev_obj_unlock(vdev);
|
|
|
-
|
|
|
- tdls_debug("TDLS uapsd id %d, srvc %d, sus %d, dir %d psb %d delay %d",
|
|
|
- sta_id, srvc_int, sus_int, dir, psb, delay_interval);
|
|
|
- for (i = 0; i < AC_PRIORITY_NUM; i++) {
|
|
|
- tdls_uapsd_params.wmm_ac = ac[i];
|
|
|
- tdls_uapsd_params.user_priority = tid[i];
|
|
|
- tdls_uapsd_params.service_interval = srvc_int;
|
|
|
- tdls_uapsd_params.delay_interval = delay_interval;
|
|
|
- tdls_uapsd_params.suspend_interval = sus_int;
|
|
|
-
|
|
|
- tdls_trig_params.vdevid = vdev_id;
|
|
|
- tdls_trig_params.num_ac = 1;
|
|
|
- tdls_trig_params.auto_triggerparam = &tdls_uapsd_params;
|
|
|
-
|
|
|
- qdf_mem_copy(tdls_trig_params.peer_addr,
|
|
|
- macaddr, QDF_MAC_ADDR_SIZE);
|
|
|
- status = tgt_tdls_set_uapsd(psoc, &tdls_trig_params);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("Failed to set uapsd for vdev %d, status %d",
|
|
|
- vdev_id, status);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_enable_link(struct tdls_oper_request *req)
|
|
|
-{
|
|
|
- struct tdls_peer *peer;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- uint8_t *mac;
|
|
|
- struct tdls_peer_update_state *peer_update_param;
|
|
|
- QDF_STATUS status;
|
|
|
- uint32_t feature;
|
|
|
- uint8_t id;
|
|
|
-
|
|
|
- vdev = req->vdev;
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("NULL vdev object");
|
|
|
- qdf_mem_free(req);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- /* vdev reference cnt is acquired in ucfg_tdls_oper */
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
-
|
|
|
- if (!vdev_obj || !soc_obj) {
|
|
|
- tdls_err("tdls vdev_obj: %pK soc_obj: %pK", vdev_obj, soc_obj);
|
|
|
- status = QDF_STATUS_E_NULL_VALUE;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- mac = req->peer_addr;
|
|
|
- peer = tdls_find_peer(vdev_obj, mac);
|
|
|
- if (!peer) {
|
|
|
- tdls_err(QDF_MAC_ADDR_STR
|
|
|
- " not found, ignore NL80211_TDLS_ENABLE_LINK",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac));
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_debug("enable link for peer " QDF_MAC_ADDR_STR " link state %d",
|
|
|
- QDF_MAC_ADDR_ARRAY(mac), peer->link_status);
|
|
|
- if (!TDLS_STA_INDEX_CHECK(peer->sta_id)) {
|
|
|
- tdls_err("invalid sta idx %u for " QDF_MAC_ADDR_STR,
|
|
|
- peer->sta_id, QDF_MAC_ADDR_ARRAY(mac));
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- peer->tdls_support = TDLS_CAP_SUPPORTED;
|
|
|
- if (TDLS_LINK_CONNECTED != peer->link_status)
|
|
|
- tdls_set_peer_link_status(peer, TDLS_LINK_CONNECTED,
|
|
|
- TDLS_LINK_SUCCESS);
|
|
|
-
|
|
|
- id = wlan_vdev_get_id(vdev);
|
|
|
- status = soc_obj->tdls_reg_peer(soc_obj->tdls_peer_context,
|
|
|
- id, mac, peer->sta_id,
|
|
|
- peer->qos);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("TDLS register peer fail, status %d", status);
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param));
|
|
|
- if (!peer_update_param) {
|
|
|
- tdls_err("memory allocation failed");
|
|
|
- status = QDF_STATUS_E_NOMEM;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_extract_peer_state_param(peer_update_param, peer);
|
|
|
-
|
|
|
- status = tdls_wma_update_peer_state(soc_obj, peer_update_param);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- qdf_mem_free(peer_update_param);
|
|
|
- status = QDF_STATUS_E_PERM;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_increment_peer_count(soc_obj);
|
|
|
- feature = soc_obj->tdls_configs.tdls_feature_flags;
|
|
|
-
|
|
|
- if (soc_obj->tdls_dp_vdev_update)
|
|
|
- soc_obj->tdls_dp_vdev_update(&soc_obj->soc,
|
|
|
- peer->sta_id,
|
|
|
- soc_obj->tdls_update_dp_vdev_flags,
|
|
|
- ((peer->link_status ==
|
|
|
- TDLS_LINK_CONNECTED) ? true : false));
|
|
|
-
|
|
|
- tdls_debug("TDLS buffer sta: %d, uapsd_mask %d",
|
|
|
- TDLS_IS_BUFFER_STA_ENABLED(feature),
|
|
|
- soc_obj->tdls_configs.tdls_uapsd_mask);
|
|
|
-
|
|
|
- if (TDLS_IS_BUFFER_STA_ENABLED(feature) ||
|
|
|
- soc_obj->tdls_configs.tdls_uapsd_mask)
|
|
|
- tdls_update_uapsd(soc_obj->soc,
|
|
|
- vdev, peer->sta_id, 0, 0, BI_DIR, 1,
|
|
|
- soc_obj->tdls_configs.delayed_trig_framint);
|
|
|
-error:
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_config_force_peer() - configure an externally controllable TDLS peer
|
|
|
- * @req: TDLS operation request
|
|
|
- *
|
|
|
- * This is not the tdls_process_cmd function. No need to acquire the reference
|
|
|
- * count, release reference count and free the request, the caller handle it
|
|
|
- * correctly.
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS if success; other values if failed
|
|
|
- */
|
|
|
-static QDF_STATUS tdls_config_force_peer(
|
|
|
- struct tdls_oper_config_force_peer_request *req)
|
|
|
-{
|
|
|
- struct tdls_peer *peer;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct wlan_objmgr_pdev *pdev;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- const uint8_t *macaddr;
|
|
|
- uint32_t feature;
|
|
|
- QDF_STATUS status;
|
|
|
- struct tdls_peer_update_state *peer_update_param;
|
|
|
-
|
|
|
- macaddr = req->peer_addr;
|
|
|
- tdls_debug("NL80211_TDLS_SETUP for " QDF_MAC_ADDR_STR,
|
|
|
- QDF_MAC_ADDR_ARRAY(macaddr));
|
|
|
-
|
|
|
- vdev = req->vdev;
|
|
|
- pdev = wlan_vdev_get_pdev(vdev);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- if (!pdev || !vdev_obj || !soc_obj) {
|
|
|
- tdls_err("pdev: %pK, vdev_obj: %pK, soc_obj: %pK",
|
|
|
- pdev, vdev_obj, soc_obj);
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
-
|
|
|
- feature = soc_obj->tdls_configs.tdls_feature_flags;
|
|
|
- if (!TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) ||
|
|
|
- !TDLS_IS_IMPLICIT_TRIG_ENABLED(feature)) {
|
|
|
- tdls_err("TDLS ext ctrl or Imp Trig not enabled, %x", feature);
|
|
|
- return QDF_STATUS_E_NOSUPPORT;
|
|
|
- }
|
|
|
-
|
|
|
- peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param));
|
|
|
- if (!peer_update_param) {
|
|
|
- tdls_err("memory allocation failed");
|
|
|
- return QDF_STATUS_E_NOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- peer = tdls_get_peer(vdev_obj, macaddr);
|
|
|
- if (!peer) {
|
|
|
- tdls_err("peer " QDF_MAC_ADDR_STR " does not exist",
|
|
|
- QDF_MAC_ADDR_ARRAY(macaddr));
|
|
|
- status = QDF_STATUS_E_NULL_VALUE;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- status = tdls_set_force_peer(vdev_obj, macaddr, true);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("set force peer failed");
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- /* Update the peer mac to firmware, so firmware could update the
|
|
|
- * connection table
|
|
|
- */
|
|
|
- peer_update_param->vdev_id = wlan_vdev_get_id(vdev);
|
|
|
- qdf_mem_copy(peer_update_param->peer_macaddr,
|
|
|
- macaddr, QDF_MAC_ADDR_SIZE);
|
|
|
- peer_update_param->peer_state = TDLS_PEER_ADD_MAC_ADDR;
|
|
|
-
|
|
|
- status = tdls_wma_update_peer_state(soc_obj, peer_update_param);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("update peer state failed");
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- soc_obj->tdls_external_peer_count++;
|
|
|
-
|
|
|
- /* Validate if off channel is DFS channel */
|
|
|
- if (wlan_reg_is_dfs_ch(pdev, req->chan)) {
|
|
|
- tdls_err("Resetting TDLS off-channel from %d to %d",
|
|
|
- req->chan, WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF);
|
|
|
- req->chan = WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF;
|
|
|
- }
|
|
|
- tdls_set_extctrl_param(peer, req->chan, req->max_latency, req->op_class,
|
|
|
- req->min_bandwidth);
|
|
|
-
|
|
|
- tdls_set_callback(peer, req->callback);
|
|
|
-
|
|
|
- tdls_set_ct_mode(soc_obj->soc);
|
|
|
- if (soc_obj->enable_tdls_connection_tracker)
|
|
|
- tdls_implicit_enable(vdev_obj);
|
|
|
-
|
|
|
- return status;
|
|
|
-error:
|
|
|
- qdf_mem_free(peer_update_param);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_process_setup_peer() - process configure an externally
|
|
|
- * controllable TDLS peer
|
|
|
- * @req: TDLS operation request
|
|
|
- *
|
|
|
- * Return: QDF_STATUS_SUCCESS if success; other values if failed
|
|
|
- */
|
|
|
-QDF_STATUS tdls_process_setup_peer(struct tdls_oper_request *req)
|
|
|
-{
|
|
|
- struct tdls_oper_config_force_peer_request peer_req;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- tdls_debug("Configure external TDLS peer " QDF_MAC_ADDR_STR,
|
|
|
- QDF_MAC_ADDR_ARRAY(req->peer_addr));
|
|
|
-
|
|
|
- /* reference cnt is acquired in ucfg_tdls_oper */
|
|
|
- vdev = req->vdev;
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("NULL vdev object");
|
|
|
- status = QDF_STATUS_E_NULL_VALUE;
|
|
|
- goto freereq;
|
|
|
- }
|
|
|
-
|
|
|
- qdf_mem_zero(&peer_req, sizeof(peer_req));
|
|
|
- peer_req.vdev = vdev;
|
|
|
- qdf_mem_copy(peer_req.peer_addr, req->peer_addr, QDF_MAC_ADDR_SIZE);
|
|
|
-
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- if (!soc_obj) {
|
|
|
- tdls_err("NULL soc object");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- peer_req.chan = soc_obj->tdls_configs.tdls_pre_off_chan_num;
|
|
|
-
|
|
|
- status = tdls_config_force_peer(&peer_req);
|
|
|
-error:
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
-freereq:
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req)
|
|
|
-{
|
|
|
- struct tdls_peer *peer;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct wlan_objmgr_vdev *vdev;
|
|
|
- const uint8_t *macaddr;
|
|
|
- uint32_t feature;
|
|
|
- QDF_STATUS status;
|
|
|
- struct tdls_peer_update_state *peer_update_param;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- macaddr = req->peer_addr;
|
|
|
- tdls_debug("NL80211_TDLS_TEARDOWN for " QDF_MAC_ADDR_STR,
|
|
|
- QDF_MAC_ADDR_ARRAY(macaddr));
|
|
|
-
|
|
|
- vdev = req->vdev;
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("NULL vdev object");
|
|
|
- qdf_mem_free(req);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- /* reference cnt is acquired in ucfg_tdls_oper */
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(req->vdev);
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj);
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- feature = soc_obj->tdls_configs.tdls_feature_flags;
|
|
|
- if (!TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) ||
|
|
|
- !TDLS_IS_IMPLICIT_TRIG_ENABLED(feature)) {
|
|
|
- tdls_err("TDLS ext ctrl or Imp Trig not enabled, %x", feature);
|
|
|
- status = QDF_STATUS_E_NOSUPPORT;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- peer = tdls_find_peer(vdev_obj, macaddr);
|
|
|
- if (!peer) {
|
|
|
- tdls_err("peer matching " QDF_MAC_ADDR_STR " not found",
|
|
|
- QDF_MAC_ADDR_ARRAY(macaddr));
|
|
|
- status = QDF_STATUS_E_NULL_VALUE;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_set_peer_link_status(peer, TDLS_LINK_TEARING,
|
|
|
- TDLS_LINK_UNSPECIFIED);
|
|
|
-
|
|
|
- if (soc_obj->tdls_dp_vdev_update)
|
|
|
- soc_obj->tdls_dp_vdev_update(&soc_obj->soc,
|
|
|
- peer->sta_id,
|
|
|
- soc_obj->tdls_update_dp_vdev_flags,
|
|
|
- false);
|
|
|
-
|
|
|
- if (soc_obj->tdls_event_cb) {
|
|
|
- qdf_mem_copy(ind.peer_mac, macaddr, QDF_MAC_ADDR_SIZE);
|
|
|
- ind.vdev = vdev;
|
|
|
- ind.reason = TDLS_TEARDOWN_PEER_UNSPEC_REASON;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_TEARDOWN_REQ, &ind);
|
|
|
- }
|
|
|
-
|
|
|
- status = tdls_set_force_peer(vdev_obj, macaddr, false);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("set force peer failed");
|
|
|
- status = QDF_STATUS_E_INVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- if (soc_obj->tdls_external_peer_count)
|
|
|
- soc_obj->tdls_external_peer_count--;
|
|
|
-
|
|
|
- tdls_set_callback(peer, NULL);
|
|
|
- peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param));
|
|
|
- if (!peer_update_param) {
|
|
|
- tdls_err("memory allocation failed");
|
|
|
- status = QDF_STATUS_E_NOMEM;
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- peer_update_param->vdev_id = wlan_vdev_get_id(vdev);
|
|
|
- qdf_mem_copy(peer_update_param->peer_macaddr,
|
|
|
- macaddr, QDF_MAC_ADDR_SIZE);
|
|
|
- peer_update_param->peer_state = TDLS_PEER_REMOVE_MAC_ADDR;
|
|
|
- status = tdls_wma_update_peer_state(soc_obj, peer_update_param);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- qdf_mem_free(peer_update_param);
|
|
|
- goto error;
|
|
|
- }
|
|
|
- tdls_set_ct_mode(soc_obj->soc);
|
|
|
- if (!soc_obj->enable_tdls_connection_tracker)
|
|
|
- tdls_implicit_disable(vdev_obj);
|
|
|
-
|
|
|
-error:
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static const char *tdls_evt_to_str(enum tdls_event_msg_type type)
|
|
|
-{
|
|
|
- switch (type) {
|
|
|
- case TDLS_SHOULD_DISCOVER:
|
|
|
- return "SHOULD_DISCOVER";
|
|
|
- case TDLS_SHOULD_TEARDOWN:
|
|
|
- return "SHOULD_TEARDOWN";
|
|
|
- case TDLS_PEER_DISCONNECTED:
|
|
|
- return "SHOULD_PEER_DISCONNECTED";
|
|
|
- case TDLS_CONNECTION_TRACKER_NOTIFY:
|
|
|
- return "CONNECTION_TRACKER_NOTIFICATION";
|
|
|
- default:
|
|
|
- return "INVALID_TYPE";
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_should_discover(struct wlan_objmgr_vdev *vdev,
|
|
|
- struct tdls_event_info *evt)
|
|
|
-{
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct tdls_peer *curr_peer;
|
|
|
- uint32_t feature;
|
|
|
- uint16_t type;
|
|
|
-
|
|
|
- /*TODO ignore this if any concurrency detected*/
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
- type = evt->message_type;
|
|
|
-
|
|
|
- tdls_debug("TDLS %s: " QDF_MAC_ADDR_STR "reason %d",
|
|
|
- tdls_evt_to_str(type),
|
|
|
- QDF_MAC_ADDR_ARRAY(evt->peermac.bytes),
|
|
|
- evt->peer_reason);
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s",
|
|
|
- soc_obj, vdev_obj, tdls_evt_to_str(type));
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
- if (soc_obj->tdls_nss_switch_in_progress) {
|
|
|
- tdls_err("TDLS antenna switching, ignore %s",
|
|
|
- tdls_evt_to_str(type));
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
- }
|
|
|
-
|
|
|
- curr_peer = tdls_get_peer(vdev_obj, evt->peermac.bytes);
|
|
|
- if (!curr_peer) {
|
|
|
- tdls_notice("curr_peer is null");
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- if (TDLS_LINK_CONNECTED == curr_peer->link_status) {
|
|
|
- tdls_err("TDLS link status is connected, ignore");
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
- }
|
|
|
-
|
|
|
- feature = soc_obj->tdls_configs.tdls_feature_flags;
|
|
|
- if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) &&
|
|
|
- !curr_peer->is_forced_peer) {
|
|
|
- tdls_debug("curr_peer is not forced, ignore %s",
|
|
|
- tdls_evt_to_str(type));
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_debug("initiate TDLS setup on %s, ext: %d, force: %d, reason: %d",
|
|
|
- tdls_evt_to_str(type),
|
|
|
- TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature),
|
|
|
- curr_peer->is_forced_peer, evt->peer_reason);
|
|
|
- vdev_obj->curr_candidate = curr_peer;
|
|
|
- tdls_implicit_send_discovery_request(vdev_obj);
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_should_teardown(struct wlan_objmgr_vdev *vdev,
|
|
|
- struct tdls_event_info *evt)
|
|
|
-{
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct tdls_peer *curr_peer;
|
|
|
- uint32_t reason;
|
|
|
- uint16_t type;
|
|
|
-
|
|
|
- type = evt->message_type;
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
-
|
|
|
- tdls_debug("TDLS %s: " QDF_MAC_ADDR_STR "reason %d",
|
|
|
- tdls_evt_to_str(type),
|
|
|
- QDF_MAC_ADDR_ARRAY(evt->peermac.bytes), evt->peer_reason);
|
|
|
-
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s",
|
|
|
- soc_obj, vdev_obj, tdls_evt_to_str(type));
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- curr_peer = tdls_find_peer(vdev_obj, evt->peermac.bytes);
|
|
|
- if (!curr_peer) {
|
|
|
- tdls_notice("curr_peer is null");
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- reason = evt->peer_reason;
|
|
|
- if (TDLS_LINK_CONNECTED == curr_peer->link_status) {
|
|
|
- tdls_err("%s reason: %d for" QDF_MAC_ADDR_STR,
|
|
|
- tdls_evt_to_str(type), evt->peer_reason,
|
|
|
- QDF_MAC_ADDR_ARRAY(evt->peermac.bytes));
|
|
|
- if (reason == TDLS_TEARDOWN_RSSI ||
|
|
|
- reason == TDLS_DISCONNECTED_PEER_DELETE ||
|
|
|
- reason == TDLS_TEARDOWN_PTR_TIMEOUT ||
|
|
|
- reason == TDLS_TEARDOWN_NO_RSP)
|
|
|
- reason = TDLS_TEARDOWN_PEER_UNREACHABLE;
|
|
|
- else
|
|
|
- reason = TDLS_TEARDOWN_PEER_UNSPEC_REASON;
|
|
|
-
|
|
|
- tdls_indicate_teardown(vdev_obj, curr_peer, reason);
|
|
|
- } else {
|
|
|
- tdls_err("TDLS link is not connected, ignore %s",
|
|
|
- tdls_evt_to_str(type));
|
|
|
- }
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_connection_tracker_notify(struct wlan_objmgr_vdev *vdev,
|
|
|
- struct tdls_event_info *evt)
|
|
|
-{
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- uint16_t type;
|
|
|
-
|
|
|
- type = evt->message_type;
|
|
|
- soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
|
|
|
- vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
|
|
|
-
|
|
|
- if (!soc_obj || !vdev_obj) {
|
|
|
- tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s",
|
|
|
- soc_obj, vdev_obj, tdls_evt_to_str(type));
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- /*TODO connection tracker update*/
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_process_set_responder() - Set/clear TDLS peer's responder role
|
|
|
- * @set_req: set responder request
|
|
|
- *
|
|
|
- * Return: 0 for success or -EINVAL otherwise
|
|
|
- */
|
|
|
-static
|
|
|
-int tdls_process_set_responder(struct tdls_set_responder_req *set_req)
|
|
|
-{
|
|
|
- struct tdls_peer *curr_peer;
|
|
|
- struct tdls_vdev_priv_obj *tdls_vdev;
|
|
|
-
|
|
|
- tdls_vdev = wlan_vdev_get_tdls_vdev_obj(set_req->vdev);
|
|
|
- if (!tdls_vdev) {
|
|
|
- tdls_err("tdls vdev obj is NULL");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- curr_peer = tdls_get_peer(tdls_vdev, set_req->peer_mac);
|
|
|
- if (curr_peer == NULL) {
|
|
|
- tdls_err("curr_peer is NULL");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- curr_peer->is_responder = set_req->responder;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * tdls_set_responder() - Set/clear TDLS peer's responder role
|
|
|
- * @set_req: set responder request
|
|
|
- *
|
|
|
- * Return: 0 for success or -EINVAL otherwise
|
|
|
- */
|
|
|
-int tdls_set_responder(struct tdls_set_responder_req *set_req)
|
|
|
-{
|
|
|
- QDF_STATUS status;
|
|
|
-
|
|
|
- if (!set_req || !set_req->vdev) {
|
|
|
- tdls_err("Invalid input params %pK", set_req);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- status = wlan_objmgr_vdev_try_get_ref(set_req->vdev, WLAN_TDLS_NB_ID);
|
|
|
- if (QDF_STATUS_SUCCESS != status) {
|
|
|
- tdls_err("vdev object is deleted");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- status = tdls_process_set_responder(set_req);
|
|
|
-
|
|
|
- wlan_objmgr_vdev_release_ref(set_req->vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(set_req);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static int tdls_teardown_links(struct tdls_soc_priv_obj *soc_obj, uint32_t mode)
|
|
|
-{
|
|
|
- uint8_t staidx;
|
|
|
- struct tdls_peer *curr_peer;
|
|
|
- struct tdls_conn_info *conn_rec;
|
|
|
- int ret = 0;
|
|
|
-
|
|
|
- conn_rec = soc_obj->tdls_conn_info;
|
|
|
- for (staidx = 0; staidx < soc_obj->max_num_tdls_sta; staidx++) {
|
|
|
- if (conn_rec[staidx].sta_id == INVALID_TDLS_PEER_ID)
|
|
|
- continue;
|
|
|
-
|
|
|
- curr_peer = tdls_find_all_peer(soc_obj,
|
|
|
- conn_rec[staidx].peer_mac.bytes);
|
|
|
- if (!curr_peer)
|
|
|
- continue;
|
|
|
-
|
|
|
- /* if supported only 1x1, skip it */
|
|
|
- if (curr_peer->spatial_streams == HW_MODE_SS_1x1)
|
|
|
- continue;
|
|
|
-
|
|
|
- tdls_debug("Indicate TDLS teardown (staId %d)",
|
|
|
- curr_peer->sta_id);
|
|
|
- tdls_indicate_teardown(curr_peer->vdev_priv, curr_peer,
|
|
|
- TDLS_TEARDOWN_PEER_UNSPEC_REASON);
|
|
|
-
|
|
|
- soc_obj->tdls_teardown_peers_cnt++;
|
|
|
- }
|
|
|
-
|
|
|
- if (soc_obj->tdls_teardown_peers_cnt >= 1) {
|
|
|
- soc_obj->tdls_nss_switch_in_progress = true;
|
|
|
- tdls_debug("TDLS peers to be torn down = %d",
|
|
|
- soc_obj->tdls_teardown_peers_cnt);
|
|
|
-
|
|
|
- /* set the antenna switch transition mode */
|
|
|
- if (mode == HW_MODE_SS_1x1) {
|
|
|
- soc_obj->tdls_nss_transition_mode =
|
|
|
- TDLS_NSS_TRANSITION_S_2x2_to_1x1;
|
|
|
- ret = -EAGAIN;
|
|
|
- } else {
|
|
|
- soc_obj->tdls_nss_transition_mode =
|
|
|
- TDLS_NSS_TRANSITION_S_1x1_to_2x2;
|
|
|
- ret = 0;
|
|
|
- }
|
|
|
- tdls_debug("TDLS teardown for antenna switch operation starts");
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_process_antenna_switch(struct tdls_antenna_switch_request *req)
|
|
|
-{
|
|
|
- QDF_STATUS status;
|
|
|
- struct tdls_soc_priv_obj *soc_obj;
|
|
|
- struct tdls_vdev_priv_obj *vdev_obj;
|
|
|
- struct wlan_objmgr_vdev *vdev = NULL;
|
|
|
- uint32_t vdev_nss;
|
|
|
- int ant_switch_state = 0;
|
|
|
- uint32_t vdev_id;
|
|
|
- enum QDF_OPMODE opmode;
|
|
|
- uint8_t channel;
|
|
|
- struct tdls_osif_indication ind;
|
|
|
-
|
|
|
- if (!req) {
|
|
|
- tdls_err("null req");
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
-
|
|
|
- vdev = req->vdev;
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("null vdev");
|
|
|
- qdf_mem_free(req);
|
|
|
- return QDF_STATUS_E_INVAL;
|
|
|
- }
|
|
|
-
|
|
|
- status = tdls_get_vdev_objects(vdev, &vdev_obj, &soc_obj);
|
|
|
- if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
- tdls_err("can't get vdev_obj & soc_obj");
|
|
|
- goto get_obj_err;
|
|
|
- }
|
|
|
-
|
|
|
- if (soc_obj->connected_peer_count == 0)
|
|
|
- goto ant_sw_done;
|
|
|
-
|
|
|
- if (soc_obj->tdls_nss_switch_in_progress) {
|
|
|
- if (!soc_obj->tdls_nss_teardown_complete) {
|
|
|
- tdls_err("TDLS antenna switch is in progress");
|
|
|
- goto ant_sw_in_progress;
|
|
|
- } else {
|
|
|
- goto ant_sw_done;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- vdev_id = wlan_vdev_get_id(vdev);
|
|
|
- opmode = wlan_vdev_mlme_get_opmode(vdev);
|
|
|
- channel = policy_mgr_get_channel(soc_obj->soc,
|
|
|
- policy_mgr_convert_device_mode_to_qdf_type(opmode),
|
|
|
- &vdev_id);
|
|
|
-
|
|
|
- /* Check supported nss for TDLS, if is 1x1, no need to teardown links */
|
|
|
- if (WLAN_REG_IS_24GHZ_CH(channel))
|
|
|
- vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_2g;
|
|
|
- else
|
|
|
- vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_5g;
|
|
|
-
|
|
|
- if (vdev_nss == HW_MODE_SS_1x1) {
|
|
|
- tdls_debug("Supported NSS is 1x1, no need to teardown TDLS links");
|
|
|
- goto ant_sw_done;
|
|
|
- }
|
|
|
-
|
|
|
- if (tdls_teardown_links(soc_obj, req->mode) == 0)
|
|
|
- goto ant_sw_done;
|
|
|
-
|
|
|
-ant_sw_in_progress:
|
|
|
- ant_switch_state = -EAGAIN;
|
|
|
-ant_sw_done:
|
|
|
- if (soc_obj->tdls_event_cb) {
|
|
|
- ind.vdev = vdev;
|
|
|
- ind.status = ant_switch_state;
|
|
|
- soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
|
|
- TDLS_EVENT_ANTENNA_SWITCH, &ind);
|
|
|
- }
|
|
|
-
|
|
|
- if (soc_obj->tdls_nss_switch_in_progress &&
|
|
|
- soc_obj->tdls_nss_teardown_complete) {
|
|
|
- soc_obj->tdls_nss_switch_in_progress = false;
|
|
|
- soc_obj->tdls_nss_teardown_complete = false;
|
|
|
- }
|
|
|
- tdls_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
|
|
|
- soc_obj->tdls_nss_switch_in_progress,
|
|
|
- soc_obj->tdls_nss_teardown_complete);
|
|
|
-
|
|
|
-get_obj_err:
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-QDF_STATUS tdls_antenna_switch_flush_callback(struct scheduler_msg *msg)
|
|
|
-{
|
|
|
- struct tdls_antenna_switch_request *req;
|
|
|
-
|
|
|
- if (!msg || !msg->bodyptr) {
|
|
|
- tdls_err("msg: 0x%pK", msg);
|
|
|
- return QDF_STATUS_E_NULL_VALUE;
|
|
|
- }
|
|
|
- req = msg->bodyptr;
|
|
|
- wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return QDF_STATUS_SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-void wlan_tdls_offchan_parms_callback(struct wlan_objmgr_vdev *vdev)
|
|
|
-{
|
|
|
- if (!vdev) {
|
|
|
- tdls_err("vdev is NULL");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
|
|
-}
|
|
|
-
|
|
|
-int tdls_process_set_offchannel(struct tdls_set_offchannel *req)
|
|
|
-{
|
|
|
- int status;
|
|
|
- struct tdls_vdev_priv_obj *tdls_vdev_obj;
|
|
|
- struct tdls_soc_priv_obj *tdls_soc_obj;
|
|
|
-
|
|
|
- if (tdls_get_vdev_objects(req->vdev, &tdls_vdev_obj, &tdls_soc_obj) !=
|
|
|
- QDF_STATUS_SUCCESS) {
|
|
|
- status = -ENOTSUPP;
|
|
|
- goto free;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_debug("TDLS offchannel to be configured %d", req->offchannel);
|
|
|
-
|
|
|
- if (req->offchannel)
|
|
|
- status = tdls_set_tdls_offchannel(tdls_soc_obj,
|
|
|
- req->offchannel);
|
|
|
- else
|
|
|
- status = -ENOTSUPP;
|
|
|
-
|
|
|
-free:
|
|
|
-
|
|
|
- if (req->callback)
|
|
|
- req->callback(req->vdev);
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-int tdls_process_set_offchan_mode(struct tdls_set_offchanmode *req)
|
|
|
-{
|
|
|
- int status;
|
|
|
-
|
|
|
- tdls_debug("TDLS offchan mode to be configured %d", req->offchan_mode);
|
|
|
- status = tdls_set_tdls_offchannelmode(req->vdev, req->offchan_mode);
|
|
|
-
|
|
|
- if (req->callback)
|
|
|
- req->callback(req->vdev);
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-int tdls_process_set_secoffchanneloffset(
|
|
|
- struct tdls_set_secoffchanneloffset *req)
|
|
|
-{
|
|
|
- int status;
|
|
|
- struct tdls_vdev_priv_obj *tdls_vdev_obj;
|
|
|
- struct tdls_soc_priv_obj *tdls_soc_obj;
|
|
|
-
|
|
|
- if (tdls_get_vdev_objects(req->vdev, &tdls_vdev_obj, &tdls_soc_obj) !=
|
|
|
- QDF_STATUS_SUCCESS) {
|
|
|
- status = -ENOTSUPP;
|
|
|
- goto free;
|
|
|
- }
|
|
|
-
|
|
|
- tdls_debug("TDLS offchannel offset to be configured %d",
|
|
|
- req->offchan_offset);
|
|
|
- status = tdls_set_tdls_secoffchanneloffset(tdls_soc_obj,
|
|
|
- req->offchan_offset);
|
|
|
-
|
|
|
-free:
|
|
|
-
|
|
|
- if (req->callback)
|
|
|
- req->callback(req->vdev);
|
|
|
- qdf_mem_free(req);
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|