blob: 7d62c2cd4b6d553839c27ac9ad92e92fb9667721 [file] [log] [blame]
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* The original Work has been changed by NXP.
*
* 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.
*
* Copyright 2018 NXP
*
******************************************************************************/
/******************************************************************************
*
* This file contains the action functions for the NFA HCI.
*
******************************************************************************/
#include <string.h>
#include <android-base/stringprintf.h>
#include <base/logging.h>
#include "nfa_dm_int.h"
#include "nfa_hci_api.h"
#include "nfa_hci_defs.h"
#include "nfa_hci_int.h"
#if (NXP_EXTNS == TRUE)
#include "nfa_ee_int.h"
#endif
using android::base::StringPrintf;
extern bool nfc_debug_enabled;
/* Static local functions */
static void nfa_hci_api_register(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_get_gate_pipe_list(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_alloc_gate(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_get_host_list(tNFA_HCI_EVENT_DATA* p_evt_data);
static bool nfa_hci_api_get_reg_value(tNFA_HCI_EVENT_DATA* p_evt_data);
static bool nfa_hci_api_set_reg_value(tNFA_HCI_EVENT_DATA* p_evt_data);
static bool nfa_hci_api_create_pipe(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_open_pipe(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_close_pipe(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_delete_pipe(tNFA_HCI_EVENT_DATA* p_evt_data);
static bool nfa_hci_api_send_event(tNFA_HCI_EVENT_DATA* p_evt_data);
static bool nfa_hci_api_send_cmd(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_send_rsp(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_api_add_static_pipe(tNFA_HCI_EVENT_DATA* p_evt_data);
static void nfa_hci_handle_identity_mgmt_gate_pkt(uint8_t* p_data,
tNFA_HCI_DYN_PIPE* p_pipe);
static void nfa_hci_handle_loopback_gate_pkt(uint8_t* p_data, uint16_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe);
static void nfa_hci_handle_connectivity_gate_pkt(uint8_t* p_data,
uint16_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe);
static void nfa_hci_handle_generic_gate_cmd(uint8_t* p_data, uint8_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe);
static void nfa_hci_handle_generic_gate_rsp(uint8_t* p_data, uint8_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe);
static void nfa_hci_handle_generic_gate_evt(uint8_t* p_data, uint16_t data_len,
tNFA_HCI_DYN_GATE* p_gate,
tNFA_HCI_DYN_PIPE* p_pipe);
#if(NXP_EXTNS == TRUE)
static void nfa_hci_handle_identity_mgmt_app_gate_hcp_msg_data (uint8_t *p_data, uint16_t data_len,
tNFA_HCI_DYN_PIPE *p_pipe);
static void nfa_hci_handle_apdu_app_gate_hcp_msg_data (uint8_t *p_data, uint16_t data_len,
tNFA_HCI_DYN_PIPE *p_pipe);
static bool nfa_hci_api_send_apdu (tNFA_HCI_EVENT_DATA *p_evt_data);
static bool nfa_hci_api_abort_apdu (tNFA_HCI_EVENT_DATA *p_evt_data);
static void nfa_hci_handle_clear_all_pipe_cmd(uint8_t source_host);
static void nfa_hci_api_add_prop_host_info ();
static void nfa_hci_get_pipe_state_cb(uint8_t event, uint16_t param_len, uint8_t* p_param);
static void nfa_hci_update_pipe_status(uint8_t gateId, uint8_t pipeId);
#endif
/*******************************************************************************
**
** Function nfa_hci_check_pending_api_requests
**
** Description This function handles pending API requests
**
** Returns none
**
*******************************************************************************/
void nfa_hci_check_pending_api_requests(void) {
NFC_HDR* p_msg;
tNFA_HCI_EVENT_DATA* p_evt_data;
bool b_free;
/* If busy, or API queue is empty, then exit */
if ((nfa_hci_cb.hci_state != NFA_HCI_STATE_IDLE) ||
((p_msg = (NFC_HDR*)GKI_dequeue(&nfa_hci_cb.hci_host_reset_api_q)) ==
NULL))
return;
/* Process API request */
p_evt_data = (tNFA_HCI_EVENT_DATA*)p_msg;
/* Save the application handle */
nfa_hci_cb.app_in_use = p_evt_data->comm.hci_handle;
b_free = true;
switch (p_msg->event) {
case NFA_HCI_API_CREATE_PIPE_EVT:
if (nfa_hci_api_create_pipe(p_evt_data) == false) b_free = false;
break;
case NFA_HCI_API_GET_REGISTRY_EVT:
if (nfa_hci_api_get_reg_value(p_evt_data) == false) b_free = false;
break;
case NFA_HCI_API_SET_REGISTRY_EVT:
if (nfa_hci_api_set_reg_value(p_evt_data) == false) b_free = false;
break;
case NFA_HCI_API_SEND_CMD_EVT:
if (nfa_hci_api_send_cmd(p_evt_data) == false) b_free = false;
break;
case NFA_HCI_API_SEND_EVENT_EVT:
if (nfa_hci_api_send_event(p_evt_data) == false) b_free = false;
break;
#if(NXP_EXTNS == TRUE)
case NFA_HCI_API_SEND_APDU_EVT:
if (nfa_hci_api_send_apdu (p_evt_data) == false) b_free = false;
break;
case NFA_HCI_API_ABORT_APDU_EVT:
if (nfa_hci_api_abort_apdu (p_evt_data) == false) b_free = false;
break;
#endif
}
if (b_free) GKI_freebuf(p_msg);
}
/*******************************************************************************
**
** Function nfa_hci_check_api_requests
**
** Description This function handles API requests
**
** Returns none
**
*******************************************************************************/
void nfa_hci_check_api_requests(void) {
NFC_HDR* p_msg;
tNFA_HCI_EVENT_DATA* p_evt_data;
for (;;) {
/* If busy, or API queue is empty, then exit */
if ((nfa_hci_cb.hci_state != NFA_HCI_STATE_IDLE) ||
((p_msg = (NFC_HDR*)GKI_dequeue(&nfa_hci_cb.hci_api_q)) == NULL))
break;
/* Process API request */
p_evt_data = (tNFA_HCI_EVENT_DATA*)p_msg;
/* Save the application handle */
nfa_hci_cb.app_in_use = p_evt_data->comm.hci_handle;
switch (p_msg->event) {
case NFA_HCI_API_REGISTER_APP_EVT:
nfa_hci_api_register(p_evt_data);
break;
case NFA_HCI_API_DEREGISTER_APP_EVT:
nfa_hci_api_deregister(p_evt_data);
break;
case NFA_HCI_API_GET_APP_GATE_PIPE_EVT:
nfa_hci_api_get_gate_pipe_list(p_evt_data);
break;
case NFA_HCI_API_ALLOC_GATE_EVT:
nfa_hci_api_alloc_gate(p_evt_data);
break;
case NFA_HCI_API_DEALLOC_GATE_EVT:
nfa_hci_api_dealloc_gate(p_evt_data);
break;
case NFA_HCI_API_GET_HOST_LIST_EVT:
nfa_hci_api_get_host_list(p_evt_data);
break;
case NFA_HCI_API_GET_REGISTRY_EVT:
if (nfa_hci_api_get_reg_value(p_evt_data) == false) continue;
break;
case NFA_HCI_API_SET_REGISTRY_EVT:
if (nfa_hci_api_set_reg_value(p_evt_data) == false) continue;
break;
case NFA_HCI_API_CREATE_PIPE_EVT:
if (nfa_hci_api_create_pipe(p_evt_data) == false) continue;
break;
case NFA_HCI_API_OPEN_PIPE_EVT:
nfa_hci_api_open_pipe(p_evt_data);
break;
case NFA_HCI_API_CLOSE_PIPE_EVT:
nfa_hci_api_close_pipe(p_evt_data);
break;
case NFA_HCI_API_DELETE_PIPE_EVT:
nfa_hci_api_delete_pipe(p_evt_data);
break;
case NFA_HCI_API_SEND_CMD_EVT:
if (nfa_hci_api_send_cmd(p_evt_data) == false) continue;
break;
case NFA_HCI_API_SEND_RSP_EVT:
nfa_hci_api_send_rsp(p_evt_data);
break;
case NFA_HCI_API_SEND_EVENT_EVT:
if (nfa_hci_api_send_event(p_evt_data) == false) continue;
break;
case NFA_HCI_API_ADD_STATIC_PIPE_EVT:
nfa_hci_api_add_static_pipe(p_evt_data);
break;
#if(NXP_EXTNS == TRUE)
case NFA_HCI_API_SEND_APDU_EVT:
if (nfa_hci_api_send_apdu (p_evt_data) == false) continue;
break;
case NFA_HCI_API_ABORT_APDU_EVT:
if (nfa_hci_api_abort_apdu (p_evt_data) == false) continue;
break;
#endif
default:
LOG(ERROR) << StringPrintf("Unknown event: 0x%04x", p_msg->event);
break;
}
GKI_freebuf(p_msg);
}
}
/*******************************************************************************
**
** Function nfa_hci_api_register
**
** Description action function to register the events for the given AID
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_register(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_EVT_DATA evt_data;
char* p_app_name = p_evt_data->app_info.app_name;
tNFA_HCI_CBACK* p_cback = p_evt_data->app_info.p_cback;
int xx, yy;
uint8_t num_gates = 0, num_pipes = 0;
tNFA_HCI_DYN_GATE* pg = nfa_hci_cb.cfg.dyn_gates;
/* First, see if the application was already registered */
for (xx = 0; xx < NFA_HCI_MAX_APP_CB; xx++) {
if ((nfa_hci_cb.cfg.reg_app_names[xx][0] != 0) &&
!strncmp(p_app_name, &nfa_hci_cb.cfg.reg_app_names[xx][0],
strlen(p_app_name))) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_hci_api_register (%s) Reusing: %u", p_app_name, xx);
break;
}
}
if (xx != NFA_HCI_MAX_APP_CB) {
nfa_hci_cb.app_in_use = (tNFA_HANDLE)(xx | NFA_HANDLE_GROUP_HCI);
/* The app was registered, find the number of gates and pipes associated to
* the app */
for (yy = 0; yy < NFA_HCI_MAX_GATE_CB; yy++, pg++) {
if (pg->gate_owner == nfa_hci_cb.app_in_use) {
num_gates++;
num_pipes += nfa_hciu_count_pipes_on_gate(pg);
}
}
} else {
/* Not registered, look for a free entry */
for (xx = 0; xx < NFA_HCI_MAX_APP_CB; xx++) {
if (nfa_hci_cb.cfg.reg_app_names[xx][0] == 0) {
memset(&nfa_hci_cb.cfg.reg_app_names[xx][0], 0,
sizeof(nfa_hci_cb.cfg.reg_app_names[xx]));
strncpy(&nfa_hci_cb.cfg.reg_app_names[xx][0], p_app_name,
NFA_MAX_HCI_APP_NAME_LEN);
nfa_hci_cb.nv_write_needed = true;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_hci_api_register (%s) Allocated: %u", p_app_name, xx);
break;
}
}
if (xx == NFA_HCI_MAX_APP_CB) {
LOG(ERROR) << StringPrintf("nfa_hci_api_register (%s) NO ENTRIES",
p_app_name);
evt_data.hci_register.status = NFA_STATUS_FAILED;
p_evt_data->app_info.p_cback(NFA_HCI_REGISTER_EVT, &evt_data);
return;
}
}
evt_data.hci_register.num_pipes = num_pipes;
evt_data.hci_register.num_gates = num_gates;
nfa_hci_cb.p_app_cback[xx] = p_cback;
nfa_hci_cb.cfg.b_send_conn_evts[xx] = p_evt_data->app_info.b_send_conn_evts;
evt_data.hci_register.hci_handle = (tNFA_HANDLE)(xx | NFA_HANDLE_GROUP_HCI);
evt_data.hci_register.status = NFA_STATUS_OK;
/* notify NFA_HCI_REGISTER_EVT to the application */
p_evt_data->app_info.p_cback(NFA_HCI_REGISTER_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_hci_api_deregister
**
** Description action function to deregister the given application
**
** Returns None
**
*******************************************************************************/
void nfa_hci_api_deregister(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_CBACK* p_cback = NULL;
int xx;
tNFA_HCI_DYN_PIPE* p_pipe;
tNFA_HCI_DYN_GATE* p_gate;
/* If needed, find the application registration handle */
if (p_evt_data != NULL) {
for (xx = 0; xx < NFA_HCI_MAX_APP_CB; xx++) {
if ((nfa_hci_cb.cfg.reg_app_names[xx][0] != 0) &&
!strncmp(p_evt_data->app_info.app_name,
&nfa_hci_cb.cfg.reg_app_names[xx][0],
strlen(p_evt_data->app_info.app_name))) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_hci_api_deregister (%s) inx: %u",
p_evt_data->app_info.app_name, xx);
break;
}
}
if (xx == NFA_HCI_MAX_APP_CB) {
LOG(WARNING) << StringPrintf("Unknown app: %s",
p_evt_data->app_info.app_name);
return;
}
nfa_hci_cb.app_in_use = (tNFA_HANDLE)(xx | NFA_HANDLE_GROUP_HCI);
p_cback = nfa_hci_cb.p_app_cback[xx];
} else {
nfa_sys_stop_timer(&nfa_hci_cb.timer);
/* We are recursing through deleting all the app's pipes and gates */
p_cback = nfa_hci_cb.p_app_cback[nfa_hci_cb.app_in_use & NFA_HANDLE_MASK];
}
/* See if any pipe is owned by this app */
if (nfa_hciu_find_pipe_by_owner(nfa_hci_cb.app_in_use) == NULL) {
/* No pipes, release all gates owned by this app */
while ((p_gate = nfa_hciu_find_gate_by_owner(nfa_hci_cb.app_in_use)) !=
NULL)
nfa_hciu_release_gate(p_gate->gate_id);
memset(&nfa_hci_cb.cfg
.reg_app_names[nfa_hci_cb.app_in_use & NFA_HANDLE_MASK][0],
0, NFA_MAX_HCI_APP_NAME_LEN + 1);
nfa_hci_cb.p_app_cback[nfa_hci_cb.app_in_use & NFA_HANDLE_MASK] = NULL;
nfa_hci_cb.nv_write_needed = true;
evt_data.hci_deregister.status = NFC_STATUS_OK;
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_APP_DEREGISTER)
nfa_hci_cb.hci_state = NFA_HCI_STATE_IDLE;
/* notify NFA_HCI_DEREGISTER_EVT to the application */
if (p_cback) p_cback(NFA_HCI_DEREGISTER_EVT, &evt_data);
} else if ((p_pipe = nfa_hciu_find_active_pipe_by_owner(
nfa_hci_cb.app_in_use)) == NULL) {
/* No pipes, release all gates owned by this app */
while ((p_gate = nfa_hciu_find_gate_with_nopipes_by_owner(
nfa_hci_cb.app_in_use)) != NULL)
nfa_hciu_release_gate(p_gate->gate_id);
nfa_hci_cb.p_app_cback[nfa_hci_cb.app_in_use & NFA_HANDLE_MASK] = NULL;
nfa_hci_cb.nv_write_needed = true;
evt_data.hci_deregister.status = NFC_STATUS_FAILED;
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_APP_DEREGISTER)
nfa_hci_cb.hci_state = NFA_HCI_STATE_IDLE;
/* notify NFA_HCI_DEREGISTER_EVT to the application */
if (p_cback) p_cback(NFA_HCI_DEREGISTER_EVT, &evt_data);
} else {
/* Delete all active pipes created for the application before de registering
**/
nfa_hci_cb.hci_state = NFA_HCI_STATE_APP_DEREGISTER;
nfa_hciu_send_delete_pipe_cmd(p_pipe->pipe_id);
}
}
/*******************************************************************************
**
** Function nfa_hci_api_get_gate_pipe_list
**
** Description action function to get application allocated gates and
** application created pipes
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_get_gate_pipe_list(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_EVT_DATA evt_data;
int xx, yy;
tNFA_HCI_DYN_GATE* pg = nfa_hci_cb.cfg.dyn_gates;
tNFA_HCI_DYN_PIPE* pp = nfa_hci_cb.cfg.dyn_pipes;
evt_data.gates_pipes.num_gates = 0;
evt_data.gates_pipes.num_pipes = 0;
for (xx = 0; xx < NFA_HCI_MAX_GATE_CB; xx++, pg++) {
if (pg->gate_owner == p_evt_data->get_gate_pipe_list.hci_handle) {
evt_data.gates_pipes.gate[evt_data.gates_pipes.num_gates++] = pg->gate_id;
pp = nfa_hci_cb.cfg.dyn_pipes;
/* Loop through looking for a match */
for (yy = 0; yy < NFA_HCI_MAX_PIPE_CB; yy++, pp++) {
if (pp->local_gate == pg->gate_id)
evt_data.gates_pipes.pipe[evt_data.gates_pipes.num_pipes++] =
*(tNFA_HCI_PIPE_INFO*)pp;
}
}
}
#if(NXP_EXTNS == TRUE)
evt_data.gates_pipes.num_host_created_pipes = 0;
#else
evt_data.gates_pipes.num_uicc_created_pipes = 0;
#endif
/* Loop through all pipes that are connected to connectivity gate */
for (xx = 0, pp = nfa_hci_cb.cfg.dyn_pipes; xx < NFA_HCI_MAX_PIPE_CB;
xx++, pp++) {
if (pp->pipe_id != 0 && pp->local_gate == NFA_HCI_CONNECTIVITY_GATE) {
#if(NXP_EXTNS == TRUE)
memcpy(&evt_data.gates_pipes.host_created_pipe
[evt_data.gates_pipes.num_host_created_pipes++],
#else
memcpy(&evt_data.gates_pipes.uicc_created_pipe
[evt_data.gates_pipes.num_uicc_created_pipes++],
#endif
pp, sizeof(tNFA_HCI_PIPE_INFO));
} else if (pp->pipe_id != 0 && pp->local_gate == NFA_HCI_LOOP_BACK_GATE) {
#if(NXP_EXTNS == TRUE)
memcpy(&evt_data.gates_pipes.host_created_pipe
[evt_data.gates_pipes.num_host_created_pipes++],
#else
memcpy(&evt_data.gates_pipes.uicc_created_pipe
[evt_data.gates_pipes.num_uicc_created_pipes++],
#endif
pp, sizeof(tNFA_HCI_PIPE_INFO));
#if(NXP_EXTNS == TRUE)
} else if (pp->local_gate == NFA_HCI_ID_MNGMNT_APP_GATE) {
/* Identity Management Gate - Pipes connected to this gate are to be saved
** to other_uicc_pipe array and to increment num_other_uicc_pipes
*/
memcpy(&evt_data.gates_pipes.host_created_pipe
[evt_data.gates_pipes.num_host_created_pipes++],
pp, sizeof(tNFA_HCI_PIPE_INFO));
#endif
} else if (pp->pipe_id >= NFA_HCI_FIRST_DYNAMIC_PIPE &&
pp->pipe_id <= NFA_HCI_LAST_DYNAMIC_PIPE && pp->pipe_id &&
pp->local_gate >= NFA_HCI_FIRST_PROP_GATE &&
pp->local_gate <= NFA_HCI_LAST_PROP_GATE) {
for (xx = 0, pg = nfa_hci_cb.cfg.dyn_gates; xx < NFA_HCI_MAX_GATE_CB;
xx++, pg++) {
if (pp->local_gate == pg->gate_id) {
if (!pg->gate_owner)
#if(NXP_EXTNS == TRUE)
memcpy(&evt_data.gates_pipes.host_created_pipe
[evt_data.gates_pipes.num_host_created_pipes++],
#else
memcpy(&evt_data.gates_pipes.uicc_created_pipe
[evt_data.gates_pipes.num_uicc_created_pipes++],
#endif
pp, sizeof(tNFA_HCI_PIPE_INFO));
break;
}
}
}
}
evt_data.gates_pipes.status = NFA_STATUS_OK;
/* notify NFA_HCI_GET_GATE_PIPE_LIST_EVT to the application */
nfa_hciu_send_to_app(NFA_HCI_GET_GATE_PIPE_LIST_EVT, &evt_data,
p_evt_data->get_gate_pipe_list.hci_handle);
}
/*******************************************************************************
**
** Function nfa_hci_api_alloc_gate
**
** Description action function to allocate gate
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_alloc_gate(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HANDLE app_handle = p_evt_data->comm.hci_handle;
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_DYN_GATE* p_gate;
p_gate = nfa_hciu_alloc_gate(p_evt_data->gate_info.gate, app_handle);
if (p_gate) {
if (!p_gate->gate_owner) {
/* No app owns the gate yet */
p_gate->gate_owner = app_handle;
} else if (p_gate->gate_owner != app_handle) {
/* Some other app owns the gate */
p_gate = NULL;
LOG(ERROR) << StringPrintf("The Gate (0X%02x) already taken!",
p_evt_data->gate_info.gate);
}
}
evt_data.allocated.gate = p_gate ? p_gate->gate_id : 0;
evt_data.allocated.status = p_gate ? NFA_STATUS_OK : NFA_STATUS_FAILED;
/* notify NFA_HCI_ALLOCATE_GATE_EVT to the application */
nfa_hciu_send_to_app(NFA_HCI_ALLOCATE_GATE_EVT, &evt_data, app_handle);
}
/*******************************************************************************
**
** Function nfa_hci_api_dealloc_gate
**
** Description action function to deallocate the given generic gate
**
** Returns None
**
*******************************************************************************/
void nfa_hci_api_dealloc_gate(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_EVT_DATA evt_data;
uint8_t gate_id;
tNFA_HCI_DYN_GATE* p_gate;
tNFA_HCI_DYN_PIPE* p_pipe;
tNFA_HANDLE app_handle;
/* p_evt_data may be NULL if we are recursively deleting pipes */
if (p_evt_data) {
gate_id = p_evt_data->gate_dealloc.gate;
app_handle = p_evt_data->gate_dealloc.hci_handle;
} else {
nfa_sys_stop_timer(&nfa_hci_cb.timer);
gate_id = nfa_hci_cb.local_gate_in_use;
app_handle = nfa_hci_cb.app_in_use;
}
evt_data.deallocated.gate = gate_id;
;
p_gate = nfa_hciu_find_gate_by_gid(gate_id);
if (p_gate == NULL) {
evt_data.deallocated.status = NFA_STATUS_UNKNOWN_GID;
} else if (p_gate->gate_owner != app_handle) {
evt_data.deallocated.status = NFA_STATUS_FAILED;
} else {
/* See if any pipe is owned by this app */
if (nfa_hciu_find_pipe_on_gate(p_gate->gate_id) == NULL) {
nfa_hciu_release_gate(p_gate->gate_id);
nfa_hci_cb.nv_write_needed = true;
evt_data.deallocated.status = NFA_STATUS_OK;
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_REMOVE_GATE)
nfa_hci_cb.hci_state = NFA_HCI_STATE_IDLE;
} else if ((p_pipe = nfa_hciu_find_active_pipe_on_gate(p_gate->gate_id)) ==
NULL) {
/* UICC is not active at the moment and cannot delete the pipe */
nfa_hci_cb.nv_write_needed = true;
evt_data.deallocated.status = NFA_STATUS_FAILED;
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_REMOVE_GATE)
nfa_hci_cb.hci_state = NFA_HCI_STATE_IDLE;
} else {
/* Delete pipes on the gate */
nfa_hci_cb.local_gate_in_use = gate_id;
nfa_hci_cb.app_in_use = app_handle;
nfa_hci_cb.hci_state = NFA_HCI_STATE_REMOVE_GATE;
nfa_hciu_send_delete_pipe_cmd(p_pipe->pipe_id);
return;
}
}
nfa_hciu_send_to_app(NFA_HCI_DEALLOCATE_GATE_EVT, &evt_data, app_handle);
}
/*******************************************************************************
**
** Function nfa_hci_api_get_host_list
**
** Description action function to get the host list from HCI network
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_get_host_list(tNFA_HCI_EVENT_DATA* p_evt_data) {
uint8_t app_inx = p_evt_data->get_host_list.hci_handle & NFA_HANDLE_MASK;
nfa_hci_cb.app_in_use = p_evt_data->get_host_list.hci_handle;
/* Send Get Host List command on "Internal request" or requested by registered
* application with valid handle and callback function */
if ((nfa_hci_cb.app_in_use == NFA_HANDLE_INVALID) ||
((app_inx < NFA_HCI_MAX_APP_CB) &&
(nfa_hci_cb.p_app_cback[app_inx] != NULL))) {
nfa_hciu_send_get_param_cmd(NFA_HCI_ADMIN_PIPE, NFA_HCI_HOST_LIST_INDEX);
}
}
/*******************************************************************************
**
** Function nfa_hci_api_create_pipe
**
** Description action function to create a pipe
**
** Returns TRUE, if the command is processed
** FALSE, if command is queued for processing later
**
*******************************************************************************/
static bool nfa_hci_api_create_pipe(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_DYN_GATE* p_gate =
nfa_hciu_find_gate_by_gid(p_evt_data->create_pipe.source_gate);
tNFA_HCI_EVT_DATA evt_data;
bool report_failed = false;
/* Verify that the app owns the gate that the pipe is being created on */
if ((p_gate == NULL) ||
(p_gate->gate_owner != p_evt_data->create_pipe.hci_handle)) {
report_failed = true;
LOG(ERROR) << StringPrintf(
"nfa_hci_api_create_pipe Cannot create pipe! APP: 0x%02x does not own "
"the gate:0x%x",
p_evt_data->create_pipe.hci_handle,
p_evt_data->create_pipe.source_gate);
} else if (nfa_hciu_check_pipe_between_gates(
p_evt_data->create_pipe.source_gate,
p_evt_data->create_pipe.dest_host,
p_evt_data->create_pipe.dest_gate)) {
report_failed = true;
LOG(ERROR) << StringPrintf(
"nfa_hci_api_create_pipe : Cannot create multiple pipe between the "
"same two gates!");
}
if (report_failed) {
evt_data.created.source_gate = p_evt_data->create_pipe.source_gate;
evt_data.created.status = NFA_STATUS_FAILED;
nfa_hciu_send_to_app(NFA_HCI_CREATE_PIPE_EVT, &evt_data,
p_evt_data->open_pipe.hci_handle);
} else {
if (nfa_hciu_is_host_reseting(p_evt_data->create_pipe.dest_gate)) {
GKI_enqueue(&nfa_hci_cb.hci_host_reset_api_q, (NFC_HDR*)p_evt_data);
return false;
}
nfa_hci_cb.local_gate_in_use = p_evt_data->create_pipe.source_gate;
nfa_hci_cb.remote_gate_in_use = p_evt_data->create_pipe.dest_gate;
nfa_hci_cb.remote_host_in_use = p_evt_data->create_pipe.dest_host;
nfa_hci_cb.app_in_use = p_evt_data->create_pipe.hci_handle;
nfa_hciu_send_create_pipe_cmd(p_evt_data->create_pipe.source_gate,
p_evt_data->create_pipe.dest_host,
p_evt_data->create_pipe.dest_gate);
}
return true;
}
/*******************************************************************************
**
** Function nfa_hci_api_open_pipe
**
** Description action function to open a pipe
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_open_pipe(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_DYN_PIPE* p_pipe =
nfa_hciu_find_pipe_by_pid(p_evt_data->open_pipe.pipe);
tNFA_HCI_DYN_GATE* p_gate = NULL;
if (p_pipe != NULL) p_gate = nfa_hciu_find_gate_by_gid(p_pipe->local_gate);
if ((p_pipe != NULL) && (p_gate != NULL) &&
(nfa_hciu_is_active_host(p_pipe->dest_host)) &&
(p_gate->gate_owner == p_evt_data->open_pipe.hci_handle)) {
if (p_pipe->pipe_state == NFA_HCI_PIPE_CLOSED) {
nfa_hciu_send_open_pipe_cmd(p_evt_data->open_pipe.pipe);
} else {
evt_data.opened.pipe = p_evt_data->open_pipe.pipe;
evt_data.opened.status = NFA_STATUS_OK;
nfa_hciu_send_to_app(NFA_HCI_OPEN_PIPE_EVT, &evt_data,
p_evt_data->open_pipe.hci_handle);
}
} else {
evt_data.opened.pipe = p_evt_data->open_pipe.pipe;
evt_data.opened.status = NFA_STATUS_FAILED;
nfa_hciu_send_to_app(NFA_HCI_OPEN_PIPE_EVT, &evt_data,
p_evt_data->open_pipe.hci_handle);
}
}
/*******************************************************************************
**
** Function nfa_hci_api_get_reg_value
**
** Description action function to get the reg value of the specified index
**
** Returns TRUE, if the command is processed
** FALSE, if command is queued for processing later
**
*******************************************************************************/
static bool nfa_hci_api_get_reg_value(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_DYN_PIPE* p_pipe =
nfa_hciu_find_pipe_by_pid(p_evt_data->get_registry.pipe);
tNFA_HCI_DYN_GATE* p_gate;
tNFA_STATUS status = NFA_STATUS_FAILED;
tNFA_HCI_EVT_DATA evt_data;
if (p_pipe != NULL) {
p_gate = nfa_hciu_find_gate_by_gid(p_pipe->local_gate);
if ((p_gate != NULL) && (nfa_hciu_is_active_host(p_pipe->dest_host)) &&
(p_gate->gate_owner == p_evt_data->get_registry.hci_handle)) {
nfa_hci_cb.app_in_use = p_evt_data->get_registry.hci_handle;
if (nfa_hciu_is_host_reseting(p_pipe->dest_host)) {
GKI_enqueue(&nfa_hci_cb.hci_host_reset_api_q, (NFC_HDR*)p_evt_data);
return false;
}
if (p_pipe->pipe_state == NFA_HCI_PIPE_CLOSED) {
LOG(WARNING) << StringPrintf(
"nfa_hci_api_get_reg_value pipe:%d not open",
p_evt_data->get_registry.pipe);
} else {
status = nfa_hciu_send_get_param_cmd(p_evt_data->get_registry.pipe,
p_evt_data->get_registry.reg_inx);
if (status == NFA_STATUS_OK) return true;
}
}
}
evt_data.cmd_sent.status = status;
/* Send NFA_HCI_CMD_SENT_EVT to notify failure */
nfa_hciu_send_to_app(NFA_HCI_CMD_SENT_EVT, &evt_data,
p_evt_data->get_registry.hci_handle);
return true;
}
/*******************************************************************************
**
** Function nfa_hci_api_set_reg_value
**
** Description action function to set the reg value at specified index
**
** Returns TRUE, if the command is processed
** FALSE, if command is queued for processing later
**
*******************************************************************************/
static bool nfa_hci_api_set_reg_value(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_DYN_PIPE* p_pipe =
nfa_hciu_find_pipe_by_pid(p_evt_data->set_registry.pipe);
tNFA_HCI_DYN_GATE* p_gate;
tNFA_STATUS status = NFA_STATUS_FAILED;
tNFA_HCI_EVT_DATA evt_data;
if (p_pipe != NULL) {
p_gate = nfa_hciu_find_gate_by_gid(p_pipe->local_gate);
if ((p_gate != NULL) && (nfa_hciu_is_active_host(p_pipe->dest_host)) &&
(p_gate->gate_owner == p_evt_data->set_registry.hci_handle)) {
nfa_hci_cb.app_in_use = p_evt_data->set_registry.hci_handle;
if (nfa_hciu_is_host_reseting(p_pipe->dest_host)) {
GKI_enqueue(&nfa_hci_cb.hci_host_reset_api_q, (NFC_HDR*)p_evt_data);
return false;
}
if (p_pipe->pipe_state == NFA_HCI_PIPE_CLOSED) {
LOG(WARNING) << StringPrintf(
"nfa_hci_api_set_reg_value pipe:%d not open",
p_evt_data->set_registry.pipe);
} else {
status = nfa_hciu_send_set_param_cmd(
p_evt_data->set_registry.pipe, p_evt_data->set_registry.reg_inx,
p_evt_data->set_registry.size, p_evt_data->set_registry.data);
if (status == NFA_STATUS_OK) return true;
}
}
}
evt_data.cmd_sent.status = status;
/* Send NFA_HCI_CMD_SENT_EVT to notify failure */
nfa_hciu_send_to_app(NFA_HCI_CMD_SENT_EVT, &evt_data,
p_evt_data->set_registry.hci_handle);
return true;
}
/*******************************************************************************
**
** Function nfa_hci_api_close_pipe
**
** Description action function to close a pipe
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_close_pipe(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_DYN_PIPE* p_pipe =
nfa_hciu_find_pipe_by_pid(p_evt_data->close_pipe.pipe);
tNFA_HCI_DYN_GATE* p_gate = NULL;
if (p_pipe != NULL) p_gate = nfa_hciu_find_gate_by_gid(p_pipe->local_gate);
if ((p_pipe != NULL) && (p_gate != NULL) &&
(nfa_hciu_is_active_host(p_pipe->dest_host)) &&
(p_gate->gate_owner == p_evt_data->close_pipe.hci_handle)) {
if (p_pipe->pipe_state == NFA_HCI_PIPE_OPENED) {
nfa_hciu_send_close_pipe_cmd(p_evt_data->close_pipe.pipe);
} else {
evt_data.closed.status = NFA_STATUS_OK;
evt_data.closed.pipe = p_evt_data->close_pipe.pipe;
nfa_hciu_send_to_app(NFA_HCI_CLOSE_PIPE_EVT, &evt_data,
p_evt_data->close_pipe.hci_handle);
}
} else {
evt_data.closed.status = NFA_STATUS_FAILED;
evt_data.closed.pipe = 0x00;
nfa_hciu_send_to_app(NFA_HCI_CLOSE_PIPE_EVT, &evt_data,
p_evt_data->close_pipe.hci_handle);
}
}
/*******************************************************************************
**
** Function nfa_hci_api_delete_pipe
**
** Description action function to delete a pipe
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_delete_pipe(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_DYN_PIPE* p_pipe =
nfa_hciu_find_pipe_by_pid(p_evt_data->delete_pipe.pipe);
tNFA_HCI_DYN_GATE* p_gate = NULL;
if (p_pipe != NULL) {
p_gate = nfa_hciu_find_gate_by_gid(p_pipe->local_gate);
if ((p_gate != NULL) &&
(p_gate->gate_owner == p_evt_data->delete_pipe.hci_handle) &&
(nfa_hciu_is_active_host(p_pipe->dest_host))) {
nfa_hciu_send_delete_pipe_cmd(p_evt_data->delete_pipe.pipe);
return;
}
}
evt_data.deleted.status = NFA_STATUS_FAILED;
evt_data.deleted.pipe = 0x00;
nfa_hciu_send_to_app(NFA_HCI_DELETE_PIPE_EVT, &evt_data,
p_evt_data->close_pipe.hci_handle);
}
/*******************************************************************************
**
** Function nfa_hci_api_send_cmd
**
** Description action function to send command on the given pipe
**
** Returns TRUE, if the command is processed
** FALSE, if command is queued for processing later
**
*******************************************************************************/
static bool nfa_hci_api_send_cmd(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_STATUS status = NFA_STATUS_FAILED;
tNFA_HCI_DYN_PIPE* p_pipe;
tNFA_HCI_EVT_DATA evt_data;
tNFA_HANDLE app_handle;
#if(NXP_EXTNS == TRUE)
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info = NULL;
#endif
if ((p_pipe = nfa_hciu_find_pipe_by_pid(p_evt_data->send_cmd.pipe)) != NULL) {
app_handle = nfa_hciu_get_pipe_owner(p_evt_data->send_cmd.pipe);
if ((nfa_hciu_is_active_host(p_pipe->dest_host)) &&
((app_handle == p_evt_data->send_cmd.hci_handle ||
p_pipe->local_gate == NFA_HCI_CONNECTIVITY_GATE
#if(NXP_EXTNS == TRUE)
|| p_pipe->local_gate == NFA_HCI_APDU_GATE ||
p_pipe->local_gate == NFA_HCI_IDENTITY_MANAGEMENT_GATE
#endif
))) {
if (nfa_hciu_is_host_reseting(p_pipe->dest_host)) {
GKI_enqueue(&nfa_hci_cb.hci_host_reset_api_q, (NFC_HDR*)p_evt_data);
return false;
}
#if(NXP_EXTNS == TRUE)
p_pipe_cmdrsp_info = nfa_hciu_get_pipe_cmdrsp_info (p_evt_data->send_cmd.pipe);
if(p_pipe_cmdrsp_info == NULL) {
LOG(WARNING) << StringPrintf("nfa_hci_api_send_cmd p_pipe_cmdrsp_info is NULL");
}
else
#endif
if (p_pipe->pipe_state == NFA_HCI_PIPE_OPENED) {
nfa_hci_cb.pipe_in_use = p_evt_data->send_cmd.pipe;
status = nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_COMMAND_TYPE,
p_evt_data->send_cmd.cmd_code,
p_evt_data->send_cmd.cmd_len,
p_evt_data->send_cmd.data);
#if(NXP_EXTNS == TRUE)
if (status == NFA_STATUS_OK) {
nfa_hci_cb.pipe_in_use = p_evt_data->send_cmd.pipe;
p_pipe_cmdrsp_info->w4_cmd_rsp = true;
p_pipe_cmdrsp_info->cmd_inst_sent = p_evt_data->send_cmd.cmd_code;
if ((p_evt_data->send_cmd.cmd_code == NFA_HCI_ANY_GET_PARAMETER)
||(p_evt_data->send_cmd.cmd_code == NFA_HCI_ANY_SET_PARAMETER)) {
p_pipe_cmdrsp_info->cmd_inst_param_sent = p_evt_data->send_cmd.data[0];
}
nfa_sys_start_timer (&(p_pipe_cmdrsp_info->rsp_timer), NFA_HCI_RSP_TIMEOUT_EVT,
p_nfa_hci_cfg->hcp_response_timeout);
return true;
}
#else
if (status == NFA_STATUS_OK) return true;
#endif
} else {
LOG(WARNING) << StringPrintf("nfa_hci_api_send_cmd pipe:%d not open",
p_pipe->pipe_id);
}
} else {
LOG(WARNING) << StringPrintf(
"nfa_hci_api_send_cmd pipe:%d Owned by different application or "
"Destination host is not active",
p_pipe->pipe_id);
}
} else {
LOG(WARNING) << StringPrintf("nfa_hci_api_send_cmd pipe:%d not found",
p_evt_data->send_cmd.pipe);
}
evt_data.cmd_sent.status = status;
/* Send NFA_HCI_CMD_SENT_EVT to notify failure */
nfa_hciu_send_to_app(NFA_HCI_CMD_SENT_EVT, &evt_data,
p_evt_data->send_cmd.hci_handle);
return true;
}
/*******************************************************************************
**
** Function nfa_hci_api_send_rsp
**
** Description action function to send response on the given pipe
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_send_rsp(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_STATUS status = NFA_STATUS_FAILED;
tNFA_HCI_DYN_PIPE* p_pipe;
tNFA_HCI_EVT_DATA evt_data;
tNFA_HANDLE app_handle;
if ((p_pipe = nfa_hciu_find_pipe_by_pid(p_evt_data->send_rsp.pipe)) != NULL) {
app_handle = nfa_hciu_get_pipe_owner(p_evt_data->send_rsp.pipe);
if ((nfa_hciu_is_active_host(p_pipe->dest_host)) &&
((app_handle == p_evt_data->send_rsp.hci_handle ||
p_pipe->local_gate == NFA_HCI_CONNECTIVITY_GATE))) {
if (p_pipe->pipe_state == NFA_HCI_PIPE_OPENED) {
status = nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_RESPONSE_TYPE,
p_evt_data->send_rsp.response,
p_evt_data->send_rsp.size,
p_evt_data->send_rsp.data);
if (status == NFA_STATUS_OK) return;
} else {
LOG(WARNING) << StringPrintf("nfa_hci_api_send_rsp pipe:%d not open",
p_pipe->pipe_id);
}
} else {
LOG(WARNING) << StringPrintf(
"nfa_hci_api_send_rsp pipe:%d Owned by different application or "
"Destination host is not active",
p_pipe->pipe_id);
}
} else {
LOG(WARNING) << StringPrintf("nfa_hci_api_send_rsp pipe:%d not found",
p_evt_data->send_rsp.pipe);
}
evt_data.rsp_sent.status = status;
/* Send NFA_HCI_RSP_SENT_EVT to notify failure */
nfa_hciu_send_to_app(NFA_HCI_RSP_SENT_EVT, &evt_data,
p_evt_data->send_rsp.hci_handle);
}
/*******************************************************************************
**
** Function nfa_hci_api_send_event
**
** Description action function to send an event to the given pipe
**
** Returns TRUE, if the event is processed
** FALSE, if event is queued for processing later
**
*******************************************************************************/
static bool nfa_hci_api_send_event(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_STATUS status = NFA_STATUS_FAILED;
tNFA_HCI_DYN_PIPE* p_pipe;
tNFA_HCI_EVT_DATA evt_data;
tNFA_HANDLE app_handle;
#if(NXP_EXTNS == TRUE)
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info = NULL;
#endif
if ((p_pipe = nfa_hciu_find_pipe_by_pid(p_evt_data->send_evt.pipe)) != NULL) {
app_handle = nfa_hciu_get_pipe_owner(p_evt_data->send_evt.pipe);
if ((nfa_hciu_is_active_host(p_pipe->dest_host)) &&
((app_handle == p_evt_data->send_evt.hci_handle ||
p_pipe->local_gate == NFA_HCI_CONNECTIVITY_GATE
#if(NXP_EXTNS == TRUE)
||
p_pipe->local_gate == NFA_HCI_APDU_APP_GATE
#endif
))) {
if (nfa_hciu_is_host_reseting(p_pipe->dest_host)) {
GKI_enqueue(&nfa_hci_cb.hci_host_reset_api_q, (NFC_HDR*)p_evt_data);
return false;
}
if (p_pipe->pipe_state == NFA_HCI_PIPE_OPENED) {
#if(NXP_EXTNS == TRUE)
p_pipe_cmdrsp_info = nfa_hciu_get_pipe_cmdrsp_info (p_pipe->pipe_id);
#endif
status = nfa_hciu_send_msg(
p_pipe->pipe_id, NFA_HCI_EVENT_TYPE, p_evt_data->send_evt.evt_code,
p_evt_data->send_evt.evt_len, p_evt_data->send_evt.p_evt_buf);
if (status == NFA_STATUS_OK) {
if (p_pipe->local_gate == NFA_HCI_LOOP_BACK_GATE) {
nfa_hci_cb.w4_rsp_evt = true;
nfa_hci_cb.hci_state = NFA_HCI_STATE_WAIT_RSP;
}
if (p_evt_data->send_evt.rsp_len) {
nfa_hci_cb.pipe_in_use = p_evt_data->send_evt.pipe;
nfa_hci_cb.rsp_buf_size = p_evt_data->send_evt.rsp_len;
nfa_hci_cb.p_rsp_buf = p_evt_data->send_evt.p_rsp_buf;
#if(NXP_EXTNS == TRUE)
if(p_pipe_cmdrsp_info != NULL) {
p_pipe_cmdrsp_info->w4_rsp_apdu_evt = true;
p_pipe_cmdrsp_info->rsp_buf_size = p_evt_data->send_evt.rsp_len;
p_pipe_cmdrsp_info->p_rsp_buf = p_evt_data->send_evt.p_rsp_buf;
p_pipe_cmdrsp_info->pipe_user = p_evt_data->send_evt.hci_handle;
}
#endif
if (p_evt_data->send_evt.rsp_timeout) {
#if(NXP_EXTNS == TRUE)
if(p_pipe_cmdrsp_info != NULL) {
nfa_hci_cb.hci_state = NFA_HCI_STATE_WAIT_RSP;
nfa_sys_start_timer (&(p_pipe_cmdrsp_info->rsp_timer),
NFA_HCI_RSP_TIMEOUT_EVT,
p_evt_data->send_evt.rsp_timeout);
}
#else
nfa_hci_cb.w4_rsp_evt = true;
nfa_hci_cb.hci_state = NFA_HCI_STATE_WAIT_RSP;
nfa_sys_start_timer(&nfa_hci_cb.timer, NFA_HCI_RSP_TIMEOUT_EVT,
p_evt_data->send_evt.rsp_timeout);
#endif
} else if (p_pipe->local_gate == NFA_HCI_LOOP_BACK_GATE) {
nfa_sys_start_timer(&nfa_hci_cb.timer, NFA_HCI_RSP_TIMEOUT_EVT,
p_nfa_hci_cfg->hcp_response_timeout);
}
} else {
if (p_pipe->local_gate == NFA_HCI_LOOP_BACK_GATE) {
nfa_hci_cb.pipe_in_use = p_evt_data->send_evt.pipe;
nfa_sys_start_timer(&nfa_hci_cb.timer, NFA_HCI_RSP_TIMEOUT_EVT,
p_nfa_hci_cfg->hcp_response_timeout);
}
nfa_hci_cb.rsp_buf_size = 0;
nfa_hci_cb.p_rsp_buf = NULL;
}
}
} else {
LOG(WARNING) << StringPrintf("nfa_hci_api_send_event pipe:%d not open",
p_pipe->pipe_id);
}
} else {
LOG(WARNING) << StringPrintf(
"nfa_hci_api_send_event pipe:%d Owned by different application or "
"Destination host is not active",
p_pipe->pipe_id);
}
} else {
LOG(WARNING) << StringPrintf("nfa_hci_api_send_event pipe:%d not found",
p_evt_data->send_evt.pipe);
}
evt_data.evt_sent.status = status;
/* Send NFC_HCI_EVENT_SENT_EVT to notify status */
nfa_hciu_send_to_app(NFA_HCI_EVENT_SENT_EVT, &evt_data,
p_evt_data->send_evt.hci_handle);
return true;
}
/*******************************************************************************
**
** Function nfa_hci_api_add_static_pipe
**
** Description action function to add static pipe
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_add_static_pipe(tNFA_HCI_EVENT_DATA* p_evt_data) {
tNFA_HCI_DYN_GATE* pg;
tNFA_HCI_DYN_PIPE* pp;
tNFA_HCI_EVT_DATA evt_data;
/* Allocate a proprietary gate */
pg = nfa_hciu_alloc_gate(p_evt_data->add_static_pipe.gate,
p_evt_data->add_static_pipe.hci_handle);
if (pg != NULL) {
/* Assign new owner to the gate */
pg->gate_owner = p_evt_data->add_static_pipe.hci_handle;
/* Add the dynamic pipe to the proprietary gate */
if (nfa_hciu_add_pipe_to_gate(p_evt_data->add_static_pipe.pipe, pg->gate_id,
p_evt_data->add_static_pipe.host,
p_evt_data->add_static_pipe.gate) !=
NFA_HCI_ANY_OK) {
/* Unable to add the dynamic pipe, so release the gate */
nfa_hciu_release_gate(pg->gate_id);
evt_data.pipe_added.status = NFA_STATUS_FAILED;
nfa_hciu_send_to_app(NFA_HCI_ADD_STATIC_PIPE_EVT, &evt_data,
p_evt_data->add_static_pipe.hci_handle);
return;
}
pp = nfa_hciu_find_pipe_by_pid(p_evt_data->add_static_pipe.pipe);
if (pp != NULL) {
/* This pipe is always opened */
pp->pipe_state = NFA_HCI_PIPE_OPENED;
evt_data.pipe_added.status = NFA_STATUS_OK;
nfa_hciu_send_to_app(NFA_HCI_ADD_STATIC_PIPE_EVT, &evt_data,
p_evt_data->add_static_pipe.hci_handle);
return;
}
}
/* Unable to add static pipe */
evt_data.pipe_added.status = NFA_STATUS_FAILED;
nfa_hciu_send_to_app(NFA_HCI_ADD_STATIC_PIPE_EVT, &evt_data,
p_evt_data->add_static_pipe.hci_handle);
}
/*******************************************************************************
**
** Function nfa_hci_handle_link_mgm_gate_cmd
**
** Description This function handles incoming link management gate hci
** commands
**
** Returns none
**
*******************************************************************************/
void nfa_hci_handle_link_mgm_gate_cmd(uint8_t* p_data) {
uint8_t index;
uint8_t data[2];
uint8_t rsp_len = 0;
uint8_t response = NFA_HCI_ANY_OK;
if ((nfa_hci_cb.cfg.link_mgmt_gate.pipe00_state != NFA_HCI_PIPE_OPENED) &&
(nfa_hci_cb.inst != NFA_HCI_ANY_OPEN_PIPE)) {
nfa_hciu_send_msg(NFA_HCI_LINK_MANAGEMENT_PIPE, NFA_HCI_RESPONSE_TYPE,
NFA_HCI_ANY_E_PIPE_NOT_OPENED, 0, NULL);
return;
}
switch (nfa_hci_cb.inst) {
case NFA_HCI_ANY_SET_PARAMETER:
STREAM_TO_UINT8(index, p_data);
if (index == 1) {
STREAM_TO_UINT16(nfa_hci_cb.cfg.link_mgmt_gate.rec_errors, p_data);
} else
response = NFA_HCI_ANY_E_REG_PAR_UNKNOWN;
break;
case NFA_HCI_ANY_GET_PARAMETER:
STREAM_TO_UINT8(index, p_data);
if (index == 1) {
data[0] =
(uint8_t)((nfa_hci_cb.cfg.link_mgmt_gate.rec_errors >> 8) & 0x00FF);
data[1] = (uint8_t)(nfa_hci_cb.cfg.link_mgmt_gate.rec_errors & 0x000F);
rsp_len = 2;
} else
response = NFA_HCI_ANY_E_REG_PAR_UNKNOWN;
break;
case NFA_HCI_ANY_OPEN_PIPE:
data[0] = 0;
rsp_len = 1;
nfa_hci_cb.cfg.link_mgmt_gate.pipe00_state = NFA_HCI_PIPE_OPENED;
break;
case NFA_HCI_ANY_CLOSE_PIPE:
nfa_hci_cb.cfg.link_mgmt_gate.pipe00_state = NFA_HCI_PIPE_CLOSED;
break;
default:
response = NFA_HCI_ANY_E_CMD_NOT_SUPPORTED;
break;
}
nfa_hciu_send_msg(NFA_HCI_LINK_MANAGEMENT_PIPE, NFA_HCI_RESPONSE_TYPE,
response, rsp_len, data);
}
/*******************************************************************************
**
** Function nfa_hci_handle_pipe_open_close_cmd
**
** Description This function handles all generic gates (excluding
** connectivity gate) commands
**
** Returns none
**
*******************************************************************************/
void nfa_hci_handle_pipe_open_close_cmd(tNFA_HCI_DYN_PIPE* p_pipe) {
uint8_t data[1];
uint8_t rsp_len = 0;
tNFA_HCI_RESPONSE response = NFA_HCI_ANY_OK;
tNFA_HCI_DYN_GATE* p_gate;
if (nfa_hci_cb.inst == NFA_HCI_ANY_OPEN_PIPE) {
if ((p_gate = nfa_hciu_find_gate_by_gid(p_pipe->local_gate)) != NULL)
data[0] = nfa_hciu_count_open_pipes_on_gate(p_gate);
else
data[0] = 0;
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
rsp_len = 1;
} else if (nfa_hci_cb.inst == NFA_HCI_ANY_CLOSE_PIPE) {
p_pipe->pipe_state = NFA_HCI_PIPE_CLOSED;
}
nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_RESPONSE_TYPE, response, rsp_len,
data);
}
/*******************************************************************************
**
** Function nfa_hci_handle_admin_gate_cmd
**
** Description This function handles incoming commands on ADMIN gate
**
** Returns none
**
*******************************************************************************/
void nfa_hci_handle_admin_gate_cmd(uint8_t* p_data) {
uint8_t source_host, source_gate, dest_host, dest_gate, pipe;
uint8_t data = 0;
uint8_t rsp_len = 0;
tNFA_HCI_RESPONSE response = NFA_HCI_ANY_OK;
tNFA_HCI_DYN_GATE* pgate;
tNFA_HCI_EVT_DATA evt_data;
switch (nfa_hci_cb.inst) {
case NFA_HCI_ANY_OPEN_PIPE:
nfa_hci_cb.cfg.admin_gate.pipe01_state = NFA_HCI_PIPE_OPENED;
data = 0;
rsp_len = 1;
break;
case NFA_HCI_ANY_CLOSE_PIPE:
nfa_hci_cb.cfg.admin_gate.pipe01_state = NFA_HCI_PIPE_CLOSED;
/* Reopen the pipe immediately */
nfa_hciu_send_msg(NFA_HCI_ADMIN_PIPE, NFA_HCI_RESPONSE_TYPE, response,
rsp_len, &data);
nfa_hci_cb.app_in_use = NFA_HANDLE_INVALID;
nfa_hciu_send_open_pipe_cmd(NFA_HCI_ADMIN_PIPE);
return;
break;
case NFA_HCI_ADM_NOTIFY_PIPE_CREATED:
STREAM_TO_UINT8(source_host, p_data);
STREAM_TO_UINT8(source_gate, p_data);
STREAM_TO_UINT8(dest_host, p_data);
STREAM_TO_UINT8(dest_gate, p_data);
STREAM_TO_UINT8(pipe, p_data);
if ((dest_gate == NFA_HCI_IDENTITY_MANAGEMENT_GATE) ||
(dest_gate == NFA_HCI_LOOP_BACK_GATE)) {
response = nfa_hciu_add_pipe_to_static_gate(dest_gate, pipe,
source_host, source_gate);
} else {
if ((pgate = nfa_hciu_find_gate_by_gid(dest_gate)) != NULL) {
/* If the gate is valid, add the pipe to it */
if (nfa_hciu_check_pipe_between_gates(dest_gate, source_host,
source_gate)) {
/* Already, there is a pipe between these two gates, so will reject
*/
response = NFA_HCI_ANY_E_NOK;
} else {
response = nfa_hciu_add_pipe_to_gate(pipe, dest_gate, source_host,
source_gate);
if (response == NFA_HCI_ANY_OK) {
/* Tell the application a pipe was created with its gate */
evt_data.created.status = NFA_STATUS_OK;
evt_data.created.pipe = pipe;
evt_data.created.source_gate = dest_gate;
evt_data.created.dest_host = source_host;
evt_data.created.dest_gate = source_gate;
nfa_hciu_send_to_app(NFA_HCI_CREATE_PIPE_EVT, &evt_data,
pgate->gate_owner);
}
}
} else {
response = NFA_HCI_ANY_E_NOK;
if ((dest_gate >= NFA_HCI_FIRST_PROP_GATE) &&
(dest_gate <= NFA_HCI_LAST_PROP_GATE)) {
if (nfa_hciu_alloc_gate(dest_gate, 0))
response = nfa_hciu_add_pipe_to_gate(pipe, dest_gate, source_host,
source_gate);
}
}
}
break;
case NFA_HCI_ADM_NOTIFY_PIPE_DELETED:
STREAM_TO_UINT8(pipe, p_data);
response = nfa_hciu_release_pipe(pipe);
break;
case NFA_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED:
STREAM_TO_UINT8(source_host, p_data);
#if(NXP_EXTNS != TRUE)
nfa_hciu_remove_all_pipes_from_host(source_host);
#endif
if (source_host == NFA_HCI_HOST_CONTROLLER) {
nfa_hci_cb.cfg.link_mgmt_gate.pipe00_state = NFA_HCI_PIPE_CLOSED;
nfa_hci_cb.cfg.admin_gate.pipe01_state = NFA_HCI_PIPE_CLOSED;
#if(NXP_EXTNS == TRUE)
nfa_hciu_remove_all_pipes_from_host(source_host);
#endif
/* Reopen the admin pipe immediately */
nfa_hci_cb.app_in_use = NFA_HANDLE_INVALID;
nfa_hciu_send_open_pipe_cmd(NFA_HCI_ADMIN_PIPE);
return;
} else {
#if(NXP_EXTNS == TRUE)
nfa_hciu_send_msg(NFA_HCI_ADMIN_PIPE, NFA_HCI_RESPONSE_TYPE, response,
rsp_len, &data);
/* If starting up, handle events here */
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_hci_handle_admin_gate_cmd %d",source_host);
nfa_hci_handle_clear_all_pipe_cmd(source_host);
return;
#else
if ((source_host >= NFA_HCI_HOST_ID_UICC0) &&
(source_host <
(NFA_HCI_HOST_ID_UICC0 + NFA_HCI_MAX_HOST_IN_NETWORK))) {
nfa_hci_cb.reset_host[source_host - NFA_HCI_HOST_ID_UICC0] =
source_host;
}
#endif
}
break;
default:
response = NFA_HCI_ANY_E_CMD_NOT_SUPPORTED;
break;
}
nfa_hciu_send_msg(NFA_HCI_ADMIN_PIPE, NFA_HCI_RESPONSE_TYPE, response,
rsp_len, &data);
}
/*******************************************************************************
**
** Function nfa_hci_handle_admin_gate_rsp
**
** Description This function handles response received on admin gate
**
** Returns none
**
*******************************************************************************/
void nfa_hci_handle_admin_gate_rsp(uint8_t* p_data, uint8_t data_len) {
uint8_t source_host;
uint8_t source_gate = nfa_hci_cb.local_gate_in_use;
uint8_t dest_host = nfa_hci_cb.remote_host_in_use;
uint8_t dest_gate = nfa_hci_cb.remote_gate_in_use;
uint8_t pipe = 0;
tNFA_STATUS status;
tNFA_HCI_EVT_DATA evt_data;
uint8_t default_session[NFA_HCI_SESSION_ID_LEN] = {0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
#if(NXP_EXTNS != TRUE)
uint8_t host_count = 0;
uint8_t host_id = 0;
#endif
uint32_t os_tick;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_hci_handle_admin_gate_rsp - LastCmdSent: %s App: 0x%04x Gate: "
"0x%02x Pipe: 0x%02x",
nfa_hciu_instr_2_str(nfa_hci_cb.cmd_sent).c_str(), nfa_hci_cb.app_in_use,
nfa_hci_cb.local_gate_in_use, nfa_hci_cb.pipe_in_use);
/* If starting up, handle events here */
if ((nfa_hci_cb.hci_state == NFA_HCI_STATE_STARTUP) ||
(nfa_hci_cb.hci_state == NFA_HCI_STATE_RESTORE) ||
(nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_NETWK_ENABLE) ||
(nfa_hci_cb.hci_state == NFA_HCI_STATE_RESTORE_NETWK_ENABLE
#if(NXP_EXTNS == TRUE)
|| nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_RSP ||
nfa_hci_cb.hci_state == NFA_HCI_STATE_IDLE
#endif
)) {
if (nfa_hci_cb.inst == NFA_HCI_ANY_E_PIPE_NOT_OPENED) {
nfa_hciu_send_open_pipe_cmd(NFA_HCI_ADMIN_PIPE);
return;
}
if (nfa_hci_cb.inst != NFA_HCI_ANY_OK) {
LOG(ERROR) << StringPrintf(
"nfa_hci_handle_admin_gate_rsp - Initialization failed");
#if(NXP_EXTNS == TRUE)
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_OK);
#else
nfa_hci_startup_complete (NFA_STATUS_FAILED);
#endif
return;
}
switch (nfa_hci_cb.cmd_sent) {
case NFA_HCI_ANY_SET_PARAMETER:
if (nfa_hci_cb.param_in_use == NFA_HCI_SESSION_IDENTITY_INDEX) {
/* Set WHITELIST */
nfa_hciu_send_set_param_cmd(
NFA_HCI_ADMIN_PIPE, NFA_HCI_WHITELIST_INDEX,
p_nfa_hci_cfg->num_whitelist_host, p_nfa_hci_cfg->p_whitelist);
} else if (nfa_hci_cb.param_in_use == NFA_HCI_WHITELIST_INDEX) {
if ((nfa_hci_cb.hci_state == NFA_HCI_STATE_STARTUP) ||
(nfa_hci_cb.hci_state == NFA_HCI_STATE_RESTORE))
nfa_hci_dh_startup_complete();
if (NFA_GetNCIVersion() == NCI_VERSION_2_0) {
nfa_hci_cb.hci_state = NFA_HCI_STATE_WAIT_NETWK_ENABLE;
NFA_EeGetInfo(&nfa_hci_cb.num_nfcee, nfa_hci_cb.ee_info);
nfa_hci_enable_one_nfcee();
}
}
break;
case NFA_HCI_ANY_GET_PARAMETER:
if (nfa_hci_cb.param_in_use == NFA_HCI_HOST_LIST_INDEX) {
#if(NXP_EXTNS == TRUE)
nfa_hciu_update_host_list(data_len , p_data);
nfa_hci_cb.hci_state = NFA_HCI_STATE_WAIT_NETWK_ENABLE;
nfa_sys_stop_timer(&nfa_hci_cb.timer);
if (!nfa_hci_enable_one_nfcee ())
#else
host_count = 0;
while (host_count < NFA_HCI_MAX_HOST_IN_NETWORK) {
nfa_hci_cb.inactive_host[host_count] =
NFA_HCI_HOST_ID_UICC0 + host_count;
host_count++;
}
host_count = 0;
/* Collect active host in the Host Network */
while (host_count < data_len) {
host_id = (uint8_t)*p_data++;
if ((host_id >= NFA_HCI_HOST_ID_UICC0) &&
(host_id <
NFA_HCI_HOST_ID_UICC0 + NFA_HCI_MAX_HOST_IN_NETWORK)) {
nfa_hci_cb.inactive_host[host_id - NFA_HCI_HOST_ID_UICC0] = 0x00;
nfa_hci_cb.reset_host[host_id - NFA_HCI_HOST_ID_UICC0] = 0x00;
}
host_count++;
}
#endif
nfa_hci_startup_complete (NFA_STATUS_OK);
} else if (nfa_hci_cb.param_in_use == NFA_HCI_SESSION_IDENTITY_INDEX) {
/* The only parameter we get when initializing is the session ID.
* Check for match. */
if (!memcmp((uint8_t*)nfa_hci_cb.cfg.admin_gate.session_id, p_data,
NFA_HCI_SESSION_ID_LEN)) {
/* Session has not changed, Set WHITELIST */
nfa_hciu_send_set_param_cmd(
NFA_HCI_ADMIN_PIPE, NFA_HCI_WHITELIST_INDEX,
p_nfa_hci_cfg->num_whitelist_host, p_nfa_hci_cfg->p_whitelist);
} else {
/* Something wrong, NVRAM data could be corrupt or first start with
* default session id */
nfa_hciu_send_clear_all_pipe_cmd();
nfa_hci_cb.b_hci_netwk_reset = true;
}
}
break;
case NFA_HCI_ANY_OPEN_PIPE:
nfa_hci_cb.cfg.admin_gate.pipe01_state = NFA_HCI_PIPE_OPENED;
if (nfa_hci_cb.b_hci_netwk_reset) {
nfa_hci_cb.b_hci_netwk_reset = false;
/* Session ID is reset, Set New session id */
memcpy(
&nfa_hci_cb.cfg.admin_gate.session_id[NFA_HCI_SESSION_ID_LEN / 2],
nfa_hci_cb.cfg.admin_gate.session_id,
(NFA_HCI_SESSION_ID_LEN / 2));
os_tick = GKI_get_os_tick_count();
memcpy(nfa_hci_cb.cfg.admin_gate.session_id, (uint8_t*)&os_tick,
(NFA_HCI_SESSION_ID_LEN / 2));
nfa_hciu_send_set_param_cmd(
NFA_HCI_ADMIN_PIPE, NFA_HCI_SESSION_IDENTITY_INDEX,
NFA_HCI_SESSION_ID_LEN,
(uint8_t*)nfa_hci_cb.cfg.admin_gate.session_id);
} else {
/* First thing is to get the session ID */
nfa_hciu_send_get_param_cmd(NFA_HCI_ADMIN_PIPE,
NFA_HCI_SESSION_IDENTITY_INDEX);
}
break;
case NFA_HCI_ADM_CLEAR_ALL_PIPE:
nfa_hciu_remove_all_pipes_from_host(0);
nfa_hci_cb.cfg.admin_gate.pipe01_state = NFA_HCI_PIPE_CLOSED;
nfa_hci_cb.cfg.link_mgmt_gate.pipe00_state = NFA_HCI_PIPE_CLOSED;
nfa_hci_cb.nv_write_needed = true;
/* Open admin */
nfa_hciu_send_open_pipe_cmd(NFA_HCI_ADMIN_PIPE);
break;
#if(NXP_EXTNS == TRUE)
case NFA_HCI_ADM_CREATE_PIPE:
STREAM_TO_UINT8(source_host, p_data);
STREAM_TO_UINT8 (source_gate, p_data);
STREAM_TO_UINT8 (dest_host, p_data);
STREAM_TO_UINT8 (dest_gate, p_data);
STREAM_TO_UINT8 (pipe, p_data);
/* Sanity check */
if ( (source_gate != nfa_hci_cb.local_gate_in_use)
||(dest_gate != nfa_hci_cb.remote_gate_in_use)
||(dest_host != nfa_hci_cb.remote_host_in_use) )
{
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfa_hci_handle_admin_gate_rsp sent create pipe with gate: %u got back: %u",
nfa_hci_cb.local_gate_in_use, source_gate);
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_OK);
break;
}
nfa_hciu_add_pipe_to_gate(pipe, source_gate, dest_host, dest_gate);
nfa_hciu_send_open_pipe_cmd (pipe);
break;
#endif
}
} else {
status =
(nfa_hci_cb.inst == NFA_HCI_ANY_OK) ? NFA_STATUS_OK : NFA_STATUS_FAILED;
switch (nfa_hci_cb.cmd_sent) {
case NFA_HCI_ANY_SET_PARAMETER:
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_APP_DEREGISTER)
nfa_hci_api_deregister(NULL);
else if (nfa_hci_cb.hci_state == NFA_HCI_STATE_REMOVE_GATE)
nfa_hci_api_dealloc_gate(NULL);
break;
case NFA_HCI_ANY_GET_PARAMETER:
if (nfa_hci_cb.param_in_use == NFA_HCI_SESSION_IDENTITY_INDEX) {
if (!memcmp((uint8_t*)default_session, p_data,
NFA_HCI_SESSION_ID_LEN)) {
memcpy(&nfa_hci_cb.cfg.admin_gate
.session_id[(NFA_HCI_SESSION_ID_LEN / 2)],
nfa_hci_cb.cfg.admin_gate.session_id,
(NFA_HCI_SESSION_ID_LEN / 2));
os_tick = GKI_get_os_tick_count();
memcpy(nfa_hci_cb.cfg.admin_gate.session_id, (uint8_t*)&os_tick,
(NFA_HCI_SESSION_ID_LEN / 2));
nfa_hci_cb.nv_write_needed = true;
nfa_hciu_send_set_param_cmd(
NFA_HCI_ADMIN_PIPE, NFA_HCI_SESSION_IDENTITY_INDEX,
NFA_HCI_SESSION_ID_LEN,
(uint8_t*)nfa_hci_cb.cfg.admin_gate.session_id);
} else {
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_APP_DEREGISTER)
nfa_hci_api_deregister(NULL);
else if (nfa_hci_cb.hci_state == NFA_HCI_STATE_REMOVE_GATE)
nfa_hci_api_dealloc_gate(NULL);
}
} else if (nfa_hci_cb.param_in_use == NFA_HCI_HOST_LIST_INDEX) {
evt_data.hosts.status = status;
evt_data.hosts.num_hosts = data_len;
memcpy(evt_data.hosts.host, p_data, data_len);
#if(NXP_EXTNS == TRUE)
nfa_hciu_update_host_list(data_len , p_data);
#else
host_count = 0;
while (host_count < NFA_HCI_MAX_HOST_IN_NETWORK) {
nfa_hci_cb.inactive_host[host_count] =
NFA_HCI_HOST_ID_UICC0 + host_count;
host_count++;
}
host_count = 0;
/* Collect active host in the Host Network */
while (host_count < data_len) {
host_id = (uint8_t)*p_data++;
if ((host_id >= NFA_HCI_HOST_ID_UICC0) &&
(host_id <
NFA_HCI_HOST_ID_UICC0 + NFA_HCI_MAX_HOST_IN_NETWORK)) {
nfa_hci_cb.inactive_host[host_id - NFA_HCI_HOST_ID_UICC0] = 0x00;
nfa_hci_cb.reset_host[host_id - NFA_HCI_HOST_ID_UICC0] = 0x00;
}
host_count++;
}
#endif
if (nfa_hciu_is_no_host_resetting())
nfa_hci_check_pending_api_requests();
nfa_hciu_send_to_app(NFA_HCI_HOST_LIST_EVT, &evt_data,
nfa_hci_cb.app_in_use);
}
break;
case NFA_HCI_ADM_CREATE_PIPE:
if (status == NFA_STATUS_OK) {
STREAM_TO_UINT8(source_host, p_data);
STREAM_TO_UINT8(source_gate, p_data);
STREAM_TO_UINT8(dest_host, p_data);
STREAM_TO_UINT8(dest_gate, p_data);
STREAM_TO_UINT8(pipe, p_data);
/* Sanity check */
if (source_gate != nfa_hci_cb.local_gate_in_use) {
LOG(WARNING) << StringPrintf(
"nfa_hci_handle_admin_gate_rsp sent create pipe with gate: %u "
"got back: %u",
nfa_hci_cb.local_gate_in_use, source_gate);
break;
}
nfa_hciu_add_pipe_to_gate(pipe, source_gate, dest_host, dest_gate);
}
/* Tell the application his pipe was created or not */
evt_data.created.status = status;
evt_data.created.pipe = pipe;
evt_data.created.source_gate = source_gate;
evt_data.created.dest_host = dest_host;
evt_data.created.dest_gate = dest_gate;
nfa_hciu_send_to_app(NFA_HCI_CREATE_PIPE_EVT, &evt_data,
nfa_hci_cb.app_in_use);
break;
case NFA_HCI_ADM_DELETE_PIPE:
if (status == NFA_STATUS_OK) {
nfa_hciu_release_pipe(nfa_hci_cb.pipe_in_use);
/* If only deleting one pipe, tell the app we are done */
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_IDLE) {
evt_data.deleted.status = status;
evt_data.deleted.pipe = nfa_hci_cb.pipe_in_use;
nfa_hciu_send_to_app(NFA_HCI_DELETE_PIPE_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.hci_state == NFA_HCI_STATE_APP_DEREGISTER)
nfa_hci_api_deregister(NULL);
else if (nfa_hci_cb.hci_state == NFA_HCI_STATE_REMOVE_GATE)
nfa_hci_api_dealloc_gate(NULL);
} else {
/* If only deleting one pipe, tell the app we are done */
if (nfa_hci_cb.hci_state == NFA_HCI_STATE_IDLE) {
evt_data.deleted.status = status;
evt_data.deleted.pipe = nfa_hci_cb.pipe_in_use;
nfa_hciu_send_to_app(NFA_HCI_DELETE_PIPE_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.hci_state == NFA_HCI_STATE_APP_DEREGISTER) {
nfa_hciu_release_pipe(nfa_hci_cb.pipe_in_use);
nfa_hci_api_deregister(NULL);
} else if (nfa_hci_cb.hci_state == NFA_HCI_STATE_REMOVE_GATE) {
nfa_hciu_release_pipe(nfa_hci_cb.pipe_in_use);
nfa_hci_api_dealloc_gate(NULL);
}
}
break;
case NFA_HCI_ANY_OPEN_PIPE:
nfa_hci_cb.cfg.admin_gate.pipe01_state =
status ? NFA_HCI_PIPE_CLOSED : NFA_HCI_PIPE_OPENED;
nfa_hci_cb.nv_write_needed = true;
if (nfa_hci_cb.cfg.admin_gate.pipe01_state == NFA_HCI_PIPE_OPENED) {
/* First thing is to get the session ID */
nfa_hciu_send_get_param_cmd(NFA_HCI_ADMIN_PIPE,
NFA_HCI_SESSION_IDENTITY_INDEX);
}
break;
case NFA_HCI_ADM_CLEAR_ALL_PIPE:
nfa_hciu_remove_all_pipes_from_host(0);
nfa_hci_cb.cfg.admin_gate.pipe01_state = NFA_HCI_PIPE_CLOSED;
nfa_hci_cb.cfg.link_mgmt_gate.pipe00_state = NFA_HCI_PIPE_CLOSED;
nfa_hci_cb.nv_write_needed = true;
/* Open admin */
nfa_hciu_send_open_pipe_cmd(NFA_HCI_ADMIN_PIPE);
break;
}
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_admin_gate_evt
**
** Description This function handles events received on admin gate
**
** Returns none
**
*******************************************************************************/
void nfa_hci_handle_admin_gate_evt() {
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_API_GET_HOST_LIST* p_msg;
if (nfa_hci_cb.inst != NFA_HCI_EVT_HOT_PLUG) {
LOG(ERROR) << StringPrintf(
"nfa_hci_handle_admin_gate_evt - Unknown event on ADMIN Pipe");
return;
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_hci_handle_admin_gate_evt - HOT PLUG EVT event on ADMIN Pipe");
nfa_hci_cb.num_hot_plug_evts++;
if ((nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_NETWK_ENABLE) ||
(nfa_hci_cb.hci_state == NFA_HCI_STATE_RESTORE_NETWK_ENABLE)) {
/* Received Hot Plug evt while waiting for other Host in the network to
* bootup after DH host bootup is complete */
if ((nfa_hci_cb.ee_disable_disc) &&
(nfa_hci_cb.num_hot_plug_evts == (nfa_hci_cb.num_nfcee - 1)) &&
(nfa_hci_cb.num_ee_dis_req_ntf < (nfa_hci_cb.num_nfcee - 1))) {
/* Received expected number of Hot Plug event(s) before as many number of
* EE DISC REQ Ntf(s) are received */
nfa_sys_stop_timer(&nfa_hci_cb.timer);
/* Received HOT PLUG EVT(s), now wait some more time for EE DISC REQ
* Ntf(s) */
nfa_sys_start_timer(&nfa_hci_cb.timer, NFA_HCI_RSP_TIMEOUT_EVT,
p_nfa_hci_cfg->hci_netwk_enable_timeout);
}
} else if ((nfa_hci_cb.hci_state == NFA_HCI_STATE_STARTUP) ||
(nfa_hci_cb.hci_state == NFA_HCI_STATE_RESTORE)) {
/* Received Hot Plug evt during DH host bootup */
if ((nfa_hci_cb.ee_disable_disc) &&
(nfa_hci_cb.num_hot_plug_evts == (nfa_hci_cb.num_nfcee - 1)) &&
(nfa_hci_cb.num_ee_dis_req_ntf < (nfa_hci_cb.num_nfcee - 1))) {
/* Received expected number of Hot Plug event(s) before as many number of
* EE DISC REQ Ntf(s) are received */
nfa_hci_cb.w4_hci_netwk_init = false;
}
} else {
/* Received Hot Plug evt on UICC self reset */
evt_data.rcvd_evt.evt_code = nfa_hci_cb.inst;
/* Notify all registered application with the HOT_PLUG_EVT */
nfa_hciu_send_to_all_apps(NFA_HCI_EVENT_RCVD_EVT, &evt_data);
/* Send Get Host List after receiving any pending response */
p_msg = (tNFA_HCI_API_GET_HOST_LIST*)GKI_getbuf(
sizeof(tNFA_HCI_API_GET_HOST_LIST));
if (p_msg != NULL) {
p_msg->hdr.event = NFA_HCI_API_GET_HOST_LIST_EVT;
/* Set Invalid handle to identify this Get Host List command is internal
*/
p_msg->hci_handle = NFA_HANDLE_INVALID;
nfa_sys_sendmsg(p_msg);
}
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_dyn_pipe_pkt
**
** Description This function handles data received via dynamic pipe
**
** Returns none
**
*******************************************************************************/
void nfa_hci_handle_dyn_pipe_pkt(uint8_t pipe_id, uint8_t* p_data,
uint16_t data_len) {
tNFA_HCI_DYN_PIPE* p_pipe = nfa_hciu_find_pipe_by_pid(pipe_id);
tNFA_HCI_DYN_GATE* p_gate;
if (p_pipe == NULL) {
/* Invalid pipe ID */
LOG(ERROR) << StringPrintf("nfa_hci_handle_dyn_pipe_pkt - Unknown pipe %d",
pipe_id);
if (nfa_hci_cb.type == NFA_HCI_COMMAND_TYPE)
nfa_hciu_send_msg(pipe_id, NFA_HCI_RESPONSE_TYPE, NFA_HCI_ANY_E_NOK, 0,
NULL);
return;
}
if (p_pipe->local_gate == NFA_HCI_IDENTITY_MANAGEMENT_GATE) {
nfa_hci_handle_identity_mgmt_gate_pkt(p_data, p_pipe);
#if(NXP_EXTNS == TRUE)
} else if (p_pipe->local_gate == NFA_HCI_ID_MNGMNT_APP_GATE) {
nfa_hci_handle_identity_mgmt_app_gate_hcp_msg_data (p_data, data_len, p_pipe);
} else if (p_pipe->local_gate == NFA_HCI_APDU_APP_GATE) {
nfa_hci_handle_apdu_app_gate_hcp_msg_data (p_data, data_len, p_pipe);
#endif
} else if (p_pipe->local_gate == NFA_HCI_LOOP_BACK_GATE) {
nfa_hci_handle_loopback_gate_pkt(p_data, data_len, p_pipe);
} else if (p_pipe->local_gate == NFA_HCI_CONNECTIVITY_GATE) {
nfa_hci_handle_connectivity_gate_pkt(p_data, data_len, p_pipe);
} else {
p_gate = nfa_hciu_find_gate_by_gid(p_pipe->local_gate);
if (p_gate == NULL) {
LOG(ERROR) << StringPrintf(
"nfa_hci_handle_dyn_pipe_pkt - Pipe's gate %d is corrupt",
p_pipe->local_gate);
if (nfa_hci_cb.type == NFA_HCI_COMMAND_TYPE)
nfa_hciu_send_msg(pipe_id, NFA_HCI_RESPONSE_TYPE, NFA_HCI_ANY_E_NOK, 0,
NULL);
return;
}
/* Check if data packet is a command, response or event */
switch (nfa_hci_cb.type) {
case NFA_HCI_COMMAND_TYPE:
nfa_hci_handle_generic_gate_cmd(p_data, (uint8_t)data_len, p_pipe);
break;
case NFA_HCI_RESPONSE_TYPE:
nfa_hci_handle_generic_gate_rsp(p_data, (uint8_t)data_len, p_pipe);
break;
case NFA_HCI_EVENT_TYPE:
nfa_hci_handle_generic_gate_evt(p_data, data_len, p_gate, p_pipe);
break;
}
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_identity_mgmt_gate_pkt
**
** Description This function handles incoming Identity Management gate hci
** commands
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_identity_mgmt_gate_pkt(uint8_t* p_data,
tNFA_HCI_DYN_PIPE* p_pipe) {
uint8_t data[20];
uint8_t index;
uint8_t gate_rsp[3 + NFA_HCI_MAX_GATE_CB], num_gates;
uint16_t rsp_len = 0;
uint8_t* p_rsp = data;
tNFA_HCI_RESPONSE response = NFA_HCI_ANY_OK;
/* We never send commands on a pipe where the local gate is the identity
* management
* gate, so only commands should be processed.
*/
if (nfa_hci_cb.type != NFA_HCI_COMMAND_TYPE) return;
switch (nfa_hci_cb.inst) {
case NFA_HCI_ANY_GET_PARAMETER:
index = *(p_data++);
if (p_pipe->pipe_state == NFA_HCI_PIPE_OPENED) {
switch (index) {
case NFA_HCI_VERSION_SW_INDEX:
data[0] = (uint8_t)((NFA_HCI_VERSION_SW >> 16) & 0xFF);
data[1] = (uint8_t)((NFA_HCI_VERSION_SW >> 8) & 0xFF);
data[2] = (uint8_t)((NFA_HCI_VERSION_SW)&0xFF);
rsp_len = 3;
break;
case NFA_HCI_HCI_VERSION_INDEX:
data[0] = NFA_HCI_VERSION;
rsp_len = 1;
break;
case NFA_HCI_VERSION_HW_INDEX:
data[0] = (uint8_t)((NFA_HCI_VERSION_HW >> 16) & 0xFF);
data[1] = (uint8_t)((NFA_HCI_VERSION_HW >> 8) & 0xFF);
data[2] = (uint8_t)((NFA_HCI_VERSION_HW)&0xFF);
rsp_len = 3;
break;
case NFA_HCI_VENDOR_NAME_INDEX:
memcpy(data, NFA_HCI_VENDOR_NAME, strlen(NFA_HCI_VENDOR_NAME));
rsp_len = (uint8_t)strlen(NFA_HCI_VENDOR_NAME);
break;
case NFA_HCI_MODEL_ID_INDEX:
data[0] = NFA_HCI_MODEL_ID;
rsp_len = 1;
break;
case NFA_HCI_GATES_LIST_INDEX:
gate_rsp[0] = NFA_HCI_LOOP_BACK_GATE;
gate_rsp[1] = NFA_HCI_IDENTITY_MANAGEMENT_GATE;
gate_rsp[2] = NFA_HCI_CONNECTIVITY_GATE;
num_gates = nfa_hciu_get_allocated_gate_list(&gate_rsp[3]);
rsp_len = num_gates + 3;
p_rsp = gate_rsp;
break;
default:
response = NFA_HCI_ANY_E_NOK;
break;
}
} else {
response = NFA_HCI_ANY_E_PIPE_NOT_OPENED;
}
break;
case NFA_HCI_ANY_OPEN_PIPE:
data[0] = 0;
rsp_len = 1;
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
break;
case NFA_HCI_ANY_CLOSE_PIPE:
p_pipe->pipe_state = NFA_HCI_PIPE_CLOSED;
break;
default:
response = NFA_HCI_ANY_E_CMD_NOT_SUPPORTED;
break;
}
nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_RESPONSE_TYPE, response, rsp_len,
p_rsp);
}
/*******************************************************************************
**
** Function nfa_hci_handle_generic_gate_cmd
**
** Description This function handles all generic gates (excluding
** connectivity gate) commands
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_generic_gate_cmd(uint8_t* p_data, uint8_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe) {
tNFA_HCI_EVT_DATA evt_data;
tNFA_HANDLE app_handle = nfa_hciu_get_pipe_owner(p_pipe->pipe_id);
switch (nfa_hci_cb.inst) {
case NFA_HCI_ANY_SET_PARAMETER:
evt_data.registry.pipe = p_pipe->pipe_id;
evt_data.registry.index = *p_data++;
if (data_len > 0) data_len--;
evt_data.registry.data_len = data_len;
memcpy(evt_data.registry.reg_data, p_data, data_len);
nfa_hciu_send_to_app(NFA_HCI_SET_REG_CMD_EVT, &evt_data, app_handle);
break;
case NFA_HCI_ANY_GET_PARAMETER:
evt_data.registry.pipe = p_pipe->pipe_id;
evt_data.registry.index = *p_data;
evt_data.registry.data_len = 0;
nfa_hciu_send_to_app(NFA_HCI_GET_REG_CMD_EVT, &evt_data, app_handle);
break;
case NFA_HCI_ANY_OPEN_PIPE:
nfa_hci_handle_pipe_open_close_cmd(p_pipe);
evt_data.opened.pipe = p_pipe->pipe_id;
evt_data.opened.status = NFA_STATUS_OK;
nfa_hciu_send_to_app(NFA_HCI_OPEN_PIPE_EVT, &evt_data, app_handle);
break;
case NFA_HCI_ANY_CLOSE_PIPE:
nfa_hci_handle_pipe_open_close_cmd(p_pipe);
evt_data.closed.pipe = p_pipe->pipe_id;
evt_data.opened.status = NFA_STATUS_OK;
nfa_hciu_send_to_app(NFA_HCI_CLOSE_PIPE_EVT, &evt_data, app_handle);
break;
default:
/* Could be application specific command, pass it on */
evt_data.cmd_rcvd.status = NFA_STATUS_OK;
evt_data.cmd_rcvd.pipe = p_pipe->pipe_id;
;
evt_data.cmd_rcvd.cmd_code = nfa_hci_cb.inst;
evt_data.cmd_rcvd.cmd_len = data_len;
if (data_len <= NFA_MAX_HCI_CMD_LEN)
memcpy(evt_data.cmd_rcvd.cmd_data, p_data, data_len);
nfa_hciu_send_to_app(NFA_HCI_CMD_RCVD_EVT, &evt_data, app_handle);
break;
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_generic_gate_rsp
**
** Description This function handles all generic gates (excluding
** connectivity) response
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_generic_gate_rsp(uint8_t* p_data, uint8_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe) {
tNFA_HCI_EVT_DATA evt_data;
tNFA_STATUS status = NFA_STATUS_OK;
if (nfa_hci_cb.inst != NFA_HCI_ANY_OK) status = NFA_STATUS_FAILED;
if (nfa_hci_cb.cmd_sent == NFA_HCI_ANY_OPEN_PIPE) {
if (status == NFA_STATUS_OK) p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
nfa_hci_cb.nv_write_needed = true;
/* Tell application */
evt_data.opened.status = status;
evt_data.opened.pipe = p_pipe->pipe_id;
nfa_hciu_send_to_app(NFA_HCI_OPEN_PIPE_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.cmd_sent == NFA_HCI_ANY_CLOSE_PIPE) {
p_pipe->pipe_state = NFA_HCI_PIPE_CLOSED;
nfa_hci_cb.nv_write_needed = true;
/* Tell application */
evt_data.opened.status = status;
;
evt_data.opened.pipe = p_pipe->pipe_id;
nfa_hciu_send_to_app(NFA_HCI_CLOSE_PIPE_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.cmd_sent == NFA_HCI_ANY_GET_PARAMETER) {
/* Tell application */
evt_data.registry.status = status;
evt_data.registry.pipe = p_pipe->pipe_id;
evt_data.registry.data_len = data_len;
evt_data.registry.index = nfa_hci_cb.param_in_use;
memcpy(evt_data.registry.reg_data, p_data, data_len);
nfa_hciu_send_to_app(NFA_HCI_GET_REG_RSP_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.cmd_sent == NFA_HCI_ANY_SET_PARAMETER) {
/* Tell application */
evt_data.registry.status = status;
;
evt_data.registry.pipe = p_pipe->pipe_id;
nfa_hciu_send_to_app(NFA_HCI_SET_REG_RSP_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else {
/* Could be a response to application specific command sent, pass it on */
evt_data.rsp_rcvd.status = NFA_STATUS_OK;
evt_data.rsp_rcvd.pipe = p_pipe->pipe_id;
;
evt_data.rsp_rcvd.rsp_code = nfa_hci_cb.inst;
evt_data.rsp_rcvd.rsp_len = data_len;
if (data_len <= NFA_MAX_HCI_RSP_LEN)
memcpy(evt_data.rsp_rcvd.rsp_data, p_data, data_len);
nfa_hciu_send_to_app(NFA_HCI_RSP_RCVD_EVT, &evt_data,
nfa_hci_cb.app_in_use);
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_connectivity_gate_pkt
**
** Description This function handles incoming connectivity gate packets
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_connectivity_gate_pkt(uint8_t* p_data,
uint16_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe) {
tNFA_HCI_EVT_DATA evt_data;
if (nfa_hci_cb.type == NFA_HCI_COMMAND_TYPE) {
switch (nfa_hci_cb.inst) {
case NFA_HCI_ANY_OPEN_PIPE:
case NFA_HCI_ANY_CLOSE_PIPE:
nfa_hci_handle_pipe_open_close_cmd(p_pipe);
break;
case NFA_HCI_CON_PRO_HOST_REQUEST:
/* A request to the DH to activate another host. This is not supported
* for */
/* now, we will implement it when the spec is clearer and UICCs need it.
*/
nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_RESPONSE_TYPE,
NFA_HCI_ANY_E_CMD_NOT_SUPPORTED, 0, NULL);
break;
default:
nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_RESPONSE_TYPE,
NFA_HCI_ANY_E_CMD_NOT_SUPPORTED, 0, NULL);
break;
}
} else if (nfa_hci_cb.type == NFA_HCI_RESPONSE_TYPE) {
if ((nfa_hci_cb.cmd_sent == NFA_HCI_ANY_OPEN_PIPE) &&
(nfa_hci_cb.inst == NFA_HCI_ANY_OK))
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
else if (nfa_hci_cb.cmd_sent == NFA_HCI_ANY_CLOSE_PIPE)
p_pipe->pipe_state = NFA_HCI_PIPE_CLOSED;
/* Could be a response to application specific command sent, pass it on */
evt_data.rsp_rcvd.status = NFA_STATUS_OK;
evt_data.rsp_rcvd.pipe = p_pipe->pipe_id;
;
evt_data.rsp_rcvd.rsp_code = nfa_hci_cb.inst;
evt_data.rsp_rcvd.rsp_len = data_len;
if (data_len <= NFA_MAX_HCI_RSP_LEN)
memcpy(evt_data.rsp_rcvd.rsp_data, p_data, data_len);
nfa_hciu_send_to_app(NFA_HCI_RSP_RCVD_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.type == NFA_HCI_EVENT_TYPE) {
#if(NXP_EXTNS == TRUE)
/* If its a valid Connectivity gate event then pass it on
** to all apps registered for connectivity gate events
*/
if ( (nfa_hci_cb.inst == NFA_HCI_EVT_CONNECTIVITY)
||(nfa_hci_cb.inst == NFA_HCI_EVT_TRANSACTION)
||(nfa_hci_cb.inst == NFA_HCI_EVT_OPERATION_ENDED) )
{
#endif
evt_data.rcvd_evt.pipe = p_pipe->pipe_id;
evt_data.rcvd_evt.evt_code = nfa_hci_cb.inst;
evt_data.rcvd_evt.evt_len = data_len;
evt_data.rcvd_evt.p_evt_buf = p_data;
/* notify NFA_HCI_EVENT_RCVD_EVT to the application */
nfa_hciu_send_to_apps_handling_connectivity_evts(NFA_HCI_EVENT_RCVD_EVT,
&evt_data);
#if(NXP_EXTNS == TRUE)
}
#endif
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_loopback_gate_pkt
**
** Description This function handles incoming loopback gate hci events
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_loopback_gate_pkt(uint8_t* p_data, uint16_t data_len,
tNFA_HCI_DYN_PIPE* p_pipe) {
uint8_t data[1];
uint8_t rsp_len = 0;
tNFA_HCI_RESPONSE response = NFA_HCI_ANY_OK;
tNFA_HCI_EVT_DATA evt_data;
/* Check if data packet is a command, response or event */
if (nfa_hci_cb.type == NFA_HCI_COMMAND_TYPE) {
if (nfa_hci_cb.inst == NFA_HCI_ANY_OPEN_PIPE) {
data[0] = 0;
rsp_len = 1;
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
} else if (nfa_hci_cb.inst == NFA_HCI_ANY_CLOSE_PIPE) {
p_pipe->pipe_state = NFA_HCI_PIPE_CLOSED;
} else
response = NFA_HCI_ANY_E_CMD_NOT_SUPPORTED;
nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_RESPONSE_TYPE, response, rsp_len,
data);
} else if (nfa_hci_cb.type == NFA_HCI_RESPONSE_TYPE) {
if ((nfa_hci_cb.cmd_sent == NFA_HCI_ANY_OPEN_PIPE) &&
(nfa_hci_cb.inst == NFA_HCI_ANY_OK))
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
else if (nfa_hci_cb.cmd_sent == NFA_HCI_ANY_CLOSE_PIPE)
p_pipe->pipe_state = NFA_HCI_PIPE_CLOSED;
/* Could be a response to application specific command sent, pass it on */
evt_data.rsp_rcvd.status = NFA_STATUS_OK;
evt_data.rsp_rcvd.pipe = p_pipe->pipe_id;
;
evt_data.rsp_rcvd.rsp_code = nfa_hci_cb.inst;
evt_data.rsp_rcvd.rsp_len = data_len;
if (data_len <= NFA_MAX_HCI_RSP_LEN)
memcpy(evt_data.rsp_rcvd.rsp_data, p_data, data_len);
nfa_hciu_send_to_app(NFA_HCI_RSP_RCVD_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.type == NFA_HCI_EVENT_TYPE) {
if (nfa_hci_cb.w4_rsp_evt) {
evt_data.rcvd_evt.pipe = p_pipe->pipe_id;
evt_data.rcvd_evt.evt_code = nfa_hci_cb.inst;
evt_data.rcvd_evt.evt_len = data_len;
evt_data.rcvd_evt.p_evt_buf = p_data;
nfa_hciu_send_to_app(NFA_HCI_EVENT_RCVD_EVT, &evt_data,
nfa_hci_cb.app_in_use);
} else if (nfa_hci_cb.inst == NFA_HCI_EVT_POST_DATA) {
/* Send back the same data we got */
nfa_hciu_send_msg(p_pipe->pipe_id, NFA_HCI_EVENT_TYPE,
NFA_HCI_EVT_POST_DATA, data_len, p_data);
}
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_generic_gate_evt
**
** Description This function handles incoming Generic gate hci events
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_generic_gate_evt(uint8_t* p_data, uint16_t data_len,
tNFA_HCI_DYN_GATE* p_gate,
tNFA_HCI_DYN_PIPE* p_pipe) {
tNFA_HCI_EVT_DATA evt_data;
#if(NXP_EXTNS == TRUE)
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info = NULL;
#endif
evt_data.rcvd_evt.pipe = p_pipe->pipe_id;
evt_data.rcvd_evt.evt_code = nfa_hci_cb.inst;
evt_data.rcvd_evt.evt_len = data_len;
#if(NXP_EXTNS == TRUE)
if ((p_pipe_cmdrsp_info) && (!p_pipe_cmdrsp_info->reassembly_failed))
{
#else
if (nfa_hci_cb.assembly_failed)
{
#endif
evt_data.rcvd_evt.status = NFA_STATUS_OK;
}
else
{
evt_data.rcvd_evt.status = NFA_STATUS_BUFFER_FULL;
}
evt_data.rcvd_evt.p_evt_buf = p_data;
#if(NXP_EXTNS != TRUE)
nfa_hci_cb.rsp_buf_size = 0;
nfa_hci_cb.p_rsp_buf = NULL;
#endif
/* notify NFA_HCI_EVENT_RCVD_EVT to the application */
nfa_hciu_send_to_app(NFA_HCI_EVENT_RCVD_EVT, &evt_data, p_gate->gate_owner);
}
#if(NXP_EXTNS == TRUE)
/*******************************************************************************
**
** Function nfa_hci_getApduAndConnectivity_PipeStatus
**
** Description API to retrieve APDU & Connectivity pipe created status from
** FirmWare
**
** Returns If NCI command is SUCCESS/FAILED
**
*******************************************************************************/
tNFA_STATUS nfa_hci_getApduAndConnectivity_PipeStatus()
{
tNFA_STATUS status = NFA_STATUS_OK;
uint8_t p_data[NFA_MAX_HCI_CMD_LEN];
uint8_t *p = p_data, *parm_len , *num_param;
memset(p_data, 0, sizeof(p_data));
NCI_MSG_BLD_HDR0 (p, NCI_MT_CMD, NCI_GID_CORE);
NCI_MSG_BLD_HDR1 (p, NCI_MSG_CORE_GET_CONFIG);
parm_len = p++;
num_param = p++;
UINT8_TO_STREAM (p, NXP_NFC_SET_CONFIG_PARAM_EXT);
UINT8_TO_STREAM (p, NXP_NFC_ESE_APDU_PIPE_STATUS);
(*num_param)++;
UINT8_TO_STREAM (p, NXP_NFC_SET_CONFIG_PARAM_EXT);
UINT8_TO_STREAM (p, NXP_NFC_ESE_CONN_PIPE_STATUS);
(*num_param)++;
*parm_len = (p - num_param);
if(*num_param != 0x00)
{
status = nfa_hciu_send_raw_cmd(p-p_data, p_data, nfa_hci_get_pipe_state_cb);
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf
("nfa_hci_getApduConnectivity_PipeStatus %x",*num_param);
return status;
}
/*******************************************************************************
**
** Function nfa_hci_get_pipe_state_cb
**
** Description Callback API to retrieve APDU & Connectivity pipe created
** status from FirmWare
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_get_pipe_state_cb(__attribute__((unused))uint8_t event, __attribute__((unused))uint16_t param_len, __attribute__((unused))uint8_t* p_param)
{
uint8_t num_param_id = 0x00;
uint8_t NFA_PARAM_ID_INDEX = 0x04;
uint8_t param_id1 = 0x00;
uint8_t param_id2 = 0x00;
uint8_t status = 0x00;
nfa_sys_stop_timer (&nfa_hci_cb.timer);
p_param += NFA_PARAM_ID_INDEX;
STREAM_TO_UINT8(num_param_id , p_param);
while(num_param_id > 0x00)
{
STREAM_TO_UINT8(param_id1 , p_param);
STREAM_TO_UINT8(param_id2 , p_param);
p_param++;
STREAM_TO_UINT8(status , p_param);
if(param_id1 == NXP_NFC_SET_CONFIG_PARAM_EXT
&& param_id2 == NXP_NFC_ESE_APDU_PIPE_STATUS)
{
/*Update eSE APDU pipe status*/
if(status == 1)
{
/*UINT8 local_gate, UINT8 pipe_id, UINT8 dest_host, UINT8 dest_gate*/
if(!nfa_hciu_check_pipe_between_gates(NFA_HCI_APDU_APP_GATE, NFA_HCI_FIRST_PROP_HOST,
NFA_HCI_APDU_GATE))
{
nfa_hci_update_pipe_status(NFA_HCI_APDU_GATE, NFA_HCI_APDUESE_PIPE);
if(nfa_hciu_find_gate_by_gid (NFA_HCI_APDU_GATE) == NULL)
{
tNFA_HCI_DYN_GATE *pg;
int xx;
for (xx = 0, pg = nfa_hci_cb.cfg.dyn_gates; xx < NFA_HCI_MAX_GATE_CB; xx++, pg++)
{
if (pg->gate_id == 0)
{
/* Found a free gate control block */
pg->gate_id = NFA_HCI_APDU_GATE;
pg->gate_owner = NFA_HANDLE_GROUP_HCI;
pg->pipe_inx_mask = 0;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf ("nfa_hci_alloc_apdu_gate id:%d app_handle: 0x%04x",
NFA_HCI_APDU_GATE, NFA_HANDLE_GROUP_HCI);
break;
}
}
}
}
}
else
{
nfa_hciu_release_pipe (NFA_HCI_APDUESE_PIPE);
}
}
else if(param_id1 == NXP_NFC_SET_CONFIG_PARAM_EXT
&& param_id2 == NXP_NFC_ESE_CONN_PIPE_STATUS)
{
/*Update eSE Connectivity pipe status*/
if(status == 1)
{
if(!nfa_hciu_check_pipe_between_gates(NFA_HCI_CONNECTIVITY_GATE, NFA_HCI_FIRST_PROP_HOST,
NFA_HCI_CONNECTIVITY_GATE))
{
nfa_hci_update_pipe_status(NFA_HCI_CONNECTIVITY_GATE, NFA_HCI_CONN_ESE_PIPE);
}
}
else
{
nfa_hciu_release_pipe (NFA_HCI_CONN_ESE_PIPE);
}
}
num_param_id--;
}
}
/*******************************************************************************
**
** Function nfa_hci_update_pipe_status
**
** Description API to update APDU & Connectivity pipe hci_cfg status
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_update_pipe_status(uint8_t gateId, uint8_t pipeId)
{
uint8_t count = 0;
nfa_hciu_add_pipe_to_static_gate(gateId, pipeId, NFA_HCI_FIRST_PROP_HOST, gateId);
/*Set the pipe status HCI_OPENED*/
for (count = 0;count < NFA_HCI_MAX_PIPE_CB;count++)
{
if(((nfa_hci_cb.cfg.dyn_pipes[count].dest_host) == NFA_HCI_FIRST_PROP_HOST) &&
((nfa_hci_cb.cfg.dyn_pipes[count].dest_gate) == gateId)
&&((nfa_hci_cb.cfg.dyn_pipes[count].local_gate) == gateId))
{
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf
("Set the pipe state to open -- %d !!!",nfa_hci_cb.cfg.dyn_pipes[count].pipe_id);
nfa_hci_cb.cfg.dyn_pipes[count].pipe_state = NFA_HCI_PIPE_OPENED;
break;
}
}
}
/*******************************************************************************
**
** Function nfa_hci_set_apdu_pipe_ready_for_host
**
** Description Set APDU pipe for specified host ready for sending APDU
** transaction on it
**
** Returns TRUE, if APDU pipe set ready operation is compelete
** FALSE, not ready yet
**
*******************************************************************************/
static bool nfa_hci_set_apdu_pipe_ready_for_host (uint8_t host_id)
{
uint8_t gate_id;
tNFA_HCI_DYN_PIPE *p_id_mgmnt_pipe;
tNFA_HCI_DYN_PIPE *p_apdu_pipe;
if ((p_id_mgmnt_pipe = nfa_hciu_find_id_pipe_for_host (host_id)) == NULL)
{
nfa_hciu_reset_apdu_pipe_registry_info_of_host (host_id);
nfa_hciu_reset_gate_list_of_host (host_id);
nfa_hci_cb.app_in_use = NFA_HCI_APP_HANDLE_NONE;
nfa_hciu_send_create_pipe_cmd (NFA_HCI_ID_MNGMNT_APP_GATE, host_id,
NFA_HCI_IDENTITY_MANAGEMENT_GATE);
}
else
{
if (p_id_mgmnt_pipe->pipe_state == NFA_HCI_PIPE_CLOSED)
{
nfa_hciu_reset_apdu_pipe_registry_info_of_host (host_id);
nfa_hciu_reset_gate_list_of_host (host_id);
nfa_hciu_send_open_pipe_cmd (p_id_mgmnt_pipe->pipe_id);
}
else
{
/* ID Management Pipe in open state */
if ((p_apdu_pipe = nfa_hciu_find_dyn_apdu_pipe_for_host (host_id)) == NULL)
{
/* No APDU Pipe, Check if APDU gate or General Purpose APDU gate exist */
gate_id = nfa_hciu_find_server_apdu_gate_for_host (host_id);
if (gate_id != 0)
{
/* APDU Gate exist with no APDU Pipe on it, create now*/
nfa_hci_cb.app_in_use = NFA_HCI_APP_HANDLE_NONE;
nfa_hciu_send_create_pipe_cmd (NFA_HCI_APDU_APP_GATE,
host_id, gate_id);
}
else
{
/* No APDU/General Purpose APDU Gate exist, Proceed to next UICC host */
return false;
}
}
else
{
/* APDU Pipe exist */
if (p_apdu_pipe->pipe_state == NFA_HCI_PIPE_CLOSED)
{
nfa_hciu_send_open_pipe_cmd (p_apdu_pipe->pipe_id);
}
else
{
return false;
}
}
}
}
return true;
}
/*******************************************************************************
**
** Function nfa_hci_handle_pending_host_reset
**
** Description Find next active UICC/eSE reset pending in the reset cb.
**
** Returns TRUE, if all supported APDU pipes are ready
** FALSE, if at least one APDU pipe is not ready yet
**
*******************************************************************************/
void nfa_hci_handle_pending_host_reset() {
uint8_t xx;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfa_hci_handle_pending_host_reset");
for(xx = 0; xx < NFA_HCI_MAX_HOST_IN_NETWORK; xx++) {
if(nfa_hci_cb.reset_host[xx].reset_cfg & NFCEE_INIT_COMPLETED) {
nfa_hciu_clear_host_resetting(nfa_hci_cb.curr_nfcee, NFCEE_INIT_COMPLETED);
tNFA_HCI_EVT_DATA evt_data;
evt_data.status = NFA_STATUS_OK;
evt_data.rcvd_evt.evt_code = NFA_HCI_EVT_INIT_COMPLETED;
nfa_hciu_send_to_all_apps(NFA_HCI_EVENT_RCVD_EVT, &evt_data);
}
else if(nfa_hci_cb.reset_host[xx].reset_cfg & NFCEE_HCI_NOTIFY_ALL_PIPE_CLEARED) {
nfa_hci_handle_clear_all_pipe_cmd(nfa_hci_cb.reset_host[xx].host_id);
break;
} else if (nfa_hci_cb.reset_host[xx].reset_cfg & NFCEE_UNRECOVERABLE_ERRROR) {
nfa_hci_release_transceive(nfa_hci_cb.reset_host[xx].host_id);
nfa_hci_cb.curr_nfcee = nfa_hci_cb.reset_host[xx].host_id;
nfa_hci_cb.next_nfcee_idx = 0x00;
if(NFC_NfceeDiscover(true) == NFC_STATUS_FAILED) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("NFCEE_UNRECOVERABLE_ERRROR unable to handle");
}
}
break;
}
if(xx == NFA_HCI_MAX_HOST_IN_NETWORK)
nfa_hci_check_pending_api_requests();
}
/*******************************************************************************
**
** Function nfa_hci_check_set_apdu_pipe_ready_for_next_host
**
** Description Find next active UICC/eSE host starting from the specified
** host in the network and Set APDU pipe for specified host
** ready for sending APDU transaction on it
**
** Returns TRUE, if all supported APDU pipes are ready
** FALSE, if at least one APDU pipe is not ready yet
**
*******************************************************************************/
bool nfa_hci_check_set_apdu_pipe_ready_for_next_host ()
{
tNFA_HCI_HOST_INFO *p_host;
bool done = false;
LOG(ERROR) << StringPrintf("nfa_hci_check_set_apdu_pipe_ready_for_next_host %d",
nfa_hci_cb.curr_nfcee);
uint8_t xx;
for(xx = 0; xx < NFA_HCI_MAX_HOST_IN_NETWORK; xx++) {
p_host = &nfa_hci_cb.cfg.host[xx];
if (nfa_hci_cb.curr_nfcee == p_host->host_id) {
nfa_hciu_clear_host_resetting(p_host->host_id, NFCEE_HCI_NOTIFY_ALL_PIPE_CLEARED);
if(p_host->host_id == NFA_HCI_FIRST_PROP_HOST)
nfa_hci_api_add_prop_host_info();
done = nfa_hci_set_apdu_pipe_ready_for_host (p_host->host_id);
break;
}
}
return done;
}
/*******************************************************************************
**
** Function nfa_hci_handle_identity_mngmnt_app_gate_hcp_msg_data
**
** Description This function handles incoming identity management application
** gate hcp packets
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_identity_mgmt_app_gate_hcp_msg_data (uint8_t *p_data, uint16_t data_len,
tNFA_HCI_DYN_PIPE *p_pipe)
{
uint8_t gate_id = 0;
tNFA_HCI_DYN_PIPE *p_apdu_pipe;
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info;
p_pipe_cmdrsp_info = nfa_hciu_get_pipe_cmdrsp_info (p_pipe->pipe_id);
if (p_pipe_cmdrsp_info == NULL)
{
LOG(ERROR) << StringPrintf(
"nfa_hci_handle_identity_mngmnt_app_gate_hcp_msg_data (): Invalid Pipe [0x%02x]",
p_pipe->pipe_id);
return;
}
if (nfa_hci_cb.type == NFA_HCI_RESPONSE_TYPE)
{
p_pipe_cmdrsp_info->w4_cmd_rsp = false;
if (p_pipe_cmdrsp_info->cmd_inst_sent == NFA_HCI_ANY_OPEN_PIPE)
{
p_pipe_cmdrsp_info->cmd_inst_sent = 0;
if (nfa_hci_cb.inst == NFA_HCI_ANY_OK)
{
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
}
/*if (nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_NETWK_ENABLE)
{*/
if (nfa_hci_cb.inst == NFA_HCI_ANY_OK)
{
nfa_hciu_reset_apdu_pipe_registry_info_of_host (p_pipe->dest_host);
nfa_hciu_reset_gate_list_of_host (p_pipe->dest_host);
nfa_hciu_send_get_param_cmd (p_pipe->pipe_id, NFA_HCI_GATES_LIST_INDEX);
return;
}
else
{
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_FAILED);
}
/*
}
else
{
nfa_hci_startup_complete (NFA_STATUS_FAILED);
}*/
}
else if (p_pipe_cmdrsp_info->cmd_inst_sent == NFA_HCI_ANY_GET_PARAMETER)
{
p_pipe_cmdrsp_info->cmd_inst_sent = 0;
if (p_pipe_cmdrsp_info->cmd_inst_param_sent == NFA_HCI_GATES_LIST_INDEX)
{
p_pipe_cmdrsp_info->cmd_inst_param_sent = 0;
/*if (nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_NETWK_ENABLE)
{*/
if (nfa_hci_cb.inst == NFA_HCI_ANY_OK)
{
nfa_hciu_update_gate_list_of_host (p_pipe->dest_host, (uint8_t) data_len, p_data);
/* Check if Dynamic APDU pipe exist for the host */
if ((p_apdu_pipe = nfa_hciu_find_dyn_apdu_pipe_for_host (p_pipe->dest_host)) == NULL)
{
/* No APDU Pipe exist, check if APDU gate or General Purpose APDU gate exist */
gate_id = nfa_hciu_find_server_apdu_gate_for_host (p_pipe->dest_host);
if (gate_id != 0)
{
/* APDU Gate exist with no APDU Pipe on it, create now*/
nfa_hci_cb.app_in_use = NFA_HCI_APP_HANDLE_NONE;
nfa_hciu_send_create_pipe_cmd (NFA_HCI_APDU_APP_GATE,
p_pipe->dest_host, gate_id);
}
else
{
/* No APDU/General Purpose APDU Gate exist, check next one */
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_OK);
}
}
else
{
/* APDU Pipe exist */
if (p_apdu_pipe->pipe_state == NFA_HCI_PIPE_CLOSED)
{
/* APDU Pipe is in closed state, Open it */
nfa_hciu_send_open_pipe_cmd (p_apdu_pipe->pipe_id);
return;
}
else
{
/* APDU Pipe for this host is already open, Move to next one */
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_OK);
}
}
}
else
{
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_FAILED);
}
// }
}
}
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_apdu_app_gate_hcp_msg_data
**
** Description This function handles incoming APDU application gate hcp
**
** Returns none
**
*******************************************************************************/
static void nfa_hci_handle_apdu_app_gate_hcp_msg_data (uint8_t *p_data, uint16_t data_len,
tNFA_HCI_DYN_PIPE *p_pipe)
{
uint8_t cmd_inst_param;
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info;
tNFA_HCI_APDU_PIPE_REG_INFO *p_apdu_pipe_reg_info;
p_pipe_cmdrsp_info = nfa_hciu_get_pipe_cmdrsp_info (p_pipe->pipe_id);
p_apdu_pipe_reg_info = nfa_hciu_find_apdu_pipe_registry_info_for_host (p_pipe->dest_host);
if (p_pipe_cmdrsp_info == NULL)
{
LOG(ERROR) << StringPrintf("nfa_hci_handle_apdu_app_gate_hcp_msg_data (): Invalid Pipe [0x%02x]",
p_pipe->pipe_id);
return;
}
if (p_apdu_pipe_reg_info == NULL)
{
LOG(ERROR) << StringPrintf ("nfa_hci_handle_apdu_app_gate_hcp_msg_data (): Invalid host [0x%02x]",
p_pipe->dest_host);
return;
}
/* Check if data packet is a command, response or event */
if (nfa_hci_cb.type == NFA_HCI_COMMAND_TYPE)
{
/* Just incase if server host close and open the APDU Pipe */
switch (nfa_hci_cb.inst)
{
case NFA_HCI_ANY_OPEN_PIPE:
nfa_hciu_reset_apdu_pipe_registry_info_of_host (p_pipe->dest_host);
/* Set flag to indicate waiting for ETSI_HCI_EVT_ATR */
p_pipe_cmdrsp_info->w4_atr_evt = true;
case NFA_HCI_ANY_CLOSE_PIPE:
nfa_hci_handle_pipe_open_close_cmd (p_pipe);
break;
default:
nfa_hciu_send_msg (p_pipe->pipe_id, NFA_HCI_RESPONSE_TYPE,
NFA_HCI_ANY_E_CMD_NOT_SUPPORTED, 0, NULL);
break;
}
}
else if (nfa_hci_cb.type == NFA_HCI_RESPONSE_TYPE)
{
p_pipe_cmdrsp_info->w4_cmd_rsp = false;
if (p_pipe_cmdrsp_info->cmd_inst_sent == NFA_HCI_ANY_OPEN_PIPE)
{
p_pipe_cmdrsp_info->cmd_inst_sent = 0;
if (nfa_hci_cb.inst == NFA_HCI_ANY_OK)
{
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
/* Set flag to indicate waiting for ETSI_HCI_EVT_ATR */
p_pipe_cmdrsp_info->w4_atr_evt = true;
nfa_hci_cb.nv_write_needed = true;
}
//if (nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_NETWK_ENABLE)
{
if (nfa_hci_cb.inst == NFA_HCI_ANY_OK)
{
/* Read Registry */
nfa_hciu_send_get_param_cmd (p_pipe->pipe_id, NFA_HCI_MAX_C_APDU_SIZE_INDEX);
}
else
{
/* Check APDU Pipe for next UICC host */
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_OK);
}
}
}
else if (p_pipe_cmdrsp_info->cmd_inst_sent == NFA_HCI_ANY_GET_PARAMETER)
{
cmd_inst_param = p_pipe_cmdrsp_info->cmd_inst_param_sent;
p_pipe_cmdrsp_info->cmd_inst_sent = 0;
p_pipe_cmdrsp_info->cmd_inst_param_sent = 0;
/* Only in NFA_HCI_STATE_W4_NETWK_ENABLE state, the registries are read */
if (nfa_hci_cb.inst == NFA_HCI_ANY_OK)
{
if (cmd_inst_param == NFA_HCI_MAX_C_APDU_SIZE_INDEX)
{
STREAM_TO_UINT16 (p_apdu_pipe_reg_info->max_cmd_apdu_size, p_data);
nfa_hciu_send_get_param_cmd (p_pipe->pipe_id, NFA_HCI_MAX_WAIT_TIME_INDEX);
}
else if (cmd_inst_param == NFA_HCI_MAX_WAIT_TIME_INDEX)
{
STREAM_TO_UINT16 (p_apdu_pipe_reg_info->max_wait_time, p_data);
p_apdu_pipe_reg_info->reg_info_valid = true;
if(p_pipe->dest_host == 0xC0)
{
if(nfcFL.eseFL._NCI_NFCEE_PWR_LINK_CMD)
NFC_NfceePLConfig(p_pipe->dest_host, 0x01);
}
if (!nfa_hci_enable_one_nfcee ())
{
nfa_hci_startup_complete (NFA_STATUS_OK);
}
}
}
else
{
if (!nfa_hci_enable_one_nfcee ())
nfa_hci_startup_complete (NFA_STATUS_OK);
}
}
}
else if (nfa_hci_cb.type == NFA_HCI_EVENT_TYPE)
{
LOG(ERROR) << StringPrintf("nfa_hci_handle_apdu_app_gate_hcp_msg_data (): nfa_hci_cb.inst: %x",
nfa_hci_cb.inst);//debug
switch (nfa_hci_cb.inst)
{
case NFA_HCI_EVT_R_APDU:
if (p_pipe_cmdrsp_info->w4_rsp_apdu_evt)
{
/* Waiting for Response APDU */
p_pipe_cmdrsp_info->w4_rsp_apdu_evt = false;
evt_data.apdu_rcvd.host_id = p_pipe->dest_host;
evt_data.apdu_rcvd.apdu_len = data_len;
if (!p_pipe_cmdrsp_info->reassembly_failed)
{
evt_data.apdu_rcvd.status = NFA_STATUS_OK;
}
else
{
evt_data.apdu_rcvd.status = NFA_STATUS_BUFFER_FULL;
}
evt_data.apdu_rcvd.p_apdu = p_data;
/* notify NFA_HCI_RSP_APDU_RCVD_EVT to app that is waiting for response APDU */
nfa_hciu_send_to_app (NFA_HCI_RSP_APDU_RCVD_EVT, &evt_data,
p_pipe_cmdrsp_info->pipe_user);
p_pipe_cmdrsp_info->p_rsp_buf = NULL;
p_pipe_cmdrsp_info->rsp_buf_size = 0;
nfa_hci_cb.m_wtx_count = 0;
/* Release the temporary ownership for APDU Pipe given to the App */
p_pipe_cmdrsp_info->pipe_user = NFA_HCI_APP_HANDLE_NONE;
}
break;
case NFA_HCI_EVT_WTX:
if (p_pipe_cmdrsp_info->w4_rsp_apdu_evt ||
p_pipe_cmdrsp_info->w4_atr_evt)
{
if(p_nfa_hci_cfg->max_wtx_count) {
if(nfa_hci_cb.m_wtx_count >= p_nfa_hci_cfg->max_wtx_count) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("%s: Max WTX count reached",__func__);
nfa_hci_cb.m_wtx_count = 0;
if(p_pipe_cmdrsp_info->w4_rsp_apdu_evt) {
evt_data.apdu_rcvd.apdu_len = 0;
evt_data.apdu_rcvd.p_apdu = NULL;
evt_data.apdu_rcvd.status = NFA_STATUS_HCI_WTX_TIMEOUT;
nfa_hciu_send_to_app (NFA_HCI_RSP_APDU_RCVD_EVT, &evt_data,
p_pipe_cmdrsp_info->pipe_user);
} else if(p_pipe_cmdrsp_info->w4_atr_evt) {
evt_data.apdu_aborted.atr_len = 0;
evt_data.apdu_aborted.status = NFA_STATUS_HCI_WTX_TIMEOUT;
evt_data.apdu_aborted.host_id = p_pipe->dest_host;
p_pipe_cmdrsp_info->w4_atr_evt = false;
/* notify NFA_HCI_APDU_ABORTED_EVT to app that requested to ABORT command APDU */
nfa_hciu_send_to_app (NFA_HCI_APDU_ABORTED_EVT, &evt_data,
p_pipe_cmdrsp_info->pipe_user);
}
return;
}
else
{
nfa_hci_cb.m_wtx_count++;
}
}
/* More processing time needed for APDU sent to UICC */
nfa_sys_start_timer (&(p_pipe_cmdrsp_info->rsp_timer),
NFA_HCI_RSP_TIMEOUT_EVT, p_pipe_cmdrsp_info->rsp_timeout);
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_handle_apdu_app_gate_hcp_msg_data ()p_pipe_cmdrsp_info->rsp_timeout %x",p_pipe_cmdrsp_info->rsp_timeout);//debug
}
break;
case NFA_HCI_EVT_ATR:
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_handle_apdu_app_gate_hcp_msg_data (): EVT_ATR_RSP recived w4_atr_evt: %x p_pipe_cmdrsp_info->w4_rsp_apdu_evt: %x",p_pipe_cmdrsp_info->w4_atr_evt, p_pipe_cmdrsp_info->w4_rsp_apdu_evt);//debug
if (p_pipe_cmdrsp_info->w4_rsp_apdu_evt || p_pipe_cmdrsp_info->w4_atr_evt)
{
p_pipe_cmdrsp_info->w4_rsp_apdu_evt = false;
evt_data.apdu_aborted.atr_len = data_len;
evt_data.apdu_aborted.p_atr = p_data;
evt_data.apdu_aborted.status = NFA_STATUS_OK;
evt_data.apdu_aborted.host_id = p_pipe->dest_host;
/* notify NFA_HCI_APDU_ABORTED_EVT to app that requested to ABORT command APDU */
nfa_hciu_send_to_app (NFA_HCI_APDU_ABORTED_EVT, &evt_data,
p_pipe_cmdrsp_info->pipe_user);
if(nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_RSP)
nfa_hci_cb.hci_state = NFA_HCI_STATE_IDLE;
if (p_pipe_cmdrsp_info->rsp_buf_size)
{
p_pipe_cmdrsp_info->rsp_buf_size = 0;
p_pipe_cmdrsp_info->p_rsp_buf = NULL;
}
/* Release the temporary ownership for APDU Pipe given to the App */
p_pipe_cmdrsp_info->pipe_user = NFA_HCI_APP_HANDLE_NONE;
}
p_pipe_cmdrsp_info->w4_atr_evt = false;
break;
default:
/* Invalid Event, just drop */
break;
}
}
}
/*******************************************************************************
**
** Function nfa_hci_api_send_apdu
**
** Description action function to send command APDU on APDU pipe
**
** Returns TRUE, if the command APDU is processed
** FALSE, if event is queued for processing later
**
*******************************************************************************/
static bool nfa_hci_api_send_apdu (tNFA_HCI_EVENT_DATA *p_evt_data)
{
uint8_t pipe_id= 0;;
uint8_t evt_code;
uint32_t max_wait_time = NFA_HCI_EVT_SW_PROC_LATENCY;
tNFC_STATUS status = NFA_STATUS_FAILED;
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_DYN_PIPE *p_pipe;
tNFA_HCI_PIPE_STATE pipe_state;
tNFA_HCI_API_SEND_APDU_EVT *p_send_apdu = (tNFA_HCI_API_SEND_APDU_EVT*)&p_evt_data->send_evt;
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info = NULL;
tNFA_HCI_APDU_PIPE_REG_INFO *p_apdu_pipe_reg_info = NULL;
if (nfa_hciu_is_active_host (p_send_apdu->host_id))
{
if (nfa_hciu_is_host_reseting (p_send_apdu->host_id))
{
GKI_enqueue (&nfa_hci_cb.hci_host_reset_api_q, (NFC_HDR *) p_evt_data);
return FALSE;
}
if ((p_pipe = nfa_hciu_find_dyn_apdu_pipe_for_host (p_send_apdu->host_id)) != NULL)
{
pipe_id = p_pipe->pipe_id;
pipe_state = p_pipe->pipe_state;
evt_code = NFA_HCI_EVT_C_APDU;
} else
{
LOG(ERROR) << StringPrintf("nfa_hci_api_send_apdu (): Pipe [0x%02x] Info not available", pipe_id);
}
if (pipe_id != NFA_HCI_INVALID_PIPE)
{
p_pipe_cmdrsp_info = nfa_hciu_get_pipe_cmdrsp_info (pipe_id);
p_apdu_pipe_reg_info = nfa_hciu_find_apdu_pipe_registry_info_for_host (p_send_apdu->host_id);
}
if ( (p_pipe_cmdrsp_info == NULL)
||(p_apdu_pipe_reg_info == NULL) )
{
LOG(ERROR) << StringPrintf("nfa_hci_api_send_apdu (): Pipe [0x%02x] Info not available", pipe_id);
evt_data.apdu_rcvd.host_id = p_send_apdu->host_id;
evt_data.apdu_rcvd.apdu_len = 0;
evt_data.apdu_rcvd.status = NFA_STATUS_FAILED;
evt_data.apdu_rcvd.p_apdu = NULL;
nfa_hciu_send_to_app (NFA_HCI_RSP_APDU_RCVD_EVT, &evt_data,
p_send_apdu->hci_handle);
}
else if (pipe_state != NFA_HCI_PIPE_OPENED)
{
LOG(ERROR) << StringPrintf("nfa_hci_api_send_apdu (): APDU Pipe[0x%02x] is closed", pipe_id);
evt_data.apdu_rcvd.host_id = p_send_apdu->host_id;
evt_data.apdu_rcvd.apdu_len = 0;
evt_data.apdu_rcvd.status = NFA_STATUS_FAILED;
evt_data.apdu_rcvd.p_apdu = NULL;
nfa_hciu_send_to_app (NFA_HCI_RSP_APDU_RCVD_EVT, &evt_data,
p_send_apdu->hci_handle);
}
else if (p_pipe_cmdrsp_info->w4_atr_evt)
{
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_api_send_apdu (): APDU Server is not initialized yet! sending failed to upper layer");
evt_data.apdu_rcvd.host_id = p_send_apdu->host_id;
evt_data.apdu_rcvd.apdu_len = 0;
evt_data.apdu_rcvd.status = NFA_STATUS_FAILED;
evt_data.apdu_rcvd.p_apdu = NULL;
nfa_hciu_send_to_app (NFA_HCI_RSP_APDU_RCVD_EVT, &evt_data,
p_send_apdu->hci_handle);
}
else if (p_pipe_cmdrsp_info->w4_rsp_apdu_evt)
{
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_api_send_apdu (): APDU Pipe[0x%02x] is busy!", pipe_id);
}
// else if ( (p_apdu_pipe_reg_info->reg_info_valid)
// &&(p_send_apdu->cmd_apdu_len > p_apdu_pipe_reg_info->max_cmd_apdu_size) )
// {
// NFA_TRACE_WARNING1 ("nfa_hci_api_send_apdu (): APDU cannot exceed [0x%04x] bytes",
// p_apdu_pipe_reg_info->max_cmd_apdu_size);
// }
else
{
/* Send Command APDU on APDU pipe */
status = nfa_hciu_send_msg (pipe_id, NFA_HCI_EVENT_TYPE, evt_code,
p_send_apdu->cmd_apdu_len,
p_send_apdu->p_cmd_apdu);
if (status == NFA_STATUS_OK)
{
/* Response APDU is expected */
p_pipe_cmdrsp_info->w4_rsp_apdu_evt = true;
nfa_hci_cb.hci_state = NFA_HCI_STATE_WAIT_RSP;
/* Remember the app that is sending Command APDU on
** the pipe for routing the response APDU later to it
*/
p_pipe_cmdrsp_info->pipe_user = p_send_apdu->hci_handle;
p_pipe_cmdrsp_info->rsp_timeout = p_send_apdu->rsp_timeout;
max_wait_time += p_send_apdu->rsp_timeout;
/* Response APDU/ETSI_HCI_EVT_WTX is expected
** within specified interval of time */
nfa_sys_start_timer (&(p_pipe_cmdrsp_info->rsp_timer),
NFA_HCI_RSP_TIMEOUT_EVT,
max_wait_time);
LOG(ERROR) << StringPrintf ("nfa_hci_api_send_apdu (): Wait time[0x%02x]",
max_wait_time);
p_pipe_cmdrsp_info->rsp_buf_size = p_send_apdu->rsp_apdu_buf_size;
p_pipe_cmdrsp_info->p_rsp_buf = p_send_apdu->p_rsp_apdu_buf;
}
else
{
LOG(ERROR) << StringPrintf ("nfa_hci_api_send_apdu (): Sending APDU on Pipe[0x%02x] failed",
pipe_id);
}
}
}
else
{
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_api_send_apdu (): Host[0x%02x] inactive", p_send_apdu->host_id);
}
return true;
}
/*******************************************************************************
**
** Function nfa_hci_api_abort_apdu
**
** Description action function to abort APDU commad
**
** Returns TRUE, if the abort APDU is processed
** FALSE, if event is queued for processing later
**
*******************************************************************************/
static bool nfa_hci_api_abort_apdu (tNFA_HCI_EVENT_DATA *p_evt_data)
{
NFC_HDR *p_msg;
uint8_t pipe_id = 0;;
tNFC_STATUS status = NFA_STATUS_FAILED;
bool send_abort_ntf = FALSE;
bool apdu_dropped = FALSE;
bool host_reseting = FALSE;
tNFA_HCI_EVT_DATA evt_data;
tNFA_HCI_DYN_PIPE *p_pipe;
tNFA_HCI_PIPE_STATE pipe_state;
tNFA_HCI_EVENT_DATA *p_queue_evt_data;
tNFA_HCI_API_ABORT_APDU_EVT *p_abort_apdu = &p_evt_data->abort_apdu;
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info = NULL;
tNFA_HCI_APDU_PIPE_REG_INFO *p_apdu_pipe_reg_info = NULL;
host_reseting = nfa_hciu_is_host_reseting (p_abort_apdu->host_id);
if (host_reseting)
{
/* Host reset will automatically abort the APDU Command if it was sent on the APDU
** pipe and so no need to send ABORT_EVT on the APDU pipe. If the APDU Command is
** not yet sent but waiting in hci_host_reset_api_q queue to be sent then just
** flush the command from the queue so it will never be sent
*/
p_msg = (NFC_HDR *) GKI_getfirst (&nfa_hci_cb.hci_host_reset_api_q);
while (p_msg != NULL)
{
/* Check if the buffered API request is for Sending APDU command */
if (p_msg->event == NFA_HCI_API_SEND_APDU_EVT)
{
p_queue_evt_data = (tNFA_HCI_EVENT_DATA *) p_msg;
if ( (p_queue_evt_data->send_apdu.hci_handle == p_abort_apdu->hci_handle)
&&(p_queue_evt_data->send_apdu.host_id == p_abort_apdu->host_id) )
{
/* It is the same app that sent the APDU command is now requesting it to abort */
GKI_remove_from_queue (&nfa_hci_cb.hci_host_reset_api_q, p_msg);
GKI_freebuf (p_msg);
apdu_dropped = true;
break;
}
}
p_msg = (NFC_HDR *) GKI_getnext (p_msg);
}
}
if ((p_pipe = nfa_hciu_find_dyn_apdu_pipe_for_host (p_abort_apdu->host_id)) != NULL)
{
/* APDU pipe on APDU gate/APDU Generic purpose gate */
pipe_id = p_pipe->pipe_id;
pipe_state = p_pipe->pipe_state;
if (!host_reseting && p_pipe->dest_gate == NFA_HCI_APDU_GATE)
{
/* To send Abort event on the APDU pipe */
send_abort_ntf = TRUE;
}
}
if (pipe_id != NFA_HCI_INVALID_PIPE)
{
p_pipe_cmdrsp_info = nfa_hciu_get_pipe_cmdrsp_info (pipe_id);
p_apdu_pipe_reg_info = nfa_hciu_find_apdu_pipe_registry_info_for_host (p_abort_apdu->host_id);
}
if ( (p_pipe_cmdrsp_info == NULL)
||(p_apdu_pipe_reg_info == NULL) )
{
LOG(ERROR) << StringPrintf ("nfa_hci_api_abort_apdu (): Pipe [0x%02x] Info not available", pipe_id);
}
else if (pipe_state != NFA_HCI_PIPE_OPENED)
{
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_api_abort_apdu (): APDU Pipe[0x%02x] is closed", pipe_id);
}
#if 0
else if ( (!apdu_dropped)
&&( (!p_pipe_cmdrsp_info->w4_rsp_apdu_evt)
||(p_pipe_cmdrsp_info->pipe_user != p_abort_apdu->hci_handle) ) )
{
NFA_TRACE_WARNING1 ("nfa_hci_api_abort_apdu(): No APDU sent by app on Pipe[0x%02x]",
pipe_id);
}
#endif
else if (p_pipe_cmdrsp_info->msg_rx_len > 0)
{
/* Too late to Abort command-APDU as one or more fragment of response APDU is already
** received. NFA_HCI_RSP_APDU_RCVD_EVT will be reported after all fragments of response
** APDU is received or on timeout. Now, report Abort operation failed
*/
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_api_abort_apdu(): Too late to Abort as C-APDU is processed");
}
else
{
/* No response APDU is received, release Rsp APDU buffer so that if any
** Rsp APDU is received later for the command APDU sent, it will be dropped
*/
p_pipe_cmdrsp_info->p_rsp_buf = NULL;
p_pipe_cmdrsp_info->pipe_user = p_abort_apdu->hci_handle;
p_pipe_cmdrsp_info->rsp_buf_size = 0;
p_pipe_cmdrsp_info->w4_rsp_apdu_evt = false;
/* Stop timer that was started to wait for Response APDU */
nfa_sys_stop_timer (&(p_pipe_cmdrsp_info->rsp_timer));
if (send_abort_ntf)
{
/* APDU sent on APDU pipe connected to APDU Gate, Send ABORT event on the APDU pipe */
status = nfa_hciu_send_msg (pipe_id, NFA_HCI_EVENT_TYPE, NFA_HCI_EVT_ABORT, 0, 0);
if (status == NFA_STATUS_OK)
{
/* Restart timer to wait for EVT_ATR for the EVT_ABORT sent */
p_pipe_cmdrsp_info->rsp_timeout = p_abort_apdu->rsp_timeout;
nfa_sys_start_timer (&(p_pipe_cmdrsp_info->rsp_timer),
NFA_HCI_RSP_TIMEOUT_EVT,
(p_abort_apdu->rsp_timeout + NFA_HCI_EVT_SW_PROC_LATENCY));
/* EVT_ATR is expected */
p_pipe_cmdrsp_info->w4_atr_evt = true;
return true;
}
}
else
{
/* APDU sent on APDU pipe connected to general purpose APDU gate/static APDU pipe
** (or) APDU is dropped before it was sent on APDU pipe
*/
status = NFA_STATUS_OK;
}
}
evt_data.apdu_aborted.atr_len = 0x00;
evt_data.apdu_aborted.p_atr = NULL;
evt_data.apdu_aborted.status = status;
evt_data.apdu_aborted.host_id = p_abort_apdu->host_id;
/* Send NFA_HCI_APDU_ABORTED_EVT to notify status */
nfa_hciu_send_to_app (NFA_HCI_APDU_ABORTED_EVT, &evt_data, p_abort_apdu->hci_handle);
return true;
}
/*******************************************************************************
**
** Function nfa_hci_api_add_prop_host_info
**
** Description This api is used to fill data for eSE.
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_api_add_prop_host_info ()
{
uint8_t NFA_HCI_PROP_HOST_GATE_LIST[] = {NFA_HCI_CARD_RF_A_GATE, NFA_HCI_LOOP_BACK_GATE,
NFA_HCI_IDENTITY_MANAGEMENT_GATE, NFA_HCI_APDU_GATE};
if ((!nfa_hciu_check_pipe_between_gates(NFA_HCI_ID_MNGMNT_APP_GATE, NFA_HCI_FIRST_PROP_HOST,
NFA_HCI_IDENTITY_MANAGEMENT_GATE))) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf ("nfa_hci_api_add_prop_host_info");
nfa_hciu_add_pipe_to_gate(NFA_HCI_DEFAULT_ID_MANAGEMENT_PIPE, NFA_HCI_ID_MNGMNT_APP_GATE, NFA_HCI_FIRST_PROP_HOST,
NFA_HCI_IDENTITY_MANAGEMENT_GATE);
tNFA_HCI_DYN_PIPE* p_pipe = nfa_hciu_find_pipe_by_pid(NFA_HCI_DEFAULT_ID_MANAGEMENT_PIPE);
if(p_pipe)
{
p_pipe->pipe_state = NFA_HCI_PIPE_OPENED;
nfa_hciu_reset_apdu_pipe_registry_info_of_host (p_pipe->dest_host);
nfa_hciu_update_gate_list_of_host (p_pipe->dest_host, sizeof(NFA_HCI_PROP_HOST_GATE_LIST), NFA_HCI_PROP_HOST_GATE_LIST);
}
}
}
/*******************************************************************************
**
** Function nfa_hci_handle_clear_all_pipe_cmd
**
** Description handle clear all pipe cmd from host
**
** Returns None
**
*******************************************************************************/
static void nfa_hci_handle_clear_all_pipe_cmd(uint8_t source_host) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_hci_handle_clear_all_pipe_cmd pipe:%d source host",source_host);
tNFA_HCI_DYN_PIPE *p_pipe = NULL;
tNFA_HCI_PIPE_CMDRSP_INFO *p_pipe_cmdrsp_info = NULL;
tNFA_STATUS status = NFA_STATUS_FAILED;
nfa_hciu_add_host_resetting(source_host, NFCEE_HCI_NOTIFY_ALL_PIPE_CLEARED);
if(nfa_hci_cb.hci_state == NFA_HCI_STATE_WAIT_RSP ||
nfa_hci_cb.hci_state == NFA_HCI_STATE_IDLE) {
if(nfa_hci_cb.w4_rsp_evt == true)
nfa_sys_stop_timer(&nfa_hci_cb.timer);
if ((p_pipe = nfa_hciu_find_dyn_apdu_pipe_for_host (source_host)) != NULL) {
p_pipe_cmdrsp_info = nfa_hciu_get_pipe_cmdrsp_info (p_pipe->pipe_id);
if(p_pipe_cmdrsp_info != NULL) {
if (p_pipe_cmdrsp_info->w4_atr_evt)
nfa_sys_stop_timer(&p_pipe_cmdrsp_info->rsp_timer);
else if (p_pipe_cmdrsp_info->w4_rsp_apdu_evt || p_pipe_cmdrsp_info->w4_cmd_rsp)
nfa_sys_stop_timer(&p_pipe_cmdrsp_info->rsp_timer);
}
}
/*nfa_hci_cb.hci_state = NFA_HCI_STATE_WAIT_NETWK_ENABLE;*/
nfa_hciu_remove_all_pipes_from_host(source_host);
/*Trigger pipe creation*/
nfa_hci_cb.curr_nfcee = source_host;
if(source_host == 0xC0)
{
if(nfcFL.eseFL._NCI_NFCEE_PWR_LINK_CMD)
NFC_NfceePLConfig(source_host, 0x03);
}
status = NFC_NfceeModeSet(source_host, NFC_MODE_ACTIVATE);
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_hci_handle_clear_all_pipe_cmd pipe:%d source host",status);
if(status == NFA_STATUS_REFUSED) {
/*Mode set ntf pending , pipe will be created on recieving ntf*/
} else if (status != NFA_STATUS_OK) {
nfa_hciu_clear_host_resetting(nfa_hci_cb.curr_nfcee, NFCEE_HCI_NOTIFY_ALL_PIPE_CLEARED);
if(!nfa_hci_check_set_apdu_pipe_ready_for_next_host ()) {
nfa_hci_handle_pending_host_reset();
}
}
}
else {
nfa_hciu_remove_all_pipes_from_host(source_host);
}
}
#endif