/******************************************************************************
*
* Copyright (C) 2011-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.
*
******************************************************************************/
/******************************************************************************
*
* This file contains the action functions the NFA_CE state machine.
*
******************************************************************************/
#include <string.h>
#include <android-base/stringprintf.h>
#include <base/logging.h>
#include "ce_api.h"
#include "ndef_utils.h"
#include "nfa_ce_int.h"
#include "nfa_mem_co.h"
#if (NFC_NFCEE_INCLUDED == TRUE)
#include "nfa_ee_int.h"
#endif
using android::base::StringPrintf;
extern bool nfc_debug_enabled;
/*****************************************************************************
* Protocol-specific event handlers
*****************************************************************************/
/*******************************************************************************
**
** Function nfa_ce_handle_t3t_evt
**
** Description Handler for Type-3 tag card emulation events
**
** Returns Nothing
**
*******************************************************************************/
void nfa_ce_handle_t3t_evt(tCE_EVENT event, tCE_DATA* p_ce_data) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA conn_evt;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ce_handle_t3t_evt: event 0x%x", event);
/* For the felica on host for nfcFcallback */
for (uint8_t idx = 0; idx < NFA_CE_LISTEN_INFO_IDX_INVALID; idx++) {
if ((p_cb->listen_info[idx].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[idx].flags & NFA_CE_LISTEN_INFO_FELICA) &&
(p_cb->listen_info[idx].flags & NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND)) {
p_cb->idx_cur_active = idx;
p_cb->p_active_conn_cback =
p_cb->listen_info[p_cb->idx_cur_active].p_conn_cback;
break;
}
}
switch (event) {
case CE_T3T_NDEF_UPDATE_START_EVT:
/* Notify app using callback associated with the active ndef */
if (p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) {
conn_evt.status = NFA_STATUS_OK;
(*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_START_EVT, &conn_evt);
} else {
LOG(ERROR) << StringPrintf(
"nfa_ce_handle_t3t_evt: got CE_T3T_UPDATE_START_EVT, but no active "
"NDEF");
}
break;
case CE_T3T_NDEF_UPDATE_CPLT_EVT:
/* Notify app using callback associated with the active ndef */
if (p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) {
conn_evt.ndef_write_cplt.status = NFA_STATUS_OK;
conn_evt.ndef_write_cplt.len = p_ce_data->update_info.length;
conn_evt.ndef_write_cplt.p_data = p_ce_data->update_info.p_data;
(*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_CPLT_EVT, &conn_evt);
} else {
LOG(ERROR) << StringPrintf(
"nfa_ce_handle_t3t_evt: got CE_T3T_UPDATE_CPLT_EVT, but no active "
"NDEF");
}
break;
case CE_T3T_RAW_FRAME_EVT:
if (p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) {
conn_evt.data.status = p_ce_data->raw_frame.status;
conn_evt.data.p_data = (uint8_t*)(p_ce_data->raw_frame.p_data + 1) +
p_ce_data->raw_frame.p_data->offset;
conn_evt.data.len = p_ce_data->raw_frame.p_data->len;
(*p_cb->p_active_conn_cback)(NFA_DATA_EVT, &conn_evt);
} else {
/* If we have not notified the app of activation, do so now */
if (p_cb->listen_info[p_cb->idx_cur_active].flags &
NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND) {
p_cb->listen_info[p_cb->idx_cur_active].flags &=
~NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND;
conn_evt.ce_activated.handle =
NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);
memcpy(&(conn_evt.ce_activated.activate_ntf),
&p_cb->activation_params, sizeof(tNFC_ACTIVATE_DEVT));
conn_evt.ce_activated.status = NFA_STATUS_OK;
(*p_cb->p_active_conn_cback)(NFA_CE_ACTIVATED_EVT, &conn_evt);
}
/* Notify app of t3t raw data */
conn_evt.ce_data.status = p_ce_data->raw_frame.status;
conn_evt.ce_data.handle =
(NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active));
conn_evt.ce_data.p_data = (uint8_t*)(p_ce_data->raw_frame.p_data + 1) +
p_ce_data->raw_frame.p_data->offset;
conn_evt.ce_data.len = p_ce_data->raw_frame.p_data->len;
(*p_cb->p_active_conn_cback)(NFA_CE_DATA_EVT, &conn_evt);
}
GKI_freebuf(p_ce_data->raw_frame.p_data);
break;
default:
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ce_handle_t3t_evt unhandled event=0x%02x", event);
break;
}
}
/*******************************************************************************
**
** Function nfa_ce_handle_t4t_evt
**
** Description Handler for Type-4 tag card emulation events (for NDEF case)
**
** Returns Nothing
**
*******************************************************************************/
void nfa_ce_handle_t4t_evt(tCE_EVENT event, tCE_DATA* p_ce_data) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA conn_evt;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ce_handle_t4t_evt: event 0x%x", event);
/* AID for NDEF selected. we had notified the app of activation. */
p_cb->idx_cur_active = NFA_CE_LISTEN_INFO_IDX_NDEF;
if (p_cb->listen_info[p_cb->idx_cur_active].flags &
NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND) {
p_cb->p_active_conn_cback =
p_cb->listen_info[p_cb->idx_cur_active].p_conn_cback;
}
switch (event) {
case CE_T4T_NDEF_UPDATE_START_EVT:
conn_evt.status = NFA_STATUS_OK;
(*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_START_EVT, &conn_evt);
break;
case CE_T4T_NDEF_UPDATE_CPLT_EVT:
conn_evt.ndef_write_cplt.len = p_ce_data->update_info.length;
conn_evt.ndef_write_cplt.p_data = p_ce_data->update_info.p_data;
if (NDEF_MsgValidate(p_ce_data->update_info.p_data,
p_ce_data->update_info.length, true) != NDEF_OK)
conn_evt.ndef_write_cplt.status = NFA_STATUS_FAILED;
else
conn_evt.ndef_write_cplt.status = NFA_STATUS_OK;
(*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_CPLT_EVT, &conn_evt);
break;
case CE_T4T_NDEF_UPDATE_ABORT_EVT:
conn_evt.ndef_write_cplt.len = 0;
conn_evt.ndef_write_cplt.status = NFA_STATUS_FAILED;
conn_evt.ndef_write_cplt.p_data = NULL;
(*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_CPLT_EVT, &conn_evt);
break;
default:
/* CE_T4T_RAW_FRAME_EVT is not used in NFA CE */
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ce_handle_t4t_evt unhandled event=0x%02x", event);
break;
}
}
/*******************************************************************************
**
** Function nfa_ce_handle_t4t_aid_evt
**
** Description Handler for Type-4 tag AID events (for AIDs registered using
** NFA_CeRegisterT4tAidOnDH)
**
** Returns Nothing
**
*******************************************************************************/
void nfa_ce_handle_t4t_aid_evt(tCE_EVENT event, tCE_DATA* p_ce_data) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
uint8_t listen_info_idx;
tNFA_CONN_EVT_DATA conn_evt;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ce_handle_t4t_aid_evt: event 0x%x", event);
/* Get listen_info for this aid callback */
for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_IDX_INVALID;
listen_info_idx++) {
if ((p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_T4T_AID) &&
(p_cb->listen_info[listen_info_idx].t4t_aid_handle ==
p_ce_data->raw_frame.aid_handle)) {
p_cb->idx_cur_active = listen_info_idx;
p_cb->p_active_conn_cback =
p_cb->listen_info[p_cb->idx_cur_active].p_conn_cback;
break;
}
}
if (event == CE_T4T_RAW_FRAME_EVT) {
if (listen_info_idx != NFA_CE_LISTEN_INFO_IDX_INVALID) {
/* Found listen_info entry */
conn_evt.ce_activated.handle =
NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);
/* If we have not notified the app of activation, do so now */
if (p_cb->listen_info[p_cb->idx_cur_active].flags &
NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND) {
p_cb->listen_info[p_cb->idx_cur_active].flags &=
~NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND;
memcpy(&(conn_evt.ce_activated.activate_ntf), &p_cb->activation_params,
sizeof(tNFC_ACTIVATE_DEVT));
conn_evt.ce_activated.status = NFA_STATUS_OK;
(*p_cb->p_active_conn_cback)(NFA_CE_ACTIVATED_EVT, &conn_evt);
}
/* Notify app of AID data */
conn_evt.ce_data.status = p_ce_data->raw_frame.status;
conn_evt.ce_data.handle =
NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);
conn_evt.ce_data.p_data = (uint8_t*)(p_ce_data->raw_frame.p_data + 1) +
p_ce_data->raw_frame.p_data->offset;
conn_evt.ce_data.len = p_ce_data->raw_frame.p_data->len;
(*p_cb->p_active_conn_cback)(NFA_CE_DATA_EVT, &conn_evt);
} else {
LOG(ERROR) << StringPrintf(
"nfa_ce_handle_t4t_aid_evt: unable to find listen_info for aid hdl "
"%i",
p_ce_data->raw_frame.aid_handle);
}
GKI_freebuf(p_ce_data->raw_frame.p_data);
}
}
/*****************************************************************************
* Discovery configuration and discovery event handlers
*****************************************************************************/
/*******************************************************************************
**
** Function nfa_ce_discovery_cback
**
** Description Processing event from discovery callback
**
** Returns None
**
*******************************************************************************/
void nfa_ce_discovery_cback(tNFA_DM_RF_DISC_EVT event, tNFC_DISCOVER* p_data) {
tNFA_CE_MSG ce_msg;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event:0x%02X", event);
switch (event) {
case NFA_DM_RF_DISC_START_EVT:
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ce_handle_disc_start (status=0x%x)", p_data->start);
break;
case NFA_DM_RF_DISC_ACTIVATED_EVT:
ce_msg.activate_ntf.hdr.event = NFA_CE_ACTIVATE_NTF_EVT;
ce_msg.activate_ntf.p_activation_params = &p_data->activate;
nfa_ce_hdl_event((NFC_HDR*)&ce_msg);
break;
case NFA_DM_RF_DISC_DEACTIVATED_EVT:
/* DM broadcasts deactivaiton event in listen sleep state, so check before
* processing */
if (nfa_ce_cb.flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) {
ce_msg.hdr.event = NFA_CE_DEACTIVATE_NTF_EVT;
ce_msg.hdr.layer_specific = p_data->deactivate.type;
nfa_ce_hdl_event((NFC_HDR*)&ce_msg);
}
break;
default:
LOG(ERROR) << StringPrintf("Unexpected event");
break;
}
}
/*******************************************************************************
**
** Function nfc_ce_t3t_set_listen_params
**
** Description Set t3t listening parameters
**
** Returns Nothing
**
*******************************************************************************/
void nfc_ce_t3t_set_listen_params(void) {
uint8_t i;
tNFA_CE_CB* p_cb = &nfa_ce_cb;
uint8_t tlv[128], *p_params;
uint8_t tlv_size;
uint16_t t3t_flags2_mask = 0xFFFF; /* Mask of which T3T_IDs are disabled */
uint8_t t3t_idx = 0;
uint8_t adv_Feat = 1;
uint8_t t3tPMM[NCI_T3T_PMM_LEN] = {0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
/* Point to start of tlv buffer */
p_params = tlv;
/* Set system code and NFCID2 */
for (i = 0; i < NFA_CE_LISTEN_INFO_MAX; i++) {
if ((p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[i].protocol_mask & NFA_PROTOCOL_MASK_T3T)) {
/* Set tag's system code and NFCID2 */
UINT8_TO_STREAM(p_params, NFC_PMID_LF_T3T_ID1 + t3t_idx); /* type */
/* length */
UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_ID(NFC_GetNCIVersion()));
/* System Code */
UINT16_TO_BE_STREAM(p_params, p_cb->listen_info[i].t3t_system_code);
ARRAY_TO_BE_STREAM(p_params, p_cb->listen_info[i].t3t_nfcid2,
NCI_RF_F_UID_LEN);
if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
ARRAY_TO_BE_STREAM(p_params, p_cb->listen_info[i].t3t_pmm,
NCI_T3T_PMM_LEN);
}
/* Set mask for this ID */
t3t_flags2_mask &= ~((uint16_t)(1 << t3t_idx));
t3t_idx++;
}
}
/* For NCI draft 22+, the polarity of NFC_PMID_LF_T3T_FLAGS2 is flipped */
t3t_flags2_mask = ~t3t_flags2_mask;
UINT8_TO_STREAM(p_params, NFC_PMID_LF_T3T_FLAGS2); /* type */
UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_FLAGS2); /* length */
/* Mask of IDs to disable listening */
UINT16_TO_STREAM(p_params, t3t_flags2_mask);
if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
/*Name changed in NCI2.0*/
UINT8_TO_STREAM(p_params, NCI_PARAM_ID_LF_T3T_RD_ALLOWED); /* type */
UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_RD_ALLOWED); /* length */
} else {
UINT8_TO_STREAM(p_params, NCI_PARAM_ID_LF_CON_ADV_FEAT); /* type */
UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_CON_ADV_FEAT); /* length */
}
UINT8_TO_STREAM(p_params, adv_Feat);
if (NFC_GetNCIVersion() != NCI_VERSION_2_0) {
UINT8_TO_STREAM(p_params, NCI_PARAM_ID_LF_T3T_PMM); /* type */
UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_PMM); /* length */
ARRAY_TO_BE_STREAM(p_params, t3tPMM, NCI_T3T_PMM_LEN);
}
tlv_size = (uint8_t)(p_params - tlv);
if (appl_dta_mode_flag == 0x01) {
nfa_dm_cb.eDtaMode |= NFA_DTA_HCEF_MODE;
}
nfa_dm_check_set_config(tlv_size, (uint8_t*)tlv, false);
}
/*******************************************************************************
**
** Function nfa_ce_t3t_generate_rand_nfcid
**
** Description Generate a random NFCID2 for Type-3 tag
**
** Returns Nothing
**
*******************************************************************************/
void nfa_ce_t3t_generate_rand_nfcid(uint8_t nfcid2[NCI_RF_F_UID_LEN]) {
uint32_t rand_seed = GKI_get_tick_count();
/* For Type-3 tag, nfcid2 starts witn 02:fe */
nfcid2[0] = 0x02;
nfcid2[1] = 0xFE;
/* The remaining 6 bytes are random */
nfcid2[2] = (uint8_t)(rand_seed & 0xFF);
nfcid2[3] = (uint8_t)(rand_seed >> 8 & 0xFF);
rand_seed >>= (rand_seed & 3);
nfcid2[4] = (uint8_t)(rand_seed & 0xFF);
nfcid2[5] = (uint8_t)(rand_seed >> 8 & 0xFF);
rand_seed >>= (rand_seed & 3);
nfcid2[6] = (uint8_t)(rand_seed & 0xFF);
nfcid2[7] = (uint8_t)(rand_seed >> 8 & 0xFF);
}
/*******************************************************************************
**
** Function nfa_ce_start_listening
**
** Description Start listening
**
** Returns NFA_STATUS_OK if successful
**
*******************************************************************************/
tNFA_STATUS nfa_ce_start_listening(void) {
tNFA_DM_DISC_TECH_PROTO_MASK listen_mask;
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_HANDLE disc_handle;
uint8_t listen_info_idx;
/*************************************************************************/
/* Construct protocol preference list to listen for */
/* First, get protocol preference for active NDEF (if any) */
if ((p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle ==
NFA_HANDLE_INVALID)) {
listen_mask = 0;
if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
NFA_PROTOCOL_MASK_T3T) {
/* set T3T config params */
nfc_ce_t3t_set_listen_params();
listen_mask |= NFA_DM_DISC_MASK_LF_T3T;
}
if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
NFA_PROTOCOL_MASK_ISO_DEP) {
listen_mask |= nfa_ce_cb.isodep_disc_mask;
}
disc_handle = nfa_dm_add_rf_discover(listen_mask, NFA_DM_DISC_HOST_ID_DH,
nfa_ce_discovery_cback);
if (disc_handle == NFA_HANDLE_INVALID)
return (NFA_STATUS_FAILED);
else
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle =
disc_handle;
}
/* Next, add protocols from non-NDEF, if any */
for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_IDX_INVALID;
listen_info_idx++) {
/* add RF discovery to DM only if it is not added yet */
if ((p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[listen_info_idx].rf_disc_handle ==
NFA_HANDLE_INVALID)) {
if (p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_FELICA) {
/* set T3T config params */
nfc_ce_t3t_set_listen_params();
disc_handle = nfa_dm_add_rf_discover(NFA_DM_DISC_MASK_LF_T3T,
NFA_DM_DISC_HOST_ID_DH,
nfa_ce_discovery_cback);
if (disc_handle == NFA_HANDLE_INVALID)
return (NFA_STATUS_FAILED);
else
p_cb->listen_info[listen_info_idx].rf_disc_handle = disc_handle;
} else if (p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_T4T_AID) {
disc_handle = nfa_dm_add_rf_discover(nfa_ce_cb.isodep_disc_mask,
NFA_DM_DISC_HOST_ID_DH,
nfa_ce_discovery_cback);
if (disc_handle == NFA_HANDLE_INVALID)
return (NFA_STATUS_FAILED);
else
p_cb->listen_info[listen_info_idx].rf_disc_handle = disc_handle;
}
#if (NFC_NFCEE_INCLUDED == TRUE)
else if (p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_UICC) {
listen_mask = 0;
if (nfa_ee_is_active(p_cb->listen_info[listen_info_idx].ee_handle)) {
if (p_cb->listen_info[listen_info_idx].tech_mask &
NFA_TECHNOLOGY_MASK_A) {
listen_mask |= NFA_DM_DISC_MASK_LA_ISO_DEP;
}
if (p_cb->listen_info[listen_info_idx].tech_mask &
NFA_TECHNOLOGY_MASK_B) {
listen_mask |= NFA_DM_DISC_MASK_LB_ISO_DEP;
}
if (p_cb->listen_info[listen_info_idx].tech_mask &
NFA_TECHNOLOGY_MASK_F) {
listen_mask |= NFA_DM_DISC_MASK_LF_T3T;
}
if (p_cb->listen_info[listen_info_idx].tech_mask &
NFA_TECHNOLOGY_MASK_B_PRIME) {
listen_mask |= NFA_DM_DISC_MASK_L_B_PRIME;
}
}
if (listen_mask) {
/* Start listening for requested technologies */
/* register discovery callback to NFA DM */
disc_handle = nfa_dm_add_rf_discover(
listen_mask,
(tNFA_DM_DISC_HOST_ID)(
p_cb->listen_info[listen_info_idx].ee_handle & 0x00FF),
nfa_ce_discovery_cback);
if (disc_handle == NFA_HANDLE_INVALID)
return (NFA_STATUS_FAILED);
else {
p_cb->listen_info[listen_info_idx].rf_disc_handle = disc_handle;
p_cb->listen_info[listen_info_idx].tech_proto_mask = listen_mask;
}
} else {
LOG(ERROR) << StringPrintf(
"UICC[0x%x] is not activated",
p_cb->listen_info[listen_info_idx].ee_handle);
}
}
#endif
}
}
return NFA_STATUS_OK;
}
/*******************************************************************************
**
** Function nfa_ce_restart_listen_check
**
** Description Called on deactivation. Check if any active listen_info
** entries to listen for
**
** Returns TRUE if listening is restarted.
** FALSE if listening not restarted
**
*******************************************************************************/
bool nfa_ce_restart_listen_check(void) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
uint8_t listen_info_idx;
/* Check if any active entries in listen_info table */
for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_MAX;
listen_info_idx++) {
if (p_cb->listen_info[listen_info_idx].flags & NFA_CE_LISTEN_INFO_IN_USE)
break;
}
/* Restart listening if there are any active listen_info entries */
if (listen_info_idx != NFA_CE_LISTEN_INFO_IDX_INVALID) {
/* restart listening */
nfa_ce_start_listening();
} else {
/* No active listen_info entries */
return false;
}
return true;
}
/*******************************************************************************
**
** Function nfa_ce_remove_listen_info_entry
**
** Description Remove entry from listen_info table. (when API deregister is
** called or listen_start failed)
**
**
** Returns Nothing
**
*******************************************************************************/
void nfa_ce_remove_listen_info_entry(uint8_t listen_info_idx, bool notify_app) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA conn_evt;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("NFA_CE: removing listen_info entry %i", listen_info_idx);
/* Notify app that listening has stopped if requested (for API deregister) */
/* For LISTEN_START failures, app has already notified of NFA_LISTEN_START_EVT
* failure */
if (notify_app) {
if (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_NDEF) {
conn_evt.status = NFA_STATUS_OK;
(*p_cb->listen_info[listen_info_idx].p_conn_cback)(
NFA_CE_LOCAL_TAG_CONFIGURED_EVT, &conn_evt);
}
#if (NFC_NFCEE_INCLUDED == TRUE)
else if (p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_UICC) {
conn_evt.status = NFA_STATUS_OK;
(*p_cb->listen_info[listen_info_idx].p_conn_cback)(
NFA_CE_UICC_LISTEN_CONFIGURED_EVT, &conn_evt);
}
#endif
else {
conn_evt.ce_deregistered.handle = NFA_HANDLE_GROUP_CE | listen_info_idx;
(*p_cb->listen_info[listen_info_idx].p_conn_cback)(
NFA_CE_DEREGISTERED_EVT, &conn_evt);
}
}
/* Handle NDEF stopping */
if (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_NDEF) {
/* clear NDEF contents */
CE_T3tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
CE_T4tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
if (p_cb->listen_info[listen_info_idx].protocol_mask &
NFA_PROTOCOL_MASK_T3T) {
p_cb->listen_info[listen_info_idx].protocol_mask = 0;
/* clear T3T Flags for NDEF */
nfc_ce_t3t_set_listen_params();
}
/* Free scratch buffer for this NDEF, if one was allocated */
nfa_ce_free_scratch_buf();
}
/* If stopping listening Felica system code, then clear T3T Flags for this */
else if (p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_FELICA) {
p_cb->listen_info[listen_info_idx].protocol_mask = 0;
/* clear T3T Flags for registered Felica system code */
nfc_ce_t3t_set_listen_params();
}
/* If stopping listening T4T AID, then deregister this AID from CE_T4T */
else if (p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_T4T_AID) {
/* Free t4t_aid_cback used by this AID */
CE_T4tDeregisterAID(p_cb->listen_info[listen_info_idx].t4t_aid_handle);
}
if (p_cb->listen_info[listen_info_idx].rf_disc_handle != NFA_HANDLE_INVALID) {
nfa_dm_delete_rf_discover(
p_cb->listen_info[listen_info_idx].rf_disc_handle);
p_cb->listen_info[listen_info_idx].rf_disc_handle = NFA_HANDLE_INVALID;
}
/* Remove entry from listen_info table */
p_cb->listen_info[listen_info_idx].flags = 0;
}
/*******************************************************************************
**
** Function nfa_ce_free_scratch_buf
**
** Description free scratch buffer (if one is allocated)
**
** Returns nothing
**
*******************************************************************************/
void nfa_ce_free_scratch_buf(void) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
if (p_cb->p_scratch_buf) {
nfa_mem_co_free(p_cb->p_scratch_buf);
p_cb->p_scratch_buf = NULL;
}
}
/*******************************************************************************
**
** Function nfa_ce_realloc_scratch_buffer
**
** Description Set scratch buffer if necessary (for writable NDEF messages)
**
** Returns NFA_STATUS_OK if successful
**
*******************************************************************************/
tNFA_STATUS nfa_ce_realloc_scratch_buffer(void) {
tNFA_STATUS result = NFA_STATUS_OK;
/* If current NDEF message is read-only, then we do not need a scratch buffer
*/
if (nfa_ce_cb.listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
NFC_CE_LISTEN_INFO_READONLY_NDEF) {
/* Free existing scratch buffer, if one was allocated */
nfa_ce_free_scratch_buf();
} else {
/* If no scratch buffer allocated yet, or if current scratch buffer size is
* different from current ndef size, */
/* then allocate a new scratch buffer. */
if ((nfa_ce_cb.p_scratch_buf == NULL) ||
(nfa_ce_cb.scratch_buf_size != nfa_ce_cb.ndef_max_size)) {
/* Free existing scratch buffer, if one was allocated */
nfa_ce_free_scratch_buf();
nfa_ce_cb.p_scratch_buf =
(uint8_t*)nfa_mem_co_alloc(nfa_ce_cb.ndef_max_size);
if (nfa_ce_cb.p_scratch_buf != NULL) {
nfa_ce_cb.scratch_buf_size = nfa_ce_cb.ndef_max_size;
} else {
LOG(ERROR) << StringPrintf(
"Unable to allocate scratch buffer for writable NDEF message (%i "
"bytes)",
nfa_ce_cb.ndef_max_size);
result = NFA_STATUS_FAILED;
}
}
}
return (result);
}
/*******************************************************************************
**
** Function nfa_ce_set_content
**
** Description Set NDEF contents
**
** Returns void
**
*******************************************************************************/
tNFC_STATUS nfa_ce_set_content(void) {
tNFC_STATUS status;
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_PROTOCOL_MASK ndef_protocol_mask;
bool readonly;
/* Check if listening for NDEF */
if (!(p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
NFA_CE_LISTEN_INFO_IN_USE)) {
/* Not listening for NDEF */
return (NFA_STATUS_OK);
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Setting NDEF contents");
readonly = (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
NFC_CE_LISTEN_INFO_READONLY_NDEF)
? true
: false;
ndef_protocol_mask =
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask;
/* Allocate a scratch buffer if needed (for handling write-requests) */
status = nfa_ce_realloc_scratch_buffer();
if (status == NFA_STATUS_OK) {
if ((ndef_protocol_mask & NFA_PROTOCOL_MASK_T3T) &&
(status == NFA_STATUS_OK)) {
/* Type3Tag - NFC-F */
status = CE_T3tSetLocalNDEFMsg(readonly, p_cb->ndef_max_size,
p_cb->ndef_cur_size, p_cb->p_ndef_data,
p_cb->p_scratch_buf);
}
if ((ndef_protocol_mask & NFA_PROTOCOL_MASK_ISO_DEP) &&
(status == NFA_STATUS_OK)) {
/* ISODEP/4A,4B- NFC-A or NFC-B */
status = CE_T4tSetLocalNDEFMsg(readonly, p_cb->ndef_max_size,
p_cb->ndef_cur_size, p_cb->p_ndef_data,
p_cb->p_scratch_buf);
}
}
if (status != NFA_STATUS_OK) {
/* clear NDEF contents */
CE_T3tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
CE_T4tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
LOG(ERROR) << StringPrintf("Unable to set contents (error %02x)", status);
}
return (status);
}
/*******************************************************************************
**
** Function nfa_ce_activate_ntf
**
** Description Action when activation has occured (NFA_CE_ACTIVATE_NTF_EVT)
**
** - Find the listen_info entry assocated with this activation
** - get the app callback that registered for this listen
** - call CE_SetActivatedTagType with activation parameters
**
** Returns TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_activate_ntf(tNFA_CE_MSG* p_ce_msg) {
tNFC_ACTIVATE_DEVT* p_activation_params =
p_ce_msg->activate_ntf.p_activation_params;
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA conn_evt;
tCE_CBACK* p_ce_cback = NULL;
uint16_t t3t_system_code = 0xFFFF;
uint8_t listen_info_idx = NFA_CE_LISTEN_INFO_IDX_INVALID;
uint8_t* p_nfcid2 = NULL;
uint8_t i;
bool t4t_activate_pending = false;
bool t3t_activate_pending = false;
bool t3t_offhost_entry_found = false;
uint8_t t3t_activate_idx = 0;
uint8_t t3t_offhost_idx = 0;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"protocol=%d", p_ce_msg->activate_ntf.p_activation_params->protocol);
/* Tag is in listen active state */
p_cb->flags |= NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP;
/* Store activation parameters */
memcpy(&p_cb->activation_params, p_activation_params,
sizeof(tNFC_ACTIVATE_DEVT));
/* Find the listen_info entry corresponding to this activation */
if (p_cb->activation_params.protocol == NFA_PROTOCOL_T3T) {
/* Look for T3T entries in listen_info table that match activated system
* code and NFCID2 */
for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_IDX_INVALID;
listen_info_idx++) {
/* Look for entries with NFA_PROTOCOL_MASK_T3T */
if (p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_IN_USE) {
if (p_cb->listen_info[listen_info_idx].protocol_mask &
NFA_PROTOCOL_MASK_T3T) {
/* Check if system_code and nfcid2 that matches activation params */
p_nfcid2 = p_cb->listen_info[listen_info_idx].t3t_nfcid2;
t3t_system_code = p_cb->listen_info[listen_info_idx].t3t_system_code;
/* Compare NFCID2 (note: NFCC currently does not return system code in
* activation parameters) */
if ((memcmp(p_nfcid2,
p_cb->activation_params.rf_tech_param.param.lf.nfcid2,
NCI_RF_F_UID_LEN) == 0)
/* && (t3t_system_code == p_ce_msg->activation.p_activate_info->rf_tech_param.param.lf.system_code) */) {
p_cb->listen_info[listen_info_idx].flags |=
NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND;
t3t_activate_pending = true;
t3t_activate_idx = listen_info_idx;
}
}
/* Check if entry is for T3T UICC */
if ((p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_UICC) &&
(p_cb->listen_info[listen_info_idx].tech_mask &
NFA_TECHNOLOGY_MASK_F)) {
t3t_offhost_entry_found = true;
t3t_offhost_idx = listen_info_idx;
}
}
}
p_ce_cback = nfa_ce_handle_t3t_evt;
/* If listening for PROTO_T3T on DH and eSE/UICC, then notify CE module
* now and wait for reader/writer to SELECT a target */
if (t3t_activate_pending && t3t_offhost_entry_found) {
CE_SetActivatedTagType(&p_cb->activation_params, t3t_system_code,
p_ce_cback);
return true;
} else if (t3t_activate_pending) {
listen_info_idx = t3t_activate_idx;
} else if (t3t_offhost_entry_found) {
listen_info_idx = t3t_offhost_idx;
}
} else if (p_cb->activation_params.protocol == NFA_PROTOCOL_ISO_DEP) {
p_ce_cback = nfa_ce_handle_t4t_evt;
/* For T4T, we do not know which AID will be selected yet */
/* For all T4T entries in listen_info, set T4T_ACTIVATE_NOTIFY_PENDING flag
*/
for (i = 0; i < NFA_CE_LISTEN_INFO_IDX_INVALID; i++) {
if (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) {
if (p_cb->listen_info[i].protocol_mask & NFA_PROTOCOL_MASK_ISO_DEP) {
/* Found listen_info table entry for T4T raw listen */
p_cb->listen_info[i].flags |= NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND;
/* If entry if for NDEF, select it, so application gets nofitifed of
* ACTIVATE_EVT now */
if (i == NFA_CE_LISTEN_INFO_IDX_NDEF) {
listen_info_idx = NFA_CE_LISTEN_INFO_IDX_NDEF;
}
t4t_activate_pending = true;
}
#if (NFC_NFCEE_INCLUDED == TRUE)
/* Check if entry is for ISO_DEP UICC */
if (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC) {
if (((p_cb->activation_params.rf_tech_param.mode ==
NFC_DISCOVERY_TYPE_LISTEN_A) &&
(p_cb->listen_info[i].tech_proto_mask &
NFA_DM_DISC_MASK_LA_ISO_DEP)) ||
((p_cb->activation_params.rf_tech_param.mode ==
NFC_DISCOVERY_TYPE_LISTEN_B) &&
(p_cb->listen_info[i].tech_proto_mask &
NFA_DM_DISC_MASK_LB_ISO_DEP))) {
listen_info_idx = i;
}
}
#endif
}
}
/* If listening for ISO_DEP, but not NDEF nor UICC, then notify CE module
* now and wait for reader/writer to SELECT an AID */
if (t4t_activate_pending &&
(listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID)) {
CE_SetActivatedTagType(&p_cb->activation_params, 0, p_ce_cback);
return true;
}
} else if (p_cb->activation_params.intf_param.type ==
NFC_INTERFACE_EE_DIRECT_RF) {
/* search any entry listening UICC */
for (i = 0; i < NFA_CE_LISTEN_INFO_IDX_INVALID; i++) {
if ((p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC)) {
listen_info_idx = i;
break;
}
}
}
/* Check if valid listen_info entry was found */
if ((listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID) ||
((listen_info_idx == NFA_CE_LISTEN_INFO_IDX_NDEF) &&
!(p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
NFA_CE_LISTEN_INFO_IN_USE))) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"No listen_info found for this activation. listen_info_idx=%d",
listen_info_idx);
return true;
}
p_cb->listen_info[listen_info_idx].flags &=
~NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND;
p_cb->listen_info[listen_info_idx].flags &=
~NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND;
/* Get CONN_CBACK for this activation */
p_cb->p_active_conn_cback = p_cb->listen_info[listen_info_idx].p_conn_cback;
p_cb->idx_cur_active = listen_info_idx;
if ((p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) ||
(p_cb->listen_info[p_cb->idx_cur_active].flags &
NFA_CE_LISTEN_INFO_UICC)) {
memcpy(&(conn_evt.activated.activate_ntf), &p_cb->activation_params,
sizeof(tNFC_ACTIVATE_DEVT));
(*p_cb->p_active_conn_cback)(NFA_ACTIVATED_EVT, &conn_evt);
} else {
conn_evt.ce_activated.handle =
NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);
memcpy(&(conn_evt.ce_activated.activate_ntf), &p_cb->activation_params,
sizeof(tNFC_ACTIVATE_DEVT));
conn_evt.ce_activated.status = NFA_STATUS_OK;
(*p_cb->p_active_conn_cback)(NFA_CE_ACTIVATED_EVT, &conn_evt);
}
/* we don't need any CE subsystem in case of NFCEE direct RF interface */
if (p_ce_cback) {
/* Notify CE subsystem */
CE_SetActivatedTagType(&p_cb->activation_params, t3t_system_code,
p_ce_cback);
}
return true;
}
/*******************************************************************************
**
** Function nfa_ce_deactivate_ntf
**
** Description Action when deactivate occurs. (NFA_CE_DEACTIVATE_NTF_EVT)
**
** - If deactivate due to API deregister, then remove its entry
** from listen_info table
**
** - If NDEF was modified while activated, then restore
** original NDEF contents
**
** - Restart listening (if any active entries in listen table)
**
** Returns TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_deactivate_ntf(tNFA_CE_MSG* p_ce_msg) {
tNFC_DEACT_TYPE deact_type = (tNFC_DEACT_TYPE)p_ce_msg->hdr.layer_specific;
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA conn_evt;
uint8_t i;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("deact_type=%d", deact_type);
/* Check if deactivating to SLEEP mode */
if ((deact_type == NFC_DEACTIVATE_TYPE_SLEEP) ||
(deact_type == NFC_DEACTIVATE_TYPE_SLEEP_AF)) {
if (nfa_ce_cb.idx_wild_card == NFA_CE_LISTEN_INFO_IDX_INVALID) {
/* notify deactivated as sleep and wait for reactivation or deactivation
* to idle */
conn_evt.deactivated.type = deact_type;
/* if T4T AID application has not been selected then p_active_conn_cback
* could be NULL */
if (p_cb->p_active_conn_cback)
(*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
} else {
conn_evt.ce_deactivated.handle =
NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)nfa_ce_cb.idx_wild_card);
conn_evt.ce_deactivated.type = deact_type;
if (p_cb->p_active_conn_cback)
(*p_cb->p_active_conn_cback)(NFA_CE_DEACTIVATED_EVT, &conn_evt);
}
return true;
} else {
deact_type = NFC_DEACTIVATE_TYPE_IDLE;
}
/* Tag is in idle state */
p_cb->flags &= ~NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP;
/* First, notify app of deactivation */
for (i = 0; i < NFA_CE_LISTEN_INFO_IDX_INVALID; i++) {
if (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) {
if ((p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC) &&
(i == p_cb->idx_cur_active)) {
conn_evt.deactivated.type = deact_type;
(*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
} else if ((p_cb->activation_params.protocol == NFA_PROTOCOL_ISO_DEP) &&
(p_cb->listen_info[i].protocol_mask &
NFA_PROTOCOL_MASK_ISO_DEP)) {
/* Don't send NFA_DEACTIVATED_EVT if NFA_ACTIVATED_EVT wasn't sent */
if (!(p_cb->listen_info[i].flags &
NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND)) {
if (i == NFA_CE_LISTEN_INFO_IDX_NDEF) {
conn_evt.deactivated.type = deact_type;
(*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
} else {
conn_evt.ce_deactivated.handle =
NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)i);
conn_evt.ce_deactivated.type = deact_type;
(*p_cb->p_active_conn_cback)(NFA_CE_DEACTIVATED_EVT, &conn_evt);
}
}
} else if ((p_cb->activation_params.protocol == NFA_PROTOCOL_T3T) &&
(p_cb->listen_info[i].protocol_mask & NFA_PROTOCOL_MASK_T3T)) {
/* Don't send NFA_DEACTIVATED_EVT if NFA_ACTIVATED_EVT wasn't sent */
if (!(p_cb->listen_info[i].flags &
NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND)) {
if (i == NFA_CE_LISTEN_INFO_IDX_NDEF) {
conn_evt.deactivated.type = deact_type;
(*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
} else {
conn_evt.ce_deactivated.handle =
NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)i);
conn_evt.ce_deactivated.type = deact_type;
(*p_cb->p_active_conn_cback)(NFA_CE_DEACTIVATED_EVT, &conn_evt);
}
}
}
}
}
/* Check if app initiated the deactivation (due to API deregister). If so,
* remove entry from listen_info table. */
if (p_cb->flags & NFA_CE_FLAGS_APP_INIT_DEACTIVATION) {
p_cb->flags &= ~NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
nfa_ce_remove_listen_info_entry(p_cb->idx_cur_active, true);
}
p_cb->p_active_conn_cback = NULL;
p_cb->idx_cur_active = NFA_CE_LISTEN_INFO_IDX_INVALID;
/* Restart listening (if any listen_info entries are still active) */
nfa_ce_restart_listen_check();
return true;
}
/*******************************************************************************
**
** Function nfa_ce_disable_local_tag
**
** Description Disable local NDEF tag
** - clean up control block
** - remove NDEF discovery configuration
**
** Returns Nothing
**
*******************************************************************************/
void nfa_ce_disable_local_tag(void) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA evt_data;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Disabling local NDEF tag");
/* If local NDEF tag is in use, then disable it */
if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
NFA_CE_LISTEN_INFO_IN_USE) {
/* NDEF Tag is in not idle state */
if ((p_cb->flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) &&
(p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF)) {
/* wait for deactivation */
p_cb->flags |= NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_IDLE);
} else {
/* Notify DM to stop listening for ndef */
if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle !=
NFA_HANDLE_INVALID) {
nfa_dm_delete_rf_discover(
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle);
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle =
NFA_HANDLE_INVALID;
}
nfa_ce_remove_listen_info_entry(NFA_CE_LISTEN_INFO_IDX_NDEF, true);
}
} else {
/* Notify application */
evt_data.status = NFA_STATUS_OK;
nfa_dm_conn_cback_event_notify(NFA_CE_LOCAL_TAG_CONFIGURED_EVT, &evt_data);
}
}
/*******************************************************************************
**
** Function nfa_ce_api_cfg_local_tag
**
** Description Configure local NDEF tag
** - store ndef attributes in to control block
** - update discovery configuration
**
** Returns TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_cfg_local_tag(tNFA_CE_MSG* p_ce_msg) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA conn_evt;
/* Check if disabling local tag */
if (p_ce_msg->local_tag.protocol_mask == 0) {
nfa_ce_disable_local_tag();
return true;
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"Configuring local NDEF tag: protocol_mask=%01x cur_size=%i, "
"max_size=%i, readonly=%i uid_len=%i",
p_ce_msg->local_tag.protocol_mask, p_ce_msg->local_tag.ndef_cur_size,
p_ce_msg->local_tag.ndef_max_size, p_ce_msg->local_tag.read_only,
p_ce_msg->local_tag.uid_len);
/* If local tag was already set, then check if NFA_CeConfigureLocalTag called
* to change protocol mask */
if ((p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle !=
NFA_HANDLE_INVALID) &&
((p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
(NFA_PROTOCOL_MASK_T3T | NFA_PROTOCOL_MASK_ISO_DEP)) !=
(p_ce_msg->local_tag.protocol_mask &
(NFA_PROTOCOL_MASK_T3T | NFA_PROTOCOL_MASK_ISO_DEP)))) {
/* Listening for different tag protocols. Stop discovery */
nfa_dm_delete_rf_discover(
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle);
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle =
NFA_HANDLE_INVALID;
/* clear NDEF contents */
CE_T3tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
CE_T4tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
}
/* Store NDEF info to control block */
p_cb->p_ndef_data = p_ce_msg->local_tag.p_ndef_data;
p_cb->ndef_cur_size = p_ce_msg->local_tag.ndef_cur_size;
p_cb->ndef_max_size = p_ce_msg->local_tag.ndef_max_size;
/* Fill in LISTEN_INFO entry for NDEF */
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags =
NFA_CE_LISTEN_INFO_IN_USE;
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask =
p_ce_msg->local_tag.protocol_mask;
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].p_conn_cback =
nfa_dm_conn_cback_event_notify;
if (p_ce_msg->local_tag.read_only)
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags |=
NFC_CE_LISTEN_INFO_READONLY_NDEF;
p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].t3t_system_code =
T3T_SYSTEM_CODE_NDEF;
/* Set NDEF contents */
conn_evt.status = NFA_STATUS_FAILED;
if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
(NFA_PROTOCOL_MASK_T3T | NFA_PROTOCOL_MASK_ISO_DEP)) {
/* Ok to set contents now */
if (nfa_ce_set_content() != NFA_STATUS_OK) {
LOG(ERROR) << StringPrintf(
"nfa_ce_api_cfg_local_tag: could not set contents");
nfa_dm_conn_cback_event_notify(NFA_CE_LOCAL_TAG_CONFIGURED_EVT,
&conn_evt);
return true;
}
/* Start listening and notify app of status */
conn_evt.status = nfa_ce_start_listening();
nfa_dm_conn_cback_event_notify(NFA_CE_LOCAL_TAG_CONFIGURED_EVT, &conn_evt);
}
return true;
}
/*******************************************************************************
**
** Function nfa_ce_api_reg_listen
**
** Description Register listen params for Felica system code, T4T AID,
** or UICC
**
** Returns TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_reg_listen(tNFA_CE_MSG* p_ce_msg) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
tNFA_CONN_EVT_DATA conn_evt;
uint8_t i;
uint8_t listen_info_idx = NFA_CE_LISTEN_INFO_IDX_INVALID;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("Registering UICC/Felica/Type-4 tag listener. Type=%i",
p_ce_msg->reg_listen.listen_type);
/* Look for available entry in listen_info table */
/* - If registering UICC listen, make sure there isn't another entry for the
* ee_handle */
/* - Skip over entry 0 (reserved for local NDEF tag) */
for (i = 1; i < NFA_CE_LISTEN_INFO_MAX; i++) {
if ((p_ce_msg->reg_listen.listen_type == NFA_CE_REG_TYPE_UICC) &&
(p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC) &&
(p_cb->listen_info[i].ee_handle == p_ce_msg->reg_listen.ee_handle)) {
LOG(ERROR) << StringPrintf("UICC (0x%x) listening already specified",
p_ce_msg->reg_listen.ee_handle);
conn_evt.status = NFA_STATUS_FAILED;
nfa_dm_conn_cback_event_notify(NFA_CE_UICC_LISTEN_CONFIGURED_EVT,
&conn_evt);
return true;
}
/* If this is a free entry, and we haven't found one yet, remember it */
else if ((!(p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE)) &&
(listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID)) {
listen_info_idx = i;
}
}
/* Add new entry to listen_info table */
if (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID) {
LOG(ERROR) << StringPrintf("Maximum listen callbacks exceeded (%i)",
NFA_CE_LISTEN_INFO_MAX);
if (p_ce_msg->reg_listen.listen_type == NFA_CE_REG_TYPE_UICC) {
conn_evt.status = NFA_STATUS_FAILED;
nfa_dm_conn_cback_event_notify(NFA_CE_UICC_LISTEN_CONFIGURED_EVT,
&conn_evt);
} else {
/* Notify application */
conn_evt.ce_registered.handle = NFA_HANDLE_INVALID;
conn_evt.ce_registered.status = NFA_STATUS_FAILED;
(*p_ce_msg->reg_listen.p_conn_cback)(NFA_CE_REGISTERED_EVT, &conn_evt);
}
return true;
} else {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("NFA_CE: adding listen_info entry %i", listen_info_idx);
/* Store common parameters */
/* Mark entry as 'in-use', and NFA_CE_LISTEN_INFO_START_NTF_PND */
/* (LISTEN_START_EVT will be notified when discovery successfully starts */
p_cb->listen_info[listen_info_idx].flags =
NFA_CE_LISTEN_INFO_IN_USE | NFA_CE_LISTEN_INFO_START_NTF_PND;
p_cb->listen_info[listen_info_idx].rf_disc_handle = NFA_HANDLE_INVALID;
p_cb->listen_info[listen_info_idx].protocol_mask = 0;
/* Store type-specific parameters */
switch (p_ce_msg->reg_listen.listen_type) {
case NFA_CE_REG_TYPE_ISO_DEP:
p_cb->listen_info[listen_info_idx].protocol_mask =
NFA_PROTOCOL_MASK_ISO_DEP;
p_cb->listen_info[listen_info_idx].flags |= NFA_CE_LISTEN_INFO_T4T_AID;
p_cb->listen_info[listen_info_idx].p_conn_cback =
p_ce_msg->reg_listen.p_conn_cback;
/* Register this AID with CE_T4T */
p_cb->listen_info[listen_info_idx].t4t_aid_handle = CE_T4tRegisterAID(
p_ce_msg->reg_listen.aid_len, p_ce_msg->reg_listen.aid,
nfa_ce_handle_t4t_aid_evt);
if (p_cb->listen_info[listen_info_idx].t4t_aid_handle ==
CE_T4T_AID_HANDLE_INVALID) {
LOG(ERROR) << StringPrintf("Unable to register AID");
p_cb->listen_info[listen_info_idx].flags = 0;
/* Notify application */
conn_evt.ce_registered.handle = NFA_HANDLE_INVALID;
conn_evt.ce_registered.status = NFA_STATUS_FAILED;
(*p_ce_msg->reg_listen.p_conn_cback)(NFA_CE_REGISTERED_EVT,
&conn_evt);
return true;
}
if (p_cb->listen_info[listen_info_idx].t4t_aid_handle ==
CE_T4T_WILDCARD_AID_HANDLE)
nfa_ce_cb.idx_wild_card = listen_info_idx;
break;
case NFA_CE_REG_TYPE_FELICA:
p_cb->listen_info[listen_info_idx].protocol_mask =
NFA_PROTOCOL_MASK_T3T;
p_cb->listen_info[listen_info_idx].flags |= NFA_CE_LISTEN_INFO_FELICA;
p_cb->listen_info[listen_info_idx].p_conn_cback =
p_ce_msg->reg_listen.p_conn_cback;
/* Store system code and nfcid2 */
p_cb->listen_info[listen_info_idx].t3t_system_code =
p_ce_msg->reg_listen.system_code;
memcpy(p_cb->listen_info[listen_info_idx].t3t_nfcid2,
p_ce_msg->reg_listen.nfcid2, NCI_RF_F_UID_LEN);
memcpy(p_cb->listen_info[listen_info_idx].t3t_pmm,
p_ce_msg->reg_listen.t3tPmm, NCI_T3T_PMM_LEN);
break;
#if (NFC_NFCEE_INCLUDED == TRUE)
case NFA_CE_REG_TYPE_UICC:
p_cb->listen_info[listen_info_idx].flags |= NFA_CE_LISTEN_INFO_UICC;
p_cb->listen_info[listen_info_idx].p_conn_cback =
&nfa_dm_conn_cback_event_notify;
/* Store EE handle and Tech */
p_cb->listen_info[listen_info_idx].ee_handle =
p_ce_msg->reg_listen.ee_handle;
p_cb->listen_info[listen_info_idx].tech_mask =
p_ce_msg->reg_listen.tech_mask;
break;
#endif
}
}
/* Start listening */
conn_evt.status = nfa_ce_start_listening();
if (conn_evt.status != NFA_STATUS_OK) {
LOG(ERROR) << StringPrintf(
"nfa_ce_api_reg_listen: unable to register new listen params with DM");
p_cb->listen_info[listen_info_idx].flags = 0;
}
/* Nofitify app of status */
if (p_ce_msg->reg_listen.listen_type == NFA_CE_REG_TYPE_UICC) {
(*p_cb->listen_info[listen_info_idx].p_conn_cback)(
NFA_CE_UICC_LISTEN_CONFIGURED_EVT, &conn_evt);
} else {
conn_evt.ce_registered.handle = NFA_HANDLE_GROUP_CE | listen_info_idx;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ce_api_reg_listen: registered handle 0x%04X",
conn_evt.ce_registered.handle);
(*p_cb->listen_info[listen_info_idx].p_conn_cback)(NFA_CE_REGISTERED_EVT,
&conn_evt);
}
return true;
}
/*******************************************************************************
**
** Function nfa_ce_api_dereg_listen
**
** Description Deregister listen params
**
** Returns TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_dereg_listen(tNFA_CE_MSG* p_ce_msg) {
tNFA_CE_CB* p_cb = &nfa_ce_cb;
uint8_t listen_info_idx;
tNFA_CONN_EVT_DATA conn_evt;
#if (NFC_NFCEE_INCLUDED == TRUE)
/* Check if deregistering UICC , or virtual secure element listen */
if (p_ce_msg->dereg_listen.listen_info == NFA_CE_LISTEN_INFO_UICC) {
/* Deregistering UICC listen. Look for listen_info for this UICC ee handle
*/
for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_MAX;
listen_info_idx++) {
if ((p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_IN_USE) &&
(p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_UICC) &&
(p_cb->listen_info[listen_info_idx].ee_handle ==
p_ce_msg->dereg_listen.handle)) {
/* UICC is in not idle state */
if ((p_cb->flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) &&
(p_cb->idx_cur_active == listen_info_idx)) {
/* wait for deactivation */
p_cb->flags |= NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_IDLE);
} else {
/* Stop listening */
if (p_cb->listen_info[listen_info_idx].rf_disc_handle !=
NFA_HANDLE_INVALID) {
nfa_dm_delete_rf_discover(
p_cb->listen_info[listen_info_idx].rf_disc_handle);
p_cb->listen_info[listen_info_idx].rf_disc_handle =
NFA_HANDLE_INVALID;
}
/* Remove entry and notify application */
nfa_ce_remove_listen_info_entry(listen_info_idx, true);
}
break;
}
}
if (listen_info_idx == NFA_CE_LISTEN_INFO_MAX) {
LOG(ERROR) << StringPrintf("cannot find listen_info for UICC");
conn_evt.status = NFA_STATUS_INVALID_PARAM;
nfa_dm_conn_cback_event_notify(NFA_CE_UICC_LISTEN_CONFIGURED_EVT,
&conn_evt);
}
} else
#endif
{
/* Deregistering virtual secure element listen */
listen_info_idx = p_ce_msg->dereg_listen.handle & NFA_HANDLE_MASK;
if (nfa_ce_cb.idx_wild_card == listen_info_idx) {
nfa_ce_cb.idx_wild_card = NFA_CE_LISTEN_INFO_IDX_INVALID;
}
if ((listen_info_idx < NFA_CE_LISTEN_INFO_MAX) &&
(p_cb->listen_info[listen_info_idx].flags &
NFA_CE_LISTEN_INFO_IN_USE)) {
/* virtual secure element is in not idle state */
if ((p_cb->flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) &&
(p_cb->idx_cur_active == listen_info_idx)) {
/* wait for deactivation */
p_cb->flags |= NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_IDLE);
} else {
/* Stop listening */
if (p_cb->listen_info[listen_info_idx].rf_disc_handle !=
NFA_HANDLE_INVALID) {
nfa_dm_delete_rf_discover(
p_cb->listen_info[listen_info_idx].rf_disc_handle);
p_cb->listen_info[listen_info_idx].rf_disc_handle =
NFA_HANDLE_INVALID;
}
/* Remove entry and notify application */
nfa_ce_remove_listen_info_entry(listen_info_idx, true);
}
} else {
LOG(ERROR) << StringPrintf(
"cannot find listen_info for "
"Felica/T4tAID");
conn_evt.status = NFA_STATUS_INVALID_PARAM;
nfa_dm_conn_cback_event_notify(NFA_CE_DEREGISTERED_EVT, &conn_evt);
}
}
return true;
}
/*******************************************************************************
**
** Function nfa_ce_api_cfg_isodep_tech
**
** Description Configure the technologies (NFC-A and/or NFC-B) to listen
** for ISO-DEP
**
** Returns TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_cfg_isodep_tech(tNFA_CE_MSG* p_ce_msg) {
nfa_ce_cb.isodep_disc_mask = 0;
if (p_ce_msg->hdr.layer_specific & NFA_TECHNOLOGY_MASK_A)
nfa_ce_cb.isodep_disc_mask = NFA_DM_DISC_MASK_LA_ISO_DEP;
if (p_ce_msg->hdr.layer_specific & NFA_TECHNOLOGY_MASK_B)
nfa_ce_cb.isodep_disc_mask |= NFA_DM_DISC_MASK_LB_ISO_DEP;
return true;
}