普通文本  |  1504行  |  56.37 KB

/******************************************************************************
 *
 *  Copyright (C) 2011-2014 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  This file contains the action functions the NFA_CE state machine.
 *
 ******************************************************************************/
#include <string.h>

#include <android-base/stringprintf.h>
#include <base/logging.h>

#include "ce_api.h"
#include "ndef_utils.h"
#include "nfa_ce_int.h"
#include "nfa_mem_co.h"

#if (NFC_NFCEE_INCLUDED == TRUE)
#include "nfa_ee_int.h"
#endif

using android::base::StringPrintf;

extern bool nfc_debug_enabled;

/*****************************************************************************
* Protocol-specific event handlers
*****************************************************************************/

/*******************************************************************************
**
** Function         nfa_ce_handle_t3t_evt
**
** Description      Handler for Type-3 tag card emulation events
**
** Returns          Nothing
**
*******************************************************************************/
void nfa_ce_handle_t3t_evt(tCE_EVENT event, tCE_DATA* p_ce_data) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA conn_evt;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("nfa_ce_handle_t3t_evt: event 0x%x", event);
  /* For the felica on host for nfcFcallback */
  for (uint8_t idx = 0; idx < NFA_CE_LISTEN_INFO_IDX_INVALID; idx++) {
    if ((p_cb->listen_info[idx].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
        (p_cb->listen_info[idx].flags & NFA_CE_LISTEN_INFO_FELICA) &&
        (p_cb->listen_info[idx].flags & NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND)) {
      p_cb->idx_cur_active = idx;
      p_cb->p_active_conn_cback =
          p_cb->listen_info[p_cb->idx_cur_active].p_conn_cback;
      break;
    }
  }
  switch (event) {
    case CE_T3T_NDEF_UPDATE_START_EVT:
      /* Notify app using callback associated with the active ndef */
      if (p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) {
        conn_evt.status = NFA_STATUS_OK;
        (*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_START_EVT, &conn_evt);
      } else {
        LOG(ERROR) << StringPrintf(
            "nfa_ce_handle_t3t_evt: got CE_T3T_UPDATE_START_EVT, but no active "
            "NDEF");
      }
      break;

    case CE_T3T_NDEF_UPDATE_CPLT_EVT:
      /* Notify app using callback associated with the active ndef */
      if (p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) {
        conn_evt.ndef_write_cplt.status = NFA_STATUS_OK;
        conn_evt.ndef_write_cplt.len = p_ce_data->update_info.length;
        conn_evt.ndef_write_cplt.p_data = p_ce_data->update_info.p_data;
        (*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_CPLT_EVT, &conn_evt);
      } else {
        LOG(ERROR) << StringPrintf(
            "nfa_ce_handle_t3t_evt: got CE_T3T_UPDATE_CPLT_EVT, but no active "
            "NDEF");
      }
      break;

    case CE_T3T_RAW_FRAME_EVT:
      if (p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) {
        conn_evt.data.status = p_ce_data->raw_frame.status;
        conn_evt.data.p_data = (uint8_t*)(p_ce_data->raw_frame.p_data + 1) +
                               p_ce_data->raw_frame.p_data->offset;
        conn_evt.data.len = p_ce_data->raw_frame.p_data->len;
        (*p_cb->p_active_conn_cback)(NFA_DATA_EVT, &conn_evt);
      } else {
        /* If we have not notified the app of activation, do so now */
        if (p_cb->listen_info[p_cb->idx_cur_active].flags &
            NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND) {
          p_cb->listen_info[p_cb->idx_cur_active].flags &=
              ~NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND;

          conn_evt.ce_activated.handle =
              NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);
          memcpy(&(conn_evt.ce_activated.activate_ntf),
                 &p_cb->activation_params, sizeof(tNFC_ACTIVATE_DEVT));
          conn_evt.ce_activated.status = NFA_STATUS_OK;

          (*p_cb->p_active_conn_cback)(NFA_CE_ACTIVATED_EVT, &conn_evt);
        }
        /* Notify app of t3t raw data */
        conn_evt.ce_data.status = p_ce_data->raw_frame.status;
        conn_evt.ce_data.handle =
            (NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active));
        conn_evt.ce_data.p_data = (uint8_t*)(p_ce_data->raw_frame.p_data + 1) +
                                  p_ce_data->raw_frame.p_data->offset;
        conn_evt.ce_data.len = p_ce_data->raw_frame.p_data->len;
        (*p_cb->p_active_conn_cback)(NFA_CE_DATA_EVT, &conn_evt);
      }
      GKI_freebuf(p_ce_data->raw_frame.p_data);
      break;

    default:
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "nfa_ce_handle_t3t_evt unhandled event=0x%02x", event);
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_ce_handle_t4t_evt
**
** Description      Handler for Type-4 tag card emulation events (for NDEF case)
**
** Returns          Nothing
**
*******************************************************************************/
void nfa_ce_handle_t4t_evt(tCE_EVENT event, tCE_DATA* p_ce_data) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA conn_evt;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("nfa_ce_handle_t4t_evt: event 0x%x", event);

  /* AID for NDEF selected. we had notified the app of activation. */
  p_cb->idx_cur_active = NFA_CE_LISTEN_INFO_IDX_NDEF;
  if (p_cb->listen_info[p_cb->idx_cur_active].flags &
      NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND) {
    p_cb->p_active_conn_cback =
        p_cb->listen_info[p_cb->idx_cur_active].p_conn_cback;
  }

  switch (event) {
    case CE_T4T_NDEF_UPDATE_START_EVT:
      conn_evt.status = NFA_STATUS_OK;
      (*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_START_EVT, &conn_evt);
      break;

    case CE_T4T_NDEF_UPDATE_CPLT_EVT:
      conn_evt.ndef_write_cplt.len = p_ce_data->update_info.length;
      conn_evt.ndef_write_cplt.p_data = p_ce_data->update_info.p_data;

      if (NDEF_MsgValidate(p_ce_data->update_info.p_data,
                           p_ce_data->update_info.length, true) != NDEF_OK)
        conn_evt.ndef_write_cplt.status = NFA_STATUS_FAILED;
      else
        conn_evt.ndef_write_cplt.status = NFA_STATUS_OK;

      (*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_CPLT_EVT, &conn_evt);
      break;

    case CE_T4T_NDEF_UPDATE_ABORT_EVT:
      conn_evt.ndef_write_cplt.len = 0;
      conn_evt.ndef_write_cplt.status = NFA_STATUS_FAILED;
      conn_evt.ndef_write_cplt.p_data = NULL;
      (*p_cb->p_active_conn_cback)(NFA_CE_NDEF_WRITE_CPLT_EVT, &conn_evt);
      break;

    default:
      /* CE_T4T_RAW_FRAME_EVT is not used in NFA CE */
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "nfa_ce_handle_t4t_evt unhandled event=0x%02x", event);
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_ce_handle_t4t_aid_evt
**
** Description      Handler for Type-4 tag AID events (for AIDs registered using
**                  NFA_CeRegisterT4tAidOnDH)
**
** Returns          Nothing
**
*******************************************************************************/
void nfa_ce_handle_t4t_aid_evt(tCE_EVENT event, tCE_DATA* p_ce_data) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  uint8_t listen_info_idx;
  tNFA_CONN_EVT_DATA conn_evt;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("nfa_ce_handle_t4t_aid_evt: event 0x%x", event);

  /* Get listen_info for this aid callback */
  for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_IDX_INVALID;
       listen_info_idx++) {
    if ((p_cb->listen_info[listen_info_idx].flags &
         NFA_CE_LISTEN_INFO_IN_USE) &&
        (p_cb->listen_info[listen_info_idx].flags &
         NFA_CE_LISTEN_INFO_T4T_AID) &&
        (p_cb->listen_info[listen_info_idx].t4t_aid_handle ==
         p_ce_data->raw_frame.aid_handle)) {
      p_cb->idx_cur_active = listen_info_idx;
      p_cb->p_active_conn_cback =
          p_cb->listen_info[p_cb->idx_cur_active].p_conn_cback;
      break;
    }
  }

  if (event == CE_T4T_RAW_FRAME_EVT) {
    if (listen_info_idx != NFA_CE_LISTEN_INFO_IDX_INVALID) {
      /* Found listen_info entry */
      conn_evt.ce_activated.handle =
          NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);

      /* If we have not notified the app of activation, do so now */
      if (p_cb->listen_info[p_cb->idx_cur_active].flags &
          NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND) {
        p_cb->listen_info[p_cb->idx_cur_active].flags &=
            ~NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND;

        memcpy(&(conn_evt.ce_activated.activate_ntf), &p_cb->activation_params,
               sizeof(tNFC_ACTIVATE_DEVT));
        conn_evt.ce_activated.status = NFA_STATUS_OK;
        (*p_cb->p_active_conn_cback)(NFA_CE_ACTIVATED_EVT, &conn_evt);
      }

      /* Notify app of AID data */
      conn_evt.ce_data.status = p_ce_data->raw_frame.status;
      conn_evt.ce_data.handle =
          NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);
      conn_evt.ce_data.p_data = (uint8_t*)(p_ce_data->raw_frame.p_data + 1) +
                                p_ce_data->raw_frame.p_data->offset;
      conn_evt.ce_data.len = p_ce_data->raw_frame.p_data->len;
      (*p_cb->p_active_conn_cback)(NFA_CE_DATA_EVT, &conn_evt);
    } else {
      LOG(ERROR) << StringPrintf(
          "nfa_ce_handle_t4t_aid_evt: unable to find listen_info for aid hdl "
          "%i",
          p_ce_data->raw_frame.aid_handle);
    }

    GKI_freebuf(p_ce_data->raw_frame.p_data);
  }
}

/*****************************************************************************
* Discovery configuration and discovery event handlers
*****************************************************************************/

/*******************************************************************************
**
** Function         nfa_ce_discovery_cback
**
** Description      Processing event from discovery callback
**
** Returns          None
**
*******************************************************************************/
void nfa_ce_discovery_cback(tNFA_DM_RF_DISC_EVT event, tNFC_DISCOVER* p_data) {
  tNFA_CE_MSG ce_msg;
  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event:0x%02X", event);

  switch (event) {
    case NFA_DM_RF_DISC_START_EVT:
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "nfa_ce_handle_disc_start (status=0x%x)", p_data->start);
      break;

    case NFA_DM_RF_DISC_ACTIVATED_EVT:
      ce_msg.activate_ntf.hdr.event = NFA_CE_ACTIVATE_NTF_EVT;
      ce_msg.activate_ntf.p_activation_params = &p_data->activate;
      nfa_ce_hdl_event((NFC_HDR*)&ce_msg);
      break;

    case NFA_DM_RF_DISC_DEACTIVATED_EVT:
      /* DM broadcasts deactivaiton event in listen sleep state, so check before
       * processing */
      if (nfa_ce_cb.flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) {
        ce_msg.hdr.event = NFA_CE_DEACTIVATE_NTF_EVT;
        ce_msg.hdr.layer_specific = p_data->deactivate.type;
        nfa_ce_hdl_event((NFC_HDR*)&ce_msg);
      }
      break;

    default:
      LOG(ERROR) << StringPrintf("Unexpected event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfc_ce_t3t_set_listen_params
**
** Description      Set t3t listening parameters
**
** Returns          Nothing
**
*******************************************************************************/
void nfc_ce_t3t_set_listen_params(void) {
  uint8_t i;
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  uint8_t tlv[128], *p_params;
  uint8_t tlv_size;
  uint16_t t3t_flags2_mask = 0xFFFF; /* Mask of which T3T_IDs are disabled */
  uint8_t t3t_idx = 0;
  uint8_t adv_Feat = 1;
  uint8_t t3tPMM[NCI_T3T_PMM_LEN] = {0xFF, 0xFF, 0xFF, 0xFF,
                                     0xFF, 0xFF, 0xFF, 0xFF};

  /* Point to start of tlv buffer */
  p_params = tlv;

  /* Set system code and NFCID2 */
  for (i = 0; i < NFA_CE_LISTEN_INFO_MAX; i++) {
    if ((p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
        (p_cb->listen_info[i].protocol_mask & NFA_PROTOCOL_MASK_T3T)) {
      /* Set tag's system code and NFCID2 */
      UINT8_TO_STREAM(p_params, NFC_PMID_LF_T3T_ID1 + t3t_idx); /* type */
      /* length */
      UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_ID(NFC_GetNCIVersion()));
      /* System Code */
      UINT16_TO_BE_STREAM(p_params, p_cb->listen_info[i].t3t_system_code);
      ARRAY_TO_BE_STREAM(p_params, p_cb->listen_info[i].t3t_nfcid2,
                         NCI_RF_F_UID_LEN);
      if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
        ARRAY_TO_BE_STREAM(p_params, p_cb->listen_info[i].t3t_pmm,
                           NCI_T3T_PMM_LEN);
      }
      /* Set mask for this ID */
      t3t_flags2_mask &= ~((uint16_t)(1 << t3t_idx));
      t3t_idx++;
    }
  }

  /* For NCI draft 22+, the polarity of NFC_PMID_LF_T3T_FLAGS2 is flipped */
  t3t_flags2_mask = ~t3t_flags2_mask;

  UINT8_TO_STREAM(p_params, NFC_PMID_LF_T3T_FLAGS2);      /* type */
  UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_FLAGS2); /* length */
  /* Mask of IDs to disable listening */
  UINT16_TO_STREAM(p_params, t3t_flags2_mask);

  if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
    /*Name changed in NCI2.0*/
    UINT8_TO_STREAM(p_params, NCI_PARAM_ID_LF_T3T_RD_ALLOWED);  /* type */
    UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_RD_ALLOWED); /* length */
  } else {
    UINT8_TO_STREAM(p_params, NCI_PARAM_ID_LF_CON_ADV_FEAT);  /* type */
    UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_CON_ADV_FEAT); /* length */
  }
  UINT8_TO_STREAM(p_params, adv_Feat);

  if (NFC_GetNCIVersion() != NCI_VERSION_2_0) {
    UINT8_TO_STREAM(p_params, NCI_PARAM_ID_LF_T3T_PMM);  /* type */
    UINT8_TO_STREAM(p_params, NCI_PARAM_LEN_LF_T3T_PMM); /* length */
    ARRAY_TO_BE_STREAM(p_params, t3tPMM, NCI_T3T_PMM_LEN);
  }
  tlv_size = (uint8_t)(p_params - tlv);
  if (appl_dta_mode_flag == 0x01) {
    nfa_dm_cb.eDtaMode |= NFA_DTA_HCEF_MODE;
  }
  nfa_dm_check_set_config(tlv_size, (uint8_t*)tlv, false);
}

/*******************************************************************************
**
** Function         nfa_ce_t3t_generate_rand_nfcid
**
** Description      Generate a random NFCID2 for Type-3 tag
**
** Returns          Nothing
**
*******************************************************************************/
void nfa_ce_t3t_generate_rand_nfcid(uint8_t nfcid2[NCI_RF_F_UID_LEN]) {
  uint32_t rand_seed = GKI_get_tick_count();

  /* For Type-3 tag, nfcid2 starts witn 02:fe */
  nfcid2[0] = 0x02;
  nfcid2[1] = 0xFE;

  /* The remaining 6 bytes are random */
  nfcid2[2] = (uint8_t)(rand_seed & 0xFF);
  nfcid2[3] = (uint8_t)(rand_seed >> 8 & 0xFF);
  rand_seed >>= (rand_seed & 3);
  nfcid2[4] = (uint8_t)(rand_seed & 0xFF);
  nfcid2[5] = (uint8_t)(rand_seed >> 8 & 0xFF);
  rand_seed >>= (rand_seed & 3);
  nfcid2[6] = (uint8_t)(rand_seed & 0xFF);
  nfcid2[7] = (uint8_t)(rand_seed >> 8 & 0xFF);
}

/*******************************************************************************
**
** Function         nfa_ce_start_listening
**
** Description      Start listening
**
** Returns          NFA_STATUS_OK if successful
**
*******************************************************************************/
tNFA_STATUS nfa_ce_start_listening(void) {
  tNFA_DM_DISC_TECH_PROTO_MASK listen_mask;
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_HANDLE disc_handle;
  uint8_t listen_info_idx;

  /*************************************************************************/
  /* Construct protocol preference list to listen for */

  /* First, get protocol preference for active NDEF (if any) */
  if ((p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
       NFA_CE_LISTEN_INFO_IN_USE) &&
      (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle ==
       NFA_HANDLE_INVALID)) {
    listen_mask = 0;

    if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
        NFA_PROTOCOL_MASK_T3T) {
      /* set T3T config params */
      nfc_ce_t3t_set_listen_params();

      listen_mask |= NFA_DM_DISC_MASK_LF_T3T;
    }

    if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
        NFA_PROTOCOL_MASK_ISO_DEP) {
      listen_mask |= nfa_ce_cb.isodep_disc_mask;
    }

    disc_handle = nfa_dm_add_rf_discover(listen_mask, NFA_DM_DISC_HOST_ID_DH,
                                         nfa_ce_discovery_cback);

    if (disc_handle == NFA_HANDLE_INVALID)
      return (NFA_STATUS_FAILED);
    else
      p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle =
          disc_handle;
  }

  /* Next, add protocols from non-NDEF, if any */
  for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_IDX_INVALID;
       listen_info_idx++) {
    /* add RF discovery to DM only if it is not added yet */
    if ((p_cb->listen_info[listen_info_idx].flags &
         NFA_CE_LISTEN_INFO_IN_USE) &&
        (p_cb->listen_info[listen_info_idx].rf_disc_handle ==
         NFA_HANDLE_INVALID)) {
      if (p_cb->listen_info[listen_info_idx].flags &
          NFA_CE_LISTEN_INFO_FELICA) {
        /* set T3T config params */
        nfc_ce_t3t_set_listen_params();

        disc_handle = nfa_dm_add_rf_discover(NFA_DM_DISC_MASK_LF_T3T,
                                             NFA_DM_DISC_HOST_ID_DH,
                                             nfa_ce_discovery_cback);

        if (disc_handle == NFA_HANDLE_INVALID)
          return (NFA_STATUS_FAILED);
        else
          p_cb->listen_info[listen_info_idx].rf_disc_handle = disc_handle;
      } else if (p_cb->listen_info[listen_info_idx].flags &
                 NFA_CE_LISTEN_INFO_T4T_AID) {
        disc_handle = nfa_dm_add_rf_discover(nfa_ce_cb.isodep_disc_mask,
                                             NFA_DM_DISC_HOST_ID_DH,
                                             nfa_ce_discovery_cback);

        if (disc_handle == NFA_HANDLE_INVALID)
          return (NFA_STATUS_FAILED);
        else
          p_cb->listen_info[listen_info_idx].rf_disc_handle = disc_handle;
      }
#if (NFC_NFCEE_INCLUDED == TRUE)
      else if (p_cb->listen_info[listen_info_idx].flags &
               NFA_CE_LISTEN_INFO_UICC) {
        listen_mask = 0;
        if (nfa_ee_is_active(p_cb->listen_info[listen_info_idx].ee_handle)) {
          if (p_cb->listen_info[listen_info_idx].tech_mask &
              NFA_TECHNOLOGY_MASK_A) {
            listen_mask |= NFA_DM_DISC_MASK_LA_ISO_DEP;
          }
          if (p_cb->listen_info[listen_info_idx].tech_mask &
              NFA_TECHNOLOGY_MASK_B) {
            listen_mask |= NFA_DM_DISC_MASK_LB_ISO_DEP;
          }
          if (p_cb->listen_info[listen_info_idx].tech_mask &
              NFA_TECHNOLOGY_MASK_F) {
            listen_mask |= NFA_DM_DISC_MASK_LF_T3T;
          }
          if (p_cb->listen_info[listen_info_idx].tech_mask &
              NFA_TECHNOLOGY_MASK_B_PRIME) {
            listen_mask |= NFA_DM_DISC_MASK_L_B_PRIME;
          }
        }

        if (listen_mask) {
          /* Start listening for requested technologies */
          /* register discovery callback to NFA DM */
          disc_handle = nfa_dm_add_rf_discover(
              listen_mask,
              (tNFA_DM_DISC_HOST_ID)(
                  p_cb->listen_info[listen_info_idx].ee_handle & 0x00FF),
              nfa_ce_discovery_cback);

          if (disc_handle == NFA_HANDLE_INVALID)
            return (NFA_STATUS_FAILED);
          else {
            p_cb->listen_info[listen_info_idx].rf_disc_handle = disc_handle;
            p_cb->listen_info[listen_info_idx].tech_proto_mask = listen_mask;
          }
        } else {
          LOG(ERROR) << StringPrintf(
              "UICC[0x%x] is not activated",
              p_cb->listen_info[listen_info_idx].ee_handle);
        }
      }
#endif
    }
  }

  return NFA_STATUS_OK;
}

/*******************************************************************************
**
** Function         nfa_ce_restart_listen_check
**
** Description      Called on deactivation. Check if any active listen_info
**                  entries to listen for
**
** Returns          TRUE if listening is restarted.
**                  FALSE if listening not restarted
**
*******************************************************************************/
bool nfa_ce_restart_listen_check(void) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  uint8_t listen_info_idx;

  /* Check if any active entries in listen_info table */
  for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_MAX;
       listen_info_idx++) {
    if (p_cb->listen_info[listen_info_idx].flags & NFA_CE_LISTEN_INFO_IN_USE)
      break;
  }

  /* Restart listening if there are any active listen_info entries */
  if (listen_info_idx != NFA_CE_LISTEN_INFO_IDX_INVALID) {
    /* restart listening */
    nfa_ce_start_listening();
  } else {
    /* No active listen_info entries */
    return false;
  }

  return true;
}

/*******************************************************************************
**
** Function         nfa_ce_remove_listen_info_entry
**
** Description      Remove entry from listen_info table. (when API deregister is
**                  called or listen_start failed)
**
**
** Returns          Nothing
**
*******************************************************************************/
void nfa_ce_remove_listen_info_entry(uint8_t listen_info_idx, bool notify_app) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA conn_evt;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("NFA_CE: removing listen_info entry %i", listen_info_idx);

  /* Notify app that listening has stopped  if requested (for API deregister) */
  /* For LISTEN_START failures, app has already notified of NFA_LISTEN_START_EVT
   * failure */
  if (notify_app) {
    if (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_NDEF) {
      conn_evt.status = NFA_STATUS_OK;
      (*p_cb->listen_info[listen_info_idx].p_conn_cback)(
          NFA_CE_LOCAL_TAG_CONFIGURED_EVT, &conn_evt);
    }
#if (NFC_NFCEE_INCLUDED == TRUE)
    else if (p_cb->listen_info[listen_info_idx].flags &
             NFA_CE_LISTEN_INFO_UICC) {
      conn_evt.status = NFA_STATUS_OK;
      (*p_cb->listen_info[listen_info_idx].p_conn_cback)(
          NFA_CE_UICC_LISTEN_CONFIGURED_EVT, &conn_evt);
    }
#endif
    else {
      conn_evt.ce_deregistered.handle = NFA_HANDLE_GROUP_CE | listen_info_idx;
      (*p_cb->listen_info[listen_info_idx].p_conn_cback)(
          NFA_CE_DEREGISTERED_EVT, &conn_evt);
    }
  }

  /* Handle NDEF stopping */
  if (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_NDEF) {
    /* clear NDEF contents */
    CE_T3tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
    CE_T4tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);

    if (p_cb->listen_info[listen_info_idx].protocol_mask &
        NFA_PROTOCOL_MASK_T3T) {
      p_cb->listen_info[listen_info_idx].protocol_mask = 0;

      /* clear T3T Flags for NDEF */
      nfc_ce_t3t_set_listen_params();
    }

    /* Free scratch buffer for this NDEF, if one was allocated */
    nfa_ce_free_scratch_buf();
  }
  /* If stopping listening Felica system code, then clear T3T Flags for this */
  else if (p_cb->listen_info[listen_info_idx].flags &
           NFA_CE_LISTEN_INFO_FELICA) {
    p_cb->listen_info[listen_info_idx].protocol_mask = 0;

    /* clear T3T Flags for registered Felica system code */
    nfc_ce_t3t_set_listen_params();
  }
  /* If stopping listening T4T AID, then deregister this AID from CE_T4T */
  else if (p_cb->listen_info[listen_info_idx].flags &
           NFA_CE_LISTEN_INFO_T4T_AID) {
    /* Free t4t_aid_cback used by this AID */
    CE_T4tDeregisterAID(p_cb->listen_info[listen_info_idx].t4t_aid_handle);
  }

  if (p_cb->listen_info[listen_info_idx].rf_disc_handle != NFA_HANDLE_INVALID) {
    nfa_dm_delete_rf_discover(
        p_cb->listen_info[listen_info_idx].rf_disc_handle);
    p_cb->listen_info[listen_info_idx].rf_disc_handle = NFA_HANDLE_INVALID;
  }

  /* Remove entry from listen_info table */
  p_cb->listen_info[listen_info_idx].flags = 0;
}

/*******************************************************************************
**
** Function         nfa_ce_free_scratch_buf
**
** Description      free scratch buffer (if one is allocated)
**
** Returns          nothing
**
*******************************************************************************/
void nfa_ce_free_scratch_buf(void) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  if (p_cb->p_scratch_buf) {
    nfa_mem_co_free(p_cb->p_scratch_buf);
    p_cb->p_scratch_buf = NULL;
  }
}

/*******************************************************************************
**
** Function         nfa_ce_realloc_scratch_buffer
**
** Description      Set scratch buffer if necessary (for writable NDEF messages)
**
** Returns          NFA_STATUS_OK if successful
**
*******************************************************************************/
tNFA_STATUS nfa_ce_realloc_scratch_buffer(void) {
  tNFA_STATUS result = NFA_STATUS_OK;

  /* If current NDEF message is read-only, then we do not need a scratch buffer
   */
  if (nfa_ce_cb.listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
      NFC_CE_LISTEN_INFO_READONLY_NDEF) {
    /* Free existing scratch buffer, if one was allocated */
    nfa_ce_free_scratch_buf();
  } else {
    /* If no scratch buffer allocated yet, or if current scratch buffer size is
     * different from current ndef size, */
    /* then allocate a new scratch buffer. */
    if ((nfa_ce_cb.p_scratch_buf == NULL) ||
        (nfa_ce_cb.scratch_buf_size != nfa_ce_cb.ndef_max_size)) {
      /* Free existing scratch buffer, if one was allocated */
      nfa_ce_free_scratch_buf();

      nfa_ce_cb.p_scratch_buf =
          (uint8_t*)nfa_mem_co_alloc(nfa_ce_cb.ndef_max_size);
      if (nfa_ce_cb.p_scratch_buf != NULL) {
        nfa_ce_cb.scratch_buf_size = nfa_ce_cb.ndef_max_size;
      } else {
        LOG(ERROR) << StringPrintf(
            "Unable to allocate scratch buffer for writable NDEF message (%i "
            "bytes)",
            nfa_ce_cb.ndef_max_size);
        result = NFA_STATUS_FAILED;
      }
    }
  }

  return (result);
}

/*******************************************************************************
**
** Function         nfa_ce_set_content
**
** Description      Set NDEF contents
**
** Returns          void
**
*******************************************************************************/
tNFC_STATUS nfa_ce_set_content(void) {
  tNFC_STATUS status;
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_PROTOCOL_MASK ndef_protocol_mask;
  bool readonly;

  /* Check if listening for NDEF */
  if (!(p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
        NFA_CE_LISTEN_INFO_IN_USE)) {
    /* Not listening for NDEF */
    return (NFA_STATUS_OK);
  }

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Setting NDEF contents");

  readonly = (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
              NFC_CE_LISTEN_INFO_READONLY_NDEF)
                 ? true
                 : false;
  ndef_protocol_mask =
      p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask;

  /* Allocate a scratch buffer if needed (for handling write-requests) */
  status = nfa_ce_realloc_scratch_buffer();
  if (status == NFA_STATUS_OK) {
    if ((ndef_protocol_mask & NFA_PROTOCOL_MASK_T3T) &&
        (status == NFA_STATUS_OK)) {
      /* Type3Tag    - NFC-F */
      status = CE_T3tSetLocalNDEFMsg(readonly, p_cb->ndef_max_size,
                                     p_cb->ndef_cur_size, p_cb->p_ndef_data,
                                     p_cb->p_scratch_buf);
    }

    if ((ndef_protocol_mask & NFA_PROTOCOL_MASK_ISO_DEP) &&
        (status == NFA_STATUS_OK)) {
      /* ISODEP/4A,4B- NFC-A or NFC-B */
      status = CE_T4tSetLocalNDEFMsg(readonly, p_cb->ndef_max_size,
                                     p_cb->ndef_cur_size, p_cb->p_ndef_data,
                                     p_cb->p_scratch_buf);
    }
  }

  if (status != NFA_STATUS_OK) {
    /* clear NDEF contents */
    CE_T3tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
    CE_T4tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);

    LOG(ERROR) << StringPrintf("Unable to set contents (error %02x)", status);
  }

  return (status);
}

/*******************************************************************************
**
** Function         nfa_ce_activate_ntf
**
** Description      Action when activation has occured (NFA_CE_ACTIVATE_NTF_EVT)
**
**                  - Find the listen_info entry assocated with this activation
**                      - get the app callback that registered for this listen
**                      - call CE_SetActivatedTagType with activation parameters
**
** Returns          TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_activate_ntf(tNFA_CE_MSG* p_ce_msg) {
  tNFC_ACTIVATE_DEVT* p_activation_params =
      p_ce_msg->activate_ntf.p_activation_params;
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA conn_evt;
  tCE_CBACK* p_ce_cback = NULL;
  uint16_t t3t_system_code = 0xFFFF;
  uint8_t listen_info_idx = NFA_CE_LISTEN_INFO_IDX_INVALID;
  uint8_t* p_nfcid2 = NULL;
  uint8_t i;
  bool t4t_activate_pending = false;

  bool t3t_activate_pending = false;
  bool t3t_offhost_entry_found = false;
  uint8_t t3t_activate_idx = 0;
  uint8_t t3t_offhost_idx = 0;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "protocol=%d", p_ce_msg->activate_ntf.p_activation_params->protocol);

  /* Tag is in listen active state */
  p_cb->flags |= NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP;

  /* Store activation parameters */
  memcpy(&p_cb->activation_params, p_activation_params,
         sizeof(tNFC_ACTIVATE_DEVT));

  /* Find the listen_info entry corresponding to this activation */
  if (p_cb->activation_params.protocol == NFA_PROTOCOL_T3T) {
    /* Look for T3T entries in listen_info table that match activated system
     * code and NFCID2 */
    for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_IDX_INVALID;
         listen_info_idx++) {
      /* Look for entries with NFA_PROTOCOL_MASK_T3T */
      if (p_cb->listen_info[listen_info_idx].flags &
          NFA_CE_LISTEN_INFO_IN_USE) {
        if (p_cb->listen_info[listen_info_idx].protocol_mask &
            NFA_PROTOCOL_MASK_T3T) {
          /* Check if system_code and nfcid2 that matches activation params */
          p_nfcid2 = p_cb->listen_info[listen_info_idx].t3t_nfcid2;
          t3t_system_code = p_cb->listen_info[listen_info_idx].t3t_system_code;

          /* Compare NFCID2 (note: NFCC currently does not return system code in
           * activation parameters) */
          if ((memcmp(p_nfcid2,
                      p_cb->activation_params.rf_tech_param.param.lf.nfcid2,
                      NCI_RF_F_UID_LEN) == 0)
              /* && (t3t_system_code == p_ce_msg->activation.p_activate_info->rf_tech_param.param.lf.system_code) */) {
            p_cb->listen_info[listen_info_idx].flags |=
                NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND;
            t3t_activate_pending = true;
            t3t_activate_idx = listen_info_idx;
          }
        }

        /* Check if entry is for T3T UICC */
        if ((p_cb->listen_info[listen_info_idx].flags &
             NFA_CE_LISTEN_INFO_UICC) &&
            (p_cb->listen_info[listen_info_idx].tech_mask &
             NFA_TECHNOLOGY_MASK_F)) {
          t3t_offhost_entry_found = true;
          t3t_offhost_idx = listen_info_idx;
        }
      }
    }

    p_ce_cback = nfa_ce_handle_t3t_evt;
    /* If listening for PROTO_T3T on DH and eSE/UICC, then notify CE module
     * now and wait for reader/writer to SELECT a target */
    if (t3t_activate_pending && t3t_offhost_entry_found) {
      CE_SetActivatedTagType(&p_cb->activation_params, t3t_system_code,
                             p_ce_cback);
      return true;
    } else if (t3t_activate_pending) {
      listen_info_idx = t3t_activate_idx;
    } else if (t3t_offhost_entry_found) {
      listen_info_idx = t3t_offhost_idx;
    }
  } else if (p_cb->activation_params.protocol == NFA_PROTOCOL_ISO_DEP) {
    p_ce_cback = nfa_ce_handle_t4t_evt;

    /* For T4T, we do not know which AID will be selected yet */

    /* For all T4T entries in listen_info, set T4T_ACTIVATE_NOTIFY_PENDING flag
     */
    for (i = 0; i < NFA_CE_LISTEN_INFO_IDX_INVALID; i++) {
      if (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) {
        if (p_cb->listen_info[i].protocol_mask & NFA_PROTOCOL_MASK_ISO_DEP) {
          /* Found listen_info table entry for T4T raw listen */
          p_cb->listen_info[i].flags |= NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND;

          /* If entry if for NDEF, select it, so application gets nofitifed of
           * ACTIVATE_EVT now */
          if (i == NFA_CE_LISTEN_INFO_IDX_NDEF) {
            listen_info_idx = NFA_CE_LISTEN_INFO_IDX_NDEF;
          }

          t4t_activate_pending = true;
        }

#if (NFC_NFCEE_INCLUDED == TRUE)
        /* Check if entry is for ISO_DEP UICC */
        if (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC) {
          if (((p_cb->activation_params.rf_tech_param.mode ==
                NFC_DISCOVERY_TYPE_LISTEN_A) &&
               (p_cb->listen_info[i].tech_proto_mask &
                NFA_DM_DISC_MASK_LA_ISO_DEP)) ||
              ((p_cb->activation_params.rf_tech_param.mode ==
                NFC_DISCOVERY_TYPE_LISTEN_B) &&
               (p_cb->listen_info[i].tech_proto_mask &
                NFA_DM_DISC_MASK_LB_ISO_DEP))) {
            listen_info_idx = i;
          }
        }
#endif
      }
    }

    /* If listening for ISO_DEP, but not NDEF nor UICC, then notify CE module
     * now and wait for reader/writer to SELECT an AID */
    if (t4t_activate_pending &&
        (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID)) {
      CE_SetActivatedTagType(&p_cb->activation_params, 0, p_ce_cback);
      return true;
    }
  } else if (p_cb->activation_params.intf_param.type ==
             NFC_INTERFACE_EE_DIRECT_RF) {
    /* search any entry listening UICC */
    for (i = 0; i < NFA_CE_LISTEN_INFO_IDX_INVALID; i++) {
      if ((p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
          (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC)) {
        listen_info_idx = i;
        break;
      }
    }
  }

  /* Check if valid listen_info entry was found */
  if ((listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID) ||
      ((listen_info_idx == NFA_CE_LISTEN_INFO_IDX_NDEF) &&
       !(p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
         NFA_CE_LISTEN_INFO_IN_USE))) {
    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
        "No listen_info found for this activation. listen_info_idx=%d",
        listen_info_idx);
    return true;
  }

  p_cb->listen_info[listen_info_idx].flags &=
      ~NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND;
  p_cb->listen_info[listen_info_idx].flags &=
      ~NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND;

  /* Get CONN_CBACK for this activation */
  p_cb->p_active_conn_cback = p_cb->listen_info[listen_info_idx].p_conn_cback;
  p_cb->idx_cur_active = listen_info_idx;

  if ((p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF) ||
      (p_cb->listen_info[p_cb->idx_cur_active].flags &
       NFA_CE_LISTEN_INFO_UICC)) {
    memcpy(&(conn_evt.activated.activate_ntf), &p_cb->activation_params,
           sizeof(tNFC_ACTIVATE_DEVT));

    (*p_cb->p_active_conn_cback)(NFA_ACTIVATED_EVT, &conn_evt);
  } else {
    conn_evt.ce_activated.handle =
        NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)p_cb->idx_cur_active);
    memcpy(&(conn_evt.ce_activated.activate_ntf), &p_cb->activation_params,
           sizeof(tNFC_ACTIVATE_DEVT));
    conn_evt.ce_activated.status = NFA_STATUS_OK;

    (*p_cb->p_active_conn_cback)(NFA_CE_ACTIVATED_EVT, &conn_evt);
  }

  /* we don't need any CE subsystem in case of NFCEE direct RF interface */
  if (p_ce_cback) {
    /* Notify CE subsystem */
    CE_SetActivatedTagType(&p_cb->activation_params, t3t_system_code,
                           p_ce_cback);
  }
  return true;
}

/*******************************************************************************
**
** Function         nfa_ce_deactivate_ntf
**
** Description      Action when deactivate occurs. (NFA_CE_DEACTIVATE_NTF_EVT)
**
**                  - If deactivate due to API deregister, then remove its entry
**                    from listen_info table
**
**                  - If NDEF was modified while activated, then restore
**                    original NDEF contents
**
**                  - Restart listening (if any active entries in listen table)
**
** Returns          TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_deactivate_ntf(tNFA_CE_MSG* p_ce_msg) {
  tNFC_DEACT_TYPE deact_type = (tNFC_DEACT_TYPE)p_ce_msg->hdr.layer_specific;
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA conn_evt;
  uint8_t i;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("deact_type=%d", deact_type);

  /* Check if deactivating to SLEEP mode */
  if ((deact_type == NFC_DEACTIVATE_TYPE_SLEEP) ||
      (deact_type == NFC_DEACTIVATE_TYPE_SLEEP_AF)) {
    if (nfa_ce_cb.idx_wild_card == NFA_CE_LISTEN_INFO_IDX_INVALID) {
      /* notify deactivated as sleep and wait for reactivation or deactivation
       * to idle */
      conn_evt.deactivated.type = deact_type;

      /* if T4T AID application has not been selected then p_active_conn_cback
       * could be NULL */
      if (p_cb->p_active_conn_cback)
        (*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
    } else {
      conn_evt.ce_deactivated.handle =
          NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)nfa_ce_cb.idx_wild_card);
      conn_evt.ce_deactivated.type = deact_type;
      if (p_cb->p_active_conn_cback)
        (*p_cb->p_active_conn_cback)(NFA_CE_DEACTIVATED_EVT, &conn_evt);
    }

    return true;
  } else {
    deact_type = NFC_DEACTIVATE_TYPE_IDLE;
  }

  /* Tag is in idle state */
  p_cb->flags &= ~NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP;

  /* First, notify app of deactivation */
  for (i = 0; i < NFA_CE_LISTEN_INFO_IDX_INVALID; i++) {
    if (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) {
      if ((p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC) &&
          (i == p_cb->idx_cur_active)) {
        conn_evt.deactivated.type = deact_type;
        (*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
      } else if ((p_cb->activation_params.protocol == NFA_PROTOCOL_ISO_DEP) &&
                 (p_cb->listen_info[i].protocol_mask &
                  NFA_PROTOCOL_MASK_ISO_DEP)) {
        /* Don't send NFA_DEACTIVATED_EVT if NFA_ACTIVATED_EVT wasn't sent */
        if (!(p_cb->listen_info[i].flags &
              NFA_CE_LISTEN_INFO_T4T_ACTIVATE_PND)) {
          if (i == NFA_CE_LISTEN_INFO_IDX_NDEF) {
            conn_evt.deactivated.type = deact_type;
            (*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
          } else {
            conn_evt.ce_deactivated.handle =
                NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)i);
            conn_evt.ce_deactivated.type = deact_type;
            (*p_cb->p_active_conn_cback)(NFA_CE_DEACTIVATED_EVT, &conn_evt);
          }
        }
      } else if ((p_cb->activation_params.protocol == NFA_PROTOCOL_T3T) &&
                 (p_cb->listen_info[i].protocol_mask & NFA_PROTOCOL_MASK_T3T)) {
        /* Don't send NFA_DEACTIVATED_EVT if NFA_ACTIVATED_EVT wasn't sent */
        if (!(p_cb->listen_info[i].flags &
              NFA_CE_LISTEN_INFO_T3T_ACTIVATE_PND)) {
          if (i == NFA_CE_LISTEN_INFO_IDX_NDEF) {
            conn_evt.deactivated.type = deact_type;
            (*p_cb->p_active_conn_cback)(NFA_DEACTIVATED_EVT, &conn_evt);
          } else {
            conn_evt.ce_deactivated.handle =
                NFA_HANDLE_GROUP_CE | ((tNFA_HANDLE)i);
            conn_evt.ce_deactivated.type = deact_type;
            (*p_cb->p_active_conn_cback)(NFA_CE_DEACTIVATED_EVT, &conn_evt);
          }
        }
      }
    }
  }

  /* Check if app initiated the deactivation (due to API deregister). If so,
   * remove entry from listen_info table. */
  if (p_cb->flags & NFA_CE_FLAGS_APP_INIT_DEACTIVATION) {
    p_cb->flags &= ~NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
    nfa_ce_remove_listen_info_entry(p_cb->idx_cur_active, true);
  }

  p_cb->p_active_conn_cback = NULL;
  p_cb->idx_cur_active = NFA_CE_LISTEN_INFO_IDX_INVALID;

  /* Restart listening (if any listen_info entries are still active) */
  nfa_ce_restart_listen_check();

  return true;
}

/*******************************************************************************
**
** Function         nfa_ce_disable_local_tag
**
** Description      Disable local NDEF tag
**                      - clean up control block
**                      - remove NDEF discovery configuration
**
** Returns          Nothing
**
*******************************************************************************/
void nfa_ce_disable_local_tag(void) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA evt_data;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("Disabling local NDEF tag");

  /* If local NDEF tag is in use, then disable it */
  if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
      NFA_CE_LISTEN_INFO_IN_USE) {
    /* NDEF Tag is in not idle state */
    if ((p_cb->flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) &&
        (p_cb->idx_cur_active == NFA_CE_LISTEN_INFO_IDX_NDEF)) {
      /* wait for deactivation */
      p_cb->flags |= NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
      nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_IDLE);
    } else {
      /* Notify DM to stop listening for ndef  */
      if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle !=
          NFA_HANDLE_INVALID) {
        nfa_dm_delete_rf_discover(
            p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle);
        p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle =
            NFA_HANDLE_INVALID;
      }
      nfa_ce_remove_listen_info_entry(NFA_CE_LISTEN_INFO_IDX_NDEF, true);
    }
  } else {
    /* Notify application */
    evt_data.status = NFA_STATUS_OK;
    nfa_dm_conn_cback_event_notify(NFA_CE_LOCAL_TAG_CONFIGURED_EVT, &evt_data);
  }
}

/*******************************************************************************
**
** Function         nfa_ce_api_cfg_local_tag
**
** Description      Configure local NDEF tag
**                      - store ndef attributes in to control block
**                      - update discovery configuration
**
** Returns          TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_cfg_local_tag(tNFA_CE_MSG* p_ce_msg) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA conn_evt;

  /* Check if disabling local tag */
  if (p_ce_msg->local_tag.protocol_mask == 0) {
    nfa_ce_disable_local_tag();
    return true;
  }

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "Configuring local NDEF tag: protocol_mask=%01x cur_size=%i, "
      "max_size=%i, readonly=%i uid_len=%i",
      p_ce_msg->local_tag.protocol_mask, p_ce_msg->local_tag.ndef_cur_size,
      p_ce_msg->local_tag.ndef_max_size, p_ce_msg->local_tag.read_only,
      p_ce_msg->local_tag.uid_len);

  /* If local tag was already set, then check if NFA_CeConfigureLocalTag called
   * to change protocol mask  */
  if ((p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags &
       NFA_CE_LISTEN_INFO_IN_USE) &&
      (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle !=
       NFA_HANDLE_INVALID) &&
      ((p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
        (NFA_PROTOCOL_MASK_T3T | NFA_PROTOCOL_MASK_ISO_DEP)) !=
       (p_ce_msg->local_tag.protocol_mask &
        (NFA_PROTOCOL_MASK_T3T | NFA_PROTOCOL_MASK_ISO_DEP)))) {
    /* Listening for different tag protocols. Stop discovery */
    nfa_dm_delete_rf_discover(
        p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle);
    p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].rf_disc_handle =
        NFA_HANDLE_INVALID;

    /* clear NDEF contents */
    CE_T3tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
    CE_T4tSetLocalNDEFMsg(true, 0, 0, NULL, NULL);
  }

  /* Store NDEF info to control block */
  p_cb->p_ndef_data = p_ce_msg->local_tag.p_ndef_data;
  p_cb->ndef_cur_size = p_ce_msg->local_tag.ndef_cur_size;
  p_cb->ndef_max_size = p_ce_msg->local_tag.ndef_max_size;

  /* Fill in LISTEN_INFO entry for NDEF */
  p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags =
      NFA_CE_LISTEN_INFO_IN_USE;
  p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask =
      p_ce_msg->local_tag.protocol_mask;
  p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].p_conn_cback =
      nfa_dm_conn_cback_event_notify;
  if (p_ce_msg->local_tag.read_only)
    p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].flags |=
        NFC_CE_LISTEN_INFO_READONLY_NDEF;
  p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].t3t_system_code =
      T3T_SYSTEM_CODE_NDEF;

  /* Set NDEF contents */
  conn_evt.status = NFA_STATUS_FAILED;

  if (p_cb->listen_info[NFA_CE_LISTEN_INFO_IDX_NDEF].protocol_mask &
      (NFA_PROTOCOL_MASK_T3T | NFA_PROTOCOL_MASK_ISO_DEP)) {
    /* Ok to set contents now */
    if (nfa_ce_set_content() != NFA_STATUS_OK) {
      LOG(ERROR) << StringPrintf(
          "nfa_ce_api_cfg_local_tag: could not set contents");
      nfa_dm_conn_cback_event_notify(NFA_CE_LOCAL_TAG_CONFIGURED_EVT,
                                     &conn_evt);
      return true;
    }

    /* Start listening and notify app of status */
    conn_evt.status = nfa_ce_start_listening();
    nfa_dm_conn_cback_event_notify(NFA_CE_LOCAL_TAG_CONFIGURED_EVT, &conn_evt);
  }

  return true;
}

/*******************************************************************************
**
** Function         nfa_ce_api_reg_listen
**
** Description      Register listen params for Felica system code, T4T AID,
**                  or UICC
**
** Returns          TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_reg_listen(tNFA_CE_MSG* p_ce_msg) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  tNFA_CONN_EVT_DATA conn_evt;
  uint8_t i;
  uint8_t listen_info_idx = NFA_CE_LISTEN_INFO_IDX_INVALID;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("Registering UICC/Felica/Type-4 tag listener. Type=%i",
                      p_ce_msg->reg_listen.listen_type);

  /* Look for available entry in listen_info table */
  /* - If registering UICC listen, make sure there isn't another entry for the
   * ee_handle  */
  /* - Skip over entry 0 (reserved for local NDEF tag) */
  for (i = 1; i < NFA_CE_LISTEN_INFO_MAX; i++) {
    if ((p_ce_msg->reg_listen.listen_type == NFA_CE_REG_TYPE_UICC) &&
        (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE) &&
        (p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_UICC) &&
        (p_cb->listen_info[i].ee_handle == p_ce_msg->reg_listen.ee_handle)) {
      LOG(ERROR) << StringPrintf("UICC (0x%x) listening already specified",
                                 p_ce_msg->reg_listen.ee_handle);
      conn_evt.status = NFA_STATUS_FAILED;
      nfa_dm_conn_cback_event_notify(NFA_CE_UICC_LISTEN_CONFIGURED_EVT,
                                     &conn_evt);
      return true;
    }
    /* If this is a free entry, and we haven't found one yet, remember it */
    else if ((!(p_cb->listen_info[i].flags & NFA_CE_LISTEN_INFO_IN_USE)) &&
             (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID)) {
      listen_info_idx = i;
    }
  }

  /* Add new entry to listen_info table */
  if (listen_info_idx == NFA_CE_LISTEN_INFO_IDX_INVALID) {
    LOG(ERROR) << StringPrintf("Maximum listen callbacks exceeded (%i)",
                               NFA_CE_LISTEN_INFO_MAX);

    if (p_ce_msg->reg_listen.listen_type == NFA_CE_REG_TYPE_UICC) {
      conn_evt.status = NFA_STATUS_FAILED;
      nfa_dm_conn_cback_event_notify(NFA_CE_UICC_LISTEN_CONFIGURED_EVT,
                                     &conn_evt);
    } else {
      /* Notify application */
      conn_evt.ce_registered.handle = NFA_HANDLE_INVALID;
      conn_evt.ce_registered.status = NFA_STATUS_FAILED;
      (*p_ce_msg->reg_listen.p_conn_cback)(NFA_CE_REGISTERED_EVT, &conn_evt);
    }
    return true;
  } else {
    DLOG_IF(INFO, nfc_debug_enabled)
        << StringPrintf("NFA_CE: adding listen_info entry %i", listen_info_idx);

    /* Store common parameters */
    /* Mark entry as 'in-use', and NFA_CE_LISTEN_INFO_START_NTF_PND */
    /* (LISTEN_START_EVT will be notified when discovery successfully starts */
    p_cb->listen_info[listen_info_idx].flags =
        NFA_CE_LISTEN_INFO_IN_USE | NFA_CE_LISTEN_INFO_START_NTF_PND;
    p_cb->listen_info[listen_info_idx].rf_disc_handle = NFA_HANDLE_INVALID;
    p_cb->listen_info[listen_info_idx].protocol_mask = 0;

    /* Store type-specific parameters */
    switch (p_ce_msg->reg_listen.listen_type) {
      case NFA_CE_REG_TYPE_ISO_DEP:
        p_cb->listen_info[listen_info_idx].protocol_mask =
            NFA_PROTOCOL_MASK_ISO_DEP;
        p_cb->listen_info[listen_info_idx].flags |= NFA_CE_LISTEN_INFO_T4T_AID;
        p_cb->listen_info[listen_info_idx].p_conn_cback =
            p_ce_msg->reg_listen.p_conn_cback;

        /* Register this AID with CE_T4T */
        p_cb->listen_info[listen_info_idx].t4t_aid_handle = CE_T4tRegisterAID(
            p_ce_msg->reg_listen.aid_len, p_ce_msg->reg_listen.aid,
            nfa_ce_handle_t4t_aid_evt);
        if (p_cb->listen_info[listen_info_idx].t4t_aid_handle ==
            CE_T4T_AID_HANDLE_INVALID) {
          LOG(ERROR) << StringPrintf("Unable to register AID");
          p_cb->listen_info[listen_info_idx].flags = 0;

          /* Notify application */
          conn_evt.ce_registered.handle = NFA_HANDLE_INVALID;
          conn_evt.ce_registered.status = NFA_STATUS_FAILED;
          (*p_ce_msg->reg_listen.p_conn_cback)(NFA_CE_REGISTERED_EVT,
                                               &conn_evt);

          return true;
        }
        if (p_cb->listen_info[listen_info_idx].t4t_aid_handle ==
            CE_T4T_WILDCARD_AID_HANDLE)
          nfa_ce_cb.idx_wild_card = listen_info_idx;
        break;

      case NFA_CE_REG_TYPE_FELICA:
        p_cb->listen_info[listen_info_idx].protocol_mask =
            NFA_PROTOCOL_MASK_T3T;
        p_cb->listen_info[listen_info_idx].flags |= NFA_CE_LISTEN_INFO_FELICA;
        p_cb->listen_info[listen_info_idx].p_conn_cback =
            p_ce_msg->reg_listen.p_conn_cback;

        /* Store system code and nfcid2 */
        p_cb->listen_info[listen_info_idx].t3t_system_code =
            p_ce_msg->reg_listen.system_code;
        memcpy(p_cb->listen_info[listen_info_idx].t3t_nfcid2,
               p_ce_msg->reg_listen.nfcid2, NCI_RF_F_UID_LEN);
        memcpy(p_cb->listen_info[listen_info_idx].t3t_pmm,
               p_ce_msg->reg_listen.t3tPmm, NCI_T3T_PMM_LEN);
        break;

#if (NFC_NFCEE_INCLUDED == TRUE)
      case NFA_CE_REG_TYPE_UICC:
        p_cb->listen_info[listen_info_idx].flags |= NFA_CE_LISTEN_INFO_UICC;
        p_cb->listen_info[listen_info_idx].p_conn_cback =
            &nfa_dm_conn_cback_event_notify;

        /* Store EE handle and Tech */
        p_cb->listen_info[listen_info_idx].ee_handle =
            p_ce_msg->reg_listen.ee_handle;
        p_cb->listen_info[listen_info_idx].tech_mask =
            p_ce_msg->reg_listen.tech_mask;
        break;
#endif
    }
  }

  /* Start listening */
  conn_evt.status = nfa_ce_start_listening();
  if (conn_evt.status != NFA_STATUS_OK) {
    LOG(ERROR) << StringPrintf(
        "nfa_ce_api_reg_listen: unable to register new listen params with DM");
    p_cb->listen_info[listen_info_idx].flags = 0;
  }

  /* Nofitify app of status */
  if (p_ce_msg->reg_listen.listen_type == NFA_CE_REG_TYPE_UICC) {
    (*p_cb->listen_info[listen_info_idx].p_conn_cback)(
        NFA_CE_UICC_LISTEN_CONFIGURED_EVT, &conn_evt);
  } else {
    conn_evt.ce_registered.handle = NFA_HANDLE_GROUP_CE | listen_info_idx;
    DLOG_IF(INFO, nfc_debug_enabled)
        << StringPrintf("nfa_ce_api_reg_listen: registered handle 0x%04X",
                        conn_evt.ce_registered.handle);
    (*p_cb->listen_info[listen_info_idx].p_conn_cback)(NFA_CE_REGISTERED_EVT,
                                                       &conn_evt);
  }

  return true;
}

/*******************************************************************************
**
** Function         nfa_ce_api_dereg_listen
**
** Description      Deregister listen params
**
** Returns          TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_dereg_listen(tNFA_CE_MSG* p_ce_msg) {
  tNFA_CE_CB* p_cb = &nfa_ce_cb;
  uint8_t listen_info_idx;
  tNFA_CONN_EVT_DATA conn_evt;

#if (NFC_NFCEE_INCLUDED == TRUE)
  /* Check if deregistering UICC , or virtual secure element listen */
  if (p_ce_msg->dereg_listen.listen_info == NFA_CE_LISTEN_INFO_UICC) {
    /* Deregistering UICC listen. Look for listen_info for this UICC ee handle
     */
    for (listen_info_idx = 0; listen_info_idx < NFA_CE_LISTEN_INFO_MAX;
         listen_info_idx++) {
      if ((p_cb->listen_info[listen_info_idx].flags &
           NFA_CE_LISTEN_INFO_IN_USE) &&
          (p_cb->listen_info[listen_info_idx].flags &
           NFA_CE_LISTEN_INFO_UICC) &&
          (p_cb->listen_info[listen_info_idx].ee_handle ==
           p_ce_msg->dereg_listen.handle)) {
        /* UICC is in not idle state */
        if ((p_cb->flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) &&
            (p_cb->idx_cur_active == listen_info_idx)) {
          /* wait for deactivation */
          p_cb->flags |= NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
          nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_IDLE);
        } else {
          /* Stop listening */
          if (p_cb->listen_info[listen_info_idx].rf_disc_handle !=
              NFA_HANDLE_INVALID) {
            nfa_dm_delete_rf_discover(
                p_cb->listen_info[listen_info_idx].rf_disc_handle);
            p_cb->listen_info[listen_info_idx].rf_disc_handle =
                NFA_HANDLE_INVALID;
          }

          /* Remove entry and notify application */
          nfa_ce_remove_listen_info_entry(listen_info_idx, true);
        }
        break;
      }
    }

    if (listen_info_idx == NFA_CE_LISTEN_INFO_MAX) {
      LOG(ERROR) << StringPrintf("cannot find listen_info for UICC");
      conn_evt.status = NFA_STATUS_INVALID_PARAM;
      nfa_dm_conn_cback_event_notify(NFA_CE_UICC_LISTEN_CONFIGURED_EVT,
                                     &conn_evt);
    }
  } else
#endif
  {
    /* Deregistering virtual secure element listen */
    listen_info_idx = p_ce_msg->dereg_listen.handle & NFA_HANDLE_MASK;
    if (nfa_ce_cb.idx_wild_card == listen_info_idx) {
      nfa_ce_cb.idx_wild_card = NFA_CE_LISTEN_INFO_IDX_INVALID;
    }

    if ((listen_info_idx < NFA_CE_LISTEN_INFO_MAX) &&
        (p_cb->listen_info[listen_info_idx].flags &
         NFA_CE_LISTEN_INFO_IN_USE)) {
      /* virtual secure element is in not idle state */
      if ((p_cb->flags & NFA_CE_FLAGS_LISTEN_ACTIVE_SLEEP) &&
          (p_cb->idx_cur_active == listen_info_idx)) {
        /* wait for deactivation */
        p_cb->flags |= NFA_CE_FLAGS_APP_INIT_DEACTIVATION;
        nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      } else {
        /* Stop listening */
        if (p_cb->listen_info[listen_info_idx].rf_disc_handle !=
            NFA_HANDLE_INVALID) {
          nfa_dm_delete_rf_discover(
              p_cb->listen_info[listen_info_idx].rf_disc_handle);
          p_cb->listen_info[listen_info_idx].rf_disc_handle =
              NFA_HANDLE_INVALID;
        }

        /* Remove entry and notify application */
        nfa_ce_remove_listen_info_entry(listen_info_idx, true);
      }
    } else {
      LOG(ERROR) << StringPrintf(
          "cannot find listen_info for "
          "Felica/T4tAID");
      conn_evt.status = NFA_STATUS_INVALID_PARAM;
      nfa_dm_conn_cback_event_notify(NFA_CE_DEREGISTERED_EVT, &conn_evt);
    }
  }

  return true;
}

/*******************************************************************************
**
** Function         nfa_ce_api_cfg_isodep_tech
**
** Description      Configure the technologies (NFC-A and/or NFC-B) to listen
**                  for ISO-DEP
**
** Returns          TRUE (message buffer to be freed by caller)
**
*******************************************************************************/
bool nfa_ce_api_cfg_isodep_tech(tNFA_CE_MSG* p_ce_msg) {
  nfa_ce_cb.isodep_disc_mask = 0;
  if (p_ce_msg->hdr.layer_specific & NFA_TECHNOLOGY_MASK_A)
    nfa_ce_cb.isodep_disc_mask = NFA_DM_DISC_MASK_LA_ISO_DEP;

  if (p_ce_msg->hdr.layer_specific & NFA_TECHNOLOGY_MASK_B)
    nfa_ce_cb.isodep_disc_mask |= NFA_DM_DISC_MASK_LB_ISO_DEP;
  return true;
}