blob: 8ad5b5895dc5c07c1b5bfbcd8107b2e788f2f2d3 [file] [log] [blame]
/*
* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/**
* DOC: HDD object manager API source file to create/destroy PSOC,
* PDEV, VDEV and PEER objects.
*/
#include <wlan_hdd_object_manager.h>
#include <wlan_osif_priv.h>
#include <wlan_reg_ucfg_api.h>
#include <target_if.h>
#include <os_if_spectral_netlink.h>
#define LOW_2GHZ_FREQ 2312
#define HIGH_2GHZ_FREQ 2732
#define LOW_5GHZ_FREQ 4912
#define HIGH_5GHZ_FREQ 6100
static void hdd_init_pdev_os_priv(struct hdd_context *hdd_ctx,
struct pdev_osif_priv *os_priv)
{
/* Initialize the OS private structure*/
os_priv->wiphy = hdd_ctx->wiphy;
os_priv->legacy_osif_priv = hdd_ctx;
wlan_cfg80211_scan_priv_init(hdd_ctx->hdd_pdev);
os_if_spectral_netlink_init(hdd_ctx->hdd_pdev);
}
static void hdd_deinit_pdev_os_priv(struct wlan_objmgr_pdev *pdev)
{
wlan_cfg80211_scan_priv_deinit(pdev);
}
static void hdd_init_vdev_os_priv(struct hdd_adapter *adapter,
struct vdev_osif_priv *os_priv)
{
/* Initialize the vdev OS private structure*/
os_priv->wdev = adapter->dev->ieee80211_ptr;
os_priv->legacy_osif_priv = adapter;
wlan_cfg80211_tdls_priv_init(os_priv);
}
static void hdd_init_psoc_qdf_ctx(struct wlan_objmgr_psoc *psoc)
{
qdf_device_t qdf_ctx;
qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
if (!qdf_ctx) {
hdd_err("qdf ctx is null, can't set to soc object");
return;
}
wlan_psoc_set_qdf_dev(psoc, qdf_ctx);
}
int hdd_objmgr_create_and_store_psoc(struct hdd_context *hdd_ctx,
uint8_t psoc_id)
{
QDF_STATUS status;
struct wlan_objmgr_psoc *psoc;
psoc = wlan_objmgr_psoc_obj_create(psoc_id, WLAN_DEV_OL);
if (!psoc)
return -ENOMEM;
status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_HDD_ID_OBJ_MGR);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failed to acquire psoc ref; status:%d", status);
QDF_BUG(false);
goto psoc_destroy;
}
hdd_init_psoc_qdf_ctx(psoc);
hdd_ctx->hdd_psoc = psoc;
return 0;
psoc_destroy:
wlan_objmgr_psoc_obj_delete(psoc);
return qdf_status_to_os_return(status);
}
int hdd_objmgr_release_and_destroy_psoc(struct hdd_context *hdd_ctx)
{
QDF_STATUS status;
struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
hdd_ctx->hdd_psoc = NULL;
QDF_BUG(psoc);
if (!psoc)
return -EINVAL;
wlan_objmgr_print_ref_all_objects_per_psoc(psoc);
status = wlan_objmgr_psoc_obj_delete(psoc);
wlan_objmgr_psoc_release_ref(psoc, WLAN_HDD_ID_OBJ_MGR);
return qdf_status_to_os_return(status);
}
int hdd_objmgr_create_and_store_pdev(struct hdd_context *hdd_ctx)
{
QDF_STATUS status;
struct wlan_objmgr_psoc *psoc = hdd_ctx->hdd_psoc;
struct wlan_objmgr_pdev *pdev;
struct pdev_osif_priv *priv;
struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr;
if (!psoc) {
hdd_err("Psoc NULL");
return -EINVAL;
}
priv = qdf_mem_malloc(sizeof(*priv));
if (priv == NULL) {
hdd_err("pdev os obj create failed");
return -ENOMEM;
}
reg_cap_ptr = ucfg_reg_get_hal_reg_cap(psoc);
reg_cap_ptr->phy_id = 0;
reg_cap_ptr->low_2ghz_chan = LOW_2GHZ_FREQ;
reg_cap_ptr->high_2ghz_chan = HIGH_2GHZ_FREQ;
reg_cap_ptr->low_5ghz_chan = LOW_5GHZ_FREQ;
reg_cap_ptr->high_5ghz_chan = HIGH_5GHZ_FREQ;
pdev = wlan_objmgr_pdev_obj_create(psoc, priv);
if (!pdev) {
hdd_err("pdev obj create failed");
status = QDF_STATUS_E_NOMEM;
goto free_priv;
}
status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_HDD_ID_OBJ_MGR);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failed to acquire pdev ref; status:%d", status);
QDF_BUG(false);
goto pdev_destroy;
}
status = target_if_alloc_pdev_tgt_info(pdev);
if (status != QDF_STATUS_SUCCESS) {
hdd_err("pdev tgt info alloc failed");
goto pdev_destroy;
}
hdd_ctx->hdd_pdev = pdev;
sme_store_pdev(hdd_ctx->hHal, hdd_ctx->hdd_pdev);
hdd_init_pdev_os_priv(hdd_ctx, priv);
return 0;
pdev_destroy:
wlan_objmgr_pdev_obj_delete(pdev);
free_priv:
qdf_mem_free(priv);
return qdf_status_to_os_return(status);
}
int hdd_objmgr_release_and_destroy_pdev(struct hdd_context *hdd_ctx)
{
QDF_STATUS status;
struct wlan_objmgr_pdev *pdev = hdd_ctx->hdd_pdev;
struct pdev_osif_priv *osif_priv;
hdd_ctx->hdd_pdev = NULL;
QDF_BUG(pdev);
if (!pdev)
return -EINVAL;
target_if_free_pdev_tgt_info(pdev);
hdd_deinit_pdev_os_priv(pdev);
osif_priv = wlan_pdev_get_ospriv(pdev);
wlan_pdev_reset_ospriv(pdev);
qdf_mem_free(osif_priv);
status = wlan_objmgr_pdev_obj_delete(pdev);
wlan_objmgr_pdev_release_ref(pdev, WLAN_HDD_ID_OBJ_MGR);
return qdf_status_to_os_return(status);
}
int hdd_objmgr_create_and_store_vdev(struct wlan_objmgr_pdev *pdev,
struct hdd_adapter *adapter)
{
QDF_STATUS status;
int errno;
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_peer *peer;
struct vdev_osif_priv *osif_priv;
struct wlan_vdev_create_params vdev_params = {0};
QDF_BUG(pdev);
if (!pdev) {
hdd_err("pdev is null");
return -EINVAL;
}
osif_priv = qdf_mem_malloc(sizeof(*osif_priv));
if (!osif_priv) {
hdd_err("Failed to allocate osif_priv; out of memory");
return -ENOMEM;
}
hdd_init_vdev_os_priv(adapter, osif_priv);
vdev_params.opmode = adapter->device_mode;
vdev_params.osifp = osif_priv;
qdf_mem_copy(vdev_params.macaddr,
adapter->mac_addr.bytes,
QDF_NET_MAC_ADDR_MAX_LEN);
vdev = wlan_objmgr_vdev_obj_create(pdev, &vdev_params);
if (!vdev) {
hdd_err("Failed to create vdev object");
errno = -ENOMEM;
goto osif_priv_free;
}
/*
* To enable legacy use cases, we need to delay physical vdev destroy
* until after the sme session has been closed. We accomplish this by
* getting a reference here.
*/
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failed to acquire vdev ref; status:%d", status);
errno = qdf_status_to_os_return(status);
goto vdev_destroy;
}
peer = wlan_objmgr_peer_obj_create(vdev, WLAN_PEER_SELF,
vdev_params.macaddr);
if (!peer) {
hdd_err("Failed to create self peer for adapter mode %d",
adapter->device_mode);
errno = -ENOMEM;
goto vdev_put_ref;
}
adapter->hdd_vdev = vdev;
adapter->session_id = wlan_vdev_get_id(vdev);
return 0;
vdev_put_ref:
wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
vdev_destroy:
wlan_objmgr_vdev_obj_delete(vdev);
osif_priv_free:
qdf_mem_free(osif_priv);
return errno;
}
int hdd_objmgr_release_and_destroy_vdev(struct hdd_adapter *adapter)
{
QDF_STATUS status;
struct wlan_objmgr_vdev *vdev = adapter->hdd_vdev;
struct vdev_osif_priv *osif_priv;
uint8_t *self_mac_addr;
adapter->hdd_vdev = NULL;
adapter->session_id = HDD_SESSION_ID_INVALID;
QDF_BUG(vdev);
if (!vdev)
return -EINVAL;
osif_priv = wlan_vdev_get_ospriv(vdev);
wlan_vdev_reset_ospriv(vdev);
QDF_BUG(osif_priv);
if (osif_priv) {
wlan_cfg80211_tdls_priv_deinit(osif_priv);
qdf_mem_free(osif_priv);
}
self_mac_addr = wlan_vdev_mlme_get_macaddr(vdev);
if (hdd_objmgr_remove_peer_object(vdev, self_mac_addr))
hdd_err("Self peer delete failed");
status = wlan_objmgr_vdev_obj_delete(vdev);
wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
return qdf_status_to_os_return(status);
}
int hdd_objmgr_add_peer_object(struct wlan_objmgr_vdev *vdev,
enum QDF_OPMODE adapter_mode,
uint8_t *mac_addr,
bool is_p2p_type)
{
enum wlan_peer_type peer_type;
struct wlan_objmgr_peer *peer;
if ((adapter_mode == QDF_STA_MODE) ||
(adapter_mode == QDF_P2P_CLIENT_MODE)) {
peer_type = WLAN_PEER_AP;
} else if ((adapter_mode == QDF_SAP_MODE) ||
(adapter_mode == QDF_P2P_GO_MODE)) {
if (is_p2p_type) {
peer_type = WLAN_PEER_P2P_CLI;
} else {
peer_type = WLAN_PEER_STA;
}
} else if (adapter_mode == QDF_IBSS_MODE) {
peer_type = WLAN_PEER_IBSS;
} else if (adapter_mode == QDF_NDI_MODE) {
peer_type = WLAN_PEER_NDP;
} else {
hdd_err("Unsupported device mode %d", adapter_mode);
return -EINVAL;
}
if (!vdev) {
hdd_err("vdev NULL");
QDF_ASSERT(0);
return -EFAULT;
}
peer = wlan_objmgr_peer_obj_create(vdev, peer_type, mac_addr);
if (!peer)
return -ENOMEM;
hdd_debug("Peer object "MAC_ADDRESS_STR" add success! Type: %d",
MAC_ADDR_ARRAY(mac_addr), peer_type);
return 0;
}
int hdd_objmgr_remove_peer_object(struct wlan_objmgr_vdev *vdev,
uint8_t *mac_addr)
{
struct wlan_objmgr_psoc *psoc;
struct wlan_objmgr_peer *peer;
if (!vdev) {
hdd_err("vdev NULL");
QDF_ASSERT(0);
return -EINVAL;
}
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
hdd_err("Psoc NUll");
QDF_ASSERT(0);
return -EINVAL;
}
peer = wlan_objmgr_get_peer(psoc, mac_addr, WLAN_HDD_ID_OBJ_MGR);
if (peer) {
wlan_objmgr_peer_obj_delete(peer);
/* Unref to decrement ref happened in find_peer */
wlan_objmgr_peer_release_ref(peer, WLAN_HDD_ID_OBJ_MGR);
hdd_info("Peer obj "MAC_ADDRESS_STR" deleted",
MAC_ADDR_ARRAY(mac_addr));
return 0;
}
hdd_err("Peer obj "MAC_ADDRESS_STR" not found",
MAC_ADDR_ARRAY(mac_addr));
return -EINVAL;
}
int hdd_objmgr_set_peer_mlme_auth_state(struct wlan_objmgr_vdev *vdev,
bool is_authenticated)
{
struct wlan_objmgr_peer *peer;
QDF_STATUS status;
wlan_vdev_obj_lock(vdev);
peer = wlan_vdev_get_bsspeer(vdev);
wlan_vdev_obj_unlock(vdev);
if (!peer) {
hdd_err("peer is null");
return -EINVAL;
}
status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID);
if (status != QDF_STATUS_SUCCESS)
return -EINVAL;
wlan_peer_obj_lock(peer);
wlan_peer_mlme_set_auth_state(peer, is_authenticated);
wlan_peer_obj_unlock(peer);
wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
return 0;
}
int hdd_objmgr_set_peer_mlme_state(struct wlan_objmgr_vdev *vdev,
enum wlan_peer_state peer_state)
{
struct wlan_objmgr_peer *peer;
wlan_vdev_obj_lock(vdev);
peer = wlan_vdev_get_bsspeer(vdev);
wlan_vdev_obj_unlock(vdev);
if (!peer) {
hdd_err("peer is null");
return -EINVAL;
}
wlan_peer_obj_lock(peer);
wlan_peer_mlme_set_state(peer, WLAN_ASSOC_STATE);
wlan_peer_obj_unlock(peer);
return 0;
}