| /****************************************************************************** |
| * |
| * 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; |
| |
| DLOG_IF(INFO, nfc_debug_enabled) |
| << StringPrintf("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 { |
| 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 { |
| 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; |
| |
| 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) */) { |
| /* 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))) { |
| 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; |
| |
| /* 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)) { |
| 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; |
| } |