blob: 4e5b493dd09daaba69be769f95986191f6d0e17a [file] [log] [blame]
/*
* Copyright (c) 2016-2019 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_mgmt_txrx_utils_api.c
* This file contains mgmt txrx public API definitions for umac
* converged components.
*/
#include "wlan_mgmt_txrx_utils_api.h"
#include "../../core/src/wlan_mgmt_txrx_main_i.h"
#include "wlan_objmgr_psoc_obj.h"
#include "wlan_objmgr_global_obj.h"
#include "wlan_objmgr_pdev_obj.h"
#include "wlan_objmgr_vdev_obj.h"
#include "wlan_objmgr_peer_obj.h"
#include "qdf_nbuf.h"
#include "wlan_lmac_if_api.h"
/**
* wlan_mgmt_txrx_psoc_obj_create_notification() - called from objmgr when psoc
* is created
* @psoc: psoc context
* @arg: argument
*
* This function gets called from object manager when psoc is being created and
* creates mgmt_txrx context, mgmt desc pool.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS wlan_mgmt_txrx_psoc_obj_create_notification(
struct wlan_objmgr_psoc *psoc,
void *arg)
{
struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
QDF_STATUS status;
if (!psoc) {
mgmt_txrx_err("psoc context passed is NULL");
status = QDF_STATUS_E_INVAL;
goto err_return;
}
mgmt_txrx_psoc_ctx = qdf_mem_malloc(sizeof(*mgmt_txrx_psoc_ctx));
if (!mgmt_txrx_psoc_ctx) {
status = QDF_STATUS_E_NOMEM;
goto err_return;
}
mgmt_txrx_psoc_ctx->psoc = psoc;
qdf_spinlock_create(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
if (wlan_objmgr_psoc_component_obj_attach(psoc,
WLAN_UMAC_COMP_MGMT_TXRX,
mgmt_txrx_psoc_ctx, QDF_STATUS_SUCCESS)
!= QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to attach mgmt txrx ctx in psoc ctx");
status = QDF_STATUS_E_FAILURE;
goto err_psoc_attach;
}
mgmt_txrx_info("Mgmt txrx creation successful, mgmt txrx ctx: %pK, psoc: %pK",
mgmt_txrx_psoc_ctx, psoc);
return QDF_STATUS_SUCCESS;
err_psoc_attach:
qdf_spinlock_destroy(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
qdf_mem_free(mgmt_txrx_psoc_ctx);
err_return:
return status;
}
/**
* wlan_mgmt_txrx_psoc_obj_destroy_notification() - called from objmgr when
* psoc is destroyed
* @psoc: psoc context
* @arg: argument
*
* This function gets called from object manager when psoc is being destroyed
* psoc deletes mgmt_txrx context, mgmt desc pool.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS wlan_mgmt_txrx_psoc_obj_destroy_notification(
struct wlan_objmgr_psoc *psoc,
void *arg)
{
struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
if (!psoc) {
mgmt_txrx_err("psoc context passed is NULL");
return QDF_STATUS_E_INVAL;
}
mgmt_txrx_psoc_ctx = wlan_objmgr_psoc_get_comp_private_obj(
psoc, WLAN_UMAC_COMP_MGMT_TXRX);
if (!mgmt_txrx_psoc_ctx) {
mgmt_txrx_err("mgmt txrx context is already NULL");
return QDF_STATUS_E_FAILURE;
}
mgmt_txrx_info("deleting mgmt txrx psoc obj, mgmt txrx ctx: %pK, psoc: %pK",
mgmt_txrx_psoc_ctx, psoc);
if (wlan_objmgr_psoc_component_obj_detach(psoc,
WLAN_UMAC_COMP_MGMT_TXRX, mgmt_txrx_psoc_ctx)
!= QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to detach mgmt txrx ctx in psoc ctx");
return QDF_STATUS_E_FAILURE;
}
qdf_spinlock_destroy(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
qdf_mem_free(mgmt_txrx_psoc_ctx);
mgmt_txrx_info("mgmt txrx deletion successful, psoc: %pK", psoc);
return QDF_STATUS_SUCCESS;
}
/**
* wlan_mgmt_txrx_pdev_obj_create_notification() - called from objmgr when pdev
* is created
* @pdev: pdev context
* @arg: argument
*
* This function gets called from object manager when pdev is being created and
* creates mgmt_txrx context, mgmt desc pool.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS wlan_mgmt_txrx_pdev_obj_create_notification(
struct wlan_objmgr_pdev *pdev,
void *arg)
{
struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
struct mgmt_txrx_stats_t *mgmt_txrx_stats;
QDF_STATUS status;
if (!pdev) {
mgmt_txrx_err("pdev context passed is NULL");
status = QDF_STATUS_E_INVAL;
goto err_return;
}
mgmt_txrx_pdev_ctx = qdf_mem_malloc(sizeof(*mgmt_txrx_pdev_ctx));
if (!mgmt_txrx_pdev_ctx) {
status = QDF_STATUS_E_NOMEM;
goto err_return;
}
mgmt_txrx_pdev_ctx->pdev = pdev;
status = wlan_mgmt_txrx_desc_pool_init(mgmt_txrx_pdev_ctx);
if (status != QDF_STATUS_SUCCESS) {
mgmt_txrx_err(
"Failed to initialize mgmt desc. pool with status: %u",
status);
goto err_desc_pool_init;
}
mgmt_txrx_stats = qdf_mem_malloc(sizeof(*mgmt_txrx_stats));
if (!mgmt_txrx_stats) {
status = QDF_STATUS_E_NOMEM;
goto err_mgmt_txrx_stats;
}
mgmt_txrx_pdev_ctx->mgmt_txrx_stats = mgmt_txrx_stats;
qdf_wake_lock_create(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp,
"mgmt_txrx tx_cmp");
qdf_runtime_lock_init(&mgmt_txrx_pdev_ctx->wakelock_tx_runtime_cmp);
if (wlan_objmgr_pdev_component_obj_attach(pdev,
WLAN_UMAC_COMP_MGMT_TXRX,
mgmt_txrx_pdev_ctx, QDF_STATUS_SUCCESS)
!= QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to attach mgmt txrx ctx in pdev ctx");
status = QDF_STATUS_E_FAILURE;
goto err_pdev_attach;
}
mgmt_txrx_info(
"Mgmt txrx creation successful, mgmt txrx ctx: %pK, pdev: %pK",
mgmt_txrx_pdev_ctx, pdev);
return QDF_STATUS_SUCCESS;
err_pdev_attach:
qdf_runtime_lock_deinit(&mgmt_txrx_pdev_ctx->wakelock_tx_runtime_cmp);
qdf_wake_lock_destroy(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp);
qdf_mem_free(mgmt_txrx_stats);
err_mgmt_txrx_stats:
wlan_mgmt_txrx_desc_pool_deinit(mgmt_txrx_pdev_ctx);
err_desc_pool_init:
qdf_mem_free(mgmt_txrx_pdev_ctx);
err_return:
return status;
}
/**
* wlan_mgmt_txrx_pdev_obj_destroy_notification() - called from objmgr when
* pdev is destroyed
* @pdev: pdev context
* @arg: argument
*
* This function gets called from object manager when pdev is being destroyed
* pdev deletes mgmt_txrx context, mgmt desc pool.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS wlan_mgmt_txrx_pdev_obj_destroy_notification(
struct wlan_objmgr_pdev *pdev,
void *arg)
{
struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
if (!pdev) {
mgmt_txrx_err("pdev context passed is NULL");
return QDF_STATUS_E_INVAL;
}
mgmt_txrx_pdev_ctx = wlan_objmgr_pdev_get_comp_private_obj(
pdev, WLAN_UMAC_COMP_MGMT_TXRX);
if (!mgmt_txrx_pdev_ctx) {
mgmt_txrx_err("mgmt txrx context is already NULL");
return QDF_STATUS_E_FAILURE;
}
mgmt_txrx_info("deleting mgmt txrx pdev obj, mgmt txrx ctx: %pK, pdev: %pK",
mgmt_txrx_pdev_ctx, pdev);
if (wlan_objmgr_pdev_component_obj_detach(pdev,
WLAN_UMAC_COMP_MGMT_TXRX, mgmt_txrx_pdev_ctx)
!= QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to detach mgmt txrx ctx in pdev ctx");
return QDF_STATUS_E_FAILURE;
}
wlan_mgmt_txrx_desc_pool_deinit(mgmt_txrx_pdev_ctx);
qdf_mem_free(mgmt_txrx_pdev_ctx->mgmt_txrx_stats);
qdf_runtime_lock_deinit(&mgmt_txrx_pdev_ctx->wakelock_tx_runtime_cmp);
qdf_wake_lock_destroy(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp);
qdf_mem_free(mgmt_txrx_pdev_ctx);
mgmt_txrx_info("mgmt txrx deletion successful, pdev: %pK", pdev);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_init(void)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
status = wlan_objmgr_register_psoc_create_handler(
WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_psoc_obj_create_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to register mgmt txrx psoc create handler");
goto err_psoc_create;
}
status = wlan_objmgr_register_psoc_destroy_handler(
WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_psoc_obj_destroy_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to register mgmt txrx psoc destroy handler");
goto err_psoc_delete;
}
status = wlan_objmgr_register_pdev_create_handler(
WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_pdev_obj_create_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to register mgmt txrx pdev obj create handler");
goto err_pdev_create;
}
status = wlan_objmgr_register_pdev_destroy_handler(
WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_pdev_obj_destroy_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
mgmt_txrx_err("Failed to register mgmt txrx obj destroy handler");
goto err_pdev_delete;
}
mgmt_txrx_info("Successfully registered create and destroy handlers with objmgr");
return QDF_STATUS_SUCCESS;
err_pdev_delete:
wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_pdev_obj_create_notification, NULL);
err_pdev_create:
wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_psoc_obj_destroy_notification, NULL);
err_psoc_delete:
wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_psoc_obj_create_notification, NULL);
err_psoc_create:
return status;
}
QDF_STATUS wlan_mgmt_txrx_deinit(void)
{
if (wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_psoc_obj_create_notification,
NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
if (wlan_objmgr_unregister_psoc_destroy_handler(
WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_psoc_obj_destroy_notification,
NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
if (wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_pdev_obj_create_notification,
NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
if (wlan_objmgr_unregister_pdev_destroy_handler(
WLAN_UMAC_COMP_MGMT_TXRX,
wlan_mgmt_txrx_pdev_obj_destroy_notification,
NULL)
!= QDF_STATUS_SUCCESS) {
return QDF_STATUS_E_FAILURE;
}
mgmt_txrx_info("Successfully unregistered create and destroy handlers with objmgr");
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_mgmt_frame_tx(struct wlan_objmgr_peer *peer,
void *context,
qdf_nbuf_t buf,
mgmt_tx_download_comp_cb tx_comp_cb,
mgmt_ota_comp_cb tx_ota_comp_cb,
enum wlan_umac_comp_id comp_id,
void *mgmt_tx_params)
{
struct mgmt_txrx_desc_elem_t *desc;
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_pdev *pdev;
struct mgmt_txrx_priv_pdev_context *txrx_ctx;
struct wlan_objmgr_vdev *vdev;
QDF_STATUS status;
if (!peer) {
mgmt_txrx_err("peer passed is NULL");
return QDF_STATUS_E_NULL_VALUE;
}
status = wlan_objmgr_peer_try_get_ref(peer, WLAN_MGMT_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
mgmt_txrx_err("failed to get ref count for peer %pK", peer);
return QDF_STATUS_E_NULL_VALUE;
}
vdev = wlan_peer_get_vdev(peer);
if (!vdev) {
mgmt_txrx_err("vdev unavailable for peer %pK", peer);
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
return QDF_STATUS_E_NULL_VALUE;
}
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
mgmt_txrx_err("psoc unavailable for peer %pK vdev %pK",
peer, vdev);
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
return QDF_STATUS_E_NULL_VALUE;
}
pdev = wlan_vdev_get_pdev(vdev);
if (!pdev) {
mgmt_txrx_err("pdev unavailable for peer %pK vdev %pK",
peer, vdev);
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
return QDF_STATUS_E_NULL_VALUE;
}
txrx_ctx = (struct mgmt_txrx_priv_pdev_context *)
wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_MGMT_TXRX);
if (!txrx_ctx) {
mgmt_txrx_err("No txrx context for peer %pK pdev %pK",
peer, pdev);
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
return QDF_STATUS_E_NULL_VALUE;
}
desc = wlan_mgmt_txrx_desc_get(txrx_ctx);
if (!desc) {
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
return QDF_STATUS_E_RESOURCES;
}
desc->nbuf = buf;
desc->tx_ota_cmpl_cb = tx_ota_comp_cb;
desc->tx_dwnld_cmpl_cb = tx_comp_cb;
desc->peer = peer;
desc->vdev_id = wlan_vdev_get_id(vdev);
desc->context = context;
if (!psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.mgmt_tx_send) {
mgmt_txrx_err(
"mgmt txrx txop to send mgmt frame is NULL for psoc: %pK",
psoc);
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
desc->nbuf = NULL;
wlan_mgmt_txrx_desc_put(txrx_ctx, desc->desc_id);
return QDF_STATUS_E_FAILURE;
}
if (psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.mgmt_tx_send(
vdev, buf, desc->desc_id, mgmt_tx_params)) {
mgmt_txrx_err("Mgmt send fail for peer %pK psoc %pK pdev: %pK",
peer, psoc, pdev);
wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID);
desc->nbuf = NULL;
wlan_mgmt_txrx_desc_put(txrx_ctx, desc->desc_id);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_beacon_frame_tx(struct wlan_objmgr_peer *peer,
qdf_nbuf_t buf,
enum wlan_umac_comp_id comp_id)
{
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_psoc *psoc;
vdev = wlan_peer_get_vdev(peer);
if (!vdev) {
mgmt_txrx_err("vdev unavailable for peer %pK", peer);
return QDF_STATUS_E_NULL_VALUE;
}
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
mgmt_txrx_err("psoc unavailable for peer %pK", peer);
return QDF_STATUS_E_NULL_VALUE;
}
if (!psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.beacon_send) {
mgmt_txrx_err("mgmt txrx tx op to send beacon frame is NULL for psoc: %pK",
psoc);
return QDF_STATUS_E_FAILURE;
}
if (psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.beacon_send(vdev, buf)) {
mgmt_txrx_err("Beacon send fail for peer %pK psoc %pK",
peer, psoc);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_SUPPORT_FILS
QDF_STATUS
wlan_mgmt_txrx_fd_action_frame_tx(struct wlan_objmgr_vdev *vdev,
qdf_nbuf_t buf,
enum wlan_umac_comp_id comp_id)
{
struct wlan_objmgr_psoc *psoc;
uint32_t vdev_id;
if (!vdev) {
mgmt_txrx_err("Invalid vdev");
return QDF_STATUS_E_NULL_VALUE;
}
vdev_id = wlan_vdev_get_id(vdev);
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
mgmt_txrx_err("psoc unavailable for vdev %d", vdev_id);
return QDF_STATUS_E_NULL_VALUE;
}
if (!psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.fd_action_frame_send) {
mgmt_txrx_err("mgmt txrx txop to send fd action frame is NULL");
return QDF_STATUS_E_FAILURE;
}
if (psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.fd_action_frame_send(
vdev, buf)) {
mgmt_txrx_err("FD send fail for vdev %d", vdev_id);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
#endif /* WLAN_SUPPORT_FILS */
/**
* wlan_mgmt_txrx_create_rx_handler() - creates rx handler node for umac comp.
* @mgmt_txrx_psoc_ctx: mgmt txrx context
* @mgmt_rx_cb: mgmt rx callback to be registered
* @comp_id: umac component id
* @frm_type: mgmt. frame for which cb to be registered.
*
* This function creates rx handler node for frame type and
* umac component passed in the func.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS wlan_mgmt_txrx_create_rx_handler(
struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx,
mgmt_frame_rx_callback mgmt_rx_cb,
enum wlan_umac_comp_id comp_id,
enum mgmt_frame_type frm_type)
{
struct mgmt_rx_handler *rx_handler;
rx_handler = qdf_mem_malloc(sizeof(*rx_handler));
if (!rx_handler)
return QDF_STATUS_E_NOMEM;
rx_handler->comp_id = comp_id;
rx_handler->rx_cb = mgmt_rx_cb;
qdf_spin_lock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
rx_handler->next = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type];
mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type] = rx_handler;
qdf_spin_unlock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
mgmt_txrx_info("Callback registered for comp_id: %d, frm_type: %d",
comp_id, frm_type);
return QDF_STATUS_SUCCESS;
}
/**
* wlan_mgmt_txrx_delete_rx_handler() - deletes rx handler node for umac comp.
* @mgmt_txrx_psoc_ctx: mgmt txrx context
* @mgmt_rx_cb: mgmt rx callback to be deregistered
* @comp_id: umac component id
* @frm_type: mgmt. frame for which cb to be registered.
*
* This function deletes rx handler node for frame type and
* umac component passed in the func.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS wlan_mgmt_txrx_delete_rx_handler(
struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx,
mgmt_frame_rx_callback mgmt_rx_cb,
enum wlan_umac_comp_id comp_id,
enum mgmt_frame_type frm_type)
{
struct mgmt_rx_handler *rx_handler = NULL, *rx_handler_prev = NULL;
bool delete = false;
qdf_spin_lock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
rx_handler = mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type];
while (rx_handler) {
if (rx_handler->comp_id == comp_id &&
rx_handler->rx_cb == mgmt_rx_cb) {
if (rx_handler_prev)
rx_handler_prev->next =
rx_handler->next;
else
mgmt_txrx_psoc_ctx->mgmt_rx_comp_cb[frm_type] =
rx_handler->next;
qdf_mem_free(rx_handler);
delete = true;
break;
}
rx_handler_prev = rx_handler;
rx_handler = rx_handler->next;
}
qdf_spin_unlock_bh(&mgmt_txrx_psoc_ctx->mgmt_txrx_psoc_ctx_lock);
if (!delete) {
mgmt_txrx_err("No callback registered for comp_id: %d, frm_type: %d",
comp_id, frm_type);
return QDF_STATUS_E_FAILURE;
}
mgmt_txrx_info("Callback deregistered for comp_id: %d, frm_type: %d",
comp_id, frm_type);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_register_rx_cb(
struct wlan_objmgr_psoc *psoc,
enum wlan_umac_comp_id comp_id,
struct mgmt_txrx_mgmt_frame_cb_info *frm_cb_info,
uint8_t num_entries)
{
struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
QDF_STATUS status;
uint8_t i, j;
if (!psoc) {
mgmt_txrx_err("psoc context is NULL");
return QDF_STATUS_E_INVAL;
}
if (comp_id >= WLAN_UMAC_MAX_COMPONENTS) {
mgmt_txrx_err("Invalid component id %d passed", comp_id);
return QDF_STATUS_E_INVAL;
}
if (!num_entries || num_entries >= MGMT_MAX_FRAME_TYPE) {
mgmt_txrx_err("Invalid value for num_entries: %d passed",
num_entries);
return QDF_STATUS_E_INVAL;
}
if (!frm_cb_info) {
mgmt_txrx_err("frame cb info pointer is NULL");
return QDF_STATUS_E_INVAL;
}
mgmt_txrx_psoc_ctx = (struct mgmt_txrx_priv_psoc_context *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_MGMT_TXRX);
if (!mgmt_txrx_psoc_ctx) {
mgmt_txrx_err("mgmt txrx context is NULL");
return QDF_STATUS_E_FAILURE;
}
for (i = 0; i < num_entries; i++) {
status = wlan_mgmt_txrx_create_rx_handler(mgmt_txrx_psoc_ctx,
frm_cb_info[i].mgmt_rx_cb, comp_id,
frm_cb_info[i].frm_type);
if (status != QDF_STATUS_SUCCESS) {
for (j = 0; j < i; j++) {
wlan_mgmt_txrx_delete_rx_handler(
mgmt_txrx_psoc_ctx,
frm_cb_info[j].mgmt_rx_cb,
comp_id, frm_cb_info[j].frm_type);
}
return status;
}
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_deregister_rx_cb(
struct wlan_objmgr_psoc *psoc,
enum wlan_umac_comp_id comp_id,
struct mgmt_txrx_mgmt_frame_cb_info *frm_cb_info,
uint8_t num_entries)
{
struct mgmt_txrx_priv_psoc_context *mgmt_txrx_psoc_ctx;
uint8_t i;
if (!psoc) {
mgmt_txrx_err("psoc context is NULL");
return QDF_STATUS_E_INVAL;
}
if (comp_id >= WLAN_UMAC_MAX_COMPONENTS) {
mgmt_txrx_err("Invalid component id %d passed", comp_id);
return QDF_STATUS_E_INVAL;
}
if (!num_entries || num_entries >= MGMT_MAX_FRAME_TYPE) {
mgmt_txrx_err("Invalid value for num_entries: %d passed",
num_entries);
return QDF_STATUS_E_INVAL;
}
if (!frm_cb_info) {
mgmt_txrx_err("frame cb info pointer is NULL");
return QDF_STATUS_E_INVAL;
}
mgmt_txrx_psoc_ctx = (struct mgmt_txrx_priv_psoc_context *)
wlan_objmgr_psoc_get_comp_private_obj(psoc,
WLAN_UMAC_COMP_MGMT_TXRX);
if (!mgmt_txrx_psoc_ctx) {
mgmt_txrx_err("mgmt txrx context is NULL");
return QDF_STATUS_E_FAILURE;
}
for (i = 0; i < num_entries; i++) {
wlan_mgmt_txrx_delete_rx_handler(mgmt_txrx_psoc_ctx,
frm_cb_info[i].mgmt_rx_cb, comp_id,
frm_cb_info[i].frm_type);
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_psoc_open(struct wlan_objmgr_psoc *psoc)
{
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_psoc_close(struct wlan_objmgr_psoc *psoc)
{
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_pdev_open(struct wlan_objmgr_pdev *pdev)
{
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_pdev_close(struct wlan_objmgr_pdev *pdev)
{
struct wlan_objmgr_psoc *psoc;
struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
struct mgmt_txrx_desc_elem_t *mgmt_desc;
uint32_t pool_size;
uint32_t index;
if (!pdev) {
mgmt_txrx_err("pdev context is NULL");
return QDF_STATUS_E_INVAL;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
mgmt_txrx_err("psoc unavailable for pdev %pK", pdev);
return QDF_STATUS_E_NULL_VALUE;
}
mgmt_txrx_pdev_ctx = (struct mgmt_txrx_priv_pdev_context *)
wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_MGMT_TXRX);
if (!mgmt_txrx_pdev_ctx) {
mgmt_txrx_err("mgmt txrx context is NULL");
return QDF_STATUS_E_FAILURE;
}
pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size;
if (!pool_size) {
mgmt_txrx_err("pool size is 0");
return QDF_STATUS_E_FAILURE;
}
for (index = 0; index < pool_size; index++) {
if (mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[index].in_use) {
mgmt_txrx_info(
"mgmt descriptor with desc id: %d not in freelist",
index);
mgmt_desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[index];
if (psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.
tx_drain_nbuf_op)
psoc->soc_cb.tx_ops.mgmt_txrx_tx_ops.
tx_drain_nbuf_op(pdev, mgmt_desc->nbuf);
qdf_nbuf_free(mgmt_desc->nbuf);
wlan_objmgr_peer_release_ref(mgmt_desc->peer,
WLAN_MGMT_NB_ID);
wlan_mgmt_txrx_desc_put(mgmt_txrx_pdev_ctx, index);
}
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS wlan_mgmt_txrx_vdev_drain(struct wlan_objmgr_vdev *vdev,
mgmt_frame_fill_peer_cb mgmt_fill_peer_cb,
void *status)
{
struct wlan_objmgr_pdev *pdev;
struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx;
struct mgmt_txrx_desc_elem_t *mgmt_desc;
struct wlan_objmgr_peer *peer;
struct wlan_objmgr_vdev *peer_vdev;
uint32_t pool_size;
int i;
if (!vdev) {
mgmt_txrx_err("vdev context is NULL");
return QDF_STATUS_E_INVAL;
}
pdev = wlan_vdev_get_pdev(vdev);
if (!pdev) {
mgmt_txrx_err("pdev context is NULL");
return QDF_STATUS_E_INVAL;
}
mgmt_txrx_pdev_ctx = (struct mgmt_txrx_priv_pdev_context *)
wlan_objmgr_pdev_get_comp_private_obj(pdev,
WLAN_UMAC_COMP_MGMT_TXRX);
if (!mgmt_txrx_pdev_ctx) {
mgmt_txrx_err("mgmt txrx context is NULL");
return QDF_STATUS_E_FAILURE;
}
pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size;
if (!pool_size) {
mgmt_txrx_err("pool size is 0");
return QDF_STATUS_E_FAILURE;
}
for (i = 0; i < pool_size; i++) {
if (mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].in_use) {
mgmt_desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i];
peer = mgmt_txrx_get_peer(pdev, mgmt_desc->desc_id);
if (peer) {
peer_vdev = wlan_peer_get_vdev(peer);
if (peer_vdev == vdev) {
if (mgmt_fill_peer_cb)
mgmt_fill_peer_cb(peer, mgmt_desc->nbuf);
mgmt_txrx_tx_completion_handler(pdev,
mgmt_desc->desc_id, 0, status);
}
}
}
}
return QDF_STATUS_SUCCESS;
}