/* * 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; }