/******************************************************************************
*
* Copyright (C) 2010-2014 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* NFA interface to LLCP
*
******************************************************************************/
#include "nfa_p2p_api.h"
#include <string.h>
#include "llcp_api.h"
#include "llcp_defs.h"
#include "nfa_p2p_int.h"
#include "nfa_sys.h"
#include "nfa_sys_int.h"
#include "nfc_api.h"
/*****************************************************************************
** Constants
*****************************************************************************/
/*******************************************************************************
**
** Function NFA_P2pRegisterServer
**
** Description This function is called to listen to a SAP as server on
** LLCP.
**
** NFA_P2P_REG_SERVER_EVT will be returned with status and
** handle.
**
** If server_sap is set to NFA_P2P_ANY_SAP, then NFA will
** allocate a SAP between LLCP_LOWER_BOUND_SDP_SAP and
** LLCP_UPPER_BOUND_SDP_SAP Otherwise, server_sap must be
** between (LLCP_SDP_SAP + 1) and LLCP_UPPER_BOUND_SDP_SAP
**
** link_type : NFA_P2P_LLINK_TYPE and/or NFA_P2P_DLINK_TYPE
**
** Note: If RF discovery is started,
** NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
** happen before calling this function
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pRegisterServer(uint8_t server_sap,
tNFA_P2P_LINK_TYPE link_type,
char* p_service_name,
tNFA_P2P_CBACK* p_cback) {
tNFA_P2P_API_REG_SERVER* p_msg;
P2P_TRACE_API3(
"NFA_P2pRegisterServer (): server_sap:0x%02x, link_type:0x%x, SN:<%s>",
server_sap, link_type, p_service_name);
if ((server_sap != NFA_P2P_ANY_SAP) &&
((server_sap <= LLCP_SAP_SDP) ||
(server_sap > LLCP_UPPER_BOUND_SDP_SAP))) {
P2P_TRACE_ERROR2(
"NFA_P2pRegisterServer (): server_sap must be between %d and %d",
LLCP_SAP_SDP + 1, LLCP_UPPER_BOUND_SDP_SAP);
return (NFA_STATUS_FAILED);
} else if (((link_type & NFA_P2P_LLINK_TYPE) == 0x00) &&
((link_type & NFA_P2P_DLINK_TYPE) == 0x00)) {
P2P_TRACE_ERROR1(
"NFA_P2pRegisterServer(): link type (0x%x) must be specified",
link_type);
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_P2P_API_REG_SERVER*)GKI_getbuf(
sizeof(tNFA_P2P_API_REG_SERVER))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_REG_SERVER_EVT;
p_msg->server_sap = server_sap;
p_msg->link_type = link_type;
strncpy(p_msg->service_name, p_service_name, LLCP_MAX_SN_LEN);
p_msg->service_name[LLCP_MAX_SN_LEN] = 0;
p_msg->p_cback = p_cback;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pRegisterClient
**
** Description This function is called to register a client service on
** LLCP.
**
** NFA_P2P_REG_CLIENT_EVT will be returned with status and
** handle.
**
** link_type : NFA_P2P_LLINK_TYPE and/or NFA_P2P_DLINK_TYPE
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pRegisterClient(tNFA_P2P_LINK_TYPE link_type,
tNFA_P2P_CBACK* p_cback) {
tNFA_P2P_API_REG_CLIENT* p_msg;
P2P_TRACE_API1("NFA_P2pRegisterClient (): link_type:0x%x", link_type);
if (((link_type & NFA_P2P_LLINK_TYPE) == 0x00) &&
((link_type & NFA_P2P_DLINK_TYPE) == 0x00)) {
P2P_TRACE_ERROR1(
"NFA_P2pRegisterClient (): link type (0x%x) must be specified",
link_type);
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_P2P_API_REG_CLIENT*)GKI_getbuf(
sizeof(tNFA_P2P_API_REG_CLIENT))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_REG_CLIENT_EVT;
p_msg->p_cback = p_cback;
p_msg->link_type = link_type;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pDeregister
**
** Description This function is called to stop listening to a SAP as server
** or stop client service on LLCP.
**
** Note: If this function is called to de-register a server and RF
** discovery is started,
** NFA_StopRfDiscovery()/NFA_RF_DISCOVERY_STOPPED_EVT should
** happen before calling this function
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pDeregister(tNFA_HANDLE handle) {
tNFA_P2P_API_DEREG* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API1("NFA_P2pDeregister (): handle:0x%02X", handle);
xx = handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR0(
"NFA_P2pDeregister (): Handle is invalid or not registered");
return (NFA_STATUS_BAD_HANDLE);
}
if ((p_msg = (tNFA_P2P_API_DEREG*)GKI_getbuf(sizeof(tNFA_P2P_API_DEREG))) !=
NULL) {
p_msg->hdr.event = NFA_P2P_API_DEREG_EVT;
p_msg->handle = handle;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pAcceptConn
**
** Description This function is called to accept a request of data link
** connection to a listening SAP on LLCP after receiving
** NFA_P2P_CONN_REQ_EVT.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pAcceptConn(tNFA_HANDLE handle, uint16_t miu, uint8_t rw) {
tNFA_P2P_API_ACCEPT_CONN* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API3("NFA_P2pAcceptConn (): handle:0x%02X, MIU:%d, RW:%d", handle,
miu, rw);
xx = handle & NFA_HANDLE_MASK;
if (!(xx & NFA_P2P_HANDLE_FLAG_CONN)) {
P2P_TRACE_ERROR0("NFA_P2pAcceptConn (): Connection Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
} else {
xx &= ~NFA_P2P_HANDLE_FLAG_CONN;
}
if ((xx >= LLCP_MAX_DATA_LINK) || (nfa_p2p_cb.conn_cb[xx].flags == 0)) {
P2P_TRACE_ERROR0("NFA_P2pAcceptConn (): Connection Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
}
if ((miu < LLCP_DEFAULT_MIU) || (nfa_p2p_cb.local_link_miu < miu)) {
P2P_TRACE_ERROR3("NFA_P2pAcceptConn (): MIU(%d) must be between %d and %d",
miu, LLCP_DEFAULT_MIU, nfa_p2p_cb.local_link_miu);
} else if ((p_msg = (tNFA_P2P_API_ACCEPT_CONN*)GKI_getbuf(
sizeof(tNFA_P2P_API_ACCEPT_CONN))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_ACCEPT_CONN_EVT;
p_msg->conn_handle = handle;
p_msg->miu = miu;
p_msg->rw = rw;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pRejectConn
**
** Description This function is called to reject a request of data link
** connection to a listening SAP on LLCP after receiving
** NFA_P2P_CONN_REQ_EVT.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pRejectConn(tNFA_HANDLE handle) {
tNFA_P2P_API_REJECT_CONN* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API1("NFA_P2pRejectConn (): handle:0x%02X", handle);
xx = handle & NFA_HANDLE_MASK;
if (!(xx & NFA_P2P_HANDLE_FLAG_CONN)) {
P2P_TRACE_ERROR0("NFA_P2pRejectConn (): Connection Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
} else {
xx &= ~NFA_P2P_HANDLE_FLAG_CONN;
}
if ((xx >= LLCP_MAX_DATA_LINK) || (nfa_p2p_cb.conn_cb[xx].flags == 0)) {
P2P_TRACE_ERROR0("NFA_P2pRejectConn (): Connection Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
}
if ((p_msg = (tNFA_P2P_API_REJECT_CONN*)GKI_getbuf(
sizeof(tNFA_P2P_API_REJECT_CONN))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_REJECT_CONN_EVT;
p_msg->conn_handle = handle;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pDisconnect
**
** Description This function is called to disconnect an existing or
** connecting data link connection.
**
** discard any pending data on data link connection if flush is
** set to TRUE
**
** NFA_P2P_DISC_EVT will be returned after data link connection
** is disconnected
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pDisconnect(tNFA_HANDLE handle, bool flush) {
tNFA_P2P_API_DISCONNECT* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API2("NFA_P2pDisconnect (): handle:0x%02X, flush=%d", handle,
flush);
xx = handle & NFA_HANDLE_MASK;
if (xx & NFA_P2P_HANDLE_FLAG_CONN) {
xx &= ~NFA_P2P_HANDLE_FLAG_CONN;
if ((xx >= LLCP_MAX_DATA_LINK) || (nfa_p2p_cb.conn_cb[xx].flags == 0)) {
P2P_TRACE_ERROR0("NFA_P2pDisconnect (): Connection Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
}
} else {
P2P_TRACE_ERROR0("NFA_P2pDisconnect (): Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
}
if ((p_msg = (tNFA_P2P_API_DISCONNECT*)GKI_getbuf(
sizeof(tNFA_P2P_API_DISCONNECT))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_DISCONNECT_EVT;
p_msg->conn_handle = handle;
p_msg->flush = flush;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pConnectByName
**
** Description This function is called to create a connection-oriented
** transport by a service name.
** NFA_P2P_CONNECTED_EVT if success
** NFA_P2P_DISC_EVT if failed
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if client is not registered
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pConnectByName(tNFA_HANDLE client_handle,
char* p_service_name, uint16_t miu,
uint8_t rw) {
tNFA_P2P_API_CONNECT* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API4(
"NFA_P2pConnectByName (): client_handle:0x%x, SN:<%s>, MIU:%d, RW:%d",
client_handle, p_service_name, miu, rw);
xx = client_handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR0("NFA_P2pConnectByName (): Client Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
}
if ((miu < LLCP_DEFAULT_MIU) ||
(nfa_p2p_cb.llcp_state != NFA_P2P_LLCP_STATE_ACTIVATED) ||
(nfa_p2p_cb.local_link_miu < miu)) {
P2P_TRACE_ERROR3(
"NFA_P2pConnectByName (): MIU(%d) must be between %d and %d or LLCP "
"link is not activated",
miu, LLCP_DEFAULT_MIU, nfa_p2p_cb.local_link_miu);
} else if ((p_msg = (tNFA_P2P_API_CONNECT*)GKI_getbuf(
sizeof(tNFA_P2P_API_CONNECT))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_CONNECT_EVT;
strncpy(p_msg->service_name, p_service_name, LLCP_MAX_SN_LEN);
p_msg->service_name[LLCP_MAX_SN_LEN] = 0;
p_msg->dsap = LLCP_INVALID_SAP;
p_msg->miu = miu;
p_msg->rw = rw;
p_msg->client_handle = client_handle;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pConnectBySap
**
** Description This function is called to create a connection-oriented
** transport by a SAP.
** NFA_P2P_CONNECTED_EVT if success
** NFA_P2P_DISC_EVT if failed
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if client is not registered
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pConnectBySap(tNFA_HANDLE client_handle, uint8_t dsap,
uint16_t miu, uint8_t rw) {
tNFA_P2P_API_CONNECT* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API4(
"NFA_P2pConnectBySap (): client_handle:0x%x, DSAP:0x%02X, MIU:%d, RW:%d",
client_handle, dsap, miu, rw);
xx = client_handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR0("NFA_P2pConnectBySap (): Client Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
}
if ((miu < LLCP_DEFAULT_MIU) ||
(nfa_p2p_cb.llcp_state != NFA_P2P_LLCP_STATE_ACTIVATED) ||
(nfa_p2p_cb.local_link_miu < miu)) {
P2P_TRACE_ERROR3(
"NFA_P2pConnectBySap (): MIU(%d) must be between %d and %d, or LLCP "
"link is not activated",
miu, LLCP_DEFAULT_MIU, nfa_p2p_cb.local_link_miu);
} else if ((p_msg = (tNFA_P2P_API_CONNECT*)GKI_getbuf(
sizeof(tNFA_P2P_API_CONNECT))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_CONNECT_EVT;
p_msg->service_name[LLCP_MAX_SN_LEN] = 0;
p_msg->dsap = dsap;
p_msg->miu = miu;
p_msg->rw = rw;
p_msg->client_handle = client_handle;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pSendUI
**
** Description This function is called to send data on connectionless
** transport.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
** NFA_STATUS_BAD_LENGTH if data length is more than remote
** link MIU
** NFA_STATUS_CONGESTED if congested
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pSendUI(tNFA_HANDLE handle, uint8_t dsap, uint16_t length,
uint8_t* p_data) {
tNFA_P2P_API_SEND_UI* p_msg;
tNFA_STATUS ret_status = NFA_STATUS_FAILED;
tNFA_HANDLE xx;
P2P_TRACE_API3("NFA_P2pSendUI (): handle:0x%X, DSAP:0x%02X, length:%d",
handle, dsap, length);
GKI_sched_lock();
xx = handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR1("NFA_P2pSendUI (): Handle (0x%X) is not valid", handle);
ret_status = NFA_STATUS_BAD_HANDLE;
} else if (length > nfa_p2p_cb.remote_link_miu) {
P2P_TRACE_ERROR3(
"NFA_P2pSendUI (): handle:0x%X, length(%d) must be less than remote "
"link MIU(%d)",
handle, length, nfa_p2p_cb.remote_link_miu);
ret_status = NFA_STATUS_BAD_LENGTH;
} else if (nfa_p2p_cb.sap_cb[xx].flags & NFA_P2P_SAP_FLAG_LLINK_CONGESTED) {
P2P_TRACE_WARNING1(
"NFA_P2pSendUI (): handle:0x%X, logical data link is already congested",
handle);
ret_status = NFA_STATUS_CONGESTED;
} else if (LLCP_IsLogicalLinkCongested(
(uint8_t)xx, nfa_p2p_cb.sap_cb[xx].num_pending_ui_pdu,
nfa_p2p_cb.total_pending_ui_pdu,
nfa_p2p_cb.total_pending_i_pdu)) {
nfa_p2p_cb.sap_cb[xx].flags |= NFA_P2P_SAP_FLAG_LLINK_CONGESTED;
P2P_TRACE_WARNING1(
"NFA_P2pSendUI(): handle:0x%X, logical data link is congested", handle);
ret_status = NFA_STATUS_CONGESTED;
} else if ((p_msg = (tNFA_P2P_API_SEND_UI*)GKI_getbuf(
sizeof(tNFA_P2P_API_SEND_UI))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_SEND_UI_EVT;
p_msg->handle = handle;
p_msg->dsap = dsap;
p_msg->p_msg = (NFC_HDR*)GKI_getpoolbuf(LLCP_POOL_ID);
if (p_msg->p_msg != NULL) {
p_msg->p_msg->len = length;
p_msg->p_msg->offset = LLCP_MIN_OFFSET;
memcpy(((uint8_t*)(p_msg->p_msg + 1) + p_msg->p_msg->offset), p_data,
length);
/* increase number of tx UI PDU which is not processed by NFA for
* congestion control */
nfa_p2p_cb.sap_cb[xx].num_pending_ui_pdu++;
nfa_p2p_cb.total_pending_ui_pdu++;
nfa_sys_sendmsg(p_msg);
ret_status = NFA_STATUS_OK;
} else {
GKI_freebuf(p_msg);
nfa_p2p_cb.sap_cb[xx].flags |= NFA_P2P_SAP_FLAG_LLINK_CONGESTED;
ret_status = NFA_STATUS_CONGESTED;
}
}
GKI_sched_unlock();
return (ret_status);
}
/*******************************************************************************
**
** Function NFA_P2pReadUI
**
** Description This function is called to read data on connectionless
** transport when receiving NFA_P2P_DATA_EVT with
** NFA_P2P_LLINK_TYPE.
**
** - Remote SAP who sent UI PDU is returned.
** - Information of UI PDU up to max_data_len is copied into
** p_data.
** - If more information of UI PDU or more UI PDU in queue then
** more is returned to TRUE.
** - Information of next UI PDU is not concatenated.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
**
*******************************************************************************/
tNFA_STATUS NFA_P2pReadUI(tNFA_HANDLE handle, uint32_t max_data_len,
uint8_t* p_remote_sap, uint32_t* p_data_len,
uint8_t* p_data, bool* p_more) {
tNFA_STATUS ret_status;
tNFA_HANDLE xx;
P2P_TRACE_API1("NFA_P2pReadUI (): handle:0x%X", handle);
GKI_sched_lock();
xx = handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR1("NFA_P2pReadUI (): Handle (0x%X) is not valid", handle);
ret_status = NFA_STATUS_BAD_HANDLE;
} else {
*p_more = LLCP_ReadLogicalLinkData((uint8_t)xx, max_data_len, p_remote_sap,
p_data_len, p_data);
ret_status = NFA_STATUS_OK;
}
GKI_sched_unlock();
return (ret_status);
}
/*******************************************************************************
**
** Function NFA_P2pFlushUI
**
** Description This function is called to flush data on connectionless
** transport.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
**
*******************************************************************************/
tNFA_STATUS NFA_P2pFlushUI(tNFA_HANDLE handle, uint32_t* p_length) {
tNFA_STATUS ret_status;
tNFA_HANDLE xx;
P2P_TRACE_API1("NFA_P2pReadUI (): handle:0x%X", handle);
GKI_sched_lock();
xx = handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR1("NFA_P2pFlushUI (): Handle (0x%X) is not valid", handle);
ret_status = NFA_STATUS_BAD_HANDLE;
*p_length = 0;
} else {
*p_length = LLCP_FlushLogicalLinkRxData((uint8_t)xx);
ret_status = NFA_STATUS_OK;
}
GKI_sched_unlock();
return (ret_status);
}
/*******************************************************************************
**
** Function NFA_P2pSendData
**
** Description This function is called to send data on connection-oriented
** transport.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
** NFA_STATUS_BAD_LENGTH if data length is more than remote MIU
** NFA_STATUS_CONGESTED if congested
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pSendData(tNFA_HANDLE handle, uint16_t length,
uint8_t* p_data) {
tNFA_P2P_API_SEND_DATA* p_msg;
tNFA_STATUS ret_status = NFA_STATUS_FAILED;
tNFA_HANDLE xx;
P2P_TRACE_API2("NFA_P2pSendData (): handle:0x%X, length:%d", handle, length);
GKI_sched_lock();
xx = handle & NFA_HANDLE_MASK;
xx &= ~NFA_P2P_HANDLE_FLAG_CONN;
if ((!(handle & NFA_P2P_HANDLE_FLAG_CONN)) || (xx >= LLCP_MAX_DATA_LINK) ||
(nfa_p2p_cb.conn_cb[xx].flags == 0)) {
P2P_TRACE_ERROR1("NFA_P2pSendData (): Handle(0x%X) is not valid", handle);
ret_status = NFA_STATUS_BAD_HANDLE;
} else if (nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_REMOTE_RW_ZERO) {
P2P_TRACE_ERROR1(
"NFA_P2pSendData (): handle:0x%X, Remote set RW to 0 (flow off)",
handle);
ret_status = NFA_STATUS_FAILED;
} else if (nfa_p2p_cb.conn_cb[xx].remote_miu < length) {
P2P_TRACE_ERROR2(
"NFA_P2pSendData (): handle:0x%X, Data more than remote MIU(%d)",
handle, nfa_p2p_cb.conn_cb[xx].remote_miu);
ret_status = NFA_STATUS_BAD_LENGTH;
} else if (nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_CONGESTED) {
P2P_TRACE_WARNING1(
"NFA_P2pSendData (): handle:0x%X, data link connection is already "
"congested",
handle);
ret_status = NFA_STATUS_CONGESTED;
} else if (LLCP_IsDataLinkCongested(nfa_p2p_cb.conn_cb[xx].local_sap,
nfa_p2p_cb.conn_cb[xx].remote_sap,
nfa_p2p_cb.conn_cb[xx].num_pending_i_pdu,
nfa_p2p_cb.total_pending_ui_pdu,
nfa_p2p_cb.total_pending_i_pdu)) {
nfa_p2p_cb.conn_cb[xx].flags |= NFA_P2P_CONN_FLAG_CONGESTED;
P2P_TRACE_WARNING1(
"NFA_P2pSendData (): handle:0x%X, data link connection is congested",
handle);
ret_status = NFA_STATUS_CONGESTED;
} else if ((p_msg = (tNFA_P2P_API_SEND_DATA*)GKI_getbuf(
sizeof(tNFA_P2P_API_SEND_DATA))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_SEND_DATA_EVT;
p_msg->conn_handle = handle;
p_msg->p_msg = (NFC_HDR*)GKI_getpoolbuf(LLCP_POOL_ID);
if (p_msg->p_msg != NULL) {
p_msg->p_msg->len = length;
p_msg->p_msg->offset = LLCP_MIN_OFFSET;
memcpy(((uint8_t*)(p_msg->p_msg + 1) + p_msg->p_msg->offset), p_data,
length);
/* increase number of tx I PDU which is not processed by NFA for
* congestion control */
nfa_p2p_cb.conn_cb[xx].num_pending_i_pdu++;
nfa_p2p_cb.total_pending_i_pdu++;
nfa_sys_sendmsg(p_msg);
ret_status = NFA_STATUS_OK;
} else {
GKI_freebuf(p_msg);
nfa_p2p_cb.conn_cb[xx].flags |= NFA_P2P_CONN_FLAG_CONGESTED;
ret_status = NFA_STATUS_CONGESTED;
}
}
GKI_sched_unlock();
return (ret_status);
}
/*******************************************************************************
**
** Function NFA_P2pReadData
**
** Description This function is called to read data on connection-oriented
** transport when receiving NFA_P2P_DATA_EVT with
** NFA_P2P_DLINK_TYPE.
**
** - Information of I PDU is copied into p_data up to
** max_data_len.
** - If more information of I PDU or more I PDU in queue, then
** more is returned to TRUE.
** - Information of next I PDU is not concatenated.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
**
*******************************************************************************/
tNFA_STATUS NFA_P2pReadData(tNFA_HANDLE handle, uint32_t max_data_len,
uint32_t* p_data_len, uint8_t* p_data,
bool* p_more) {
tNFA_STATUS ret_status;
tNFA_HANDLE xx;
P2P_TRACE_API1("NFA_P2pReadData (): handle:0x%X", handle);
GKI_sched_lock();
xx = handle & NFA_HANDLE_MASK;
xx &= ~NFA_P2P_HANDLE_FLAG_CONN;
if ((!(handle & NFA_P2P_HANDLE_FLAG_CONN)) || (xx >= LLCP_MAX_DATA_LINK) ||
(nfa_p2p_cb.conn_cb[xx].flags == 0)) {
P2P_TRACE_ERROR1("NFA_P2pReadData (): Handle(0x%X) is not valid", handle);
ret_status = NFA_STATUS_BAD_HANDLE;
} else {
*p_more = LLCP_ReadDataLinkData(nfa_p2p_cb.conn_cb[xx].local_sap,
nfa_p2p_cb.conn_cb[xx].remote_sap,
max_data_len, p_data_len, p_data);
ret_status = NFA_STATUS_OK;
}
GKI_sched_unlock();
return (ret_status);
}
/*******************************************************************************
**
** Function NFA_P2pFlushData
**
** Description This function is called to flush data on connection-oriented
** transport.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
**
*******************************************************************************/
tNFA_STATUS NFA_P2pFlushData(tNFA_HANDLE handle, uint32_t* p_length) {
tNFA_STATUS ret_status;
tNFA_HANDLE xx;
P2P_TRACE_API1("NFA_P2pFlushData (): handle:0x%X", handle);
GKI_sched_lock();
xx = handle & NFA_HANDLE_MASK;
xx &= ~NFA_P2P_HANDLE_FLAG_CONN;
if ((!(handle & NFA_P2P_HANDLE_FLAG_CONN)) || (xx >= LLCP_MAX_DATA_LINK) ||
(nfa_p2p_cb.conn_cb[xx].flags == 0)) {
P2P_TRACE_ERROR1("NFA_P2pFlushData (): Handle(0x%X) is not valid", handle);
ret_status = NFA_STATUS_BAD_HANDLE;
} else {
*p_length = LLCP_FlushDataLinkRxData(nfa_p2p_cb.conn_cb[xx].local_sap,
nfa_p2p_cb.conn_cb[xx].remote_sap);
ret_status = NFA_STATUS_OK;
}
GKI_sched_unlock();
return (ret_status);
}
/*******************************************************************************
**
** Function NFA_P2pSetLocalBusy
**
** Description This function is called to stop or resume incoming data on
** connection-oriented transport.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if handle is not valid
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pSetLocalBusy(tNFA_HANDLE conn_handle, bool is_busy) {
tNFA_P2P_API_SET_LOCAL_BUSY* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API2("NFA_P2pSetLocalBusy (): conn_handle:0x%02X, is_busy:%d",
conn_handle, is_busy);
xx = conn_handle & NFA_HANDLE_MASK;
if (!(xx & NFA_P2P_HANDLE_FLAG_CONN)) {
P2P_TRACE_ERROR0("NFA_P2pSetLocalBusy (): Connection Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
} else {
xx &= ~NFA_P2P_HANDLE_FLAG_CONN;
}
if ((xx >= LLCP_MAX_DATA_LINK) || (nfa_p2p_cb.conn_cb[xx].flags == 0)) {
P2P_TRACE_ERROR0("NFA_P2pSetLocalBusy (): Connection Handle is not valid");
return (NFA_STATUS_BAD_HANDLE);
}
if ((p_msg = (tNFA_P2P_API_SET_LOCAL_BUSY*)GKI_getbuf(
sizeof(tNFA_P2P_API_SET_LOCAL_BUSY))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_SET_LOCAL_BUSY_EVT;
p_msg->conn_handle = conn_handle;
p_msg->is_busy = is_busy;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pGetLinkInfo
**
** Description This function is called to get local/remote link MIU and
** Well-Known Service list encoded as a 16-bit field of
** connected LLCP. NFA_P2P_LINK_INFO_EVT will be returned.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if server or client is not registered
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pGetLinkInfo(tNFA_HANDLE handle) {
tNFA_P2P_API_GET_LINK_INFO* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API1("NFA_P2pGetLinkInfo (): handle:0x%x", handle);
if (nfa_p2p_cb.llcp_state != NFA_P2P_LLCP_STATE_ACTIVATED) {
P2P_TRACE_ERROR0("NFA_P2pGetLinkInfo (): LLCP link is not activated");
return (NFA_STATUS_FAILED);
}
xx = handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR0(
"NFA_P2pGetLinkInfo (): Handle is invalid or not registered");
return (NFA_STATUS_BAD_HANDLE);
}
if ((p_msg = (tNFA_P2P_API_GET_LINK_INFO*)GKI_getbuf(
sizeof(tNFA_P2P_API_GET_LINK_INFO))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_GET_LINK_INFO_EVT;
p_msg->handle = handle;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pGetRemoteSap
**
** Description This function is called to get SAP associated by service
** name on connected remote LLCP.
** NFA_P2P_SDP_EVT will be returned.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_BAD_HANDLE if server or client is not registered
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pGetRemoteSap(tNFA_HANDLE handle, char* p_service_name) {
tNFA_P2P_API_GET_REMOTE_SAP* p_msg;
tNFA_HANDLE xx;
P2P_TRACE_API2("NFA_P2pGetRemoteSap(): handle:0x%x, SN:<%s>", handle,
p_service_name);
if (nfa_p2p_cb.llcp_state != NFA_P2P_LLCP_STATE_ACTIVATED) {
P2P_TRACE_ERROR0("NFA_P2pGetRemoteSap(): LLCP link is not activated");
return (NFA_STATUS_FAILED);
}
xx = handle & NFA_HANDLE_MASK;
if ((xx >= NFA_P2P_NUM_SAP) || (nfa_p2p_cb.sap_cb[xx].p_cback == NULL)) {
P2P_TRACE_ERROR0(
"NFA_P2pGetRemoteSap (): Handle is invalid or not registered");
return (NFA_STATUS_BAD_HANDLE);
}
if ((p_msg = (tNFA_P2P_API_GET_REMOTE_SAP*)GKI_getbuf(
sizeof(tNFA_P2P_API_GET_REMOTE_SAP))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_GET_REMOTE_SAP_EVT;
p_msg->handle = handle;
strncpy(p_msg->service_name, p_service_name, LLCP_MAX_SN_LEN);
p_msg->service_name[LLCP_MAX_SN_LEN] = 0;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pSetLLCPConfig
**
** Description This function is called to change LLCP config parameters.
** Application must call while LLCP is not activated.
**
** Parameters descriptions (default value)
** - Local Link MIU (LLCP_MIU)
** - Option parameter (LLCP_OPT_VALUE)
** - Response Waiting Time Index (LLCP_WAITING_TIME)
** - Local Link Timeout (LLCP_LTO_VALUE)
** - Inactivity Timeout as initiator role
** (LLCP_INIT_INACTIVITY_TIMEOUT)
** - Inactivity Timeout as target role
** (LLCP_TARGET_INACTIVITY_TIMEOUT)
** - Delay SYMM response (LLCP_DELAY_RESP_TIME)
** - Data link connection timeout
** (LLCP_DATA_LINK_CONNECTION_TOUT)
** - Delay timeout to send first PDU as initiator
** (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU)
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_P2pSetLLCPConfig(uint16_t link_miu, uint8_t opt, uint8_t wt,
uint16_t link_timeout,
uint16_t inact_timeout_init,
uint16_t inact_timeout_target,
uint16_t symm_delay,
uint16_t data_link_timeout,
uint16_t delay_first_pdu_timeout) {
tNFA_P2P_API_SET_LLCP_CFG* p_msg;
P2P_TRACE_API4(
"NFA_P2pSetLLCPConfig ():link_miu:%d, opt:0x%02X, wt:%d, link_timeout:%d",
link_miu, opt, wt, link_timeout);
P2P_TRACE_API4(
" inact_timeout(init:%d, target:%d), "
"symm_delay:%d, data_link_timeout:%d",
inact_timeout_init, inact_timeout_target, symm_delay, data_link_timeout);
P2P_TRACE_API1(" delay_first_pdu_timeout:%d",
delay_first_pdu_timeout);
if (nfa_p2p_cb.llcp_state == NFA_P2P_LLCP_STATE_ACTIVATED) {
P2P_TRACE_ERROR0("NFA_P2pSetLLCPConfig (): LLCP link is activated");
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_P2P_API_SET_LLCP_CFG*)GKI_getbuf(
sizeof(tNFA_P2P_API_SET_LLCP_CFG))) != NULL) {
p_msg->hdr.event = NFA_P2P_API_SET_LLCP_CFG_EVT;
p_msg->link_miu = link_miu;
p_msg->opt = opt;
p_msg->wt = wt;
p_msg->link_timeout = link_timeout;
p_msg->inact_timeout_init = inact_timeout_init;
p_msg->inact_timeout_target = inact_timeout_target;
p_msg->symm_delay = symm_delay;
p_msg->data_link_timeout = data_link_timeout;
p_msg->delay_first_pdu_timeout = delay_first_pdu_timeout;
nfa_sys_sendmsg(p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_P2pGetLLCPConfig
**
** Description This function is called to read LLCP config parameters.
**
** Parameters descriptions
** - Local Link MIU
** - Option parameter
** - Response Waiting Time Index
** - Local Link Timeout
** - Inactivity Timeout as initiator role
** - Inactivity Timeout as target role
** - Delay SYMM response
** - Data link connection timeout
** - Delay timeout to send first PDU as initiator
**
** Returns None
**
*******************************************************************************/
void NFA_P2pGetLLCPConfig(uint16_t* p_link_miu, uint8_t* p_opt, uint8_t* p_wt,
uint16_t* p_link_timeout,
uint16_t* p_inact_timeout_init,
uint16_t* p_inact_timeout_target,
uint16_t* p_symm_delay, uint16_t* p_data_link_timeout,
uint16_t* p_delay_first_pdu_timeout) {
LLCP_GetConfig(p_link_miu, p_opt, p_wt, p_link_timeout, p_inact_timeout_init,
p_inact_timeout_target, p_symm_delay, p_data_link_timeout,
p_delay_first_pdu_timeout);
P2P_TRACE_API4(
"NFA_P2pGetLLCPConfig () link_miu:%d, opt:0x%02X, wt:%d, link_timeout:%d",
*p_link_miu, *p_opt, *p_wt, *p_link_timeout);
P2P_TRACE_API4(
" inact_timeout(init:%d, target:%d), "
"symm_delay:%d, data_link_timeout:%d",
*p_inact_timeout_init, *p_inact_timeout_target, *p_symm_delay,
*p_data_link_timeout);
P2P_TRACE_API1(" delay_first_pdu_timeout:%d",
*p_delay_first_pdu_timeout);
}
/*******************************************************************************
**
** Function NFA_P2pSetTraceLevel
**
** Description This function sets the trace level for P2P. If called with
** a value of 0xFF, it simply returns the current trace level.
**
** Returns The new or current trace level
**
*******************************************************************************/
uint8_t NFA_P2pSetTraceLevel(uint8_t new_level) {
if (new_level != 0xFF) nfa_p2p_cb.trace_level = new_level;
return (nfa_p2p_cb.trace_level);
}