/******************************************************************************
*
* Copyright (C) 2010-2014 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file contains the action functions for NFA-EE
*
******************************************************************************/
#include <string.h>
#include <android-base/stringprintf.h>
#include <base/logging.h>
#include "nfa_api.h"
#include "nfa_dm_int.h"
#include "nfa_ee_int.h"
#include "nfa_hci_int.h"
using android::base::StringPrintf;
extern bool nfc_debug_enabled;
/* the de-bounce timer:
* The NFA-EE API functions are called to set the routing and VS configuration.
* When this timer expires, the configuration is sent to NFCC all at once.
* This is the timeout value for the de-bounce timer. */
#ifndef NFA_EE_ROUT_TIMEOUT_VAL
#define NFA_EE_ROUT_TIMEOUT_VAL 1000
#endif
#define NFA_EE_ROUT_BUF_SIZE 540
#define NFA_EE_ROUT_MAX_TLV_SIZE 0xFD
/* the following 2 tables convert the technology mask in API and control block
* to the command for NFCC */
#define NFA_EE_NUM_TECH 3
const uint8_t nfa_ee_tech_mask_list[NFA_EE_NUM_TECH] = {
NFA_TECHNOLOGY_MASK_A, NFA_TECHNOLOGY_MASK_B, NFA_TECHNOLOGY_MASK_F};
const uint8_t nfa_ee_tech_list[NFA_EE_NUM_TECH] = {
NFC_RF_TECHNOLOGY_A, NFC_RF_TECHNOLOGY_B, NFC_RF_TECHNOLOGY_F};
/* the following 2 tables convert the protocol mask in API and control block to
* the command for NFCC */
#define NFA_EE_NUM_PROTO 5
static void add_route_tech_proto_tlv(uint8_t** pp, uint8_t tlv_type,
uint8_t nfcee_id, uint8_t pwr_cfg,
uint8_t tech_proto) {
*(*pp)++ = tlv_type;
*(*pp)++ = 3;
*(*pp)++ = nfcee_id;
*(*pp)++ = pwr_cfg;
*(*pp)++ = tech_proto;
}
static void add_route_aid_tlv(uint8_t** pp, uint8_t* pa, uint8_t nfcee_id,
uint8_t pwr_cfg, uint8_t tag) {
pa++; /* EMV tag */
uint8_t len = *pa++; /* aid_len */
*(*pp)++ = tag;
*(*pp)++ = len + 2;
*(*pp)++ = nfcee_id;
*(*pp)++ = pwr_cfg;
/* copy the AID */
memcpy(*pp, pa, len);
*pp += len;
}
static void add_route_sys_code_tlv(uint8_t** p_buff, uint8_t* p_sys_code_cfg,
uint8_t sys_code_rt_loc,
uint8_t sys_code_pwr_cfg) {
*(*p_buff)++ = NFC_ROUTE_TAG_SYSCODE | nfa_ee_cb.route_block_control;
*(*p_buff)++ = NFA_EE_SYSTEM_CODE_LEN + 2;
*(*p_buff)++ = sys_code_rt_loc;
*(*p_buff)++ = sys_code_pwr_cfg;
/* copy the system code */
memcpy(*p_buff, p_sys_code_cfg, NFA_EE_SYSTEM_CODE_LEN);
*p_buff += NFA_EE_SYSTEM_CODE_LEN;
}
const uint8_t nfa_ee_proto_mask_list[NFA_EE_NUM_PROTO] = {
NFA_PROTOCOL_MASK_T1T, NFA_PROTOCOL_MASK_T2T, NFA_PROTOCOL_MASK_T3T,
NFA_PROTOCOL_MASK_ISO_DEP, NFA_PROTOCOL_MASK_NFC_DEP};
const uint8_t nfa_ee_proto_list[NFA_EE_NUM_PROTO] = {
NFC_PROTOCOL_T1T, NFC_PROTOCOL_T2T, NFC_PROTOCOL_T3T, NFC_PROTOCOL_ISO_DEP,
NFC_PROTOCOL_NFC_DEP};
static void nfa_ee_report_discover_req_evt(void);
static void nfa_ee_build_discover_req_evt(tNFA_EE_DISCOVER_REQ* p_evt_data);
void nfa_ee_check_set_routing(uint16_t new_size, int* p_max_len, uint8_t* p,
int* p_cur_offset);
/*******************************************************************************
**
** Function nfa_ee_trace_aid
**
** Description trace AID
**
** Returns void
**
*******************************************************************************/
static void nfa_ee_trace_aid(std::string p_str, uint8_t id, uint8_t aid_len,
uint8_t* p) {
int len = aid_len;
int xx, yy = 0;
char buff[100];
buff[0] = 0;
if (aid_len > NFA_MAX_AID_LEN) {
LOG(ERROR) << StringPrintf("aid_len: %d exceeds max(%d)", aid_len,
NFA_MAX_AID_LEN);
len = NFA_MAX_AID_LEN;
}
for (xx = 0; xx < len; xx++) {
yy += sprintf(&buff[yy], "%02x ", *p);
p++;
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"%s id:0x%x len=%d aid:%s", p_str.c_str(), id, aid_len, buff);
}
/*******************************************************************************
**
** Function nfa_ee_update_route_size
**
** Description Update the size required for technology and protocol routing
** of the given NFCEE ID.
**
** Returns void
**
*******************************************************************************/
static void nfa_ee_update_route_size(tNFA_EE_ECB* p_cb) {
int xx;
uint8_t power_cfg = 0;
p_cb->size_mask = 0;
/* add the Technology based routing */
for (xx = 0; xx < NFA_EE_NUM_TECH; xx++) {
power_cfg = 0;
if (p_cb->tech_switch_on & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_ON;
if (p_cb->tech_switch_off & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SWITCH_OFF;
if (p_cb->tech_battery_off & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_BATT_OFF;
if ((power_cfg & NCI_ROUTE_PWR_STATE_ON) &&
(NFC_GetNCIVersion() == NCI_VERSION_2_0)) {
if (p_cb->tech_screen_lock & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_ON_LOCK();
if (p_cb->tech_screen_off & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_UNLOCK();
if (p_cb->tech_screen_off_lock & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_LOCK();
}
if (power_cfg) {
/* 5 = 1 (tag) + 1 (len) + 1(nfcee_id) + 1(power cfg) + 1 (technology) */
p_cb->size_mask += 5;
}
}
/* add the Protocol based routing */
for (xx = 0; xx < NFA_EE_NUM_PROTO; xx++) {
power_cfg = 0;
if (p_cb->proto_switch_on & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_ON;
if (p_cb->proto_switch_off & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SWITCH_OFF;
if (p_cb->proto_battery_off & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_BATT_OFF;
if ((power_cfg & NCI_ROUTE_PWR_STATE_ON) &&
(NFC_GetNCIVersion() == NCI_VERSION_2_0)) {
if (p_cb->proto_screen_lock & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_ON_LOCK();
if (p_cb->proto_screen_off & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_UNLOCK();
if (p_cb->proto_screen_off_lock & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_LOCK();
}
if (power_cfg) {
/* 5 = 1 (tag) + 1 (len) + 1(nfcee_id) + 1(power cfg) + 1 (protocol) */
p_cb->size_mask += 5;
}
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_update_route_size nfcee_id:0x%x size_mask:%d",
p_cb->nfcee_id, p_cb->size_mask);
}
/*******************************************************************************
**
** Function nfa_ee_update_route_aid_size
**
** Description Update the size required for AID routing
** of the given NFCEE ID.
**
** Returns void
**
*******************************************************************************/
static void nfa_ee_update_route_aid_size(tNFA_EE_ECB* p_cb) {
uint8_t *pa, len;
int start_offset;
int xx;
p_cb->size_aid = 0;
if (p_cb->aid_entries) {
start_offset = 0;
for (xx = 0; xx < p_cb->aid_entries; xx++) {
/* add one AID entry */
if (p_cb->aid_rt_info[xx] & NFA_EE_AE_ROUTE) {
pa = &p_cb->aid_cfg[start_offset];
pa++; /* EMV tag */
len = *pa++; /* aid_len */
/* 4 = 1 (tag) + 1 (len) + 1(nfcee_id) + 1(power cfg) */
p_cb->size_aid += 4;
p_cb->size_aid += len;
}
start_offset += p_cb->aid_len[xx];
}
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_update_route_aid_size nfcee_id:0x%x size_aid:%d",
p_cb->nfcee_id, p_cb->size_aid);
}
/*******************************************************************************
**
** Function nfa_ee_update_route_sys_code_size
**
** Description Update the size required for system code routing
** of the given NFCEE ID.
**
** Returns void
**
*******************************************************************************/
static void nfa_ee_update_route_sys_code_size(tNFA_EE_ECB* p_cb) {
p_cb->size_sys_code = 0;
if (p_cb->sys_code_cfg_entries) {
for (uint8_t xx = 0; xx < p_cb->sys_code_cfg_entries; xx++) {
if (p_cb->sys_code_rt_loc_vs_info[xx] & NFA_EE_AE_ROUTE) {
/* 4 = 1 (tag) + 1 (len) + 1(nfcee_id) + 1(power cfg) */
p_cb->size_sys_code += 4;
p_cb->size_sys_code += NFA_EE_SYSTEM_CODE_LEN;
}
}
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ee_update_route_sys_code_size nfcee_id:0x%x size_sys_code:%d",
p_cb->nfcee_id, p_cb->size_sys_code);
}
/*******************************************************************************
**
** Function nfa_ee_total_lmrt_size
**
** Description the total listen mode routing table size
**
** Returns uint16_t
**
*******************************************************************************/
static uint16_t nfa_ee_total_lmrt_size(void) {
int xx;
uint16_t lmrt_size = 0;
tNFA_EE_ECB* p_cb;
p_cb = &nfa_ee_cb.ecb[NFA_EE_CB_4_DH];
lmrt_size += p_cb->size_mask;
lmrt_size += p_cb->size_aid;
lmrt_size += p_cb->size_sys_code;
p_cb = &nfa_ee_cb.ecb[nfa_ee_cb.cur_ee - 1];
for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb--) {
if (p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE) {
lmrt_size += p_cb->size_mask;
lmrt_size += p_cb->size_aid;
lmrt_size += p_cb->size_sys_code;
}
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_total_lmrt_size size:%d", lmrt_size);
return lmrt_size;
}
static void nfa_ee_add_tech_route_to_ecb(tNFA_EE_ECB* p_cb, uint8_t* pp,
uint8_t* p, uint8_t* ps,
int* p_cur_offset) {
uint8_t num_tlv = *ps;
/* add the Technology based routing */
for (int xx = 0; xx < NFA_EE_NUM_TECH; xx++) {
uint8_t power_cfg = 0;
if (p_cb->tech_switch_on & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_ON;
if (p_cb->tech_switch_off & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SWITCH_OFF;
if (p_cb->tech_battery_off & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_BATT_OFF;
if ((power_cfg & NCI_ROUTE_PWR_STATE_ON) &&
(NFC_GetNCIVersion() == NCI_VERSION_2_0)) {
if (p_cb->tech_screen_lock & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_ON_LOCK();
if (p_cb->tech_screen_off & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_UNLOCK();
if (p_cb->tech_screen_off_lock & nfa_ee_tech_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_LOCK();
}
if (power_cfg) {
add_route_tech_proto_tlv(&pp, NFC_ROUTE_TAG_TECH, p_cb->nfcee_id,
power_cfg, nfa_ee_tech_list[xx]);
num_tlv++;
if (power_cfg != NCI_ROUTE_PWR_STATE_ON)
nfa_ee_cb.ee_cfged |= NFA_EE_CFGED_OFF_ROUTING;
}
}
/* update the num_tlv and current offset */
uint8_t entry_size = (uint8_t)(pp - p);
*p_cur_offset += entry_size;
*ps = num_tlv;
}
static void nfa_ee_add_proto_route_to_ecb(tNFA_EE_ECB* p_cb, uint8_t* pp,
uint8_t* p, uint8_t* ps,
int* p_cur_offset) {
uint8_t num_tlv = *ps;
/* add the Protocol based routing */
for (int xx = 0; xx < NFA_EE_NUM_PROTO; xx++) {
uint8_t power_cfg = 0, proto_tag = 0;
if (p_cb->proto_switch_on & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_ON;
if (p_cb->proto_switch_off & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SWITCH_OFF;
if (p_cb->proto_battery_off & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_BATT_OFF;
if (power_cfg) {
/* Applying Route Block for ISO DEP Protocol, so that AIDs
* which are not in the routing table can also be blocked */
if (nfa_ee_proto_mask_list[xx] == NFA_PROTOCOL_MASK_ISO_DEP) {
proto_tag = NFC_ROUTE_TAG_PROTO | nfa_ee_cb.route_block_control;
/* Enable screen on lock power state for ISO-DEP protocol to
enable HCE screen lock */
if ((power_cfg & NCI_ROUTE_PWR_STATE_ON) &&
(NFC_GetNCIVersion() == NCI_VERSION_2_0)) {
if (p_cb->proto_screen_lock & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_ON_LOCK();
if (p_cb->proto_screen_off & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_UNLOCK();
if (p_cb->proto_screen_off_lock & nfa_ee_proto_mask_list[xx])
power_cfg |= NCI_ROUTE_PWR_STATE_SCREEN_OFF_LOCK();
}
} else {
proto_tag = NFC_ROUTE_TAG_PROTO;
}
add_route_tech_proto_tlv(&pp, proto_tag, p_cb->nfcee_id, power_cfg,
nfa_ee_proto_list[xx]);
num_tlv++;
if (power_cfg != NCI_ROUTE_PWR_STATE_ON)
nfa_ee_cb.ee_cfged |= NFA_EE_CFGED_OFF_ROUTING;
}
}
/* add NFC-DEP routing to HOST */
if (p_cb->nfcee_id == NFC_DH_ID) {
add_route_tech_proto_tlv(&pp, NFC_ROUTE_TAG_PROTO, NFC_DH_ID,
NCI_ROUTE_PWR_STATE_ON, NFC_PROTOCOL_NFC_DEP);
num_tlv++;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s - NFC DEP added for DH!!!", __func__);
}
/* update the num_tlv and current offset */
uint8_t entry_size = (uint8_t)(pp - p);
*p_cur_offset += entry_size;
*ps = num_tlv;
}
static void nfa_ee_add_aid_route_to_ecb(tNFA_EE_ECB* p_cb, uint8_t* pp,
uint8_t* p, uint8_t* ps,
int* p_cur_offset, int* p_max_len) {
uint8_t num_tlv = *ps;
/* add the AID routing */
if (p_cb->aid_entries) {
int start_offset = 0;
for (int xx = 0; xx < p_cb->aid_entries; xx++) {
/* remember the beginning of this AID routing entry, just in case we
* need to put it in next command */
uint8_t route_qual = 0;
uint8_t* p_start = pp;
/* add one AID entry */
if (p_cb->aid_rt_info[xx] & NFA_EE_AE_ROUTE) {
num_tlv++;
uint8_t* pa = &p_cb->aid_cfg[start_offset];
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"%s - p_cb->aid_info%x", __func__, p_cb->aid_info[xx]);
if (p_cb->aid_info[xx] & NCI_ROUTE_QUAL_LONG_SELECT) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s - %x", __func__,
p_cb->aid_info[xx] & NCI_ROUTE_QUAL_LONG_SELECT);
route_qual |= NCI_ROUTE_QUAL_LONG_SELECT;
}
if (p_cb->aid_info[xx] & NCI_ROUTE_QUAL_SHORT_SELECT) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s - %x", __func__,
p_cb->aid_info[xx] & NCI_ROUTE_QUAL_SHORT_SELECT);
route_qual |= NCI_ROUTE_QUAL_SHORT_SELECT;
}
uint8_t tag =
NFC_ROUTE_TAG_AID | nfa_ee_cb.route_block_control | route_qual;
add_route_aid_tlv(&pp, pa, p_cb->nfcee_id, p_cb->aid_pwr_cfg[xx], tag);
}
start_offset += p_cb->aid_len[xx];
uint8_t new_size = (uint8_t)(pp - p_start);
nfa_ee_check_set_routing(new_size, p_max_len, ps, p_cur_offset);
if (*ps == 0) {
/* just sent routing command, update local */
*ps = 1;
num_tlv = *ps;
*p_cur_offset = new_size;
pp = ps + 1;
p = pp;
memcpy(p, p_start, new_size);
pp += new_size;
} else {
/* add the new entry */
*ps = num_tlv;
*p_cur_offset += new_size;
}
}
} else {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s - No AID entries available", __func__);
}
}
static void nfa_ee_add_sys_code_route_to_ecb(tNFA_EE_ECB* p_cb, uint8_t* pp,
uint8_t* p, uint8_t* p_buff,
int* p_cur_offset,
int* p_max_len) {
uint8_t num_tlv = *p_buff;
/* add the SC routing */
if (p_cb->sys_code_cfg_entries) {
int start_offset = 0;
for (int xx = 0; xx < p_cb->sys_code_cfg_entries; xx++) {
/* remember the beginning of this SC routing entry, just in case we
* need to put it in next command */
uint8_t* p_start = pp;
/* add one SC entry */
if (p_cb->sys_code_rt_loc_vs_info[xx] & NFA_EE_AE_ROUTE) {
uint8_t* p_sys_code_cfg = &p_cb->sys_code_cfg[start_offset];
if (nfa_ee_is_active(p_cb->sys_code_rt_loc[xx] | NFA_HANDLE_GROUP_EE)) {
add_route_sys_code_tlv(&pp, p_sys_code_cfg, p_cb->sys_code_rt_loc[xx],
p_cb->sys_code_pwr_cfg[xx]);
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_ROUTING;
num_tlv++;
} else {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s - ignoring route loc%x", __func__,
p_cb->sys_code_rt_loc[xx]);
}
}
start_offset += NFA_EE_SYSTEM_CODE_LEN;
uint8_t new_size = (uint8_t)(pp - p_start);
nfa_ee_check_set_routing(new_size, p_max_len, p_buff, p_cur_offset);
if (*p_buff == 0 && (num_tlv > 0x00)) {
/* just sent routing command, update local */
*p_buff = 1;
num_tlv = *p_buff;
*p_cur_offset = new_size;
pp = p_buff + 1;
p = pp;
memcpy(p, p_start, new_size);
pp += new_size;
} else {
/* add the new entry */
*p_buff = num_tlv;
*p_cur_offset += new_size;
}
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ee_route_add_one_ecb_by_route_order --num_tlv:- %d", num_tlv);
} else {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s - No SC entries available", __func__);
}
}
/*******************************************************************************
**
** Function nfa_ee_conn_cback
**
** Description process connection callback event from stack
**
** Returns void
**
*******************************************************************************/
static void nfa_ee_conn_cback(uint8_t conn_id, tNFC_CONN_EVT event,
tNFC_CONN* p_data) {
tNFA_EE_NCI_CONN cbk;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ee_conn_cback: conn_id: %d, event=0x%02x", conn_id, event);
cbk.hdr.event = NFA_EE_NCI_CONN_EVT;
if (event == NFC_DATA_CEVT) {
/* Treat data event specially to avoid potential memory leak */
cbk.hdr.event = NFA_EE_NCI_DATA_EVT;
}
cbk.conn_id = conn_id;
cbk.event = event;
cbk.p_data = p_data;
tNFA_EE_MSG nfa_ee_msg;
nfa_ee_msg.conn = cbk;
nfa_ee_evt_hdlr(&nfa_ee_msg.hdr);
}
/*******************************************************************************
**
** Function nfa_ee_find_total_aid_len
**
** Description Find the total len in aid_cfg from start_entry to the last
**
** Returns void
**
*******************************************************************************/
int nfa_ee_find_total_aid_len(tNFA_EE_ECB* p_cb, int start_entry) {
int len = 0, xx;
if (p_cb->aid_entries > start_entry) {
for (xx = start_entry; xx < p_cb->aid_entries; xx++) {
len += p_cb->aid_len[xx];
}
}
return len;
}
/*******************************************************************************
**
** Function nfa_ee_find_total_sys_code_len
**
** Description Find the total len in sys_code_cfg from start_entry to the
** last in the given ecb.
**
** Returns void
**
*******************************************************************************/
int nfa_ee_find_total_sys_code_len(tNFA_EE_ECB* p_cb, int start_entry) {
int len = 0;
if (p_cb->sys_code_cfg_entries > start_entry) {
for (int xx = start_entry; xx < p_cb->sys_code_cfg_entries; xx++) {
len += NFA_EE_SYSTEM_CODE_LEN;
}
}
return len;
}
/*******************************************************************************
**
** Function nfa_all_ee_find_total_sys_code_len
**
** Description Find the total len in sys_code_cfg from start_entry to the
** last for all EE and DH.
**
** Returns total length
**
*******************************************************************************/
int nfa_all_ee_find_total_sys_code_len() {
int total_len = 0;
for (int32_t xx = 0; xx < NFA_EE_NUM_ECBS; xx++) {
tNFA_EE_ECB* p_cb = &nfa_ee_cb.ecb[xx];
total_len += nfa_ee_find_total_sys_code_len(p_cb, 0);
}
return total_len;
}
/*******************************************************************************
**
** Function nfa_ee_find_aid_offset
**
** Description Given the AID, find the associated tNFA_EE_ECB and the
** offset in aid_cfg[]. *p_entry is the index.
**
** Returns void
**
*******************************************************************************/
tNFA_EE_ECB* nfa_ee_find_aid_offset(uint8_t aid_len, uint8_t* p_aid,
int* p_offset, int* p_entry) {
int xx, yy, aid_len_offset, offset;
tNFA_EE_ECB *p_ret = NULL, *p_ecb;
p_ecb = &nfa_ee_cb.ecb[NFA_EE_CB_4_DH];
aid_len_offset = 1; /* skip the tag */
for (yy = 0; yy < nfa_ee_cb.cur_ee; yy++, p_ecb++) {
if (p_ecb->aid_entries) {
offset = 0;
for (xx = 0; xx < p_ecb->aid_entries; xx++) {
if ((p_ecb->aid_cfg[offset + aid_len_offset] == aid_len) &&
(memcmp(&p_ecb->aid_cfg[offset + aid_len_offset + 1], p_aid,
aid_len) == 0)) {
p_ret = p_ecb;
if (p_offset) *p_offset = offset;
if (p_entry) *p_entry = xx;
break;
}
offset += p_ecb->aid_len[xx];
}
if (p_ret) {
/* found the entry already */
break;
}
}
p_ecb = &nfa_ee_cb.ecb[yy];
}
return p_ret;
}
/*******************************************************************************
**
** Function nfa_ee_find_sys_code_offset
**
** Description Given the System Code, find the associated tNFA_EE_ECB and
*the
** offset in sys_code_cfg[]. *p_entry is the index.
**
** Returns void
**
*******************************************************************************/
tNFA_EE_ECB* nfa_ee_find_sys_code_offset(uint16_t sys_code, int* p_offset,
int* p_entry) {
tNFA_EE_ECB* p_ret = NULL;
for (uint8_t xx = 0; xx < NFA_EE_NUM_ECBS; xx++) {
tNFA_EE_ECB* p_ecb = &nfa_ee_cb.ecb[xx];
uint8_t mask = nfa_ee_ecb_to_mask(p_ecb);
if ((nfa_ee_cb.ee_cfged & mask) == 0 || p_ecb->sys_code_cfg_entries == 0) {
continue; /*try next ecb*/
}
if (p_ecb->sys_code_cfg_entries) {
uint8_t offset = 0;
for (uint8_t yy = 0; yy < p_ecb->sys_code_cfg_entries; yy++) {
if ((memcmp(&p_ecb->sys_code_cfg[offset], &sys_code,
NFA_EE_SYSTEM_CODE_LEN) == 0)) {
p_ret = p_ecb;
if (p_offset) *p_offset = offset;
if (p_entry) *p_entry = yy;
break;
}
offset += NFA_EE_SYSTEM_CODE_LEN;
}
if (p_ret) {
/* found the entry already */
return p_ret;
}
}
}
return p_ret;
}
/*******************************************************************************
**
** Function nfa_ee_report_event
**
** Description report the given event to the callback
**
** Returns void
**
*******************************************************************************/
void nfa_ee_report_event(tNFA_EE_CBACK* p_cback, tNFA_EE_EVT event,
tNFA_EE_CBACK_DATA* p_data) {
int xx;
/* use the given callback, if not NULL */
if (p_cback) {
(*p_cback)(event, p_data);
return;
}
/* if the given is NULL, report to all registered ones */
for (xx = 0; xx < NFA_EE_MAX_CBACKS; xx++) {
if (nfa_ee_cb.p_ee_cback[xx] != NULL) {
(*nfa_ee_cb.p_ee_cback[xx])(event, p_data);
}
}
}
/*******************************************************************************
**
** Function nfa_ee_start_timer
**
** Description start the de-bounce timer
**
** Returns void
**
*******************************************************************************/
void nfa_ee_start_timer(void) {
if (nfa_dm_is_active())
nfa_sys_start_timer(&nfa_ee_cb.timer, NFA_EE_ROUT_TIMEOUT_EVT,
NFA_EE_ROUT_TIMEOUT_VAL);
}
/*******************************************************************************
**
** Function nfa_ee_api_discover
**
** Description process discover command from user
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_discover(tNFA_EE_MSG* p_data) {
tNFA_EE_CBACK* p_cback = p_data->ee_discover.p_cback;
tNFA_EE_CBACK_DATA evt_data = {0};
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("in_use:%d", nfa_ee_cb.discv_timer.in_use);
if (nfa_ee_cb.discv_timer.in_use) {
nfa_sys_stop_timer(&nfa_ee_cb.discv_timer);
if (NFA_GetNCIVersion() != NCI_VERSION_2_0) NFC_NfceeDiscover(false);
}
if (nfa_ee_cb.p_ee_disc_cback == NULL &&
NFC_NfceeDiscover(true) == NFC_STATUS_OK) {
nfa_ee_cb.p_ee_disc_cback = p_cback;
} else {
evt_data.status = NFA_STATUS_FAILED;
nfa_ee_report_event(p_cback, NFA_EE_DISCOVER_EVT, &evt_data);
}
}
/*******************************************************************************
**
** Function nfa_ee_api_register
**
** Description process register command from user
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_register(tNFA_EE_MSG* p_data) {
int xx;
tNFA_EE_CBACK* p_cback = p_data->ee_register.p_cback;
tNFA_EE_CBACK_DATA evt_data = {0};
bool found = false;
evt_data.ee_register = NFA_STATUS_FAILED;
/* loop through all entries to see if there's a matching callback */
for (xx = 0; xx < NFA_EE_MAX_CBACKS; xx++) {
if (nfa_ee_cb.p_ee_cback[xx] == p_cback) {
evt_data.ee_register = NFA_STATUS_OK;
found = true;
break;
}
}
/* If no matching callback, allocated an entry */
if (!found) {
for (xx = 0; xx < NFA_EE_MAX_CBACKS; xx++) {
if (nfa_ee_cb.p_ee_cback[xx] == NULL) {
nfa_ee_cb.p_ee_cback[xx] = p_cback;
evt_data.ee_register = NFA_STATUS_OK;
break;
}
}
}
/* This callback is verified (not NULL) in NFA_EeRegister() */
(*p_cback)(NFA_EE_REGISTER_EVT, &evt_data);
/* report NFCEE Discovery Request collected during booting up */
nfa_ee_build_discover_req_evt(&evt_data.discover_req);
(*p_cback)(NFA_EE_DISCOVER_REQ_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_deregister
**
** Description process de-register command from user
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_deregister(tNFA_EE_MSG* p_data) {
tNFA_EE_CBACK* p_cback = NULL;
int index = p_data->deregister.index;
tNFA_EE_CBACK_DATA evt_data = {0};
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("nfa_ee_api_deregister");
p_cback = nfa_ee_cb.p_ee_cback[index];
nfa_ee_cb.p_ee_cback[index] = NULL;
if (p_cback) (*p_cback)(NFA_EE_DEREGISTER_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_mode_set
**
** Description process mode set command from user
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_mode_set(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb = p_data->cfg_hdr.p_cb;
tNFA_EE_MODE_SET mode_set;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"handle:0x%02x mode:%d", p_cb->nfcee_id, p_data->mode_set.mode);
mode_set.status = NFC_NfceeModeSet(p_cb->nfcee_id, p_data->mode_set.mode);
if (mode_set.status != NFC_STATUS_OK) {
/* the api is rejected at NFC layer, report the failure status right away */
mode_set.ee_handle = (tNFA_HANDLE)p_cb->nfcee_id | NFA_HANDLE_GROUP_EE;
mode_set.ee_status = p_data->mode_set.mode;
tNFA_EE_CBACK_DATA nfa_ee_cback_data;
nfa_ee_cback_data.mode_set = mode_set;
nfa_ee_report_event(NULL, NFA_EE_MODE_SET_EVT, &nfa_ee_cback_data);
return;
}
/* set the NFA_EE_STATUS_PENDING bit to indicate the status is not exactly
* active */
if (p_data->mode_set.mode == NFC_MODE_ACTIVATE)
p_cb->ee_status = NFA_EE_STATUS_PENDING | NFA_EE_STATUS_ACTIVE;
else {
p_cb->ee_status = NFA_EE_STATUS_INACTIVE;
/* DH should release the NCI connection before deactivate the NFCEE */
if (p_cb->conn_st == NFA_EE_CONN_ST_CONN) {
p_cb->conn_st = NFA_EE_CONN_ST_DISC;
NFC_ConnClose(p_cb->conn_id);
}
}
/* report the NFA_EE_MODE_SET_EVT status on the response from NFCC */
}
/*******************************************************************************
**
** Function nfa_ee_api_set_tech_cfg
**
** Description process set technology routing configuration from user
** start a 1 second timer. When the timer expires,
** the configuration collected in control block is sent to NFCC
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_set_tech_cfg(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb = p_data->cfg_hdr.p_cb;
tNFA_EE_CBACK_DATA evt_data = {0};
tNFA_TECHNOLOGY_MASK old_tech_switch_on = p_cb->tech_switch_on;
tNFA_TECHNOLOGY_MASK old_tech_switch_off = p_cb->tech_switch_off;
tNFA_TECHNOLOGY_MASK old_tech_battery_off = p_cb->tech_battery_off;
tNFA_TECHNOLOGY_MASK old_tech_screen_lock = p_cb->tech_screen_lock;
tNFA_TECHNOLOGY_MASK old_tech_screen_off = p_cb->tech_screen_off;
tNFA_TECHNOLOGY_MASK old_tech_screen_off_lock = p_cb->tech_screen_off_lock;
uint8_t old_size_mask = p_cb->size_mask;
if ((p_cb->tech_switch_on == p_data->set_tech.technologies_switch_on) &&
(p_cb->tech_switch_off == p_data->set_tech.technologies_switch_off) &&
(p_cb->tech_battery_off == p_data->set_tech.technologies_battery_off) &&
(p_cb->tech_screen_lock == p_data->set_tech.technologies_screen_lock) &&
(p_cb->tech_screen_off == p_data->set_tech.technologies_screen_off) &&
(p_cb->tech_screen_off_lock ==
p_data->set_tech.technologies_screen_off_lock)) {
/* nothing to change */
evt_data.status = NFA_STATUS_OK;
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_SET_TECH_CFG_EVT, &evt_data);
return;
}
p_cb->tech_switch_on |= p_data->set_tech.technologies_switch_on;
p_cb->tech_switch_off |= p_data->set_tech.technologies_switch_off;
p_cb->tech_battery_off |= p_data->set_tech.technologies_battery_off;
p_cb->tech_screen_lock |= p_data->set_tech.technologies_screen_lock;
p_cb->tech_screen_off |= p_data->set_tech.technologies_screen_off;
p_cb->tech_screen_off_lock |= p_data->set_tech.technologies_screen_off_lock;
nfa_ee_update_route_size(p_cb);
if (nfa_ee_total_lmrt_size() > NFC_GetLmrtSize()) {
LOG(ERROR) << StringPrintf("nfa_ee_api_set_tech_cfg Exceed LMRT size");
evt_data.status = NFA_STATUS_BUFFER_FULL;
p_cb->tech_switch_on = old_tech_switch_on;
p_cb->tech_switch_off = old_tech_switch_off;
p_cb->tech_battery_off = old_tech_battery_off;
p_cb->tech_screen_lock = old_tech_screen_lock;
p_cb->tech_screen_off = old_tech_screen_off;
p_cb->tech_screen_off_lock = old_tech_screen_off_lock;
p_cb->size_mask = old_size_mask;
} else {
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_TECH;
if (p_cb->tech_switch_on | p_cb->tech_switch_off | p_cb->tech_battery_off |
p_cb->tech_screen_lock | p_cb->tech_screen_off |
p_cb->tech_screen_off_lock) {
/* if any technology in any power mode is configured, mark this entry as
* configured */
nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
}
nfa_ee_start_timer();
}
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_SET_TECH_CFG_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_set_proto_cfg
**
** Description process set protocol routing configuration from user
** start a 1 second timer. When the timer expires,
** the configuration collected in control block is sent to NFCC
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_set_proto_cfg(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb = p_data->cfg_hdr.p_cb;
tNFA_EE_CBACK_DATA evt_data = {0};
tNFA_PROTOCOL_MASK old_proto_switch_on = p_cb->proto_switch_on;
tNFA_PROTOCOL_MASK old_proto_switch_off = p_cb->proto_switch_off;
tNFA_PROTOCOL_MASK old_proto_battery_off = p_cb->proto_battery_off;
tNFA_PROTOCOL_MASK old_proto_screen_lock = p_cb->proto_screen_lock;
tNFA_PROTOCOL_MASK old_proto_screen_off = p_cb->proto_screen_off;
tNFA_PROTOCOL_MASK old_proto_screen_off_lock = p_cb->proto_screen_off_lock;
uint8_t old_size_mask = p_cb->size_mask;
if ((p_cb->proto_switch_on == p_data->set_proto.protocols_switch_on) &&
(p_cb->proto_switch_off == p_data->set_proto.protocols_switch_off) &&
(p_cb->proto_battery_off == p_data->set_proto.protocols_battery_off) &&
(p_cb->proto_screen_lock == p_data->set_proto.protocols_screen_lock) &&
(p_cb->proto_screen_off == p_data->set_proto.protocols_screen_off) &&
(p_cb->proto_screen_off_lock ==
p_data->set_proto.protocols_screen_off_lock)) {
/* nothing to change */
evt_data.status = NFA_STATUS_OK;
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_SET_PROTO_CFG_EVT, &evt_data);
return;
}
p_cb->proto_switch_on |= p_data->set_proto.protocols_switch_on;
p_cb->proto_switch_off |= p_data->set_proto.protocols_switch_off;
p_cb->proto_battery_off |= p_data->set_proto.protocols_battery_off;
p_cb->proto_screen_lock |= p_data->set_proto.protocols_screen_lock;
p_cb->proto_screen_off |= p_data->set_proto.protocols_screen_off;
p_cb->proto_screen_off_lock |= p_data->set_proto.protocols_screen_off_lock;
nfa_ee_update_route_size(p_cb);
if (nfa_ee_total_lmrt_size() > NFC_GetLmrtSize()) {
LOG(ERROR) << StringPrintf("nfa_ee_api_set_proto_cfg Exceed LMRT size");
evt_data.status = NFA_STATUS_BUFFER_FULL;
p_cb->proto_switch_on = old_proto_switch_on;
p_cb->proto_switch_off = old_proto_switch_off;
p_cb->proto_battery_off = old_proto_battery_off;
p_cb->proto_screen_lock = old_proto_screen_lock;
p_cb->proto_screen_off = old_proto_screen_off;
p_cb->proto_screen_off_lock = old_proto_screen_off_lock;
p_cb->size_mask = old_size_mask;
} else {
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_PROTO;
if (p_cb->proto_switch_on | p_cb->proto_switch_off |
p_cb->proto_battery_off | p_cb->proto_screen_lock |
p_cb->proto_screen_off | p_cb->proto_screen_off_lock) {
/* if any protocol in any power mode is configured, mark this entry as
* configured */
nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
}
nfa_ee_start_timer();
}
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_SET_PROTO_CFG_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_add_aid
**
** Description process add an AID routing configuration from user
** start a 1 second timer. When the timer expires,
** the configuration collected in control block is sent to NFCC
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_add_aid(tNFA_EE_MSG* p_data) {
tNFA_EE_API_ADD_AID* p_add = &p_data->add_aid;
tNFA_EE_ECB* p_cb = p_data->cfg_hdr.p_cb;
tNFA_EE_ECB* p_chk_cb;
uint8_t *p, *p_start;
int len, len_needed;
tNFA_EE_CBACK_DATA evt_data = {0};
int offset = 0, entry = 0;
uint16_t new_size;
nfa_ee_trace_aid("nfa_ee_api_add_aid", p_cb->nfcee_id, p_add->aid_len,
p_add->p_aid);
p_chk_cb =
nfa_ee_find_aid_offset(p_add->aid_len, p_add->p_aid, &offset, &entry);
if (p_chk_cb) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ee_api_add_aid The AID entry is already in the database");
if (p_chk_cb == p_cb) {
p_cb->aid_rt_info[entry] |= NFA_EE_AE_ROUTE;
p_cb->aid_info[entry] = p_add->aidInfo;
new_size = nfa_ee_total_lmrt_size();
if (new_size > NFC_GetLmrtSize()) {
LOG(ERROR) << StringPrintf("Exceed LMRT size:%d (add ROUTE)", new_size);
evt_data.status = NFA_STATUS_BUFFER_FULL;
p_cb->aid_rt_info[entry] &= ~NFA_EE_AE_ROUTE;
} else {
p_cb->aid_pwr_cfg[entry] = p_add->power_state;
}
} else {
LOG(ERROR) << StringPrintf(
"The AID entry is already in the database for different NFCEE "
"ID:0x%02x",
p_chk_cb->nfcee_id);
evt_data.status = NFA_STATUS_SEMANTIC_ERROR;
}
} else {
/* Find the total length so far */
len = nfa_ee_find_total_aid_len(p_cb, 0);
/* make sure the control block has enough room to hold this entry */
len_needed = p_add->aid_len + 2; /* tag/len */
if ((len_needed + len) > NFA_EE_MAX_AID_CFG_LEN) {
LOG(ERROR) << StringPrintf(
"Exceed capacity: (len_needed:%d + len:%d) > "
"NFA_EE_MAX_AID_CFG_LEN:%d",
len_needed, len, NFA_EE_MAX_AID_CFG_LEN);
evt_data.status = NFA_STATUS_BUFFER_FULL;
} else if (p_cb->aid_entries < NFA_EE_MAX_AID_ENTRIES) {
/* 4 = 1 (tag) + 1 (len) + 1(nfcee_id) + 1(power cfg) */
new_size = nfa_ee_total_lmrt_size() + 4 + p_add->aid_len;
if (new_size > NFC_GetLmrtSize()) {
LOG(ERROR) << StringPrintf("Exceed LMRT size:%d", new_size);
evt_data.status = NFA_STATUS_BUFFER_FULL;
} else {
/* add AID */
p_cb->aid_pwr_cfg[p_cb->aid_entries] = p_add->power_state;
p_cb->aid_info[p_cb->aid_entries] = p_add->aidInfo;
p_cb->aid_rt_info[p_cb->aid_entries] = NFA_EE_AE_ROUTE;
p = p_cb->aid_cfg + len;
p_start = p;
*p++ = NFA_EE_AID_CFG_TAG_NAME;
*p++ = p_add->aid_len;
memcpy(p, p_add->p_aid, p_add->aid_len);
p += p_add->aid_len;
p_cb->aid_len[p_cb->aid_entries++] = (uint8_t)(p - p_start);
}
} else {
LOG(ERROR) << StringPrintf("Exceed NFA_EE_MAX_AID_ENTRIES:%d",
NFA_EE_MAX_AID_ENTRIES);
evt_data.status = NFA_STATUS_BUFFER_FULL;
}
}
if (evt_data.status == NFA_STATUS_OK) {
/* mark AID changed */
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_AID;
nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
nfa_ee_update_route_aid_size(p_cb);
nfa_ee_start_timer();
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"status:%d ee_cfged:0x%02x ", evt_data.status, nfa_ee_cb.ee_cfged);
/* report the status of this operation */
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_ADD_AID_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_remove_aid
**
** Description process remove an AID routing configuration from user
** start a 1 second timer. When the timer expires,
** the configuration collected in control block is sent to NFCC
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_remove_aid(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb;
tNFA_EE_CBACK_DATA evt_data = {0};
int offset = 0, entry = 0, len;
int rest_len;
tNFA_EE_CBACK* p_cback = NULL;
nfa_ee_trace_aid("nfa_ee_api_remove_aid", 0, p_data->rm_aid.aid_len,
p_data->rm_aid.p_aid);
p_cb = nfa_ee_find_aid_offset(p_data->rm_aid.aid_len, p_data->rm_aid.p_aid,
&offset, &entry);
if (p_cb && p_cb->aid_entries) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"aid_rt_info[%d]: 0x%02x", entry, p_cb->aid_rt_info[entry]);
/* mark routing and VS changed */
if (p_cb->aid_rt_info[entry] & NFA_EE_AE_ROUTE)
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_AID;
if (p_cb->aid_rt_info[entry] & NFA_EE_AE_VS)
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_VS;
/* remove the aid */
if ((entry + 1) < p_cb->aid_entries) {
/* not the last entry, move the aid entries in control block */
/* Find the total len from the next entry to the last one */
rest_len = nfa_ee_find_total_aid_len(p_cb, entry + 1);
len = p_cb->aid_len[entry];
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ee_api_remove_aid len:%d, rest_len:%d", len, rest_len);
GKI_shiftup(&p_cb->aid_cfg[offset], &p_cb->aid_cfg[offset + len],
rest_len);
rest_len = p_cb->aid_entries - entry;
GKI_shiftup(&p_cb->aid_len[entry], &p_cb->aid_len[entry + 1], rest_len);
GKI_shiftup(&p_cb->aid_pwr_cfg[entry], &p_cb->aid_pwr_cfg[entry + 1],
rest_len);
GKI_shiftup(&p_cb->aid_rt_info[entry], &p_cb->aid_rt_info[entry + 1],
rest_len);
}
/* else the last entry, just reduce the aid_entries by 1 */
p_cb->aid_entries--;
nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
nfa_ee_update_route_aid_size(p_cb);
nfa_ee_start_timer();
/* report NFA_EE_REMOVE_AID_EVT to the callback associated the NFCEE */
p_cback = p_cb->p_ee_cback;
} else {
LOG(ERROR) << StringPrintf(
"nfa_ee_api_remove_aid The AID entry is not in the database");
evt_data.status = NFA_STATUS_INVALID_PARAM;
}
nfa_ee_report_event(p_cback, NFA_EE_REMOVE_AID_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_add_sys_code
**
** Description Adds System Code routing configuration from user. When the
** timer expires, the configuration collected in control block
** is sent to NFCC
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_add_sys_code(tNFA_EE_MSG* p_data) {
tNFA_EE_CBACK_DATA evt_data = {0};
tNFA_EE_API_ADD_SYSCODE* p_add = &p_data->add_syscode;
tNFA_EE_ECB* p_cb = p_data->cfg_hdr.p_cb;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"%s id:0x%x SC:0x%X ", __func__, p_add->nfcee_id, p_add->syscode);
int offset = 0, entry = 0;
tNFA_EE_ECB* p_chk_cb =
nfa_ee_find_sys_code_offset(p_add->syscode, &offset, &entry);
if (p_chk_cb) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"%s: The SC entry already registered "
"for this NFCEE id:0x%02x",
__func__, p_add->nfcee_id);
if (p_chk_cb == p_cb) {
p_cb->sys_code_rt_loc_vs_info[entry] |= NFA_EE_AE_ROUTE;
uint16_t new_size = nfa_ee_total_lmrt_size();
if (new_size > NFC_GetLmrtSize()) {
LOG(ERROR) << StringPrintf("Exceeded LMRT size:%d (add SYSCODE)",
new_size);
evt_data.status = NFA_STATUS_BUFFER_FULL;
p_cb->sys_code_rt_loc_vs_info[entry] &= ~NFA_EE_AE_ROUTE;
} else {
p_cb->sys_code_pwr_cfg[entry] = p_add->power_state;
}
} else {
LOG(ERROR) << StringPrintf(
"%s: SystemCode entry already registered for different "
"NFCEE id:0x%02x",
__func__, p_chk_cb->nfcee_id);
evt_data.status = NFA_STATUS_REJECTED;
}
} else {
/* Find the total length so far in sys_code_cfg */
int total_sc_len = nfa_all_ee_find_total_sys_code_len();
/* make sure the control block has enough room to hold this entry */
if ((NFA_EE_SYSTEM_CODE_LEN + total_sc_len) >
NFA_EE_MAX_SYSTEM_CODE_CFG_LEN) {
LOG(ERROR) << StringPrintf(
"Exceeded capacity: (NFA_EE_SYSTEM_CODE_LEN:%d + total_sc_len:%d) > "
"NFA_EE_MAX_SYSTEM_CODE_CFG_LEN:%d",
NFA_EE_SYSTEM_CODE_LEN, total_sc_len, NFA_EE_MAX_SYSTEM_CODE_CFG_LEN);
evt_data.status = NFA_STATUS_BUFFER_FULL;
} else if (p_cb->sys_code_cfg_entries < NFA_EE_MAX_SYSTEM_CODE_ENTRIES) {
/* 6 = 1 (tag) + 1 (len) + 1(nfcee_id) + 1(power cfg) + 2(system code)*/
uint16_t new_size =
nfa_ee_total_lmrt_size() + NFA_EE_SYSTEM_CODE_TLV_SIZE;
if (new_size > NFC_GetLmrtSize()) {
LOG(ERROR) << StringPrintf("Exceeded LMRT size:%d", new_size);
evt_data.status = NFA_STATUS_BUFFER_FULL;
} else {
/* add SC entry*/
uint32_t p_cb_sc_len = nfa_ee_find_total_sys_code_len(p_cb, 0);
p_cb->sys_code_pwr_cfg[p_cb->sys_code_cfg_entries] = p_add->power_state;
p_cb->sys_code_rt_loc[p_cb->sys_code_cfg_entries] = p_add->nfcee_id;
p_cb->sys_code_rt_loc_vs_info[p_cb->sys_code_cfg_entries] =
NFA_EE_AE_ROUTE;
uint8_t* p = p_cb->sys_code_cfg + p_cb_sc_len;
memcpy(p, &p_add->syscode, NFA_EE_SYSTEM_CODE_LEN);
p += NFA_EE_SYSTEM_CODE_LEN;
p_cb->sys_code_cfg_entries++;
}
} else {
LOG(ERROR) << StringPrintf("Exceeded NFA_EE_MAX_SYSTEM_CODE_ENTRIES:%d",
NFA_EE_MAX_SYSTEM_CODE_ENTRIES);
evt_data.status = NFA_STATUS_BUFFER_FULL;
}
}
if (evt_data.status == NFA_STATUS_OK) {
/* mark SC changed */
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_SYSCODE;
nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
nfa_ee_update_route_sys_code_size(p_cb);
nfa_ee_start_timer();
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s: status:%d ee_cfged:0x%02x ", __func__,
evt_data.status, nfa_ee_cb.ee_cfged);
/* report the status of this operation */
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_ADD_SYSCODE_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_remove_sys_code
**
** Description process remove an System Code routing configuration from
** user start a 1 second timer. When the timer expires,
** the configuration collected in control block is sent to NFCC
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_remove_sys_code(tNFA_EE_MSG* p_data) {
tNFA_EE_CBACK_DATA evt_data = {0};
tNFA_EE_API_REMOVE_SYSCODE* p_remove = &p_data->rm_syscode;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s SC:0x%x", __func__, p_remove->syscode);
int offset = 0, entry = 0;
tNFA_EE_ECB* p_cb =
nfa_ee_find_sys_code_offset(p_data->rm_syscode.syscode, &offset, &entry);
if (p_cb && p_cb->sys_code_cfg_entries) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("sys_code_rt_loc_vs_info[%d]: 0x%02x", entry,
p_cb->sys_code_rt_loc_vs_info[entry]);
/* mark routing and VS changed */
if (p_cb->sys_code_rt_loc_vs_info[entry] & NFA_EE_AE_ROUTE)
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_SYSCODE;
if (p_cb->sys_code_rt_loc_vs_info[entry] & NFA_EE_AE_VS)
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_VS;
/* remove the system code */
if ((entry + 1) < p_cb->sys_code_cfg_entries) {
/* not the last entry, move the SC entries in control block */
/* Find the total len from the next entry to the last one */
int total_len = nfa_ee_find_total_sys_code_len(p_cb, entry + 1);
int rm_len = NFA_EE_SYSTEM_CODE_LEN;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_api_remove_sys_code: rm_len:%d, total_len:%d",
rm_len, total_len);
GKI_shiftup(&p_cb->sys_code_cfg[offset],
&p_cb->sys_code_cfg[offset + rm_len], total_len);
total_len = p_cb->sys_code_cfg_entries - entry;
GKI_shiftup(&p_cb->sys_code_pwr_cfg[entry],
&p_cb->sys_code_pwr_cfg[entry + 1], total_len);
GKI_shiftup(&p_cb->sys_code_rt_loc_vs_info[entry],
&p_cb->sys_code_rt_loc_vs_info[entry + 1], total_len);
GKI_shiftup(&p_cb->sys_code_rt_loc[entry],
&p_cb->sys_code_rt_loc[entry + 1], total_len);
}
/* else the last entry, just reduce the aid_entries by 1 */
p_cb->sys_code_cfg_entries--;
nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
nfa_ee_update_route_sys_code_size(p_cb);
nfa_ee_start_timer();
} else {
LOG(ERROR) << StringPrintf(
"nfa_ee_api_remove_sys_code: The SC entry is not in the database");
evt_data.status = NFA_STATUS_INVALID_PARAM;
}
/* report the status of this operation */
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_REMOVE_SYSCODE_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_lmrt_size
**
** Description Reports the remaining size in the Listen Mode Routing Table
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_lmrt_size(__attribute__((unused)) tNFA_EE_MSG* p_data) {
tNFA_EE_CBACK_DATA evt_data = {0};
uint16_t total_size = NFC_GetLmrtSize();
evt_data.size = total_size - nfa_ee_total_lmrt_size();
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_api_lmrt_size total size:%d remaining size:%d",
total_size, evt_data.size);
nfa_ee_report_event(NULL, NFA_EE_REMAINING_SIZE_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_update_now
**
** Description Initiates connection creation process to the given NFCEE
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_update_now(tNFA_EE_MSG* p_data) {
tNFA_EE_CBACK_DATA evt_data;
if (nfa_ee_cb.ee_wait_evt & NFA_EE_WAIT_UPDATE_ALL) {
LOG(ERROR) << StringPrintf(
"nfa_ee_api_update_now still waiting for update complete "
"ee_wait_evt:0x%x wait_rsp:%d",
nfa_ee_cb.ee_wait_evt, nfa_ee_cb.wait_rsp);
evt_data.status = NFA_STATUS_SEMANTIC_ERROR;
nfa_ee_report_event(NULL, NFA_EE_UPDATED_EVT, &evt_data);
return;
}
nfa_sys_stop_timer(&nfa_ee_cb.timer);
nfa_ee_cb.ee_cfged |= NFA_EE_CFGED_UPDATE_NOW;
nfa_ee_rout_timeout(p_data);
}
/*******************************************************************************
**
** Function nfa_ee_api_connect
**
** Description Initiates connection creation process to the given NFCEE
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_connect(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb = p_data->connect.p_cb;
int xx;
tNFA_EE_CBACK_DATA evt_data = {0};
evt_data.connect.status = NFA_STATUS_FAILED;
if (p_cb->conn_st == NFA_EE_CONN_ST_NONE) {
for (xx = 0; xx < p_cb->num_interface; xx++) {
if (p_data->connect.ee_interface == p_cb->ee_interface[xx]) {
p_cb->p_ee_cback = p_data->connect.p_cback;
p_cb->conn_st = NFA_EE_CONN_ST_WAIT;
p_cb->use_interface = p_data->connect.ee_interface;
evt_data.connect.status =
NFC_ConnCreate(NCI_DEST_TYPE_NFCEE, p_data->connect.nfcee_id,
p_data->connect.ee_interface, nfa_ee_conn_cback);
/* report the NFA_EE_CONNECT_EVT status on the response from NFCC */
break;
}
}
}
if (evt_data.connect.status != NCI_STATUS_OK) {
evt_data.connect.ee_handle =
(tNFA_HANDLE)p_data->connect.nfcee_id | NFA_HANDLE_GROUP_EE;
evt_data.connect.status = NFA_STATUS_INVALID_PARAM;
evt_data.connect.ee_interface = p_data->connect.ee_interface;
nfa_ee_report_event(p_data->connect.p_cback, NFA_EE_CONNECT_EVT, &evt_data);
}
}
/*******************************************************************************
**
** Function nfa_ee_api_send_data
**
** Description Send the given data packet to the given NFCEE
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_send_data(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb = p_data->send_data.p_cb;
NFC_HDR* p_pkt;
uint16_t size = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE +
p_data->send_data.data_len + NFC_HDR_SIZE;
uint8_t* p;
tNFA_STATUS status = NFA_STATUS_FAILED;
if (p_cb->conn_st == NFA_EE_CONN_ST_CONN) {
p_pkt = (NFC_HDR*)GKI_getbuf(size);
if (p_pkt) {
p_pkt->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
p_pkt->len = p_data->send_data.data_len;
p = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
memcpy(p, p_data->send_data.p_data, p_pkt->len);
NFC_SendData(p_cb->conn_id, p_pkt);
} else {
tNFA_EE_CBACK_DATA nfa_ee_cback_data;
nfa_ee_cback_data.status = status;
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_NO_MEM_ERR_EVT,
&nfa_ee_cback_data);
}
} else {
tNFA_EE_CBACK_DATA nfa_ee_cback_data;
nfa_ee_cback_data.status = status;
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_NO_CB_ERR_EVT,
&nfa_ee_cback_data);
}
}
/*******************************************************************************
**
** Function nfa_ee_api_disconnect
**
** Description Initiates closing of the connection to the given NFCEE
**
** Returns void
**
*******************************************************************************/
void nfa_ee_api_disconnect(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb = p_data->disconnect.p_cb;
tNFA_EE_CBACK_DATA evt_data = {0};
if (p_cb->conn_st == NFA_EE_CONN_ST_CONN) {
p_cb->conn_st = NFA_EE_CONN_ST_DISC;
NFC_ConnClose(p_cb->conn_id);
}
evt_data.handle = (tNFA_HANDLE)p_cb->nfcee_id | NFA_HANDLE_GROUP_EE;
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_DISCONNECT_EVT, &evt_data);
}
/*******************************************************************************
**
** Function nfa_ee_report_disc_done
**
** Description Process the callback for NFCEE discovery response
**
** Returns void
**
*******************************************************************************/
void nfa_ee_report_disc_done(bool notify_enable_done) {
tNFA_EE_CBACK* p_cback;
tNFA_EE_CBACK_DATA evt_data = {0};
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"em_state:%d num_ee_expecting:%d "
"notify_enable_done:%d",
nfa_ee_cb.em_state, nfa_ee_cb.num_ee_expecting, notify_enable_done);
if (nfa_ee_cb.num_ee_expecting == 0) {
if (notify_enable_done) {
if (nfa_ee_cb.em_state == NFA_EE_EM_STATE_INIT_DONE) {
nfa_sys_cback_notify_enable_complete(NFA_ID_EE);
if (nfa_ee_cb.p_enable_cback)
(*nfa_ee_cb.p_enable_cback)(NFA_EE_DISC_STS_ON);
} else if ((nfa_ee_cb.em_state == NFA_EE_EM_STATE_RESTORING) &&
(nfa_ee_cb.ee_flags & NFA_EE_FLAG_NOTIFY_HCI)) {
nfa_ee_cb.ee_flags &= ~NFA_EE_FLAG_NOTIFY_HCI;
if (nfa_ee_cb.p_enable_cback)
(*nfa_ee_cb.p_enable_cback)(NFA_EE_DISC_STS_ON);
}
}
if (nfa_ee_cb.p_ee_disc_cback) {
/* notify API callback */
p_cback = nfa_ee_cb.p_ee_disc_cback;
nfa_ee_cb.p_ee_disc_cback = NULL;
evt_data.status = NFA_STATUS_OK;
evt_data.ee_discover.num_ee = NFA_EE_MAX_EE_SUPPORTED;
NFA_EeGetInfo(&evt_data.ee_discover.num_ee, evt_data.ee_discover.ee_info);
nfa_ee_report_event(p_cback, NFA_EE_DISCOVER_EVT, &evt_data);
}
if ((nfa_hci_cb.hci_state == NFA_HCI_STATE_EE_RECOVERY) &&
nfa_ee_cb.p_enable_cback)
(*nfa_ee_cb.p_enable_cback)(NFA_EE_RECOVERY_REDISCOVERED);
}
}
/*******************************************************************************
**
** Function nfa_ee_restore_ntf_done
**
** Description check if any ee_status still has NFA_EE_STATUS_PENDING bit
**
** Returns TRUE, if all NFA_EE_STATUS_PENDING bits are removed
**
*******************************************************************************/
bool nfa_ee_restore_ntf_done(void) {
tNFA_EE_ECB* p_cb;
bool is_done = true;
int xx;
p_cb = nfa_ee_cb.ecb;
for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++) {
if ((p_cb->nfcee_id != NFA_EE_INVALID) &&
(p_cb->ee_old_status & NFA_EE_STATUS_RESTORING)) {
is_done = false;
break;
}
}
return is_done;
}
/*******************************************************************************
**
** Function nfa_ee_remove_pending
**
** Description check if any ee_status still has NFA_EE_STATUS_RESTORING bit
**
** Returns TRUE, if all NFA_EE_STATUS_RESTORING bits are removed
**
*******************************************************************************/
static void nfa_ee_remove_pending(void) {
tNFA_EE_ECB* p_cb;
tNFA_EE_ECB *p_cb_n, *p_cb_end;
int xx, num_removed = 0;
int first_removed = NFA_EE_MAX_EE_SUPPORTED;
p_cb = nfa_ee_cb.ecb;
for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++) {
if ((p_cb->nfcee_id != NFA_EE_INVALID) &&
(p_cb->ee_status & NFA_EE_STATUS_RESTORING)) {
p_cb->nfcee_id = NFA_EE_INVALID;
num_removed++;
if (first_removed == NFA_EE_MAX_EE_SUPPORTED) first_removed = xx;
}
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("cur_ee:%d, num_removed:%d first_removed:%d",
nfa_ee_cb.cur_ee, num_removed, first_removed);
if (num_removed && (first_removed != (nfa_ee_cb.cur_ee - num_removed))) {
/* if the removes ECB entried are not at the end, move the entries up */
p_cb_end = &nfa_ee_cb.ecb[nfa_ee_cb.cur_ee - 1];
p_cb = &nfa_ee_cb.ecb[first_removed];
for (p_cb_n = p_cb + 1; p_cb_n <= p_cb_end;) {
while ((p_cb_n->nfcee_id == NFA_EE_INVALID) && (p_cb_n <= p_cb_end)) {
p_cb_n++;
}
if (p_cb_n <= p_cb_end) {
memcpy(p_cb, p_cb_n, sizeof(tNFA_EE_ECB));
p_cb_n->nfcee_id = NFA_EE_INVALID;
}
p_cb++;
p_cb_n++;
}
}
nfa_ee_cb.cur_ee -= (uint8_t)num_removed;
}
/*******************************************************************************
**
** Function nfa_ee_nci_disc_rsp
**
** Description Process the callback for NFCEE discovery response
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_disc_rsp(tNFA_EE_MSG* p_data) {
tNFC_NFCEE_DISCOVER_REVT* p_evt = p_data->disc_rsp.p_data;
tNFA_EE_ECB* p_cb;
uint8_t xx;
uint8_t num_nfcee = p_evt->num_nfcee;
bool notify_enable_done = false;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("em_state:%d cur_ee:%d, num_nfcee:%d", nfa_ee_cb.em_state,
nfa_ee_cb.cur_ee, num_nfcee);
switch (nfa_ee_cb.em_state) {
case NFA_EE_EM_STATE_INIT:
nfa_ee_cb.cur_ee = 0;
nfa_ee_cb.num_ee_expecting = 0;
if (num_nfcee == 0) {
nfa_ee_cb.em_state = NFA_EE_EM_STATE_INIT_DONE;
notify_enable_done = true;
if (p_evt->status != NFC_STATUS_OK) {
nfa_sys_stop_timer(&nfa_ee_cb.discv_timer);
}
}
break;
case NFA_EE_EM_STATE_INIT_DONE:
if (num_nfcee) {
/* if this is initiated by api function,
* check if the number of NFCEE expected is more than what's currently
* in CB */
if (num_nfcee > NFA_EE_MAX_EE_SUPPORTED)
num_nfcee = NFA_EE_MAX_EE_SUPPORTED;
if (nfa_ee_cb.cur_ee < num_nfcee) {
p_cb = &nfa_ee_cb.ecb[nfa_ee_cb.cur_ee];
for (xx = nfa_ee_cb.cur_ee; xx < num_nfcee; xx++, p_cb++) {
/* mark the new entries as a new one */
p_cb->nfcee_id = NFA_EE_INVALID;
}
}
nfa_ee_cb.cur_ee = num_nfcee;
}
break;
case NFA_EE_EM_STATE_RESTORING:
if (num_nfcee == 0) {
nfa_ee_cb.em_state = NFA_EE_EM_STATE_INIT_DONE;
nfa_ee_remove_pending();
nfa_ee_check_restore_complete();
if (p_evt->status != NFC_STATUS_OK) {
nfa_sys_stop_timer(&nfa_ee_cb.discv_timer);
}
}
break;
}
if (p_evt->status == NFC_STATUS_OK) {
nfa_ee_cb.num_ee_expecting = p_evt->num_nfcee;
if (nfa_ee_cb.num_ee_expecting > NFA_EE_MAX_EE_SUPPORTED) {
LOG(ERROR) << StringPrintf("NFA-EE num_ee_expecting:%d > max:%d",
nfa_ee_cb.num_ee_expecting,
NFA_EE_MAX_EE_SUPPORTED);
}
}
nfa_ee_report_disc_done(notify_enable_done);
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"em_state:%d cur_ee:%d num_ee_expecting:%d", nfa_ee_cb.em_state,
nfa_ee_cb.cur_ee, nfa_ee_cb.num_ee_expecting);
}
/*******************************************************************************
**
** Function nfa_ee_nci_disc_ntf
**
** Description Process the callback for NFCEE discovery notification
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_disc_ntf(tNFA_EE_MSG* p_data) {
tNFC_NFCEE_INFO_REVT* p_ee = p_data->disc_ntf.p_data;
tNFA_EE_ECB* p_cb = NULL;
bool notify_enable_done = false;
bool notify_new_ee = false;
tNFA_EE_CBACK_DATA evt_data = {0};
tNFA_EE_INFO* p_info;
tNFA_EE_EM_STATE new_em_state = NFA_EE_EM_STATE_MAX;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"em_state:%d ee_flags:0x%x cur_ee:%d "
"num_ee_expecting:%d",
nfa_ee_cb.em_state, nfa_ee_cb.ee_flags, nfa_ee_cb.cur_ee,
nfa_ee_cb.num_ee_expecting);
if (nfa_ee_cb.num_ee_expecting) {
nfa_ee_cb.num_ee_expecting--;
if ((nfa_ee_cb.num_ee_expecting == 0) &&
(nfa_ee_cb.p_ee_disc_cback != NULL)) {
/* Discovery triggered by API function */
if (NFA_GetNCIVersion() != NCI_VERSION_2_0) NFC_NfceeDiscover(false);
}
}
switch (nfa_ee_cb.em_state) {
case NFA_EE_EM_STATE_INIT:
if (nfa_ee_cb.cur_ee < NFA_EE_MAX_EE_SUPPORTED) {
/* the cb can collect up to NFA_EE_MAX_EE_SUPPORTED ee_info */
p_cb = &nfa_ee_cb.ecb[nfa_ee_cb.cur_ee++];
}
if (nfa_ee_cb.num_ee_expecting == 0) {
/* notify init_done callback */
nfa_ee_cb.em_state = NFA_EE_EM_STATE_INIT_DONE;
notify_enable_done = true;
}
break;
case NFA_EE_EM_STATE_INIT_DONE:
p_cb = nfa_ee_find_ecb(p_ee->nfcee_id);
if (p_cb == NULL) {
/* the NFCEE ID is not in the last NFCEE discovery
* maybe it's a new one */
p_cb = nfa_ee_find_ecb(NFA_EE_INVALID);
if (p_cb) {
nfa_ee_cb.cur_ee++;
notify_new_ee = true;
}
} else if (p_cb->ecb_flags & NFA_EE_ECB_FLAGS_ORDER) {
nfa_ee_cb.cur_ee++;
notify_new_ee = true;
} else {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("cur_ee:%d ecb_flags=0x%02x ee_status=0x%x",
nfa_ee_cb.cur_ee, p_cb->ecb_flags, p_cb->ee_status);
}
break;
case NFA_EE_EM_STATE_RESTORING:
p_cb = nfa_ee_find_ecb(p_ee->nfcee_id);
if (p_cb == NULL) {
/* the NFCEE ID is not in the last NFCEE discovery
* maybe it's a new one */
p_cb = nfa_ee_find_ecb(NFA_EE_INVALID);
if (p_cb) {
nfa_ee_cb.cur_ee++;
notify_new_ee = true;
}
}
if (nfa_ee_cb.num_ee_expecting == 0) {
/* notify init_done callback */
notify_enable_done = true;
if (nfa_ee_restore_ntf_done()) {
new_em_state = NFA_EE_EM_STATE_INIT_DONE;
}
}
break;
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_nci_disc_ntf cur_ee:%d", nfa_ee_cb.cur_ee);
if (p_cb) {
p_cb->nfcee_id = p_ee->nfcee_id;
p_cb->ee_status = p_ee->ee_status;
p_cb->num_interface = p_ee->num_interface;
memcpy(p_cb->ee_interface, p_ee->ee_interface, p_ee->num_interface);
p_cb->num_tlvs = p_ee->num_tlvs;
memcpy(p_cb->ee_tlv, p_ee->ee_tlv, p_ee->num_tlvs * sizeof(tNFA_EE_TLV));
if (NFA_GetNCIVersion() == NCI_VERSION_2_0)
p_cb->ee_power_supply_status = p_ee->nfcee_power_ctrl;
if (nfa_ee_cb.em_state == NFA_EE_EM_STATE_RESTORING) {
/* NCI spec says: An NFCEE_DISCOVER_NTF that contains a Protocol type of
* "HCI Access"
* SHALL NOT contain any other additional Protocol
* i.e. check only first supported NFCEE interface is HCI access */
/* NFA_HCI module handles restoring configurations for HCI access */
if (p_cb->ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) {
if ((nfa_ee_cb.ee_flags & NFA_EE_FLAG_WAIT_HCI) == 0) {
nfa_ee_restore_one_ecb(p_cb);
}
/* else wait for NFA-HCI module to restore the HCI network information
* before enabling the NFCEE */
}
}
if ((nfa_ee_cb.p_ee_disc_cback == NULL) && (notify_new_ee == true)) {
if (nfa_dm_is_active() && (p_cb->ee_status != NFA_EE_STATUS_REMOVED)) {
/* report this NFA_EE_NEW_EE_EVT only after NFA_DM_ENABLE_EVT is
* reported */
p_info = &evt_data.new_ee;
p_info->ee_handle = NFA_HANDLE_GROUP_EE | (tNFA_HANDLE)p_cb->nfcee_id;
p_info->ee_status = p_cb->ee_status;
p_info->num_interface = p_cb->num_interface;
p_info->num_tlvs = p_cb->num_tlvs;
memcpy(p_info->ee_interface, p_cb->ee_interface, p_cb->num_interface);
memcpy(p_info->ee_tlv, p_cb->ee_tlv,
p_cb->num_tlvs * sizeof(tNFA_EE_TLV));
if (NFA_GetNCIVersion() == NCI_VERSION_2_0)
p_info->ee_power_supply_status = p_cb->ee_power_supply_status;
nfa_ee_report_event(NULL, NFA_EE_NEW_EE_EVT, &evt_data);
}
} else
nfa_ee_report_disc_done(notify_enable_done);
if (p_cb->ecb_flags & NFA_EE_ECB_FLAGS_ORDER) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("NFA_EE_ECB_FLAGS_ORDER");
p_cb->ecb_flags &= ~NFA_EE_ECB_FLAGS_ORDER;
nfa_ee_report_discover_req_evt();
}
}
if (new_em_state != NFA_EE_EM_STATE_MAX) {
nfa_ee_cb.em_state = new_em_state;
nfa_ee_check_restore_complete();
}
if ((nfa_ee_cb.cur_ee == nfa_ee_max_ee_cfg) &&
(nfa_ee_cb.em_state == NFA_EE_EM_STATE_INIT_DONE)) {
if (nfa_ee_cb.discv_timer.in_use) {
nfa_sys_stop_timer(&nfa_ee_cb.discv_timer);
p_data->hdr.event = NFA_EE_DISCV_TIMEOUT_EVT;
nfa_ee_evt_hdlr(&p_data->hdr);
}
}
}
/*******************************************************************************
**
** Function nfa_ee_nci_nfcee_status_ntf
**
** Description Process the callback for NFCEE status notification
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_nfcee_status_ntf(tNFA_EE_MSG* p_data) {
if (p_data != NULL) {
tNFC_NFCEE_STATUS_REVT* p_ee_data = p_data->nfcee_status_ntf.p_data;
if ((NFA_GetNCIVersion() == NCI_VERSION_2_0) &&
(p_ee_data->nfcee_status == NFC_NFCEE_STATUS_UNRECOVERABLE_ERROR)) {
tNFA_EE_ECB* p_cb = nfa_ee_find_ecb(p_ee_data->nfcee_id);
if (p_cb && nfa_ee_cb.p_enable_cback) {
(*nfa_ee_cb.p_enable_cback)(NFA_EE_RECOVERY_INIT);
NFC_NfceeDiscover(true);
}
}
}
}
/*******************************************************************************
**
** Function nfa_ee_check_restore_complete
**
** Description Check if restore the NFA-EE related configuration to the
** state prior to low power mode is complete.
** If complete, notify sys.
**
** Returns void
**
*******************************************************************************/
void nfa_ee_check_restore_complete(void) {
uint32_t xx;
tNFA_EE_ECB* p_cb;
bool proc_complete = true;
p_cb = nfa_ee_cb.ecb;
for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++) {
if (p_cb->ecb_flags & NFA_EE_ECB_FLAGS_RESTORE) {
/* NFA_HCI module handles restoring configurations for HCI access.
* ignore the restoring status for HCI Access */
if (p_cb->ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) {
proc_complete = false;
break;
}
}
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ee_check_restore_complete nfa_ee_cb.ee_cfg_sts:0x%02x "
"proc_complete:%d",
nfa_ee_cb.ee_cfg_sts, proc_complete);
if (proc_complete) {
/* update routing table when NFA_EE_ROUT_TIMEOUT_EVT is received */
if (nfa_ee_cb.ee_cfg_sts & NFA_EE_STS_PREV_ROUTING)
nfa_ee_api_update_now(NULL);
nfa_ee_cb.em_state = NFA_EE_EM_STATE_INIT_DONE;
nfa_sys_cback_notify_nfcc_power_mode_proc_complete(NFA_ID_EE);
}
}
/*******************************************************************************
**
** Function nfa_ee_build_discover_req_evt
**
** Description Build NFA_EE_DISCOVER_REQ_EVT for all active NFCEE
**
** Returns void
**
*******************************************************************************/
static void nfa_ee_build_discover_req_evt(tNFA_EE_DISCOVER_REQ* p_evt_data) {
tNFA_EE_ECB* p_cb;
tNFA_EE_DISCOVER_INFO* p_info;
uint8_t xx;
if (!p_evt_data) return;
p_evt_data->num_ee = 0;
p_cb = nfa_ee_cb.ecb;
p_info = p_evt_data->ee_disc_info;
for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++) {
if ((p_cb->ee_status & NFA_EE_STATUS_INT_MASK) ||
(p_cb->ee_status != NFA_EE_STATUS_ACTIVE) ||
((p_cb->ecb_flags & NFA_EE_ECB_FLAGS_DISC_REQ) == 0)) {
continue;
}
p_info->ee_handle = (tNFA_HANDLE)p_cb->nfcee_id | NFA_HANDLE_GROUP_EE;
p_info->la_protocol = p_cb->la_protocol;
p_info->lb_protocol = p_cb->lb_protocol;
p_info->lf_protocol = p_cb->lf_protocol;
p_info->lbp_protocol = p_cb->lbp_protocol;
p_evt_data->num_ee++;
p_info++;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"[%d] ee_handle:0x%x, listen protocol A:%d, B:%d, F:%d, BP:%d",
p_evt_data->num_ee, p_cb->nfcee_id, p_cb->la_protocol,
p_cb->lb_protocol, p_cb->lf_protocol, p_cb->lbp_protocol);
}
p_evt_data->status = NFA_STATUS_OK;
}
/*******************************************************************************
**
** Function nfa_ee_report_discover_req_evt
**
** Description Report NFA_EE_DISCOVER_REQ_EVT for all active NFCEE
**
** Returns void
**
*******************************************************************************/
static void nfa_ee_report_discover_req_evt(void) {
if (nfa_ee_cb.p_enable_cback)
(*nfa_ee_cb.p_enable_cback)(NFA_EE_DISC_STS_REQ);
/* if this is restoring NFCC */
if (!nfa_dm_is_active()) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_report_discover_req_evt DM is not active");
return;
}
tNFA_EE_CBACK_DATA nfa_ee_cback_data;
nfa_ee_build_discover_req_evt(&nfa_ee_cback_data.discover_req);
nfa_ee_report_event(NULL, NFA_EE_DISCOVER_REQ_EVT, &nfa_ee_cback_data);
}
/*******************************************************************************
**
** Function nfa_ee_nci_mode_set_rsp
**
** Description Process the result for NFCEE ModeSet response
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_mode_set_rsp(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb;
tNFA_EE_MODE_SET mode_set;
tNFC_NFCEE_MODE_SET_REVT* p_rsp = p_data->mode_set_rsp.p_data;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"%s handle:0x%02x mode:%d", __func__, p_rsp->nfcee_id, p_rsp->mode);
p_cb = nfa_ee_find_ecb(p_rsp->nfcee_id);
if (p_cb == NULL) {
LOG(ERROR) << StringPrintf("%s Can not find cb for handle:0x%02x", __func__,
p_rsp->nfcee_id);
return;
}
/* Do not update routing table in EE_RECOVERY state */
if (nfa_hci_cb.hci_state != NFA_HCI_STATE_EE_RECOVERY) {
/* Start routing table update debounce timer */
nfa_ee_start_timer();
}
LOG(ERROR) << StringPrintf("%s p_rsp->status:0x%02x", __func__,
p_rsp->status);
if (p_rsp->status == NFA_STATUS_OK) {
if (p_rsp->mode == NFA_EE_MD_ACTIVATE) {
p_cb->ee_status = NFC_NFCEE_STATUS_ACTIVE;
} else {
if (p_cb->tech_switch_on | p_cb->tech_switch_off |
p_cb->tech_battery_off | p_cb->proto_switch_on |
p_cb->proto_switch_off | p_cb->proto_battery_off |
p_cb->aid_entries) {
/* this NFCEE still has configuration when deactivated. clear the
* configuration */
nfa_ee_cb.ee_cfged &= ~nfa_ee_ecb_to_mask(p_cb);
nfa_ee_cb.ee_cfg_sts |= NFA_EE_STS_CHANGED_ROUTING;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("deactivating/still configured. Force update");
}
p_cb->tech_switch_on = p_cb->tech_switch_off = p_cb->tech_battery_off = 0;
p_cb->proto_switch_on = p_cb->proto_switch_off = p_cb->proto_battery_off =
0;
p_cb->aid_entries = 0;
p_cb->ee_status = NFC_NFCEE_STATUS_INACTIVE;
}
} else if (p_rsp->mode == NFA_EE_MD_ACTIVATE) {
p_cb->ee_status = NFC_NFCEE_STATUS_REMOVED;
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"status:%d ecb_flags :0x%02x ee_cfged:0x%02x ee_status:%d",
p_rsp->status, p_cb->ecb_flags, nfa_ee_cb.ee_cfged, p_cb->ee_status);
if (p_cb->ecb_flags & NFA_EE_ECB_FLAGS_RESTORE) {
if (p_cb->conn_st == NFA_EE_CONN_ST_CONN) {
/* NFA_HCI module handles restoring configurations for HCI access */
if (p_cb->ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) {
NFC_ConnCreate(NCI_DEST_TYPE_NFCEE, p_cb->nfcee_id, p_cb->use_interface,
nfa_ee_conn_cback);
}
} else {
p_cb->ecb_flags &= ~NFA_EE_ECB_FLAGS_RESTORE;
nfa_ee_check_restore_complete();
}
} else {
mode_set.status = p_rsp->status;
mode_set.ee_handle = (tNFA_HANDLE)p_rsp->nfcee_id | NFA_HANDLE_GROUP_EE;
mode_set.ee_status = p_cb->ee_status;
tNFA_EE_CBACK_DATA nfa_ee_cback_data;
nfa_ee_cback_data.mode_set = mode_set;
nfa_ee_report_event(p_cb->p_ee_cback, NFA_EE_MODE_SET_EVT,
&nfa_ee_cback_data);
if ((p_cb->ee_status == NFC_NFCEE_STATUS_INACTIVE) ||
(p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE)) {
/* Report NFA_EE_DISCOVER_REQ_EVT for all active NFCEE */
nfa_ee_report_discover_req_evt();
}
}
if (nfa_ee_cb.p_enable_cback)
(*nfa_ee_cb.p_enable_cback)(NFA_EE_MODE_SET_COMPLETE);
}
/*******************************************************************************
**
** Function nfa_ee_report_update_evt
**
** Description Check if need to report NFA_EE_UPDATED_EVT
**
** Returns void
**
*******************************************************************************/
void nfa_ee_report_update_evt(void) {
tNFA_EE_CBACK_DATA evt_data;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_report_update_evt ee_wait_evt:0x%x wait_rsp:%d",
nfa_ee_cb.ee_wait_evt, nfa_ee_cb.wait_rsp);
if (nfa_ee_cb.wait_rsp == 0) {
nfa_ee_cb.ee_wait_evt &= ~NFA_EE_WAIT_UPDATE_RSP;
if (nfa_ee_cb.ee_wait_evt & NFA_EE_WAIT_UPDATE) {
nfa_ee_cb.ee_wait_evt &= ~NFA_EE_WAIT_UPDATE;
/* finished updating NFCC; report NFA_EE_UPDATED_EVT now */
evt_data.status = NFA_STATUS_OK;
nfa_ee_report_event(NULL, NFA_EE_UPDATED_EVT, &evt_data);
}
}
}
/*******************************************************************************
**
** Function nfa_ee_nci_wait_rsp
**
** Description Process the result for NCI response
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_wait_rsp(tNFA_EE_MSG* p_data) {
tNFA_EE_NCI_WAIT_RSP* p_rsp = &p_data->wait_rsp;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("ee_wait_evt:0x%x wait_rsp:%d", nfa_ee_cb.ee_wait_evt,
nfa_ee_cb.wait_rsp);
if (nfa_ee_cb.wait_rsp) {
if (p_rsp->opcode == NCI_MSG_RF_SET_ROUTING) nfa_ee_cb.wait_rsp--;
}
nfa_ee_report_update_evt();
}
/*******************************************************************************
**
** Function nfa_ee_nci_conn
**
** Description process the connection callback events
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_conn(tNFA_EE_MSG* p_data) {
tNFA_EE_ECB* p_cb;
tNFA_EE_NCI_CONN* p_cbk = &p_data->conn;
tNFC_CONN* p_conn = p_data->conn.p_data;
NFC_HDR* p_pkt = NULL;
tNFA_EE_CBACK_DATA evt_data = {0};
tNFA_EE_EVT event = NFA_EE_INVALID;
tNFA_EE_CBACK* p_cback = NULL;
if (p_cbk->event == NFC_CONN_CREATE_CEVT) {
p_cb = nfa_ee_find_ecb(p_cbk->p_data->conn_create.id);
} else {
p_cb = nfa_ee_find_ecb_by_conn_id(p_cbk->conn_id);
if (p_cbk->event == NFC_DATA_CEVT) p_pkt = p_conn->data.p_data;
}
if (p_cb) {
p_cback = p_cb->p_ee_cback;
evt_data.handle = (tNFA_HANDLE)p_cb->nfcee_id | NFA_HANDLE_GROUP_EE;
switch (p_cbk->event) {
case NFC_CONN_CREATE_CEVT:
if (p_conn->conn_create.status == NFC_STATUS_OK) {
p_cb->conn_id = p_cbk->conn_id;
p_cb->conn_st = NFA_EE_CONN_ST_CONN;
} else {
p_cb->conn_st = NFA_EE_CONN_ST_NONE;
}
if (p_cb->ecb_flags & NFA_EE_ECB_FLAGS_RESTORE) {
p_cb->ecb_flags &= ~NFA_EE_ECB_FLAGS_RESTORE;
nfa_ee_check_restore_complete();
} else {
evt_data.connect.status = p_conn->conn_create.status;
evt_data.connect.ee_interface = p_cb->use_interface;
event = NFA_EE_CONNECT_EVT;
}
break;
case NFC_CONN_CLOSE_CEVT:
if (p_cb->conn_st != NFA_EE_CONN_ST_DISC) event = NFA_EE_DISCONNECT_EVT;
p_cb->conn_st = NFA_EE_CONN_ST_NONE;
p_cb->p_ee_cback = NULL;
p_cb->conn_id = 0;
if (nfa_ee_cb.em_state == NFA_EE_EM_STATE_DISABLING) {
if (nfa_ee_cb.ee_flags & NFA_EE_FLAG_WAIT_DISCONN) {
if (nfa_ee_cb.num_ee_expecting) {
nfa_ee_cb.num_ee_expecting--;
}
}
if (nfa_ee_cb.num_ee_expecting == 0) {
nfa_ee_cb.ee_flags &= ~NFA_EE_FLAG_WAIT_DISCONN;
nfa_ee_check_disable();
}
}
break;
case NFC_DATA_CEVT:
if (p_cb->conn_st == NFA_EE_CONN_ST_CONN) {
/* report data event only in connected state */
if (p_cb->p_ee_cback && p_pkt) {
evt_data.data.len = p_pkt->len;
evt_data.data.p_buf = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
event = NFA_EE_DATA_EVT;
p_pkt = NULL; /* so this function does not free this GKI buffer */
}
}
break;
}
if ((event != NFA_EE_INVALID) && (p_cback)) (*p_cback)(event, &evt_data);
}
if (p_pkt) GKI_freebuf(p_pkt);
}
/*******************************************************************************
**
** Function nfa_ee_nci_action_ntf
**
** Description process the NFCEE action callback event
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_action_ntf(tNFA_EE_MSG* p_data) {
tNFC_EE_ACTION_REVT* p_cbk = p_data->act.p_data;
tNFA_EE_ACTION evt_data;
evt_data.ee_handle = (tNFA_HANDLE)p_cbk->nfcee_id | NFA_HANDLE_GROUP_EE;
evt_data.trigger = p_cbk->act_data.trigger;
memcpy(&(evt_data.param), &(p_cbk->act_data.param),
sizeof(tNFA_EE_ACTION_PARAM));
tNFA_EE_CBACK_DATA nfa_ee_cback_data;
nfa_ee_cback_data.action = evt_data;
nfa_ee_report_event(NULL, NFA_EE_ACTION_EVT, &nfa_ee_cback_data);
}
/*******************************************************************************
**
** Function nfa_ee_nci_disc_req_ntf
**
** Description process the NFCEE discover request callback event
**
** Returns void
**
*******************************************************************************/
void nfa_ee_nci_disc_req_ntf(tNFA_EE_MSG* p_data) {
tNFC_EE_DISCOVER_REQ_REVT* p_cbk = p_data->disc_req.p_data;
tNFA_HANDLE ee_handle;
tNFA_EE_ECB* p_cb = NULL;
uint8_t report_ntf = 0;
uint8_t xx;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"num_info: %d cur_ee:%d", p_cbk->num_info, nfa_ee_cb.cur_ee);
for (xx = 0; xx < p_cbk->num_info; xx++) {
ee_handle = NFA_HANDLE_GROUP_EE | p_cbk->info[xx].nfcee_id;
p_cb = nfa_ee_find_ecb(p_cbk->info[xx].nfcee_id);
if (!p_cb) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"Cannot find cb for NFCEE: 0x%x", p_cbk->info[xx].nfcee_id);
p_cb = nfa_ee_find_ecb(NFA_EE_INVALID);
if (p_cb) {
p_cb->nfcee_id = p_cbk->info[xx].nfcee_id;
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_ORDER;
} else {
LOG(ERROR) << StringPrintf("Cannot allocate cb for NFCEE: 0x%x",
p_cbk->info[xx].nfcee_id);
continue;
}
} else {
report_ntf |= nfa_ee_ecb_to_mask(p_cb);
}
p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_DISC_REQ;
if (p_cbk->info[xx].op == NFC_EE_DISC_OP_ADD) {
if (p_cbk->info[xx].tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_A) {
p_cb->la_protocol = p_cbk->info[xx].protocol;
} else if (p_cbk->info[xx].tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_B) {
p_cb->lb_protocol = p_cbk->info[xx].protocol;
} else if (p_cbk->info[xx].tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_F) {
p_cb->lf_protocol = p_cbk->info[xx].protocol;
} else if (p_cbk->info[xx].tech_n_mode ==
NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) {
p_cb->lbp_protocol = p_cbk->info[xx].protocol;
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfcee_id=0x%x ee_status=0x%x ecb_flags=0x%x la_protocol=0x%x "
"la_protocol=0x%x la_protocol=0x%x",
p_cb->nfcee_id, p_cb->ee_status, p_cb->ecb_flags, p_cb->la_protocol,
p_cb->lb_protocol, p_cb->lf_protocol);
} else {
if (p_cbk->info[xx].tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_A) {
p_cb->la_protocol = 0;
} else if (p_cbk->info[xx].tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_B) {
p_cb->lb_protocol = 0;
} else if (p_cbk->info[xx].tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_F) {
p_cb->lf_protocol = 0;
} else if (p_cbk->info[xx].tech_n_mode ==
NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) {
p_cb->lbp_protocol = 0;
}
}
}
/* Report NFA_EE_DISCOVER_REQ_EVT for all active NFCEE */
if (report_ntf) nfa_ee_report_discover_req_evt();
}
/*******************************************************************************
**
** Function nfa_ee_is_active
**
** Description Check if the given NFCEE is active
**
** Returns TRUE if the given NFCEE is active
**
*******************************************************************************/
bool nfa_ee_is_active(tNFA_HANDLE nfcee_id) {
bool is_active = false;
int xx;
tNFA_EE_ECB* p_cb = nfa_ee_cb.ecb;
if ((NFA_HANDLE_GROUP_MASK & nfcee_id) == NFA_HANDLE_GROUP_EE)
nfcee_id &= NFA_HANDLE_MASK;
if (nfcee_id == NFC_DH_ID) return true;
/* compose output */
for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++) {
if ((tNFA_HANDLE)p_cb->nfcee_id == nfcee_id) {
if (p_cb->ee_status == NFA_EE_STATUS_ACTIVE) {
is_active = true;
}
break;
}
}
return is_active;
}
/*******************************************************************************
**
** Function nfa_ee_get_tech_route
**
** Description Given a power state, find the technology routing
** destination. The result is filled in the given p_handles
** in the order of A, B, F, Bprime
**
** Returns None
**
*******************************************************************************/
void nfa_ee_get_tech_route(uint8_t power_state, uint8_t* p_handles) {
int xx, yy;
tNFA_EE_ECB* p_cb;
uint8_t tech_mask_list[NFA_EE_MAX_TECH_ROUTE] = {
NFA_TECHNOLOGY_MASK_A, NFA_TECHNOLOGY_MASK_B, NFA_TECHNOLOGY_MASK_F,
NFA_TECHNOLOGY_MASK_B_PRIME};
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%d", power_state);
for (xx = 0; xx < NFA_EE_MAX_TECH_ROUTE; xx++) {
p_handles[xx] = NFC_DH_ID;
p_cb = &nfa_ee_cb.ecb[nfa_ee_cb.cur_ee - 1];
for (yy = 0; yy < nfa_ee_cb.cur_ee; yy++, p_cb--) {
if (p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE) {
switch (power_state) {
case NFA_EE_PWR_STATE_ON:
if (p_cb->tech_switch_on & tech_mask_list[xx])
p_handles[xx] = p_cb->nfcee_id;
break;
case NFA_EE_PWR_STATE_SWITCH_OFF:
if (p_cb->tech_switch_off & tech_mask_list[xx])
p_handles[xx] = p_cb->nfcee_id;
break;
case NFA_EE_PWR_STATE_BATT_OFF:
if (p_cb->tech_battery_off & tech_mask_list[xx])
p_handles[xx] = p_cb->nfcee_id;
break;
}
}
}
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("0x%x, 0x%x, 0x%x, 0x%x", p_handles[0], p_handles[1],
p_handles[2], p_handles[3]);
}
/*******************************************************************************
**
** Function nfa_ee_check_set_routing
**
** Description If the new size exceeds the capacity of next block,
** send the routing command now and reset the related
** parameters.
**
** Returns void
**
*******************************************************************************/
void nfa_ee_check_set_routing(uint16_t new_size, int* p_max_len, uint8_t* p,
int* p_cur_offset) {
uint8_t max_tlv = (uint8_t)((*p_max_len > NFA_EE_ROUT_MAX_TLV_SIZE)
? NFA_EE_ROUT_MAX_TLV_SIZE
: *p_max_len);
if (new_size + *p_cur_offset > max_tlv) {
if (NFC_SetRouting(true, *p, *p_cur_offset, p + 1) == NFA_STATUS_OK) {
nfa_ee_cb.wait_rsp++;
}
/* after the routing command is sent, re-use the same buffer to send the
* next routing command.
* reset the related parameters */
if (*p_max_len > *p_cur_offset)
*p_max_len -= *p_cur_offset; /* the max is reduced */
else
*p_max_len = 0;
*p_cur_offset = 0; /* nothing is in queue any more */
*p = 0; /* num_tlv=0 */
}
}
/*******************************************************************************
**
** Function nfa_ee_route_add_one_ecb_order
**
** Description Add the routing entries for NFCEE/DH in order defined
**
** Returns NFA_STATUS_OK, if ok to continue
**
*******************************************************************************/
void nfa_ee_route_add_one_ecb_by_route_order(tNFA_EE_ECB* p_cb, int rout_type,
int* p_max_len, bool more,
uint8_t* ps, int* p_cur_offset) {
nfa_ee_check_set_routing(p_cb->size_mask, p_max_len, ps, p_cur_offset);
/* use the first byte of the buffer (ps) to keep the num_tlv */
uint8_t num_tlv = *ps;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"%s - max_len:%d, cur_offset:%d, more:%d, num_tlv:%d,rout_type:- %d",
__func__, *p_max_len, *p_cur_offset, more, num_tlv, rout_type);
uint8_t* pp = ps + 1 + *p_cur_offset;
uint8_t* p = pp;
uint16_t tlv_size = (uint8_t)*p_cur_offset;
switch (rout_type) {
case NCI_ROUTE_ORDER_TECHNOLOGY: {
nfa_ee_add_tech_route_to_ecb(p_cb, pp, p, ps, p_cur_offset);
} break;
case NCI_ROUTE_ORDER_PROTOCOL: {
nfa_ee_add_proto_route_to_ecb(p_cb, pp, p, ps, p_cur_offset);
} break;
case NCI_ROUTE_ORDER_AID: {
nfa_ee_add_aid_route_to_ecb(p_cb, pp, p, ps, p_cur_offset, p_max_len);
} break;
case NCI_ROUTE_ORDER_SYS_CODE: {
nfa_ee_add_sys_code_route_to_ecb(p_cb, pp, p, ps, p_cur_offset,
p_max_len);
} break;
default: {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s - Route type - NA:- %d", __func__, rout_type);
}
}
/* update the total number of entries */
num_tlv = *ps;
tlv_size = nfa_ee_total_lmrt_size();
if (tlv_size) {
nfa_ee_cb.ee_cfged |= nfa_ee_ecb_to_mask(p_cb);
}
if (p_cb->ecb_flags & NFA_EE_ECB_FLAGS_ROUTING) {
nfa_ee_cb.ee_cfg_sts |= NFA_EE_STS_CHANGED_ROUTING;
}
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"ee_cfg_sts:0x%02x lmrt_size:%d", nfa_ee_cb.ee_cfg_sts, tlv_size);
if (more == false) {
/* last entry. update routing table now */
if (nfa_ee_cb.ee_cfg_sts & NFA_EE_STS_CHANGED_ROUTING) {
if (tlv_size) {
nfa_ee_cb.ee_cfg_sts |= NFA_EE_STS_PREV_ROUTING;
} else {
nfa_ee_cb.ee_cfg_sts &= ~NFA_EE_STS_PREV_ROUTING;
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s : set routing num_tlv:%d tlv_size:%d", __func__,
num_tlv, tlv_size);
if (NFC_SetRouting(more, num_tlv, (uint8_t)(*p_cur_offset), ps + 1) ==
NFA_STATUS_OK) {
nfa_ee_cb.wait_rsp++;
}
} else if (nfa_ee_cb.ee_cfg_sts & NFA_EE_STS_PREV_ROUTING) {
if (tlv_size == 0) {
nfa_ee_cb.ee_cfg_sts &= ~NFA_EE_STS_PREV_ROUTING;
/* indicated routing is configured to NFCC */
nfa_ee_cb.ee_cfg_sts |= NFA_EE_STS_CHANGED_ROUTING;
if (NFC_SetRouting(more, 0, 0, ps + 1) == NFA_STATUS_OK) {
nfa_ee_cb.wait_rsp++;
}
}
}
}
}
/*******************************************************************************
**
** Function nfa_ee_need_recfg
**
** Description Check if any API function to configure the routing table or
** VS is called since last update
**
** The algorithm for the NFCEE configuration handling is as
** follows:
**
** Each NFCEE_ID/DH has its own control block - tNFA_EE_ECB
** Each control block uses ecb_flags to keep track if an API
** that changes routing/VS is invoked. This ecb_flags is
** cleared at the end of nfa_ee_update_rout().
**
** nfa_ee_cb.ee_cfged is the bitmask of the control blocks with
** routing/VS configuration and NFA_EE_CFGED_UPDATE_NOW.
** nfa_ee_cb.ee_cfged is cleared and re-calculated at the end
** of nfa_ee_update_rout().
**
** nfa_ee_cb.ee_cfg_sts is used to check is any status is
** changed and the associated command is issued to NFCC.
** nfa_ee_cb.ee_cfg_sts is AND with NFA_EE_STS_PREV at the end
** of nfa_ee_update_rout() to clear the NFA_EE_STS_CHANGED bits
** (except NFA_EE_STS_CHANGED_CANNED_VS is cleared in
** nfa_ee_vs_cback)
**
** Returns TRUE if any configuration is changed
**
*******************************************************************************/
static bool nfa_ee_need_recfg(void) {
bool needed = false;
uint32_t xx;
tNFA_EE_ECB* p_cb;
uint8_t mask;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("ee_cfged: 0x%02x ee_cfg_sts: 0x%02x", nfa_ee_cb.ee_cfged,
nfa_ee_cb.ee_cfg_sts);
/* if no routing/vs is configured, do not need to send the info to NFCC */
if (nfa_ee_cb.ee_cfged || nfa_ee_cb.ee_cfg_sts) {
if (nfa_ee_cb.ee_cfg_sts & NFA_EE_STS_CHANGED) {
needed = true;
} else {
p_cb = &nfa_ee_cb.ecb[NFA_EE_CB_4_DH];
mask = 1 << NFA_EE_CB_4_DH;
for (xx = 0; xx <= nfa_ee_cb.cur_ee; xx++) {
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"%d: ecb_flags : 0x%02x, mask: 0x%02x", xx, p_cb->ecb_flags, mask);
if ((p_cb->ecb_flags) && (nfa_ee_cb.ee_cfged & mask)) {
needed = true;
break;
}
p_cb = &nfa_ee_cb.ecb[xx];
mask = 1 << xx;
}
}
}
return needed;
}
/*******************************************************************************
**
** Function nfa_ee_rout_timeout
**
** Description Anytime VS or routing entries are changed,
** a 1 second timer is started. This function is called when
** the timer expires or NFA_EeUpdateNow() is called.
**
** Returns void
**
*******************************************************************************/
void nfa_ee_rout_timeout(__attribute__((unused)) tNFA_EE_MSG* p_data) {
uint8_t ee_cfged = nfa_ee_cb.ee_cfged;
DLOG_IF(INFO, nfc_debug_enabled) << __func__;
if (nfa_ee_need_recfg()) {
/* discovery is not started */
nfa_ee_update_rout();
}
if (nfa_ee_cb.wait_rsp) nfa_ee_cb.ee_wait_evt |= NFA_EE_WAIT_UPDATE_RSP;
if (ee_cfged & NFA_EE_CFGED_UPDATE_NOW) {
/* need to report NFA_EE_UPDATED_EVT when done updating NFCC */
nfa_ee_cb.ee_wait_evt |= NFA_EE_WAIT_UPDATE;
if (!nfa_ee_cb.wait_rsp) {
nfa_ee_report_update_evt();
}
}
}
/*******************************************************************************
**
** Function nfa_ee_discv_timeout
**
** Description
**
**
**
** Returns void
**
*******************************************************************************/
void nfa_ee_discv_timeout(__attribute__((unused)) tNFA_EE_MSG* p_data) {
if (NFA_GetNCIVersion() != NCI_VERSION_2_0) NFC_NfceeDiscover(false);
if (nfa_ee_cb.p_enable_cback)
(*nfa_ee_cb.p_enable_cback)(NFA_EE_DISC_STS_OFF);
}
/*******************************************************************************
**
** Function nfa_ee_lmrt_to_nfcc
**
** Description This function would set the listen mode routing table
** to NFCC.
**
** Returns void
**
*******************************************************************************/
void nfa_ee_lmrt_to_nfcc(__attribute__((unused)) tNFA_EE_MSG* p_data) {
int xx;
tNFA_EE_ECB* p_cb;
uint8_t* p = NULL;
bool more = true;
bool check = true;
uint8_t last_active = NFA_EE_INVALID;
int max_len;
tNFA_STATUS status = NFA_STATUS_FAILED;
int cur_offset;
uint8_t max_tlv;
/* update routing table: DH and the activated NFCEEs */
p = (uint8_t*)GKI_getbuf(NFA_EE_ROUT_BUF_SIZE);
if (p == NULL) {
LOG(ERROR) << StringPrintf("no buffer to send routing info.");
tNFA_EE_CBACK_DATA nfa_ee_cback_data;
nfa_ee_cback_data.status = status;
nfa_ee_report_event(NULL, NFA_EE_NO_MEM_ERR_EVT, &nfa_ee_cback_data);
return;
}
/* find the last active NFCEE. */
p_cb = &nfa_ee_cb.ecb[nfa_ee_cb.cur_ee - 1];
for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb--) {
if (p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE) {
if (last_active == NFA_EE_INVALID) {
last_active = p_cb->nfcee_id;
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("last_active: 0x%x", last_active);
}
}
}
if (last_active == NFA_EE_INVALID) {
check = false;
}
max_len = NFC_GetLmrtSize();
max_tlv =
(uint8_t)((max_len > NFA_EE_ROUT_MAX_TLV_SIZE) ? NFA_EE_ROUT_MAX_TLV_SIZE
: max_len);
cur_offset = 0;
/* use the first byte of the buffer (p) to keep the num_tlv */
*p = 0;
for (int rt = NCI_ROUTE_ORDER_AID; rt <= NCI_ROUTE_ORDER_TECHNOLOGY; rt++) {
/* add the routing entries for NFCEEs */
p_cb = &nfa_ee_cb.ecb[0];
for (xx = 0; (xx < nfa_ee_cb.cur_ee) && check; xx++, p_cb++) {
if (p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE) {
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s --add the routing for NFCEEs!!", __func__);
nfa_ee_route_add_one_ecb_by_route_order(p_cb, rt, &max_len, more, p,
&cur_offset);
}
}
if (rt == NCI_ROUTE_ORDER_TECHNOLOGY) more = false;
/* add the routing entries for DH */
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("%s --add the routing for DH!!", __func__);
nfa_ee_route_add_one_ecb_by_route_order(&nfa_ee_cb.ecb[NFA_EE_CB_4_DH], rt,
&max_len, more, p, &cur_offset);
}
GKI_freebuf(p);
}
/*******************************************************************************
**
** Function nfa_ee_update_rout
**
** Description This function would set the VS and listen mode routing table
** to NFCC.
**
** Returns void
**
*******************************************************************************/
void nfa_ee_update_rout(void) {
int xx;
tNFA_EE_ECB* p_cb;
uint8_t mask;
tNFA_EE_MSG nfa_ee_msg;
DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
"nfa_ee_update_rout ee_cfg_sts:0x%02x", nfa_ee_cb.ee_cfg_sts);
/* use action function to send routing and VS configuration to NFCC */
nfa_ee_msg.hdr.event = NFA_EE_CFG_TO_NFCC_EVT;
nfa_ee_evt_hdlr(&nfa_ee_msg.hdr);
/* all configuration is updated to NFCC, clear the status mask */
nfa_ee_cb.ee_cfg_sts &= NFA_EE_STS_PREV;
nfa_ee_cb.ee_cfged = 0;
p_cb = &nfa_ee_cb.ecb[0];
for (xx = 0; xx < NFA_EE_NUM_ECBS; xx++, p_cb++) {
p_cb->ecb_flags = 0;
mask = (1 << xx);
if (p_cb->tech_switch_on | p_cb->tech_switch_off | p_cb->tech_battery_off |
p_cb->proto_switch_on | p_cb->proto_switch_off |
p_cb->proto_battery_off | p_cb->aid_entries |
p_cb->sys_code_cfg_entries) {
/* this entry has routing configuration. mark it configured */
nfa_ee_cb.ee_cfged |= mask;
}
}
DLOG_IF(INFO, nfc_debug_enabled)
<< StringPrintf("nfa_ee_update_rout ee_cfg_sts:0x%02x ee_cfged:0x%02x",
nfa_ee_cb.ee_cfg_sts, nfa_ee_cb.ee_cfged);
}