blob: 96d472b510b867dcd7694e423415e68a47d1dd6b [file] [log] [blame]
/*
* Copyright (c) 2017 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: This file contains main P2P function definitions
*/
#include <scheduler_api.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 <wlan_scan_ucfg_api.h>
#include "wlan_p2p_public_struct.h"
#include "wlan_p2p_ucfg_api.h"
#include "wlan_p2p_tgt_api.h"
#include "wlan_p2p_main.h"
#include "wlan_p2p_roc.h"
#include "wlan_p2p_off_chan_tx.h"
/**
* p2p_get_cmd_type_str() - parse cmd to string
* @cmd_type: P2P cmd type
*
* This function parse P2P cmd to string.
*
* Return: command string
*/
static char *p2p_get_cmd_type_str(enum p2p_cmd_type cmd_type)
{
switch (cmd_type) {
case P2P_ROC_REQ:
return "P2P roc request";
case P2P_CANCEL_ROC_REQ:
return "P2P cancel roc request";
case P2P_MGMT_TX:
return "P2P mgmt tx request";
case P2P_MGMT_TX_CANCEL:
return "P2P cancel mgmt tx request";
default:
return "Invalid P2P command";
}
}
/**
* p2p_get_event_type_str() - parase event to string
* @event_type: P2P event type
*
* This function parse P2P event to string.
*
* Return: event string
*/
static char *p2p_get_event_type_str(enum p2p_event_type event_type)
{
switch (event_type) {
case P2P_EVENT_SCAN_EVENT:
return "P2P scan event";
case P2P_EVENT_MGMT_TX_ACK_CNF:
return "P2P mgmt tx ack event";
case P2P_EVENT_RX_MGMT:
return "P2P mgmt rx event";
case P2P_EVENT_LO_STOPPED:
return "P2P lo stop event";
case P2P_EVENT_NOA:
return "P2P noa event";
default:
return "Invalid P2P event";
}
}
/**
* p2p_psoc_obj_create_notification() - Function to allocate per P2P
* soc private object
* @soc: soc context
* @data: Pointer to data
*
* This function gets called from object manager when psoc is being
* created and creates p2p soc context.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS p2p_psoc_obj_create_notification(
struct wlan_objmgr_psoc *soc, void *data)
{
struct p2p_soc_priv_obj *p2p_soc_obj;
QDF_STATUS status;
if (!soc) {
p2p_err("psoc context passed is NULL");
return QDF_STATUS_E_INVAL;
}
p2p_soc_obj = qdf_mem_malloc(sizeof(*p2p_soc_obj));
if (!p2p_soc_obj) {
p2p_err("Failed to allocate p2p soc private object");
return QDF_STATUS_E_NOMEM;
}
p2p_soc_obj->soc = soc;
status = wlan_objmgr_psoc_component_obj_attach(soc,
WLAN_UMAC_COMP_P2P, p2p_soc_obj,
QDF_STATUS_SUCCESS);
if (status != QDF_STATUS_SUCCESS) {
qdf_mem_free(p2p_soc_obj);
p2p_err("Failed to attach p2p component, %d", status);
return status;
}
p2p_debug("p2p soc object create successful, %p", p2p_soc_obj);
return QDF_STATUS_SUCCESS;
}
/**
* p2p_psoc_obj_destroy_notification() - Free soc private object
* @soc: soc context
* @data: Pointer to data
*
* This function gets called from object manager when psoc is being
* deleted and delete p2p soc context.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS p2p_psoc_obj_destroy_notification(
struct wlan_objmgr_psoc *soc, void *data)
{
struct p2p_soc_priv_obj *p2p_soc_obj;
QDF_STATUS status;
if (!soc) {
p2p_err("psoc context passed is NULL");
return QDF_STATUS_E_INVAL;
}
p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
WLAN_UMAC_COMP_P2P);
if (!p2p_soc_obj) {
p2p_err("p2p soc private object is NULL");
return QDF_STATUS_E_FAILURE;
}
p2p_soc_obj->soc = NULL;
status = wlan_objmgr_psoc_component_obj_detach(soc,
WLAN_UMAC_COMP_P2P, p2p_soc_obj);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to detach p2p component, %d", status);
return status;
}
p2p_debug("destroy p2p soc object, %p", p2p_soc_obj);
qdf_mem_free(p2p_soc_obj);
return QDF_STATUS_SUCCESS;
}
/**
* p2p_vdev_obj_create_notification() - Allocate per p2p vdev object
* @vdev: vdev context
* @data: Pointer to data
*
* This function gets called from object manager when vdev is being
* created and creates p2p vdev context.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS p2p_vdev_obj_create_notification(
struct wlan_objmgr_vdev *vdev, void *data)
{
struct p2p_vdev_priv_obj *p2p_vdev_obj;
QDF_STATUS status;
enum tQDF_ADAPTER_MODE mode;
if (!vdev) {
p2p_err("vdev context passed is NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_lock(vdev);
mode = wlan_vdev_mlme_get_opmode(vdev);
wlan_vdev_obj_unlock(vdev);
p2p_debug("vdev mode:%d", mode);
if (mode != QDF_P2P_GO_MODE) {
p2p_debug("won't create p2p vdev private object if it is not GO");
return QDF_STATUS_SUCCESS;
}
p2p_vdev_obj =
qdf_mem_malloc(sizeof(*p2p_vdev_obj));
if (!p2p_vdev_obj) {
p2p_err("Failed to allocate p2p vdev object");
return QDF_STATUS_E_NOMEM;
}
p2p_vdev_obj->vdev = vdev;
status = wlan_objmgr_vdev_component_obj_attach(vdev,
WLAN_UMAC_COMP_P2P, p2p_vdev_obj,
QDF_STATUS_SUCCESS);
if (status != QDF_STATUS_SUCCESS) {
qdf_mem_free(p2p_vdev_obj);
p2p_err("Failed to attach p2p component to vdev, %d",
status);
return status;
}
p2p_debug("p2p vdev object create successful, %p", p2p_vdev_obj);
return QDF_STATUS_SUCCESS;
}
/**
* p2p_vdev_obj_destroy_notification() - Free per P2P vdev object
* @vdev: vdev context
* @data: Pointer to data
*
* This function gets called from object manager when vdev is being
* deleted and delete p2p vdev context.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS p2p_vdev_obj_destroy_notification(
struct wlan_objmgr_vdev *vdev, void *data)
{
struct p2p_vdev_priv_obj *p2p_vdev_obj;
QDF_STATUS status;
enum tQDF_ADAPTER_MODE mode;
if (!vdev) {
p2p_err("vdev context passed is NULL");
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_lock(vdev);
mode = wlan_vdev_mlme_get_opmode(vdev);
wlan_vdev_obj_unlock(vdev);
p2p_debug("vdev mode:%d", mode);
if (mode != QDF_P2P_GO_MODE) {
p2p_debug("no p2p vdev private object if it is not GO");
return QDF_STATUS_SUCCESS;
}
p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
WLAN_UMAC_COMP_P2P);
if (!p2p_vdev_obj) {
p2p_debug("p2p vdev object is NULL");
return QDF_STATUS_SUCCESS;
}
p2p_vdev_obj->vdev = NULL;
status = wlan_objmgr_vdev_component_obj_detach(vdev,
WLAN_UMAC_COMP_P2P, p2p_vdev_obj);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to detach p2p component, %d", status);
return status;
}
p2p_debug("destroy p2p vdev object, p2p vdev obj:%p, noa info:%p",
p2p_vdev_obj, p2p_vdev_obj->noa_info);
if (p2p_vdev_obj->noa_info)
qdf_mem_free(p2p_vdev_obj->noa_info);
qdf_mem_free(p2p_vdev_obj);
return QDF_STATUS_SUCCESS;
}
/**
* p2p_send_noa_to_pe() - send noa information to pe
* @noa_info: vdev context
*
* This function sends noa information to pe since MCL layer need noa
* event.
*
* Return: QDF_STATUS_SUCCESS - in case of success
*/
static QDF_STATUS p2p_send_noa_to_pe(struct p2p_noa_info *noa_info)
{
struct p2p_noa_attr *noa_attr;
struct scheduler_msg msg;
if (!noa_info) {
p2p_err("noa info is null");
return QDF_STATUS_E_INVAL;
}
noa_attr = qdf_mem_malloc(sizeof(*noa_attr));
if (!noa_attr) {
p2p_err("Failed to allocate memory for tSirP2PNoaAttr");
return QDF_STATUS_E_NOMEM;
}
noa_attr->index = noa_info->index;
noa_attr->opps_ps = noa_info->opps_ps;
noa_attr->ct_win = noa_info->ct_window;
if (!noa_info->num_desc) {
p2p_debug("Zero noa descriptors");
} else {
p2p_debug("%d noa descriptors", noa_info->num_desc);
noa_attr->noa1_count =
noa_info->noa_desc[0].type_count;
noa_attr->noa1_duration =
noa_info->noa_desc[0].duration;
noa_attr->noa1_interval =
noa_info->noa_desc[0].interval;
noa_attr->noa1_start_time =
noa_info->noa_desc[0].start_time;
if (noa_info->num_desc > 1) {
noa_attr->noa2_count =
noa_info->noa_desc[1].type_count;
noa_attr->noa2_duration =
noa_info->noa_desc[1].duration;
noa_attr->noa2_interval =
noa_info->noa_desc[1].interval;
noa_attr->noa2_start_time =
noa_info->noa_desc[1].start_time;
}
}
p2p_debug("Sending P2P_NOA_ATTR_IND to pe");
msg.type = P2P_NOA_ATTR_IND;
msg.bodyval = 0;
msg.bodyptr = noa_attr;
scheduler_post_msg(QDF_MODULE_ID_PE, &msg);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS p2p_component_init(void)
{
QDF_STATUS status;
status = wlan_objmgr_register_psoc_create_handler(
WLAN_UMAC_COMP_P2P,
p2p_psoc_obj_create_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to register p2p obj create handler");
goto err_reg_psoc_create;
}
status = wlan_objmgr_register_psoc_destroy_handler(
WLAN_UMAC_COMP_P2P,
p2p_psoc_obj_destroy_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to register p2p obj delete handler");
goto err_reg_psoc_delete;
}
status = wlan_objmgr_register_vdev_create_handler(
WLAN_UMAC_COMP_P2P,
p2p_vdev_obj_create_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to register p2p vdev create handler");
goto err_reg_vdev_create;
}
status = wlan_objmgr_register_vdev_destroy_handler(
WLAN_UMAC_COMP_P2P,
p2p_vdev_obj_destroy_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to register p2p vdev delete handler");
goto err_reg_vdev_delete;
}
p2p_debug("Register p2p obj handler successful");
return QDF_STATUS_SUCCESS;
err_reg_vdev_delete:
wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_P2P,
p2p_vdev_obj_create_notification, NULL);
err_reg_vdev_create:
wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_P2P,
p2p_psoc_obj_destroy_notification, NULL);
err_reg_psoc_delete:
wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_P2P,
p2p_psoc_obj_create_notification, NULL);
err_reg_psoc_create:
return status;
}
QDF_STATUS p2p_component_deinit(void)
{
QDF_STATUS status;
QDF_STATUS ret_status = QDF_STATUS_SUCCESS;
status = wlan_objmgr_unregister_vdev_create_handler(
WLAN_UMAC_COMP_P2P,
p2p_vdev_obj_create_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to unregister p2p vdev create handler, %d",
status);
ret_status = status;
}
status = wlan_objmgr_unregister_vdev_destroy_handler(
WLAN_UMAC_COMP_P2P,
p2p_vdev_obj_destroy_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to unregister p2p vdev delete handler, %d",
status);
ret_status = status;
}
status = wlan_objmgr_unregister_psoc_create_handler(
WLAN_UMAC_COMP_P2P,
p2p_psoc_obj_create_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to unregister p2p obj create handler, %d",
status);
ret_status = status;
}
status = wlan_objmgr_unregister_psoc_destroy_handler(
WLAN_UMAC_COMP_P2P,
p2p_psoc_obj_destroy_notification,
NULL);
if (status != QDF_STATUS_SUCCESS) {
p2p_err("Failed to unregister p2p obj delete handler, %d",
status);
ret_status = status;
}
p2p_debug("Unregister p2p obj handler complete");
return ret_status;
}
QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc)
{
struct p2p_soc_priv_obj *p2p_soc_obj;
if (!soc) {
p2p_err("psoc context passed is NULL");
return QDF_STATUS_E_INVAL;
}
p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
WLAN_UMAC_COMP_P2P);
if (!p2p_soc_obj) {
p2p_err("p2p soc priviate object is NULL");
return QDF_STATUS_E_FAILURE;
}
qdf_list_create(&p2p_soc_obj->roc_q, MAX_QUEUE_LENGTH);
qdf_list_create(&p2p_soc_obj->tx_q_roc, MAX_QUEUE_LENGTH);
qdf_list_create(&p2p_soc_obj->tx_q_ack, MAX_QUEUE_LENGTH);
qdf_event_create(&p2p_soc_obj->cancel_roc_done);
p2p_debug("p2p psoc object open successful");
return QDF_STATUS_SUCCESS;
}
QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc)
{
struct p2p_soc_priv_obj *p2p_soc_obj;
if (!soc) {
p2p_err("psoc context passed is NULL");
return QDF_STATUS_E_INVAL;
}
p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
WLAN_UMAC_COMP_P2P);
if (!p2p_soc_obj) {
p2p_err("p2p soc object is NULL");
return QDF_STATUS_E_FAILURE;
}
qdf_event_destroy(&p2p_soc_obj->cancel_roc_done);
qdf_list_destroy(&p2p_soc_obj->tx_q_ack);
qdf_list_destroy(&p2p_soc_obj->tx_q_roc);
qdf_list_destroy(&p2p_soc_obj->roc_q);
p2p_debug("p2p psoc object close successful");
return QDF_STATUS_SUCCESS;
}
QDF_STATUS p2p_psoc_start(struct wlan_objmgr_psoc *soc,
struct p2p_start_param *req)
{
struct p2p_soc_priv_obj *p2p_soc_obj;
struct p2p_start_param *start_param;
if (!soc) {
p2p_err("psoc context passed is NULL");
return QDF_STATUS_E_INVAL;
}
p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
WLAN_UMAC_COMP_P2P);
if (!p2p_soc_obj) {
p2p_err("P2P soc object is NULL");
return QDF_STATUS_E_FAILURE;
}
start_param = qdf_mem_malloc(sizeof(*start_param));
if (!start_param) {
p2p_err("Failed to allocate start params");
return QDF_STATUS_E_NOMEM;
}
start_param->rx_cb = req->rx_cb;
start_param->rx_cb_data = req->rx_cb_data;
start_param->event_cb = req->event_cb;
start_param->event_cb_data = req->event_cb_data;
start_param->tx_cnf_cb = req->tx_cnf_cb;
start_param->tx_cnf_cb_data = req->tx_cnf_cb_data;
start_param->lo_event_cb = req->lo_event_cb;
start_param->lo_event_cb_data = req->lo_event_cb_data;
p2p_soc_obj->start_param = start_param;
/* register p2p lo stop and noa event */
tgt_p2p_register_lo_ev_handler(soc);
tgt_p2p_register_noa_ev_handler(soc);
/* register scan request id */
p2p_soc_obj->scan_req_id = ucfg_scan_register_requester(
soc, P2P_MODULE_NAME, tgt_p2p_scan_event_cb,
p2p_soc_obj);
p2p_debug("p2p psoc start successful, scan request id:%d",
p2p_soc_obj->scan_req_id);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc)
{
struct p2p_soc_priv_obj *p2p_soc_obj;
struct p2p_start_param *start_param;
if (!soc) {
p2p_err("psoc context passed is NULL");
return QDF_STATUS_E_INVAL;
}
p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
WLAN_UMAC_COMP_P2P);
if (!p2p_soc_obj) {
p2p_err("P2P soc object is NULL");
return QDF_STATUS_E_FAILURE;
}
start_param = p2p_soc_obj->start_param;
p2p_soc_obj->start_param = NULL;
if (!start_param) {
p2p_err("start parameters is NULL");
return QDF_STATUS_E_FAILURE;
}
/* clean up queue of p2p psoc private object */
p2p_cleanup_tx_queue(p2p_soc_obj);
p2p_cleanup_roc_queue(p2p_soc_obj);
/* unrgister scan request id*/
ucfg_scan_unregister_requester(soc, p2p_soc_obj->scan_req_id);
/* unregister p2p lo stop and noa event */
tgt_p2p_unregister_lo_ev_handler(soc);
tgt_p2p_unregister_noa_ev_handler(soc);
start_param->rx_cb = NULL;
start_param->rx_cb_data = NULL;
start_param->event_cb = NULL;
start_param->event_cb_data = NULL;
start_param->tx_cnf_cb = NULL;
start_param->tx_cnf_cb_data = NULL;
qdf_mem_free(start_param);
p2p_debug("p2p psoc stop successful");
return QDF_STATUS_SUCCESS;
}
QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg)
{
QDF_STATUS status;
p2p_debug("msg type %d, %s", msg->type,
p2p_get_cmd_type_str(msg->type));
if (!(msg->bodyptr)) {
p2p_err("Invalid message body");
return QDF_STATUS_E_INVAL;
}
switch (msg->type) {
case P2P_ROC_REQ:
status = p2p_process_roc_req(
(struct p2p_roc_context *)
msg->bodyptr);
break;
case P2P_CANCEL_ROC_REQ:
status = p2p_process_cancel_roc_req(
(struct cancel_roc_context *)
msg->bodyptr);
qdf_mem_free(msg->bodyptr);
break;
case P2P_MGMT_TX:
status = p2p_process_mgmt_tx(
(struct tx_action_context *)
msg->bodyptr);
break;
case P2P_MGMT_TX_CANCEL:
status = p2p_process_mgmt_tx_cancel(
(struct cancel_roc_context *)
msg->bodyptr);
qdf_mem_free(msg->bodyptr);
break;
default:
p2p_err("drop unexpected message received %d",
msg->type);
status = QDF_STATUS_E_INVAL;
break;
}
return status;
}
QDF_STATUS p2p_process_evt(struct scheduler_msg *msg)
{
QDF_STATUS status;
p2p_debug("msg type %d, %s", msg->type,
p2p_get_event_type_str(msg->type));
if (!(msg->bodyptr)) {
p2p_err("Invalid message body");
return QDF_STATUS_E_INVAL;
}
switch (msg->type) {
case P2P_EVENT_MGMT_TX_ACK_CNF:
status = p2p_process_mgmt_tx_ack_cnf(
(struct p2p_tx_conf_event *)
msg->bodyptr);
break;
case P2P_EVENT_RX_MGMT:
status = p2p_process_rx_mgmt(
(struct p2p_rx_mgmt_event *)
msg->bodyptr);
break;
case P2P_EVENT_LO_STOPPED:
status = p2p_process_lo_stop(
(struct p2p_lo_stop_event *)
msg->bodyptr);
break;
case P2P_EVENT_NOA:
status = p2p_process_noa(
(struct p2p_noa_event *)
msg->bodyptr);
break;
default:
p2p_err("Drop unexpected message received %d",
msg->type);
status = QDF_STATUS_E_INVAL;
break;
}
qdf_mem_free(msg->bodyptr);
msg->bodyptr = NULL;
return status;
}
QDF_STATUS p2p_process_lo_stop(
struct p2p_lo_stop_event *lo_stop_event)
{
struct p2p_lo_event *lo_evt;
struct p2p_soc_priv_obj *p2p_soc_obj;
struct p2p_start_param *start_param;
if (!lo_stop_event) {
p2p_err("invalid lo stop event");
return QDF_STATUS_E_INVAL;
}
lo_evt = lo_stop_event->lo_event;
p2p_soc_obj = lo_stop_event->p2p_soc_obj;
p2p_debug("vdev_id %d, reason %d",
lo_evt->vdev_id, lo_evt->reason_code);
if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
p2p_err("Invalid p2p soc object or start parameters");
return QDF_STATUS_E_INVAL;
}
start_param = p2p_soc_obj->start_param;
if (start_param->lo_event_cb)
start_param->lo_event_cb(
start_param->lo_event_cb_data, lo_evt);
else
p2p_err("Invalid p2p soc obj or hdd lo event callback");
qdf_mem_free(lo_evt);
return QDF_STATUS_SUCCESS;
}
QDF_STATUS p2p_process_noa(struct p2p_noa_event *noa_event)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct p2p_noa_info *noa_info;
struct p2p_vdev_priv_obj *p2p_vdev_obj;
struct p2p_soc_priv_obj *p2p_soc_obj;
struct wlan_objmgr_vdev *vdev;
struct wlan_objmgr_psoc *psoc;
enum tQDF_ADAPTER_MODE mode;
if (!noa_event) {
p2p_err("invalid noa event");
return QDF_STATUS_E_INVAL;
}
noa_info = noa_event->noa_info;
p2p_soc_obj = noa_event->p2p_soc_obj;
psoc = p2p_soc_obj->soc;
p2p_debug("psoc:%p, index:%d, opps_ps:%d, ct_window:%d, num_desc:%d, vdev_id:%d",
psoc, noa_info->index, noa_info->opps_ps,
noa_info->ct_window, noa_info->num_desc,
noa_info->vdev_id);
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
noa_info->vdev_id, WLAN_P2P_ID);
if (!vdev) {
p2p_err("vdev obj is NULL");
qdf_mem_free(noa_event->noa_info);
return QDF_STATUS_E_INVAL;
}
wlan_vdev_obj_lock(vdev);
mode = wlan_vdev_mlme_get_opmode(vdev);
wlan_vdev_obj_unlock(vdev);
p2p_debug("vdev mode:%d", mode);
if (mode != QDF_P2P_GO_MODE) {
p2p_err("invalid p2p vdev mode:%d", mode);
status = QDF_STATUS_E_INVAL;
goto fail;
}
/* must send noa to pe since of limitation*/
p2p_send_noa_to_pe(noa_info);
p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
WLAN_UMAC_COMP_P2P);
if (!(p2p_vdev_obj->noa_info)) {
p2p_vdev_obj->noa_info =
qdf_mem_malloc(sizeof(struct p2p_noa_info));
if (!(p2p_vdev_obj->noa_info)) {
p2p_err("Failed to allocate p2p noa info");
status = QDF_STATUS_E_NOMEM;
goto fail;
}
}
qdf_mem_copy(p2p_vdev_obj->noa_info, noa_info,
sizeof(struct p2p_noa_info));
fail:
qdf_mem_free(noa_event->noa_info);
wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
return status;
}