/****************************************************************************** * * 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 "ce_api.h" #include "ndef_utils.h" #include "nfa_ce_int.h" #include "nfa_dm_int.h" #include "nfa_mem_co.h" #include "nfa_sys_int.h" #if (NFC_NFCEE_INCLUDED == TRUE) #include "nfa_ee_int.h" #endif /***************************************************************************** * 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; NFA_TRACE_DEBUG1("nfa_ce_handle_t3t_evt: event 0x%x", event); 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 { NFA_TRACE_ERROR0( "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 { NFA_TRACE_ERROR0( "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 { 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: NFA_TRACE_DEBUG1("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; NFA_TRACE_DEBUG1("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 */ NFA_TRACE_DEBUG1("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; NFA_TRACE_DEBUG1("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 { NFA_TRACE_ERROR1( "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; NFA_TRACE_DEBUG1("nfa_ce_discovery_cback(): event:0x%02X", event); switch (event) { case NFA_DM_RF_DISC_START_EVT: NFA_TRACE_DEBUG1("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: NFA_TRACE_ERROR0("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[32], *p_params; uint8_t tlv_size; uint16_t t3t_flags2_mask = 0xFFFF; /* Mask of which T3T_IDs are disabled */ uint8_t t3t_idx = 0; /* 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 */ UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_ID); /* length */ /* 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); /* 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); tlv_size = (uint8_t)(p_params - tlv); 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 { NFA_TRACE_ERROR1("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; NFA_TRACE_DEBUG1("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 { NFA_TRACE_ERROR1( "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); } NFA_TRACE_DEBUG0("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); NFA_TRACE_ERROR1("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; NFA_TRACE_DEBUG1("nfa_ce_activate_ntf () 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) */) { /* Found listen_info corresponding to this activation */ break; } } /* 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)) { break; } } } p_ce_cback = nfa_ce_handle_t3t_evt; } 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))) { NFA_TRACE_DEBUG1( "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; /* 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; NFA_TRACE_DEBUG1("nfa_ce_deactivate_ntf () 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)) { 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; NFA_TRACE_DEBUG0("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; } NFA_TRACE_DEBUG5( "Configuring local NDEF tag: protocol_mask=%01x cur_size=%i, " "max_size=%i, readonly=%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) { NFA_TRACE_ERROR0("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; NFA_TRACE_DEBUG1("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)) { NFA_TRACE_ERROR1("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) { NFA_TRACE_ERROR1("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 { NFA_TRACE_DEBUG1("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) { NFA_TRACE_ERROR0("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); 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) { NFA_TRACE_ERROR0( "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; NFA_TRACE_DEBUG1("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) { NFA_TRACE_ERROR0( "nfa_ce_api_dereg_listen (): 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 { NFA_TRACE_ERROR0( "nfa_ce_api_dereg_listen (): 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; }