/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
#ifdef ESE_NFC_SYNCHRONIZATION
#include <linux/ese-nfc-sync.h>
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <android-base/stringprintf.h>
#include <base/logging.h>
#include <phNxpConfig.h>
#include <phNxpExtns_MifareStd.h>
#include <phNxpLog.h>
using android::base::StringPrintf;
extern phNxpExtns_Context_t gphNxpExtns_Context;
extern phFriNfc_NdefMap_t* NdefMap;
extern phNci_mfc_auth_cmd_t gAuthCmdBuf;
static NFCSTATUS phNxpExtns_ProcessSysMessage(phLibNfc_Message_t* msg);
static NFCSTATUS phNxpExtns_SendMsg(phLibNfc_Message_t* sysmsg);
#ifdef ESE_NFC_SYNCHRONIZATION
/* timing calculation structure*/
typedef struct time_cal {
struct timeval tv1;
struct timeval tv2;
} TimeCal;
static int fd_ese_nfc_sync; /*file descriptor to hold sync driver handle*/
#endif
/*******************************************************************************
**
** Function EXTNS_Init
**
** Description This function Initializes Mifare Classic Extns. Allocates
** required memory and initializes the Mifare Classic Vars
**
** Returns NFCSTATUS_SUCCESS if successfully initialized
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_Init(tNFA_DM_CBACK* p_nfa_dm_cback,
tNFA_CONN_CBACK* p_nfa_conn_cback) {
NFCSTATUS status = NFCSTATUS_FAILED;
/* reset config cache */
resetNxpConfig();
/* Initialize Log level */
phNxpLog_InitializeLogLevel();
/* Validate parameters */
if ((!p_nfa_dm_cback) || (!p_nfa_conn_cback)) {
LOG(ERROR) << StringPrintf("EXTNS_Init(): error null callback");
goto clean_and_return;
}
gphNxpExtns_Context.p_dm_cback = p_nfa_dm_cback;
gphNxpExtns_Context.p_conn_cback = p_nfa_conn_cback;
if (NFCSTATUS_SUCCESS != phNxpExtns_MfcModuleInit()) {
LOG(ERROR) << StringPrintf("ERROR: MFC Module Init Failed");
goto clean_and_return;
}
gphNxpExtns_Context.Extns_status = EXTNS_STATUS_OPEN;
status = NFCSTATUS_SUCCESS;
return status;
clean_and_return:
gphNxpExtns_Context.Extns_status = EXTNS_STATUS_CLOSE;
return status;
}
/*******************************************************************************
**
** Function EXTNS_Close
**
** Description This function de-initializes Mifare Classic Extns.
** De-allocates memory
**
** Returns None
**
*******************************************************************************/
void EXTNS_Close(void) {
gphNxpExtns_Context.Extns_status = EXTNS_STATUS_CLOSE;
phNxpExtns_MfcModuleDeInit();
return;
}
/*******************************************************************************
**
** Function EXTNS_MfcCallBack
**
** Description Decodes Mifare Classic Tag Response
** This is called from NFA_SendRaw Callback
**
** Returns:
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcCallBack(uint8_t* buf, uint32_t buflen) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_RX_DATA;
msg.pMsgData = buf;
msg.Size = buflen;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcCheckNDef
**
** Description Performs NDEF detection for Mifare Classic Tag
**
** Upon successful completion of NDEF detection, a
** NFA_NDEF_DETECT_EVT will be sent, to notify the application
** of the NDEF attributes (NDEF total memory size, current
** size, etc.).
**
** Returns:
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcCheckNDef(void) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_MIFARE_CHECK_NDEF;
msg.pMsgData = NULL;
msg.Size = 0;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcReadNDef
**
** Description Reads NDEF message from Mifare Classic Tag.
**
** Upon receiving the NDEF message, the message will be sent to
** the handler registered with
*EXTNS_MfcRegisterNDefTypeHandler.
**
** Returns:
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcReadNDef(void) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_MIFARE_READ_NDEF;
msg.pMsgData = NULL;
msg.Size = 0;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcPresenceCheck
**
** Description Do the check presence for Mifare Classic Tag.
**
**
** Returns:
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcPresenceCheck(void) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_MIFARE_PRESENCE_CHECK;
msg.pMsgData = NULL;
msg.Size = 0;
gAuthCmdBuf.status = NFCSTATUS_FAILED;
if (sem_init(&gAuthCmdBuf.semPresenceCheck, 0, 0) == -1) {
LOG(ERROR) << StringPrintf("%s: semaphore creation failed (errno=%d)",
__func__, errno);
return NFCSTATUS_FAILED;
}
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
sem_destroy(&gAuthCmdBuf.semPresenceCheck);
}
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcSetReadOnly
**
**
** Description:
** Sets tag as read only.
**
** When tag is set as read only, or if an error occurs, the app will be
** notified with NFA_SET_TAG_RO_EVT.
**
** Returns:
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcSetReadOnly(uint8_t* key, uint8_t len) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_MIFARE_READ_ONLY;
msg.pMsgData = key;
msg.Size = len;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcWriteNDef
**
** Description Writes NDEF data to Mifare Classic Tag.
**
** When the entire message has been written, or if an error
** occurs, the app will be notified with NFA_WRITE_CPLT_EVT.
**
** p_data needs to be persistent until NFA_WRITE_CPLT_EVT
**
** Returns:
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcWriteNDef(uint8_t* p_data, uint32_t len) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_MIFARE_WRITE_NDEF;
msg.pMsgData = p_data;
msg.Size = len;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*****************************************************************************
**
** Function EXTNS_MfcFormatTag
**
** Description Formats Mifare Classic Tag.
**
** The NFA_RW_FORMAT_CPLT_EVT, status is used to
** indicate if tag is successfully formated or not
**
** Returns
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*****************************************************************************/
NFCSTATUS EXTNS_MfcFormatTag(uint8_t* key, uint8_t len) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_MIFARE_FORMAT_NDEF;
msg.pMsgData = key;
msg.Size = len;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*****************************************************************************
**
** Function EXTNS_MfcDisconnect
**
** Description Disconnects Mifare Classic Tag.
**
** Returns
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*****************************************************************************/
NFCSTATUS EXTNS_MfcDisconnect(void) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_DISCONNECT;
msg.pMsgData = NULL;
msg.Size = 0;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*****************************************************************************
**
** Function EXTNS_MfcActivated
**
** Description Activates Mifare Classic Tag.
**
** Returns
** NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*****************************************************************************/
NFCSTATUS EXTNS_MfcActivated(void) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_ACTIVATED;
msg.pMsgData = NULL;
msg.Size = 0;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcTransceive
**
** Description Sends raw frame to Mifare Classic Tag.
**
** Returns NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcTransceive(uint8_t* p_data, uint32_t len) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
phLibNfc_Message_t msg;
msg.eMsgType = PH_NXPEXTNS_MIFARE_TRANSCEIVE;
msg.pMsgData = p_data;
msg.Size = len;
status = phNxpExtns_SendMsg(&msg);
if (NFCSTATUS_SUCCESS != status) {
LOG(ERROR) << StringPrintf("Error Sending msg to Extension Thread");
}
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcInit
**
** Description This function is used to Init Mifare Classic Extns.
** This function should be called when the tag detected is
** Mifare Classic.
**
** Returns NFCSTATUS_SUCCESS
**
*******************************************************************************/
NFCSTATUS EXTNS_MfcInit(tNFA_ACTIVATED activationData) {
tNFC_ACTIVATE_DEVT rfDetail = activationData.activate_ntf;
NdefMap->psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak =
rfDetail.rf_tech_param.param.pa.sel_rsp;
NdefMap->psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA[0] =
rfDetail.rf_tech_param.param.pa.sens_res[0];
NdefMap->psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA[1] =
rfDetail.rf_tech_param.param.pa.sens_res[1];
return NFCSTATUS_SUCCESS;
}
/*******************************************************************************
**
** Function phNxpExtns_ProcessSysMessage
**
** Description Internal function to route the request from JNI and Callback
** from NFA_SendRawFrame to right function
**
** Returns NFCSTATUS_SUCCESS if valid request
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
static NFCSTATUS phNxpExtns_ProcessSysMessage(phLibNfc_Message_t* msg) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
if (gphNxpExtns_Context.Extns_status == EXTNS_STATUS_CLOSE) {
return NFCSTATUS_FAILED;
}
switch (msg->eMsgType) {
case PH_NXPEXTNS_RX_DATA:
status = Mfc_RecvPacket((uint8_t*)msg->pMsgData, msg->Size);
break;
case PH_NXPEXTNS_MIFARE_CHECK_NDEF:
pthread_mutex_init(&gAuthCmdBuf.syncmutex, NULL);
pthread_mutex_lock(&gAuthCmdBuf.syncmutex);
status = Mfc_CheckNdef();
pthread_mutex_unlock(&gAuthCmdBuf.syncmutex);
pthread_mutex_destroy(&gAuthCmdBuf.syncmutex);
break;
case PH_NXPEXTNS_MIFARE_READ_NDEF:
status = Mfc_ReadNdef();
break;
case PH_NXPEXTNS_MIFARE_WRITE_NDEF:
status = Mfc_WriteNdef((uint8_t*)msg->pMsgData, msg->Size);
break;
case PH_NXPEXTNS_MIFARE_FORMAT_NDEF:
status = Mfc_FormatNdef((uint8_t*)msg->pMsgData, msg->Size);
break;
case PH_NXPEXTNS_DISCONNECT:
Mfc_DeactivateCbackSelect();
break;
case PH_NXPEXTNS_ACTIVATED:
Mfc_ActivateCback();
break;
case PH_NXPEXTNS_MIFARE_TRANSCEIVE:
status = Mfc_Transceive((uint8_t*)msg->pMsgData, msg->Size);
break;
case PH_NXPEXTNS_MIFARE_READ_ONLY:
status = Mfc_SetReadOnly((uint8_t*)msg->pMsgData, msg->Size);
break;
case PH_NXPEXTNS_MIFARE_PRESENCE_CHECK:
pthread_mutex_init(&gAuthCmdBuf.syncmutex, NULL);
pthread_mutex_lock(&gAuthCmdBuf.syncmutex);
status = Mfc_PresenceCheck();
pthread_mutex_unlock(&gAuthCmdBuf.syncmutex);
pthread_mutex_destroy(&gAuthCmdBuf.syncmutex);
break;
default:
status = NFCSTATUS_FAILED;
LOG(ERROR) << StringPrintf("Illegal Command for Extension");
break;
}
return status;
}
/*******************************************************************************
**
** Function phNxpExtns_SendMsg
**
** Description unlocks phNxpExtns_ProcessSysMessage with a valid message
**
** Returns NFCSTATUS_SUCCESS if successfully initiated
** NFCSTATUS_FAILED otherwise
**
*******************************************************************************/
static NFCSTATUS phNxpExtns_SendMsg(phLibNfc_Message_t* sysmsg) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
status = phNxpExtns_ProcessSysMessage(sysmsg);
return status;
}
/*******************************************************************************
**
** Function EXTNS_MfcRegisterNDefTypeHandler
**
** Description This function allows the applications to register for
** specific types of NDEF records.
**
** For records types which were not registered, the record will
** be sent to the default handler.
**
** Returns NFCSTATUS_SUCCESS
**
*******************************************************************************/
NFCSTATUS
EXTNS_MfcRegisterNDefTypeHandler(tNFA_NDEF_CBACK* ndefHandlerCallback) {
NFCSTATUS status = NFCSTATUS_FAILED;
if (NULL != ndefHandlerCallback) {
gphNxpExtns_Context.p_ndef_cback = ndefHandlerCallback;
status = NFCSTATUS_SUCCESS;
}
return status;
}
/*******************************************************************************
** Synchronizing Functions **
** Synchronizes Callback in JNI and MFC Extns **
*******************************************************************************/
bool_t EXTNS_GetConnectFlag(void) { return (gphNxpExtns_Context.ExtnsConnect); }
void EXTNS_SetConnectFlag(bool_t flagval) {
gphNxpExtns_Context.ExtnsConnect = flagval;
}
bool_t EXTNS_GetDeactivateFlag(void) {
return (gphNxpExtns_Context.ExtnsDeactivate);
}
void EXTNS_SetDeactivateFlag(bool_t flagval) {
gphNxpExtns_Context.ExtnsDeactivate = flagval;
}
bool_t EXTNS_GetCallBackFlag(void) {
return (gphNxpExtns_Context.ExtnsCallBack);
}
void EXTNS_SetCallBackFlag(bool_t flagval) {
gphNxpExtns_Context.ExtnsCallBack = flagval;
}
NFCSTATUS EXTNS_GetPresenceCheckStatus(void) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 0;
ts.tv_nsec += 100 * 1000 * 1000; // 100 milisec
if (ts.tv_nsec >= 1000 * 1000 * 1000) {
ts.tv_sec += 1;
ts.tv_nsec = ts.tv_nsec - (1000 * 1000 * 1000);
}
if (sem_timedwait(&gAuthCmdBuf.semPresenceCheck, &ts)) {
LOG(ERROR) << StringPrintf("%s: failed to wait (errno=%d)", __func__,
errno);
sem_destroy(&gAuthCmdBuf.semPresenceCheck);
gAuthCmdBuf.auth_sent = false;
return NFCSTATUS_FAILED;
}
if (sem_destroy(&gAuthCmdBuf.semPresenceCheck)) {
LOG(ERROR) << StringPrintf(
"%s: Failed to destroy check Presence semaphore (errno=%d)", __func__,
errno);
}
return gAuthCmdBuf.status;
}
void MfcPresenceCheckResult(NFCSTATUS status) {
gAuthCmdBuf.status = status;
EXTNS_SetCallBackFlag(true);
sem_post(&gAuthCmdBuf.semPresenceCheck);
}
void MfcResetPresenceCheckStatus(void) { gAuthCmdBuf.auth_sent = false; }
/*******************************************************************************
**
** Function EXTNS_CheckMfcResponse
**
** Description This function is called from JNI Transceive for Mifare
** Classic Tag status interpretation and to send the required
** status to application
**
** Returns NFCSTATUS_SUCCESS
** NFCSTATUS_FAILED
**
*******************************************************************************/
NFCSTATUS EXTNS_CheckMfcResponse(uint8_t** sTransceiveData,
uint32_t* sTransceiveDataLen) {
NFCSTATUS status = NFCSTATUS_SUCCESS;
if (*sTransceiveDataLen == 3) {
if ((*sTransceiveData)[0] == 0x10 && (*sTransceiveData)[1] != 0x0A) {
LOG(ERROR) << StringPrintf("Mifare Error in payload response");
*sTransceiveDataLen = 0x1;
*sTransceiveData += 1;
return NFCSTATUS_FAILED;
}
}
if ((*sTransceiveData)[0] == 0x40) {
*sTransceiveData += 1;
*sTransceiveDataLen = 0x01;
if ((*sTransceiveData)[0] == 0x03) {
*sTransceiveDataLen = 0x00;
status = NFCSTATUS_FAILED;
}
} else if ((*sTransceiveData)[0] == 0x10) {
*sTransceiveData += 1;
*sTransceiveDataLen = 0x10;
}
return status;
}