blob: 13122ce469521a9a7ae99a002b46423d21aebd6f [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2010-2012 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 for connection handover
*
******************************************************************************/
#include <string.h>
#include "nfc_api.h"
#include "nfa_sys.h"
#include "nfa_sys_int.h"
#include "nfa_p2p_api.h"
#include "nfa_cho_api.h"
#include "nfa_cho_int.h"
#include "nfa_mem_co.h"
/*****************************************************************************
** Constants
*****************************************************************************/
/*******************************************************************************
**
** Function NFA_ChoRegister
**
** Description This function is called to register callback function to receive
** connection handover events.
**
** On this registration, "urn:nfc:sn:handover" server will be
** registered on LLCP if enable_server is TRUE.
**
** The result of the registration is reported with NFA_CHO_REG_EVT.
**
** 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_ChoRegister (BOOLEAN enable_server,
tNFA_CHO_CBACK *p_cback)
{
tNFA_CHO_API_REG *p_msg;
CHO_TRACE_API1 ("NFA_ChoRegister (): enable_server=%d", enable_server);
if ( (nfa_cho_cb.state != NFA_CHO_ST_DISABLED)
||(nfa_cho_cb.p_cback != NULL) )
{
CHO_TRACE_ERROR0 ("NFA_ChoRegister (): Already registered or callback is not provided");
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_CHO_API_REG *) GKI_getbuf (sizeof (tNFA_CHO_API_REG))) != NULL)
{
p_msg->hdr.event = NFA_CHO_API_REG_EVT;
p_msg->enable_server = enable_server;
p_msg->p_cback = p_cback;
nfa_sys_sendmsg (p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_ChoDeregister
**
** Description This function is called to deregister callback function from NFA
** Connection Handover Application.
**
** If this is the valid deregistration, NFA Connection Handover
** Application will close the service with "urn:nfc:sn:handover"
** on LLCP and deregister NDEF type handler if any.
**
** 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_ChoDeregister (void)
{
tNFA_CHO_API_DEREG *p_msg;
CHO_TRACE_API0 ("NFA_ChoDeregister ()");
if (nfa_cho_cb.state == NFA_CHO_ST_DISABLED)
{
CHO_TRACE_ERROR0 ("NFA_ChoDeregister (): Not registered");
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_CHO_API_DEREG *) GKI_getbuf (sizeof (tNFA_CHO_API_DEREG))) != NULL)
{
p_msg->event = NFA_CHO_API_DEREG_EVT;
nfa_sys_sendmsg (p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_ChoConnect
**
** Description This function is called to create data link connection to
** Connection Handover server on peer device.
**
** It must be called after receiving NFA_CHO_ACTIVATED_EVT.
** NFA_CHO_CONNECTED_EVT will be returned if successful.
** Otherwise, NFA_CHO_DISCONNECTED_EVT will be returned.
**
** If NFA_CHO_ROLE_REQUESTER is returned in NFA_CHO_CONNECTED_EVT,
** Handover Request Message can be sent.
** If NFA_CHO_ROLE_SELECTOR is returned in NFA_CHO_CONNECTED_EVT
** because of collision, application must wait for Handover
** Request Message.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_ChoConnect (void)
{
tNFA_CHO_API_CONNECT *p_msg;
CHO_TRACE_API0 ("NFA_ChoConnect ()");
if (nfa_cho_cb.state == NFA_CHO_ST_DISABLED)
{
CHO_TRACE_ERROR0 ("NFA_ChoConnect (): Not registered");
return (NFA_STATUS_FAILED);
}
else if (nfa_cho_cb.state == NFA_CHO_ST_CONNECTED)
{
CHO_TRACE_ERROR0 ("NFA_ChoConnect (): Already connected");
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_CHO_API_CONNECT *) GKI_getbuf (sizeof (tNFA_CHO_API_CONNECT))) != NULL)
{
p_msg->event = NFA_CHO_API_CONNECT_EVT;
nfa_sys_sendmsg (p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_ChoDisconnect
**
** Description This function is called to disconnect data link connection with
** Connection Handover server on peer device.
**
** NFA_CHO_DISCONNECTED_EVT will be returned.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_ChoDisconnect (void)
{
tNFA_CHO_API_DISCONNECT *p_msg;
CHO_TRACE_API0 ("NFA_ChoDisconnect ()");
if (nfa_cho_cb.state == NFA_CHO_ST_DISABLED)
{
CHO_TRACE_ERROR0 ("NFA_ChoDisconnect (): Not registered");
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_CHO_API_DISCONNECT *) GKI_getbuf (sizeof (tNFA_CHO_API_DISCONNECT))) != NULL)
{
p_msg->event = NFA_CHO_API_DISCONNECT_EVT;
nfa_sys_sendmsg (p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_ChoSendHr
**
** Description This function is called to send Handover Request Message with
** Handover Carrier records or Alternative Carrier records.
**
** It must be called after receiving NFA_CHO_CONNECTED_EVT.
**
** NDEF may include one or more Handover Carrier records or Alternative
** Carrier records with auxiliary data.
** The records in NDEF must be matched with tNFA_CHO_AC_INFO in order.
** Payload ID must be unique and Payload ID length must be less than
** or equal to NFA_CHO_MAX_REF_NAME_LEN.
**
** The alternative carrier information of Handover Select record
** will be sent to application by NFA_CHO_SELECT_EVT. Application
** may receive NFA_CHO_REQUEST_EVT because of handover collision.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_ChoSendHr (UINT8 num_ac_info,
tNFA_CHO_AC_INFO *p_ac_info,
UINT8 *p_ndef,
UINT32 ndef_len)
{
tNFA_CHO_API_SEND_HR *p_msg;
UINT16 msg_size;
UINT8 *p_ndef_buf;
CHO_TRACE_API2 ("NFA_ChoSendHr (): num_ac_info=%d, ndef_len=%d", num_ac_info, ndef_len);
if (nfa_cho_cb.state != NFA_CHO_ST_CONNECTED)
{
CHO_TRACE_ERROR0 ("NFA_ChoSendHr (): Not connected");
return (NFA_STATUS_FAILED);
}
if (num_ac_info > NFA_CHO_MAX_AC_INFO)
{
CHO_TRACE_ERROR0 ("NFA_ChoSendHr (): Too many AC information");
return (NFA_STATUS_FAILED);
}
p_ndef_buf = (UINT8 *) GKI_getpoolbuf (LLCP_POOL_ID);
if (!p_ndef_buf)
{
CHO_TRACE_ERROR0 ("NFA_ChoSendHr (): Failed to allocate buffer for NDEF");
return NFA_STATUS_FAILED;
}
else if (ndef_len > LLCP_POOL_BUF_SIZE)
{
CHO_TRACE_ERROR1 ("NFA_ChoSendHr (): Failed to allocate buffer for %d bytes", ndef_len);
GKI_freebuf (p_ndef_buf);
return NFA_STATUS_FAILED;
}
msg_size = sizeof (tNFA_CHO_API_SEND_HR) + num_ac_info * sizeof (tNFA_CHO_AC_INFO);
if ((p_msg = (tNFA_CHO_API_SEND_HR *) GKI_getbuf (msg_size)) != NULL)
{
p_msg->hdr.event = NFA_CHO_API_SEND_HR_EVT;
memcpy (p_ndef_buf, p_ndef, ndef_len);
p_msg->p_ndef = p_ndef_buf;
p_msg->max_ndef_size = LLCP_POOL_BUF_SIZE;
p_msg->cur_ndef_size = ndef_len;
p_msg->num_ac_info = num_ac_info;
p_msg->p_ac_info = (tNFA_CHO_AC_INFO *) (p_msg + 1);
memcpy (p_msg->p_ac_info, p_ac_info, num_ac_info * sizeof (tNFA_CHO_AC_INFO));
nfa_sys_sendmsg (p_msg);
return (NFA_STATUS_OK);
}
else
{
GKI_freebuf (p_ndef_buf);
return (NFA_STATUS_FAILED);
}
}
/*******************************************************************************
**
** Function NFA_ChoSendHs
**
** Description This function is called to send Handover Select message with
** Alternative Carrier records as response to Handover Request
** message.
**
** NDEF may include one or more Alternative Carrier records with
** auxiliary data.
** The records in NDEF must be matched with tNFA_CHO_AC_INFO in order.
** Payload ID must be unique and Payload ID length must be less than
** or equal to NFA_CHO_MAX_REF_NAME_LEN.
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_ChoSendHs (UINT8 num_ac_info,
tNFA_CHO_AC_INFO *p_ac_info,
UINT8 *p_ndef,
UINT32 ndef_len)
{
tNFA_CHO_API_SEND_HS *p_msg;
UINT16 msg_size;
UINT8 *p_ndef_buf;
CHO_TRACE_API2 ("NFA_ChoSendHs(): num_ac_info=%d, ndef_len=%d",
num_ac_info, ndef_len);
if (nfa_cho_cb.state != NFA_CHO_ST_CONNECTED)
{
CHO_TRACE_ERROR0 ("NFA_ChoSendHs (): Not connected");
return (NFA_STATUS_FAILED);
}
if (num_ac_info > NFA_CHO_MAX_AC_INFO)
{
CHO_TRACE_ERROR0 ("NFA_ChoSendHs (): Too many AC information");
return (NFA_STATUS_FAILED);
}
p_ndef_buf = (UINT8 *) GKI_getpoolbuf (LLCP_POOL_ID);
if (!p_ndef_buf)
{
CHO_TRACE_ERROR0 ("NFA_ChoSendHs (): Failed to allocate buffer for NDEF");
return NFA_STATUS_FAILED;
}
else if (ndef_len > LLCP_POOL_BUF_SIZE)
{
CHO_TRACE_ERROR1 ("NFA_ChoSendHs (): Failed to allocate buffer for %d bytes", ndef_len);
GKI_freebuf (p_ndef_buf);
return NFA_STATUS_FAILED;
}
msg_size = sizeof (tNFA_CHO_API_SEND_HS) + num_ac_info * sizeof (tNFA_CHO_AC_INFO);
if ((p_msg = (tNFA_CHO_API_SEND_HS *) GKI_getbuf (msg_size)) != NULL)
{
p_msg->hdr.event = NFA_CHO_API_SEND_HS_EVT;
memcpy (p_ndef_buf, p_ndef, ndef_len);
p_msg->p_ndef = p_ndef_buf;
p_msg->max_ndef_size = LLCP_POOL_BUF_SIZE;
p_msg->cur_ndef_size = ndef_len;
p_msg->num_ac_info = num_ac_info;
p_msg->p_ac_info = (tNFA_CHO_AC_INFO *) (p_msg + 1);
memcpy (p_msg->p_ac_info, p_ac_info, num_ac_info * sizeof (tNFA_CHO_AC_INFO));
nfa_sys_sendmsg (p_msg);
return (NFA_STATUS_OK);
}
else
{
GKI_freebuf (p_ndef_buf);
return (NFA_STATUS_FAILED);
}
}
/*******************************************************************************
**
** Function NFA_ChoSendSelectError
**
** Description This function is called to send Error record to indicate failure
** to process the most recently received Handover Request message.
**
** error_reason : NFA_CHO_ERROR_TEMP_MEM
** NFA_CHO_ERROR_PERM_MEM
** NFA_CHO_ERROR_CARRIER
**
** Returns NFA_STATUS_OK if successfully initiated
** NFA_STATUS_FAILED otherwise
**
*******************************************************************************/
tNFA_STATUS NFA_ChoSendSelectError (UINT8 error_reason,
UINT32 error_data)
{
tNFA_CHO_API_SEL_ERR *p_msg;
CHO_TRACE_API2 ("NFA_ChoSendSelectError (): error_reason=0x%x, error_data=0x%x",
error_reason, error_data);
if (nfa_cho_cb.state == NFA_CHO_ST_DISABLED)
{
CHO_TRACE_ERROR0 ("NFA_ChoSendSelectError (): Not registered");
return (NFA_STATUS_FAILED);
}
if ((p_msg = (tNFA_CHO_API_SEL_ERR *) GKI_getbuf (sizeof (tNFA_CHO_API_SEL_ERR))) != NULL)
{
p_msg->hdr.event = NFA_CHO_API_SEL_ERR_EVT;
p_msg->error_reason = error_reason;
p_msg->error_data = error_data;
nfa_sys_sendmsg (p_msg);
return (NFA_STATUS_OK);
}
return (NFA_STATUS_FAILED);
}
/*******************************************************************************
**
** Function NFA_ChoSetTraceLevel
**
** Description This function sets the trace level for CHO. If called with
** a value of 0xFF, it simply returns the current trace level.
**
** Returns The new or current trace level
**
*******************************************************************************/
UINT8 NFA_ChoSetTraceLevel (UINT8 new_level)
{
if (new_level != 0xFF)
nfa_cho_cb.trace_level = new_level;
return (nfa_cho_cb.trace_level);
}
#if (defined (NFA_CHO_TEST_INCLUDED) && (NFA_CHO_TEST_INCLUDED == TRUE))
/*******************************************************************************
**
** Function NFA_ChoSetTestParam
**
** Description This function is called to set test parameters.
**
*******************************************************************************/
void NFA_ChoSetTestParam (UINT8 test_enable,
UINT8 test_version,
UINT16 test_random_number)
{
nfa_cho_cb.test_enabled = test_enable;
nfa_cho_cb.test_version = test_version;
nfa_cho_cb.test_random_number = test_random_number;
}
#endif