blob: 24ab09000963d9a828de17e004f9f238cd2e4ae4 [file] [log] [blame]
/*
* Copyright (c) 2016 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.
*/
/**
* DOC: nan_datapath.c
*
* MAC NAN Data path API implementation
*/
#include "limUtils.h"
#include "limApi.h"
#include "limAssocUtils.h"
#include "nan_datapath.h"
#include "limTypes.h"
#include "limSendMessages.h"
#include "wma_nan_datapath.h"
/**
* lim_send_ndp_event_to_sme() - generic function to prepare and send NDP
* message to SME.
* @mac_ctx: handle to mac context structure
* @msg_type: sme message type to send
* @body_ptr: buffer
* @len: buffer length
* @body_val: value
*
* Return: None
*/
static void lim_send_ndp_event_to_sme(tpAniSirGlobal mac_ctx, uint32_t msg_type,
void *body_ptr, uint32_t len, uint32_t body_val)
{
tSirMsgQ mmh_msg = {0};
mmh_msg.type = msg_type;
if (len && body_ptr) {
mmh_msg.bodyptr = vos_mem_malloc(len);
if (NULL == mmh_msg.bodyptr) {
limLog(mac_ctx, LOGE, FL("Malloc failed"));
return;
}
vos_mem_copy(mmh_msg.bodyptr, body_ptr, len);
} else {
mmh_msg.bodyval = body_val;
}
limSysProcessMmhMsgApi(mac_ctx, &mmh_msg, ePROT);
}
/**
* lim_add_ndi_peer() - Function to add ndi peer
* @mac_ctx: handle to mac structure
* @vdev_id: vdev id on which peer is added
* @peer_mac_addr: peer to be added
*
* Return: VOS_STATUS_SUCCESS on success; error number otherwise
*/
static VOS_STATUS lim_add_ndi_peer(tpAniSirGlobal mac_ctx,
uint32_t vdev_id, v_MACADDR_t peer_mac_addr)
{
tpPESession session;
tpDphHashNode sta_ds;
uint16_t assoc_id, peer_idx;
tSirRetStatus status;
session = pe_find_session_by_sme_session_id(mac_ctx,
vdev_id);
if (session == NULL) {
/* couldn't find session */
return VOS_STATUS_E_FAILURE;
}
sta_ds = dphLookupHashEntry(mac_ctx,
peer_mac_addr.bytes,
&assoc_id, &session->dph.dphHashTable);
/* peer exists, don't do anything */
if (sta_ds != NULL) {
limLog(mac_ctx, LOGE, FL("NDI Peer already exists!!"));
return VOS_STATUS_SUCCESS;
}
limLog(mac_ctx, LOG1,
FL("Need to create NDI Peer :" MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(peer_mac_addr.bytes));
peer_idx = limAssignPeerIdx(mac_ctx, session);
sta_ds = dphAddHashEntry(mac_ctx, peer_mac_addr.bytes, peer_idx,
&session->dph.dphHashTable);
if (sta_ds == NULL) {
limLog(mac_ctx, LOGE,
FL("Couldn't add dph entry"));
/* couldn't add dph entry */
return VOS_STATUS_E_FAILURE;
}
/* wma decides NDI mode from wma->inferface struct */
sta_ds->staType = STA_ENTRY_NDI_PEER;
status = limAddSta(mac_ctx, sta_ds, false, session);
if (eSIR_SUCCESS != status) {
/* couldn't add peer */
limLog(mac_ctx, LOGE,
FL("limAddSta failed status: %d"),
status);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* lim_handle_ndp_indication_event() - Function to handle SIR_HAL_NDP_INDICATION
* event from WMA
* @mac_ctx: handle to mac structure
* @ndp_ind: ndp indication event params
*
* Return: VOS_STATUS_SUCCESS on success; error number otherwise
*/
static VOS_STATUS lim_handle_ndp_indication_event(tpAniSirGlobal mac_ctx,
struct ndp_indication_event *ndp_ind)
{
VOS_STATUS status = VOS_STATUS_SUCCESS;
limLog(mac_ctx, LOG1,
FL("role: %d, vdev: %d, csid: %d, peer_mac_addr "
MAC_ADDRESS_STR),
ndp_ind->role, ndp_ind->vdev_id, ndp_ind->ncs_sk_type,
MAC_ADDR_ARRAY(ndp_ind->peer_mac_addr.bytes));
if ((ndp_ind->role == NDP_ROLE_INITIATOR) ||
((NDP_ROLE_RESPONDER == ndp_ind->role) &&
(NDP_ACCEPT_POLICY_ALL == ndp_ind->policy))) {
status = lim_add_ndi_peer(mac_ctx, ndp_ind->vdev_id,
ndp_ind->peer_mac_addr);
if (VOS_STATUS_SUCCESS != status) {
limLog(mac_ctx, LOGE,
FL("Couldn't add ndi peer, ndp_role: %d"),
ndp_ind->role);
goto ndp_indication_failed;
}
}
if (NDP_ROLE_RESPONDER == ndp_ind->role)
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_INDICATION,
ndp_ind, sizeof(*ndp_ind), 0);
/*
* With NDP indication if peer does not exists already add_sta is
* executed resulting in new peer else no action is taken. Note that
* new_peer event is not necessary event and should not be sent if case
* anything fails in this function. Rather eWNI_SME_NDP_CONFIRM_IND is
* used to indicate success of final operation and abscence of it can be
* used by service layer to identify failure.
*/
ndp_indication_failed:
/*
* Free config if failure or for NDP_ROLE_INITIATOR role
* As for success responder case this info is sent till HDD
* and will be freed in sme.
*/
if ((status != VOS_STATUS_SUCCESS) ||
(NDP_ROLE_INITIATOR == ndp_ind->role)) {
vos_mem_free(ndp_ind->ndp_config.ndp_cfg);
vos_mem_free(ndp_ind->ndp_info.ndp_app_info);
}
return status;
}
/**
* lim_ndp_responder_rsp_handler() - Handler for NDP responder rsp
* @mac_ctx: handle to mac structure
* @ndp_rsp: pointer to rsp message
* @bodyval: value
*
* Return: VOS_STATUS_SUCCESS on success; error number otherwise
*/
static VOS_STATUS lim_ndp_responder_rsp_handler(tpAniSirGlobal mac_ctx,
struct ndp_responder_rsp_event *rsp_ind, uint32_t bodyval)
{
VOS_STATUS ret_val = VOS_STATUS_SUCCESS;
if ((NULL == rsp_ind) || bodyval) {
limLog(mac_ctx, LOGE,
FL("rsp_ind is NULL or bodyval %d"), bodyval);
/* msg to unblock SME, but not send rsp to HDD */
bodyval = true;
ret_val = VOS_STATUS_E_INVAL;
goto responder_rsp;
}
if (VOS_STATUS_SUCCESS == rsp_ind->status &&
rsp_ind->create_peer == true) {
ret_val = lim_add_ndi_peer(mac_ctx, rsp_ind->vdev_id,
rsp_ind->peer_mac_addr);
if (VOS_STATUS_SUCCESS != ret_val) {
limLog(mac_ctx, LOGE,
FL("Couldn't add ndi peer"));
rsp_ind->status = VOS_STATUS_E_FAILURE;
}
}
responder_rsp:
/* send eWNI_SME_NDP_RESPONDER_RSP */
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_RESPONDER_RSP,
bodyval ? NULL : rsp_ind,
bodyval ? 0 : sizeof(*rsp_ind), bodyval);
return ret_val;
}
/**
* lim_ndp_delete_peer_by_addr() - Delete NAN data peer, given addr and vdev_id
* @mac_ctx: handle to mac context
* @vdev_id: vdev_id on which peer was added
* @peer_ndi_mac_addr: mac addr of peer
* This function deletes a peer if there was NDP_Confirm with REJECT
*
* Return: None
*/
void lim_ndp_delete_peer_by_addr(tpAniSirGlobal mac_ctx, uint8_t vdev_id,
v_MACADDR_t peer_ndi_mac_addr)
{
tpPESession session;
tpDphHashNode sta_ds;
uint16_t peer_idx;
limLog(mac_ctx, LOG1,
FL("deleting peer: "MAC_ADDRESS_STR" confirm rejected"),
MAC_ADDR_ARRAY(peer_ndi_mac_addr.bytes));
session = pe_find_session_by_sme_session_id(mac_ctx, vdev_id);
if (!session || (session->bssType != eSIR_NDI_MODE)) {
limLog(mac_ctx, LOGE,
FL("PE session is NULL or non-NDI for sme session %d"),
vdev_id);
return;
}
sta_ds = dphLookupHashEntry(mac_ctx, peer_ndi_mac_addr.bytes,
&peer_idx, &session->dph.dphHashTable);
if (!sta_ds) {
limLog(mac_ctx, LOGE, FL("Unknown NDI Peer"));
return;
}
if (sta_ds->staType != STA_ENTRY_NDI_PEER) {
limLog(mac_ctx, LOGE, FL("Non-NDI Peer ignored"));
return;
}
/*
* Call limDelSta() with response required set true. Hence DphHashEntry
* will be deleted after receiving that response.
*/
limDelSta(mac_ctx, sta_ds, true, session);
}
/**
* lim_ndp_delete_peers() - Delete NAN data peers
* @mac_ctx: handle to mac context
* @ndp_map: NDP instance/peer map
* @num_peers: number of peers entries in peer_map
* This function deletes a peer if there are no active NDPs left with that peer
*
* Return: None
*/
static void lim_ndp_delete_peers(tpAniSirGlobal mac_ctx,
struct peer_ndp_map *ndp_map, uint8_t num_peers)
{
tpDphHashNode sta_ds = NULL;
uint16_t deleted_num = 0;
int i, j;
tpPESession session;
v_MACADDR_t *deleted_peers;
uint16_t peer_idx;
bool found;
deleted_peers = vos_mem_malloc(num_peers * sizeof(*deleted_peers));
if (!deleted_peers) {
limLog(mac_ctx, LOGE, FL("Memory allocation failed"));
return;
}
vos_mem_zero(deleted_peers, num_peers * sizeof(*deleted_peers));
for (i = 0; i < num_peers; i++) {
limLog(mac_ctx, LOG1,
FL("ndp_map[%d]: MAC: " MAC_ADDRESS_STR "num_active %d"),
i,
MAC_ADDR_ARRAY(ndp_map[i].peer_ndi_mac_addr.bytes),
ndp_map[i].num_active_ndp_sessions);
/* Do not delete a peer with active NDPs */
if (ndp_map[i].num_active_ndp_sessions > 0)
continue;
session = pe_find_session_by_sme_session_id(mac_ctx,
ndp_map[i].vdev_id);
if (!session || (session->bssType != eSIR_NDI_MODE)) {
limLog(mac_ctx, LOGE,
FL("PE session is NULL or non-NDI for sme session %d"),
ndp_map[i].vdev_id);
continue;
}
/* Check if this peer is already in the deleted list */
found = false;
for (j = 0; j < deleted_num && !found; j++) {
if (vos_mem_compare(
&deleted_peers[j].bytes,
&ndp_map[i].peer_ndi_mac_addr.bytes,
VOS_MAC_ADDR_SIZE)) {
found = true;
break;
}
}
if (found)
continue;
sta_ds = dphLookupHashEntry(mac_ctx,
ndp_map[i].peer_ndi_mac_addr.bytes,
&peer_idx, &session->dph.dphHashTable);
if (!sta_ds) {
limLog(mac_ctx, LOGE, FL("Unknown NDI Peer"));
continue;
}
if (sta_ds->staType != STA_ENTRY_NDI_PEER) {
limLog(mac_ctx, LOGE,
FL("Non-NDI Peer ignored"));
continue;
}
/*
* Call limDelSta() with response required set true.
* Hence DphHashEntry will be deleted after receiving
* that response.
*/
limDelSta(mac_ctx, sta_ds, true, session);
vos_copy_macaddr(&deleted_peers[deleted_num++],
&ndp_map[i].peer_ndi_mac_addr);
}
vos_mem_free(deleted_peers);
}
/**
* lim_ndp_end_indication_handler() - Handler for NDP end indication
* @mac_ctx: handle to mac context
* @ind_buf: pointer to indication buffer
*
* It deletes peers from ndp_map. Response of that operation goes
* to LIM and HDD. But peer information does not go to service layer.
* ndp_id_list is sent to service layer; it is not interpreted by the
* driver.
*
* Return: VOS_STATUS_SUCCESS on success; error number otherwise
*/
static VOS_STATUS lim_ndp_end_indication_handler(tpAniSirGlobal mac_ctx,
uint32_t *ind_buf)
{
struct ndp_end_indication_event *ndp_event_buf =
(struct ndp_end_indication_event *)ind_buf;
int buf_size;
if (!ind_buf) {
limLog(mac_ctx, LOGE, FL("NDP end indication buffer is NULL"));
return VOS_STATUS_E_INVAL;
}
lim_ndp_delete_peers(mac_ctx, ndp_event_buf->ndp_map,
ndp_event_buf->num_ndp_ids);
buf_size = sizeof(*ndp_event_buf) + ndp_event_buf->num_ndp_ids *
sizeof(ndp_event_buf->ndp_map[0]);
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_IND,
ndp_event_buf, buf_size, false);
return VOS_STATUS_SUCCESS;
}
/**
* lim_process_ndi_del_sta_rsp() - Handle WDA_DELETE_STA_RSP in eLIM_NDI_ROLE
* @mac_ctx: Global MAC context
* @lim_msg: LIM message
* @pe_session: PE session
*
* Return: None
*/
void lim_process_ndi_del_sta_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg,
tpPESession pe_session)
{
tpDeleteStaParams del_sta_params = (tpDeleteStaParams) lim_msg->bodyptr;
tpDphHashNode sta_ds;
tSirResultCodes status = eSIR_SME_SUCCESS;
struct sme_ndp_peer_ind peer_ind;
if (!del_sta_params) {
limLog(mac_ctx, LOGE,
FL("del_sta_params is NULL"));
return;
}
if (!LIM_IS_NDI_ROLE(pe_session)) {
limLog(mac_ctx, LOGE,
FL("Session %d is not NDI role"), del_sta_params->assocId);
status = eSIR_SME_REFUSED;
goto skip_event;
}
sta_ds = dphGetHashEntry(mac_ctx, del_sta_params->assocId,
&pe_session->dph.dphHashTable);
if (!sta_ds) {
limLog(mac_ctx, LOGE,
FL("DPH Entry for STA %X is missing."),
del_sta_params->assocId);
status = eSIR_SME_REFUSED;
goto skip_event;
}
if (eHAL_STATUS_SUCCESS != del_sta_params->status) {
limLog(mac_ctx, LOGE, FL("DEL STA failed!"));
status = eSIR_SME_REFUSED;
goto skip_event;
}
limLog(mac_ctx, LOG1,
FL("Deleted STA AssocID %d staId %d MAC " MAC_ADDRESS_STR),
sta_ds->assocId, sta_ds->staIndex,
MAC_ADDR_ARRAY(sta_ds->staAddr));
/*
* Copy peer info in del peer indication before
* limDeleteDphHashEntry is called as this will be lost.
*/
peer_ind.msg_len = sizeof(peer_ind);
peer_ind.msg_type = eWNI_SME_NDP_PEER_DEPARTED_IND;
peer_ind.session_id = pe_session->smeSessionId;
peer_ind.sta_id = sta_ds->staIndex;
vos_mem_copy(&peer_ind.peer_mac_addr.bytes,
sta_ds->staAddr, sizeof(tSirMacAddr));
limReleasePeerIdx(mac_ctx, sta_ds->assocId, pe_session);
limDeleteDphHashEntry(mac_ctx, sta_ds->staAddr, sta_ds->assocId,
pe_session);
pe_session->limMlmState = eLIM_MLM_IDLE_STATE;
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_PEER_DEPARTED_IND,
&peer_ind, sizeof(peer_ind), false);
skip_event:
vos_mem_free(del_sta_params);
lim_msg->bodyptr = NULL;
}
/**
* lim_handle_ndp_event_message() - Handler for NDP events/RSP from WMA
* @mac_ctx: handle to mac structure
* @msg: pointer to message
*
* Return: VOS_STATUS_SUCCESS on success; error number otherwise
*/
VOS_STATUS lim_handle_ndp_event_message(tpAniSirGlobal mac_ctx, tpSirMsgQ msg)
{
VOS_STATUS status = VOS_STATUS_SUCCESS;
switch (msg->type) {
case SIR_HAL_NDP_CONFIRM: {
struct ndp_confirm_event *ndp_confirm = msg->bodyptr;
if (ndp_confirm->rsp_code != NDP_RESPONSE_ACCEPT &&
ndp_confirm->num_active_ndps_on_peer == 0) {
/*
* This peer was created at ndp_indication but
* ndp_confirm failed, so it needs to be deleted
*/
limLog(mac_ctx, LOGE,
FL("NDP confirm with reject and no active ndp sessions. deleting peer: "MAC_ADDRESS_STR" on vdev_id: %d"),
MAC_ADDR_ARRAY(
ndp_confirm->peer_ndi_mac_addr.bytes),
ndp_confirm->vdev_id);
lim_ndp_delete_peer_by_addr(mac_ctx,
ndp_confirm->vdev_id,
ndp_confirm->peer_ndi_mac_addr);
}
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_CONFIRM_IND,
msg->bodyptr, sizeof(*ndp_confirm),
msg->bodyval);
break;
}
case SIR_HAL_NDP_INITIATOR_RSP:
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_INITIATOR_RSP,
msg->bodyptr, sizeof(struct ndp_initiator_rsp),
msg->bodyval);
break;
case SIR_HAL_NDP_END_RSP: {
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_RSP,
msg->bodyptr,
sizeof(struct ndp_end_rsp_event),
msg->bodyval);
break;
}
case SIR_HAL_NDP_INDICATION:
status = lim_handle_ndp_indication_event(mac_ctx, msg->bodyptr);
break;
case SIR_HAL_NDP_RESPONDER_RSP:
status = lim_ndp_responder_rsp_handler(mac_ctx, msg->bodyptr,
msg->bodyval);
break;
case SIR_HAL_NDP_END_IND:
status = lim_ndp_end_indication_handler(mac_ctx, msg->bodyptr);
break;
default:
limLog(mac_ctx, LOGE, FL("Unhandled NDP event: %d"), msg->type);
status = VOS_STATUS_E_NOSUPPORT;
break;
}
vos_mem_free(msg->bodyptr);
return status;
}
/**
* lim_process_sme_ndp_initiator_req() - Handler for eWNI_SME_NDP_INITIATOR_REQ
* from SME.
* @mac_ctx: handle to mac structure
* @ndp_msg: ndp initiator request msg
*
* Return: Status of operation
*/
VOS_STATUS lim_process_sme_ndp_initiator_req(tpAniSirGlobal mac_ctx,
void *ndp_msg)
{
tSirMsgQ msg;
VOS_STATUS status;
struct sir_sme_ndp_initiator_req *sme_req =
(struct sir_sme_ndp_initiator_req *)ndp_msg;
struct ndp_initiator_req *wma_req;
if (NULL == ndp_msg) {
limLog(mac_ctx, LOGE, FL("invalid ndp_req"));
status = VOS_STATUS_E_INVAL;
goto send_initiator_rsp;
}
wma_req = vos_mem_malloc(sizeof(*wma_req));
if (wma_req == NULL) {
limLog(mac_ctx, LOGE, FL("malloc failed"));
status = VOS_STATUS_E_NOMEM;
goto send_initiator_rsp;
}
vos_mem_copy(wma_req, &sme_req->req, sizeof(*wma_req));
msg.type = SIR_HAL_NDP_INITIATOR_REQ;
msg.reserved = 0;
msg.bodyptr = wma_req;
msg.bodyval = 0;
limLog(mac_ctx, LOG1, FL("sending WDA_NDP_INITIATOR_REQ to WMA"));
MTRACE(macTraceMsgTx(mac_ctx, NO_SESSION, msg.type));
if (eSIR_SUCCESS != wdaPostCtrlMsg(mac_ctx, &msg))
limLog(mac_ctx, LOGP, FL("wdaPostCtrlMsg failed"));
return VOS_STATUS_SUCCESS;
send_initiator_rsp:
/* msg to unblock SME, but not send rsp to HDD */
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_INITIATOR_RSP,
NULL, 0, true);
return status;
}
/**
* lim_process_sme_ndp_responder_req() - Handler for NDP responder req
* @mac_ctx: handle to mac structure
* @ndp_msg: pointer to message
*
* Return: VOS_STATUS_SUCCESS on success or failure code in case of failure
*/
static VOS_STATUS lim_process_sme_ndp_responder_req(tpAniSirGlobal mac_ctx,
struct sir_sme_ndp_responder_req *lim_msg)
{
tSirMsgQ msg;
VOS_STATUS status = VOS_STATUS_SUCCESS;
struct ndp_responder_req *responder_req;
if (NULL == lim_msg) {
limLog(mac_ctx, LOGE, FL("ndp_msg is NULL"));
status = VOS_STATUS_E_INVAL;
goto send_failure_rsp;
}
responder_req = vos_mem_malloc(sizeof(*responder_req));
if (NULL == responder_req) {
limLog(mac_ctx, LOGE,
FL("Unable to allocate memory for responder_req"));
status = VOS_STATUS_E_NOMEM;
goto send_failure_rsp;
}
vos_mem_copy(responder_req, &lim_msg->req, sizeof(*responder_req));
msg.type = SIR_HAL_NDP_RESPONDER_REQ;
msg.reserved = 0;
msg.bodyptr = responder_req;
msg.bodyval = 0;
limLog(mac_ctx, LOG1, FL("sending SIR_HAL_NDP_RESPONDER_REQ to WMA"));
MTRACE(macTraceMsgTx(mac_ctx, NO_SESSION, msg.type));
if (eSIR_SUCCESS != wdaPostCtrlMsg(mac_ctx, &msg)) {
limLog(mac_ctx, LOGE, FL("wdaPostCtrlMsg failed"));
status = VOS_STATUS_E_FAILURE;
vos_mem_free(responder_req);
goto send_failure_rsp;
}
return status;
send_failure_rsp:
/* msg to unblock SME, but not send rsp to HDD */
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_RESPONDER_RSP,
NULL, 0, true);
return status;
}
/**
* lim_process_sme_ndp_data_end_req() - Handler for eWNI_SME_NDP_END_REQ
* from SME.
* @mac_ctx: handle to mac context
* @sme_msg: ndp data end request msg
*
* Return: Status of operation
*/
VOS_STATUS lim_process_sme_ndp_data_end_req(tpAniSirGlobal mac_ctx,
struct sir_sme_ndp_end_req *sme_msg)
{
tSirMsgQ msg;
uint32_t len;
VOS_STATUS status = VOS_STATUS_SUCCESS;
if (NULL == sme_msg) {
limLog(mac_ctx, LOGE, FL("invalid ndp_req"));
/* msg to unblock SME, but not send rsp to HDD */
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_RSP, NULL,
0, true);
return VOS_STATUS_E_INVAL;
}
msg.type = SIR_HAL_NDP_END_REQ;
msg.reserved = 0;
len = sizeof(*sme_msg->req) + (sme_msg->req->num_ndp_instances *
sizeof(uint32_t));
msg.bodyptr = vos_mem_malloc(len);
if (NULL == msg.bodyptr) {
/* msg to unblock SME, but not send rsp to HDD */
lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_RSP, NULL,
0, true);
return VOS_STATUS_E_NOMEM;
}
vos_mem_copy(msg.bodyptr, sme_msg->req, len);
msg.bodyval = 0;
limLog(mac_ctx, LOG1, FL("sending SIR_HAL_NDP_END_REQ to WMA"));
MTRACE(macTraceMsgTx(mac_ctx, NO_SESSION, msg.type));
if (eSIR_SUCCESS != wdaPostCtrlMsg(mac_ctx, &msg)) {
limLog(mac_ctx, LOGE,
FL("Post msg failed for SIR_HAL_NDP_END_REQ"));
status = VOS_STATUS_E_FAILURE;
}
return status;
}
/**
* lim_handle_ndp_request_message() - Handler for NDP req from SME
* @mac_ctx: handle to mac structure
* @msg: pointer to message
*
* Return: VOS_STATUS_SUCCESS on success; error number otherwise
*/
VOS_STATUS lim_handle_ndp_request_message(tpAniSirGlobal mac_ctx,
tpSirMsgQ msg)
{
VOS_STATUS status;
switch (msg->type) {
case eWNI_SME_NDP_END_REQ:
status = lim_process_sme_ndp_data_end_req(mac_ctx,
msg->bodyptr);
break;
case eWNI_SME_NDP_INITIATOR_REQ:
status = lim_process_sme_ndp_initiator_req(mac_ctx,
msg->bodyptr);
break;
case eWNI_SME_NDP_RESPONDER_REQ:
status = lim_process_sme_ndp_responder_req(mac_ctx,
msg->bodyptr);
break;
default:
limLog(mac_ctx, LOGE, FL("Unhandled NDP request: %d"),
msg->type);
status = VOS_STATUS_E_NOSUPPORT;
break;
}
return status;
}
/**
* lim_process_ndi_mlm_add_bss_rsp() - Process ADD_BSS response for NDI
* @mac_ctx: Pointer to Global MAC structure
* @lim_msgq: The MsgQ header, which contains the response buffer
* @session_entry: PE session
*
* Return: None
*/
void lim_process_ndi_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msgq,
tpPESession session_entry)
{
tLimMlmStartCnf mlm_start_cnf;
tpAddBssParams add_bss_params = (tpAddBssParams) lim_msgq->bodyptr;
if (NULL == add_bss_params) {
limLog(mac_ctx, LOGE, FL("Invalid body pointer in message"));
goto end;
}
limLog(mac_ctx, LOG1, FL("Status %d"), add_bss_params->status);
if (eHAL_STATUS_SUCCESS == add_bss_params->status) {
limLog(mac_ctx, LOG1,
FL("WDA_ADD_BSS_RSP returned eHAL_STATUS_SUCCESS"));
session_entry->limMlmState = eLIM_MLM_BSS_STARTED_STATE;
MTRACE(macTrace(mac_ctx, TRACE_CODE_MLM_STATE,
session_entry->peSessionId,
session_entry->limMlmState));
session_entry->bssIdx = (uint8_t) add_bss_params->bssIdx;
session_entry->limSystemRole = eLIM_NDI_ROLE;
session_entry->statypeForBss = STA_ENTRY_SELF;
session_entry->staId = add_bss_params->staContext.staIdx;
/* Apply previously set configuration at HW */
limApplyConfiguration(mac_ctx, session_entry);
mlm_start_cnf.resultCode = eSIR_SME_SUCCESS;
} else {
limLog(mac_ctx, LOGE,
FL("WDA_ADD_BSS_REQ failed with status %d"),
add_bss_params->status);
mlm_start_cnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL;
}
mlm_start_cnf.sessionId = session_entry->peSessionId;
limPostSmeMessage(mac_ctx, LIM_MLM_START_CNF,
(uint32_t *) &mlm_start_cnf);
end:
vos_mem_free(lim_msgq->bodyptr);
lim_msgq->bodyptr = NULL;
}
/**
* lim_ndi_del_bss_rsp() - Handler DEL BSS resp for NDI interface
* @mac_ctx: handle to mac structure
* @msg: pointer to message
* @session_entry: session entry
*
* Return: void
*/
void lim_ndi_del_bss_rsp(tpAniSirGlobal mac_ctx,
void *msg, tpPESession session_entry)
{
tSirResultCodes rc = eSIR_SME_SUCCESS;
tpDeleteBssParams del_bss = (tpDeleteBssParams) msg;
SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true);
if (del_bss == NULL) {
limLog(mac_ctx, LOGE,
FL("NDI: DEL_BSS_RSP with no body!"));
rc = eSIR_SME_STOP_BSS_FAILURE;
goto end;
}
session_entry =
peFindSessionBySessionId(mac_ctx, del_bss->sessionId);
if (!session_entry) {
limLog(mac_ctx, LOGE,
FL("Session Does not exist for given sessionID"));
goto end;
}
if (del_bss->status != eHAL_STATUS_SUCCESS) {
limLog(mac_ctx, LOGE, FL("NDI: DEL_BSS_RSP error (%x) Bss %d "),
del_bss->status, del_bss->bssIdx);
rc = eSIR_SME_STOP_BSS_FAILURE;
goto end;
}
if (limSetLinkState(mac_ctx, eSIR_LINK_IDLE_STATE,
session_entry->selfMacAddr,
session_entry->selfMacAddr, NULL, NULL)
!= eSIR_SUCCESS) {
limLog(mac_ctx, LOGE,
FL("NDI: DEL_BSS_RSP setLinkState failed"));
goto end;
}
session_entry->limMlmState = eLIM_MLM_IDLE_STATE;
end:
if (del_bss)
vos_mem_free(del_bss);
/* Delete PE session once BSS is deleted */
if (NULL != session_entry) {
limSendSmeRsp(mac_ctx, eWNI_SME_STOP_BSS_RSP,
rc, session_entry->smeSessionId,
session_entry->transactionId);
peDeleteSession(mac_ctx, session_entry);
session_entry = NULL;
}
}
/**
* lim_send_sme_ndp_add_sta_rsp() - prepares and send new peer ind to SME
* @mac_ctx: handle to mac structure
* @session: session pointer
* @add_sta_rsp: add sta response struct
*
* Return: status of operation
*/
static VOS_STATUS lim_send_sme_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx,
tpPESession session,
tAddStaParams *add_sta_rsp)
{
tSirMsgQ mmh_msg = {0};
struct sme_ndp_peer_ind *new_peer_ind;
mmh_msg.type = eWNI_SME_NDP_NEW_PEER_IND;
if (NULL == add_sta_rsp) {
limLog(mac_ctx, LOGE, FL("Invalid add_sta_rsp"));
return VOS_STATUS_E_INVAL;
}
new_peer_ind = vos_mem_malloc(sizeof(*new_peer_ind));
if (NULL == new_peer_ind) {
limLog(mac_ctx, LOGE, FL("Failed to allocate memory"));
return VOS_STATUS_E_NOMEM;
}
/* this message is going to HDD, fill in sme session id */
new_peer_ind->session_id = add_sta_rsp->smesessionId;
new_peer_ind->msg_len = sizeof(struct sme_ndp_peer_ind);
new_peer_ind->msg_type = eWNI_SME_NDP_NEW_PEER_IND;
vos_mem_copy(new_peer_ind->peer_mac_addr.bytes, add_sta_rsp->staMac,
sizeof(tSirMacAddr));
new_peer_ind->sta_id = add_sta_rsp->staIdx;
mmh_msg.bodyptr = new_peer_ind;
mmh_msg.bodyval = 0;
limSysProcessMmhMsgApi(mac_ctx, &mmh_msg, ePROT);
return VOS_STATUS_SUCCESS;
}
/**
* lim_ndp_add_sta_rsp() - handles add sta rsp for NDP from WMA
* @mac_ctx: handle to mac structure
* @session: session pointer
* @add_sta_rsp: add sta response struct
*
* Return: None
*/
void lim_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, tpPESession session,
tAddStaParams *add_sta_rsp)
{
tpDphHashNode sta_ds;
uint16_t peer_idx;
if (NULL == add_sta_rsp) {
limLog(mac_ctx, LOGE, FL("Invalid add_sta_rsp"));
vos_mem_free(add_sta_rsp);
return;
}
SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true);
sta_ds = dphLookupHashEntry(mac_ctx, add_sta_rsp->staMac, &peer_idx,
&session->dph.dphHashTable);
if (sta_ds == NULL) {
limLog(mac_ctx, LOGE,
FL("NAN: ADD_STA_RSP for unknown MAC addr "
MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(add_sta_rsp->staMac));
vos_mem_free(add_sta_rsp);
return;
}
if (add_sta_rsp->status != eHAL_STATUS_SUCCESS) {
limLog(mac_ctx, LOGE,
FL("NAN: ADD_STA_RSP error %x for MAC addr: %pM"),
add_sta_rsp->status, add_sta_rsp->staMac);
/* delete the sta_ds allocated during ADD STA */
limDeleteDphHashEntry(mac_ctx, add_sta_rsp->staMac,
peer_idx, session);
vos_mem_free(add_sta_rsp);
return;
}
sta_ds->bssId = add_sta_rsp->bssIdx;
sta_ds->staIndex = add_sta_rsp->staIdx;
sta_ds->ucUcastSig = add_sta_rsp->ucUcastSig;
sta_ds->ucBcastSig = add_sta_rsp->ucBcastSig;
sta_ds->valid = 1;
sta_ds->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE;
lim_send_sme_ndp_add_sta_rsp(mac_ctx, session, add_sta_rsp);
vos_mem_free(add_sta_rsp);
}