/****************************************************************************** * * 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