/* * Copyright (C) 2010 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. */ #include #include #include #include #include #include #include #include "com_android_nfc.h" #define ERROR_BUFFER_TOO_SMALL -12 #define ERROR_INSUFFICIENT_RESOURCES -9 #define EEDATA_SETTINGS_NUMBER 28 static phLibNfc_sConfig_t gDrvCfg; void *gHWRef; static phNfc_sData_t gInputParam; static phNfc_sData_t gOutputParam; static phLibNfc_Handle hLlcpHandle; static NFCSTATUS lastErrorStatus = NFCSTATUS_FAILED; static phLibNfc_Llcp_eLinkStatus_t g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault; static jmethodID cached_NfcManager_notifyNdefMessageListeners; static jmethodID cached_NfcManager_notifyTransactionListeners; static jmethodID cached_NfcManager_notifyLlcpLinkActivation; static jmethodID cached_NfcManager_notifyLlcpLinkDeactivated; static jmethodID cached_NfcManager_notifyTargetDeselected; static jmethodID cached_NfcManager_notifySeFieldActivated; static jmethodID cached_NfcManager_notifySeFieldDeactivated; static jmethodID cached_NfcManager_notifySeApduReceived; static jmethodID cached_NfcManager_notifySeMifareAccess; static jmethodID cached_NfcManager_notifySeEmvCardRemoval; namespace android { phLibNfc_Handle storedHandle = 0; struct nfc_jni_native_data *exported_nat = NULL; /* TODO: move product specific configuration such as this * antenna tuning into product specific configuration */ uint8_t EEDATA_Settings[EEDATA_SETTINGS_NUMBER][4] = { // DIFFERENTIAL_ANTENNA // RF Settings {0x00,0x9B,0xD1,0x0D} // Tx consumption higher than 0x0D (average 50mA) ,{0x00,0x9B,0xD2,0x24} // GSP setting for this threshold ,{0x00,0x9B,0xD3,0x0A} // Tx consumption higher than 0x0A (average 40mA) ,{0x00,0x9B,0xD4,0x22} // GSP setting for this threshold ,{0x00,0x9B,0xD5,0x08} // Tx consumption higher than 0x08 (average 30mA) ,{0x00,0x9B,0xD6,0x1E} // GSP setting for this threshold ,{0x00,0x9B,0xDD,0x1C} // GSP setting for this threshold ,{0x00,0x9B,0x84,0x13} // ANACM2 setting ,{0x00,0x99,0x81,0x7F} // ANAVMID setting PCD ,{0x00,0x99,0x31,0x70} // ANAVMID setting PICC // Enable PBTF ,{0x00,0x98,0x00,0x3F} // SECURE_ELEMENT_CONFIGURATION - No Secure Element ,{0x00,0x9F,0x09,0x00} // SWP_PBTF_RFU ,{0x00,0x9F,0x0A,0x05} // SWP_PBTF_RFLD --> RFLEVEL Detector for PBTF ,{0x00,0x9E,0xD1,0xA1} // // Change RF Level Detector ANARFLDWU ,{0x00,0x99,0x23,0x00} // Default Value is 0x01 // Polling Loop Optimisation Detection - 0x86 to enable - 0x00 to disable ,{0x00,0x9E,0x74,0x00} // Default Value is 0x00, bits 0->2: sensitivity (0==maximal, 6==minimal), bits 3->6: RFU, bit 7: (0 -> disabled, 1 -> enabled) // Polling Loop - Card Emulation Timeout ,{0x00,0x9F,0x35,0x14} // Time for which PN544 stays in Card Emulation mode after leaving RF field ,{0x00,0x9F,0x36,0x60} // Default value 0x0411 = 50 ms ---> New Value : 0x1460 = 250 ms //LLC Timer ,{0x00,0x9C,0x31,0x00} // ,{0x00,0x9C,0x32,0x00} // ,{0x00,0x9C,0x0C,0x00} // ,{0x00,0x9C,0x0D,0x00} // ,{0x00,0x9C,0x12,0x00} // ,{0x00,0x9C,0x13,0x00} // //WTX for LLCP communication ,{0x00,0x98,0xA2,0x0E} // Max value: 14 (default value: 09) //SE GPIO ,{0x00, 0x98, 0x93, 0x40} // Set NFCT ATQA ,{0x00, 0x98, 0x7D, 0x02} ,{0x00, 0x98, 0x7E, 0x00} }; /* Internal functions declaration */ static void *nfc_jni_client_thread(void *arg); static void nfc_jni_init_callback(void *pContext, NFCSTATUS status); static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status); static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status); static void nfc_jni_se_set_mode_callback(void *context, phLibNfc_Handle handle, NFCSTATUS status); static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status); static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat); static phLibNfc_eConfigLinkType parseLinkType(const char* link_name) { struct link_name_entry { phLibNfc_eConfigLinkType value; const char * name; }; const struct link_name_entry sLinkNameTable[] = { {ENUM_LINK_TYPE_COM1, "COM1"}, {ENUM_LINK_TYPE_COM2, "COM2"}, {ENUM_LINK_TYPE_COM3, "COM3"}, {ENUM_LINK_TYPE_COM4, "COM4"}, {ENUM_LINK_TYPE_COM5, "COM5"}, {ENUM_LINK_TYPE_COM6, "COM6"}, {ENUM_LINK_TYPE_COM7, "COM7"}, {ENUM_LINK_TYPE_COM8, "COM8"}, {ENUM_LINK_TYPE_I2C, "I2C"}, {ENUM_LINK_TYPE_USB, "USB"}, }; phLibNfc_eConfigLinkType ret; unsigned int i; /* NOTE: ENUM_LINK_TYPE_NB corresponds to undefined link name */ if (link_name == NULL) { return ENUM_LINK_TYPE_NB; } ret = ENUM_LINK_TYPE_NB; for (i=0 ; irunning = FALSE; } static void kill_client(nfc_jni_native_data *nat) { phDal4Nfc_Message_Wrapper_t wrapper; phLibNfc_DeferredCall_t *pMsg; usleep(50000); LOGD("Terminating client thread..."); pMsg = (phLibNfc_DeferredCall_t*)malloc(sizeof(phLibNfc_DeferredCall_t)); pMsg->pCallback = client_kill_deferred_call; pMsg->pParameter = (void*)nat; wrapper.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; wrapper.msg.pMsgData = pMsg; wrapper.msg.Size = sizeof(phLibNfc_DeferredCall_t); phDal4Nfc_msgsnd(gDrvCfg.nClientId, (struct msgbuf *)&wrapper, sizeof(phLibNfc_Message_t), 0); } static void nfc_jni_ioctl_callback(void *pContext, phNfc_sData_t *pOutput, NFCSTATUS status) { struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; LOG_CALLBACK("nfc_jni_ioctl_callback", status); /* Report the callback status and wake up the caller */ pCallbackData->status = status; sem_post(&pCallbackData->sem); } static void nfc_jni_deinit_download_callback(void *pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; LOG_CALLBACK("nfc_jni_deinit_download_callback", status); /* Report the callback status and wake up the caller */ pCallbackData->status = status; sem_post(&pCallbackData->sem); } static int nfc_jni_download(struct nfc_jni_native_data *nat, uint8_t update) { uint8_t OutputBuffer[1]; uint8_t InputBuffer[1]; struct timespec ts; NFCSTATUS status = NFCSTATUS_FAILED; phLibNfc_StackCapabilities_t caps; struct nfc_jni_callback_data cb_data; /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } if(update) { //deinit TRACE("phLibNfc_Mgt_DeInitialize() (download)"); REENTRANCE_LOCK(); status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_download_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if (status != NFCSTATUS_PENDING) { LOGE("phLibNfc_Mgt_DeInitialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); } clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 5; /* Wait for callback response */ if(sem_timedwait(&cb_data.sem, &ts)) { LOGW("Deinitialization timed out (download)"); } if(cb_data.status != NFCSTATUS_SUCCESS) { LOGW("Deinitialization FAILED (download)"); } TRACE("Deinitialization SUCCESS (download)"); } TRACE("Go in Download Mode"); phLibNfc_Download_Mode(); // Download gInputParam.buffer = InputBuffer; gInputParam.length = 0x01; gOutputParam.buffer = OutputBuffer; gOutputParam.length = 0x01; LOGD("Download new Firmware"); REENTRANCE_LOCK(); status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if(status != NFCSTATUS_PENDING) { LOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); status = NFCSTATUS_FAILED; goto clean_and_return; } TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); status = NFCSTATUS_FAILED; goto clean_and_return; } /* Download Status */ if(cb_data.status != NFCSTATUS_SUCCESS) { status = cb_data.status; goto clean_and_return; } reinit: TRACE("phLibNfc_HW_Reset()"); phLibNfc_HW_Reset(); TRACE("phLibNfc_Mgt_Initialize()"); REENTRANCE_LOCK(); status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if(status != NFCSTATUS_PENDING) { LOGE("phLibNfc_Mgt_Initialize() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); goto clean_and_return; } TRACE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); status = NFCSTATUS_FAILED; goto clean_and_return; } /* Initialization Status */ if(cb_data.status != NFCSTATUS_SUCCESS) { status = cb_data.status; goto clean_and_return; } /* ====== CAPABILITIES ======= */ REENTRANCE_LOCK(); status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); REENTRANCE_UNLOCK(); if (status != NFCSTATUS_SUCCESS) { LOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); } else { LOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, FW Update Info = %d", caps.psDevCapabilities.hal_version, caps.psDevCapabilities.fw_version, caps.psDevCapabilities.hw_version, caps.psDevCapabilities.model_id, caps.psDevCapabilities.hci_version, caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], caps.psDevCapabilities.firmware_update_info); } /*Download is successful*/ status = NFCSTATUS_SUCCESS; clean_and_return: nfc_cb_data_deinit(&cb_data); return status; } /* Initialization function */ static int nfc_jni_initialize(struct nfc_jni_native_data *nat) { struct timespec ts; uint8_t resp[16]; NFCSTATUS status; phLibNfc_StackCapabilities_t caps; char value[PROPERTY_VALUE_MAX]; int result = FALSE; phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE]; uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0; phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo; struct nfc_jni_callback_data cb_data; uint8_t firmware_status; uint8_t update = TRUE; LOGD("Start Initialization\n"); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } /* Reset stored handle */ storedHandle = 0; /* Configure hardware link */ gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600); property_get("ro.nfc.port", value, "unknown"); gDrvCfg.nLinkType = parseLinkType(value); /* ====== CONFIGURE DRIVER ======= */ TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x, 0x%08x)", gDrvCfg.nClientId, gDrvCfg.nLinkType); REENTRANCE_LOCK(); status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef); REENTRANCE_UNLOCK(); if(status == NFCSTATUS_ALREADY_INITIALISED) { LOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); } else if(status != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); goto clean_and_return; } TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0) { LOGE("pthread_create failed"); goto clean_and_return; } /* ====== INITIALIZE ======= */ TRACE("phLibNfc_Mgt_Initialize()"); REENTRANCE_LOCK(); status = phLibNfc_Mgt_Initialize(gHWRef, nfc_jni_init_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if(status != NFCSTATUS_PENDING) { LOGE("phLibNfc_Mgt_Initialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); update = FALSE; goto force_download; } TRACE("phLibNfc_Mgt_Initialize returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } /* Initialization Status */ if(cb_data.status != NFCSTATUS_SUCCESS) { update = FALSE; goto force_download; } /* ====== CAPABILITIES ======= */ REENTRANCE_LOCK(); status = phLibNfc_Mgt_GetstackCapabilities(&caps, (void*)nat); REENTRANCE_UNLOCK(); if (status != NFCSTATUS_SUCCESS) { LOGW("phLibNfc_Mgt_GetstackCapabilities returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); } else { LOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d", caps.psDevCapabilities.hal_version, caps.psDevCapabilities.fw_version, caps.psDevCapabilities.hw_version, caps.psDevCapabilities.model_id, caps.psDevCapabilities.hci_version, caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], caps.psDevCapabilities.firmware_update_info); } /* ====== FIRMWARE VERSION ======= */ if(caps.psDevCapabilities.firmware_update_info) { force_download: for (i=0; i<3; i++) { TRACE("Firmware version not UpToDate"); status = nfc_jni_download(nat, update); if(status == NFCSTATUS_SUCCESS) { LOGI("Firmware update SUCCESS"); break; } LOGW("Firmware update FAILED"); } if(i>=3) { LOGE("Unable to update firmware, giving up"); goto clean_and_return; } } else { TRACE("Firmware version UpToDate"); } /* ====== EEPROM SETTINGS ======= */ // Update EEPROM settings TRACE("****** START EEPROM SETTINGS UPDATE ******"); for (i = 0; i < EEDATA_SETTINGS_NUMBER; i++) { gInputParam.buffer = EEDATA_Settings[i]; gInputParam.length = 0x04; gOutputParam.buffer = resp; TRACE("> EEPROM SETTING: %d", i); REENTRANCE_LOCK(); status = phLibNfc_Mgt_IoCtl(gHWRef, NFC_MEM_WRITE, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if (status != NFCSTATUS_PENDING) { LOGE("phLibNfc_Mgt_IoCtl() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); goto clean_and_return; } /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } /* Initialization Status */ if (cb_data.status != NFCSTATUS_SUCCESS) { goto clean_and_return; } } TRACE("****** ALL EEPROM SETTINGS UPDATED ******"); /* ====== SECURE ELEMENTS ======= */ REENTRANCE_LOCK(); LOGD("phLibNfc_SE_GetSecureElementList()"); status = phLibNfc_SE_GetSecureElementList(SE_List, &No_SE); REENTRANCE_UNLOCK(); if (status != NFCSTATUS_SUCCESS) { LOGD("phLibNfc_SE_GetSecureElementList(): Error"); goto clean_and_return; } LOGD("\n> Number of Secure Element(s) : %d\n", No_SE); /* Display Secure Element information */ for (i = 0; i < No_SE; i++) { if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { LOGD("phLibNfc_SE_GetSecureElementList(): SMX detected, handle=%p", (void*)SE_List[i].hSecureElement); } else if (SE_List[i].eSE_Type == phLibNfc_SE_Type_UICC) { LOGD("phLibNfc_SE_GetSecureElementList(): UICC detected, handle=%p", (void*)SE_List[i].hSecureElement); } /* Set SE mode - Off */ REENTRANCE_LOCK(); status = phLibNfc_SE_SetMode(SE_List[i].hSecureElement, phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if (status != NFCSTATUS_PENDING) { LOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); goto clean_and_return; } LOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } } /* ====== LLCP ======= */ /* LLCP Params */ TRACE("****** NFC Config Mode NFCIP1 - LLCP ******"); LlcpConfigInfo.miu = nat->miu; LlcpConfigInfo.lto = nat->lto; LlcpConfigInfo.wks = nat->wks; LlcpConfigInfo.option = nat->opt; REENTRANCE_LOCK(); status = phLibNfc_Mgt_SetLlcp_ConfigParams(&LlcpConfigInfo, nfc_jni_llcpcfg_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if(status != NFCSTATUS_PENDING) { LOGE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); goto clean_and_return; } TRACE("phLibNfc_Mgt_SetLlcp_ConfigParams returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } /* ====== END ======= */ LOGI("NFC Initialized"); result = TRUE; clean_and_return: if (result != TRUE) { if(nat) { kill_client(nat); } } nfc_cb_data_deinit(&cb_data); return result; } static int is_user_build() { char value[PROPERTY_VALUE_MAX]; property_get("ro.build.type", value, ""); return !strncmp("user", value, PROPERTY_VALUE_MAX); } /* * Last-chance fallback when there is no clean way to recover * Performs a software reset */ void emergency_recovery(struct nfc_jni_native_data *nat) { if (!is_user_build()) { LOGE("emergency_recovery: force restart of NFC service"); } else { // dont recover immediately, so we can debug unsigned int t; for (t=1; t < 1000000; t <<= 1) { LOGE("emergency_recovery: NFC stack dead-locked, please show to npelly"); sleep(t); } } abort(); // force a noisy crash } void nfc_jni_reset_timeout_values() { REENTRANCE_LOCK(); phLibNfc_SetIsoXchgTimeout(NXP_ISO_XCHG_TIMEOUT); phLibNfc_SetHciTimeout(NXP_NFC_HCI_TIMEOUT); phLibNfc_SetFelicaTimeout(NXP_FELICA_XCHG_TIMEOUT); phLibNfc_SetMifareRawTimeout(NXP_MIFARE_XCHG_TIMEOUT); REENTRANCE_UNLOCK(); } /* * Restart the polling loop when unable to perform disconnect */ void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat) { int ret; struct nfc_jni_callback_data cb_data; TRACE("Restarting polling loop"); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ nfc_jni_reset_timeout_values(); /* Restart Polling loop */ TRACE("****** Start NFC Discovery ******"); REENTRANCE_LOCK(); ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_RESUME,nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); if (ret != NFCSTATUS_PENDING) { emergency_recovery(nat); goto clean_and_return; } /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } clean_and_return: nfc_cb_data_deinit(&cb_data); } /* * Utility to recover UID from target infos */ static phNfc_sData_t get_target_uid(phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo) { phNfc_sData_t uid; switch(psRemoteDevInfo->RemDevType) { case phNfc_eISO14443_A_PICC: case phNfc_eISO14443_4A_PICC: case phNfc_eISO14443_3A_PICC: case phNfc_eMifare_PICC: uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Uid; uid.length = psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.UidLength; break; case phNfc_eISO14443_B_PICC: case phNfc_eISO14443_4B_PICC: uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi; uid.length = sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.Pupi); break; case phNfc_eFelica_PICC: uid.buffer = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm; uid.length = psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDmLength; break; case phNfc_eJewel_PICC: uid.buffer = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.Uid; uid.length = psRemoteDevInfo->RemoteDevInfo.Jewel_Info.UidLength; break; case phNfc_eISO15693_PICC: uid.buffer = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Uid; uid.length = psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.UidLength; break; case phNfc_eNfcIP1_Target: case phNfc_eNfcIP1_Initiator: uid.buffer = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID; uid.length = psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.NFCID_Length; break; default: uid.buffer = NULL; uid.length = 0; break; } return uid; } /* * NFC stack message processing */ static void *nfc_jni_client_thread(void *arg) { struct nfc_jni_native_data *nat; JNIEnv *e; JavaVMAttachArgs thread_args; phDal4Nfc_Message_Wrapper_t wrapper; nat = (struct nfc_jni_native_data *)arg; thread_args.name = "NFC Message Loop"; thread_args.version = nat->env_version; thread_args.group = NULL; nat->vm->AttachCurrentThread(&e, &thread_args); pthread_setname_np(pthread_self(), "message"); TRACE("NFC client started"); nat->running = TRUE; while(nat->running == TRUE) { /* Fetch next message from the NFC stack message queue */ if(phDal4Nfc_msgrcv(gDrvCfg.nClientId, (void *)&wrapper, sizeof(phLibNfc_Message_t), 0, 0) == -1) { LOGE("NFC client received bad message"); continue; } switch(wrapper.msg.eMsgType) { case PH_LIBNFC_DEFERREDCALL_MSG: { phLibNfc_DeferredCall_t *msg = (phLibNfc_DeferredCall_t *)(wrapper.msg.pMsgData); REENTRANCE_LOCK(); msg->pCallback(msg->pParameter); REENTRANCE_UNLOCK(); break; } } } TRACE("NFC client stopped"); nat->vm->DetachCurrentThread(); return NULL; } extern uint8_t nfc_jni_is_ndef; extern uint8_t *nfc_jni_ndef_buf; extern uint32_t nfc_jni_ndef_buf_len; static phLibNfc_sNfcIPCfg_t nfc_jni_nfcip1_cfg = { 3, { 0x46, 0x66, 0x6D } }; /* * Callbacks */ /* P2P - LLCP callbacks */ static void nfc_jni_llcp_linkStatus_callback(void *pContext, phFriNfc_LlcpMac_eLinkStatus_t eLinkStatus) { phFriNfc_Llcp_sLinkParameters_t sLinkParams; JNIEnv *e; NFCSTATUS status; struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; struct nfc_jni_native_data *nat = (nfc_jni_native_data *)pContextData->pContext; nfc_jni_listen_data_t * pListenData = NULL; nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); TRACE("Callback: nfc_jni_llcp_linkStatus_callback()"); nat->vm->GetEnv( (void **)&e, nat->env_version); /* Update link status */ g_eLinkStatus = eLinkStatus; if(eLinkStatus == phFriNfc_LlcpMac_eLinkActivated) { REENTRANCE_LOCK(); status = phLibNfc_Llcp_GetRemoteInfo(hLlcpHandle, &sLinkParams); REENTRANCE_UNLOCK(); if(status != NFCSTATUS_SUCCESS) { LOGW("GetRemote Info failded - Status = %02x",status); } else { LOGI("LLCP Link activated (LTO=%d, MIU=%d, OPTION=0x%02x, WKS=0x%02x)",sLinkParams.lto, sLinkParams.miu, sLinkParams.option, sLinkParams.wks); } } else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated) { LOGI("LLCP Link deactivated"); free(pContextData); /* Reset incoming socket list */ while (!LIST_EMPTY(&pMonitor->incoming_socket_head)) { pListenData = LIST_FIRST(&pMonitor->incoming_socket_head); LIST_REMOVE(pListenData, entries); free(pListenData); } /* Notify manager that the LLCP is lost or deactivated */ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkDeactivated, nat->tag); if(e->ExceptionCheck()) { LOGE("Exception occured"); kill_client(nat); } } } static void nfc_jni_checkLlcp_callback(void *context, NFCSTATUS status) { struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)context; LOG_CALLBACK("nfc_jni_checkLlcp_callback", status); pContextData->status = status; sem_post(&pContextData->sem); } static void nfc_jni_llcpcfg_callback(void *pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext; LOG_CALLBACK("nfc_jni_llcpcfg_callback", status); /* Report the callback status and wake up the caller */ pCallbackData->status = status; sem_post(&pCallbackData->sem); } static void nfc_jni_llcp_transport_listen_socket_callback(void *pContext, phLibNfc_Handle hIncomingSocket) { phLibNfc_Handle hServiceSocket = (phLibNfc_Handle)pContext; nfc_jni_listen_data_t * pListenData = NULL; nfc_jni_native_monitor * pMonitor = nfc_jni_get_monitor(); TRACE("nfc_jni_llcp_transport_listen_socket_callback socket handle = %p", (void*)hIncomingSocket); pthread_mutex_lock(&pMonitor->incoming_socket_mutex); /* Store the connection request */ pListenData = (nfc_jni_listen_data_t*)malloc(sizeof(nfc_jni_listen_data_t)); if (pListenData == NULL) { LOGE("Failed to create structure to handle incoming LLCP connection request"); goto clean_and_return; } pListenData->pServerSocket = hServiceSocket; pListenData->pIncomingSocket = hIncomingSocket; LIST_INSERT_HEAD(&pMonitor->incoming_socket_head, pListenData, entries); /* Signal pending accept operations that the list is updated */ pthread_cond_broadcast(&pMonitor->incoming_socket_cond); clean_and_return: pthread_mutex_unlock(&pMonitor->incoming_socket_mutex); } void nfc_jni_llcp_transport_socket_err_callback(void* pContext, uint8_t nErrCode) { PHNFC_UNUSED_VARIABLE(pContext); TRACE("Callback: nfc_jni_llcp_transport_socket_err_callback()"); if(nErrCode == PHFRINFC_LLCP_ERR_FRAME_REJECTED) { LOGW("Frame Rejected - Disconnected"); } else if(nErrCode == PHFRINFC_LLCP_ERR_DISCONNECTED) { LOGD("Socket Disconnected"); } } static void nfc_jni_discover_callback(void *pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; LOG_CALLBACK("nfc_jni_discover_callback", status); pContextData->status = status; sem_post(&pContextData->sem); } static void nfc_jni_Discovery_notification_callback(void *pContext, phLibNfc_RemoteDevList_t *psRemoteDevList, uint8_t uNofRemoteDev, NFCSTATUS status) { JNIEnv *e; NFCSTATUS ret; jclass tag_cls = NULL; jobject target_array; jobject tag; jmethodID ctor; jfieldID f; const char * typeName; jbyteArray tagUid; jbyteArray generalBytes = NULL; struct nfc_jni_native_data *nat; struct timespec ts; phNfc_sData_t data; int i; int target_index = 0; // Target that will be reported (if multiple can be >0) nat = (struct nfc_jni_native_data *)pContext; nat->vm->GetEnv( (void **)&e, nat->env_version); if(status == NFCSTATUS_DESELECTED) { LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status); /* Notify manager that a target was deselected */ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected); if(e->ExceptionCheck()) { LOGE("Exception occured"); kill_client(nat); } } else { LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status); TRACE("Discovered %d tags", uNofRemoteDev); if((psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) || (psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { tag_cls = e->GetObjectClass(nat->cached_P2pDevice); if(e->ExceptionCheck()) { LOGE("Get Object Class Error"); kill_client(nat); return; } /* New target instance */ ctor = e->GetMethodID(tag_cls, "", "()V"); tag = e->NewObject(tag_cls, ctor); /* Set P2P Target mode */ f = e->GetFieldID(tag_cls, "mMode", "I"); if(psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) { LOGD("Discovered P2P Initiator"); e->SetIntField(tag, f, (jint)MODE_P2P_INITIATOR); } else { LOGD("Discovered P2P Target"); e->SetIntField(tag, f, (jint)MODE_P2P_TARGET); } if(psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) { /* Set General Bytes */ f = e->GetFieldID(tag_cls, "mGeneralBytes", "[B"); TRACE("General Bytes length ="); for(i=0;ipsRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length;i++) { LOGD("%02x ", psRemoteDevList->psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo[i]); } generalBytes = e->NewByteArray(psRemoteDevList->psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length); e->SetByteArrayRegion(generalBytes, 0, psRemoteDevList->psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo_Length, (jbyte *)psRemoteDevList->psRemoteDevInfo->RemoteDevInfo.NfcIP_Info.ATRInfo); e->SetObjectField(tag, f, generalBytes); } /* Set tag handle */ f = e->GetFieldID(tag_cls, "mHandle", "I"); e->SetIntField(tag, f,(jint)psRemoteDevList[target_index].hTargetDev); TRACE("Target handle = 0x%08x",psRemoteDevList[target_index].hTargetDev); } else { tag_cls = e->GetObjectClass(nat->cached_NfcTag); if(e->ExceptionCheck()) { kill_client(nat); return; } /* New tag instance */ ctor = e->GetMethodID(tag_cls, "", "()V"); tag = e->NewObject(tag_cls, ctor); bool multi_protocol = false; if(status == NFCSTATUS_MULTIPLE_PROTOCOLS) { TRACE("Multiple Protocol TAG detected\n"); multi_protocol = true; } else if (status == NFCSTATUS_MULTIPLE_TAGS) { // Only one tag will be used // TODO: suppose there's both a multi-proto and another // single-proto tag in the field: in that case, we'd want to make sure we // return a "complete" tag, and not just one "target", which // is then either half of the multi-proto tag or the complete // single-proto. target_index = 0; } else { target_index = 0; } /* Set tag UID */ f = e->GetFieldID(tag_cls, "mUid", "[B"); data = get_target_uid(psRemoteDevList[target_index].psRemoteDevInfo); tagUid = e->NewByteArray(data.length); if(data.length > 0) { e->SetByteArrayRegion(tagUid, 0, data.length, (jbyte *)data.buffer); } e->SetObjectField(tag, f, tagUid); /* Generate technology list */ jintArray techList; jintArray handleList; jintArray typeList; nfc_jni_get_technology_tree(e, psRemoteDevList, multi_protocol ? uNofRemoteDev : 1, &techList, &handleList, &typeList); /* Push the technology list into the java object */ f = e->GetFieldID(tag_cls, "mTechList", "[I"); e->SetObjectField(tag, f, techList); f = e->GetFieldID(tag_cls, "mTechHandles", "[I"); e->SetObjectField(tag, f, handleList); f = e->GetFieldID(tag_cls, "mTechLibNfcTypes", "[I"); e->SetObjectField(tag, f, typeList); f = e->GetFieldID(tag_cls, "mConnectedTechIndex", "I"); e->SetIntField(tag, f,(jint)-1); f = e->GetFieldID(tag_cls, "mConnectedHandle", "I"); e->SetIntField(tag, f,(jint)-1); } storedHandle = psRemoteDevList[target_index].hTargetDev; if (nat->tag != NULL) { e->DeleteGlobalRef(nat->tag); } nat->tag = e->NewGlobalRef(tag); /* Notify the service */ TRACE("Notify Nfc Service"); if((psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator) || (psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target)) { /* Store the hanlde of the P2P device */ hLlcpHandle = psRemoteDevList->hTargetDev; /* Notify manager that new a P2P device was found */ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag); if(e->ExceptionCheck()) { LOGE("Exception occured"); kill_client(nat); } } else { /* Notify manager that new a tag was found */ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag); if(e->ExceptionCheck()) { LOGE("Exception occured"); kill_client(nat); } } e->DeleteLocalRef(tag); } } static void nfc_jni_init_callback(void *pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; LOG_CALLBACK("nfc_jni_init_callback", status); pContextData->status = status; sem_post(&pContextData->sem); } static void nfc_jni_deinit_callback(void *pContext, NFCSTATUS status) { struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; LOG_CALLBACK("nfc_jni_deinit_callback", status); pContextData->status = status; sem_post(&pContextData->sem); } /* Set Secure Element mode callback*/ static void nfc_jni_smartMX_setModeCb (void* pContext, phLibNfc_Handle hSecureElement, NFCSTATUS status) { struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; LOG_CALLBACK("nfc_jni_smartMX_setModeCb", status); pContextData->status = status; sem_post(&pContextData->sem); } /* Card Emulation callback */ static void nfc_jni_transaction_callback(void *context, phLibNfc_eSE_EvtType_t evt_type, phLibNfc_Handle handle, phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status) { JNIEnv *e; jobject tmp_array = NULL; jobject mifare_block = NULL; struct nfc_jni_native_data *nat; phNfc_sData_t *aid; phNfc_sData_t *mifare_command; struct nfc_jni_callback_data *pCallbackData; int i=0; LOG_CALLBACK("nfc_jni_transaction_callback", status); nat = (struct nfc_jni_native_data *)context; nat->vm->GetEnv( (void **)&e, nat->env_version); if(status == NFCSTATUS_SUCCESS) { switch(evt_type) { case phLibNfc_eSE_EvtStartTransaction: { TRACE("> SE EVT_START_TRANSACTION"); if(evt_info->UiccEvtInfo.aid.length <= AID_MAXLEN) { aid = &(evt_info->UiccEvtInfo.aid); LOGD("> AID DETECTED"); if(aid != NULL) { char aid_str[AID_MAXLEN * 2 + 1]; aid_str[0] = '\0'; for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) { snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]); } LOGD("> AID: %s", aid_str); tmp_array = e->NewByteArray(aid->length); if (tmp_array == NULL) { goto error; } e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer); if(e->ExceptionCheck()) { goto error; } } else { goto error; } TRACE("Notify Nfc Service"); /* Notify manager that a new event occurred on a SE */ e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array); if(e->ExceptionCheck()) { goto error; } } else { LOGD("> NO AID DETECTED"); } }break; case phLibNfc_eSE_EvtApduReceived: { phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid); TRACE("> SE EVT_APDU_RECEIVED"); if (apdu != NULL) { TRACE(" APDU length=%d", apdu->length); tmp_array = e->NewByteArray(apdu->length); if (tmp_array == NULL) { goto error; } e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer); if (e->ExceptionCheck()) { goto error; } } else { TRACE(" APDU EMPTY"); } TRACE("Notify Nfc Service"); e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array); }break; case phLibNfc_eSE_EvtCardRemoval: { TRACE("> SE EVT_EMV_CARD_REMOVAL"); TRACE("Notify Nfc Service"); e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval); }break; case phLibNfc_eSE_EvtMifareAccess: { TRACE("> SE EVT_MIFARE_ACCESS"); mifare_command = &(evt_info->UiccEvtInfo.aid); TRACE("> MIFARE Block: %d",mifare_command->buffer[1]); tmp_array = e->NewByteArray(2); if (tmp_array == NULL) { goto error; } e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer); if(e->ExceptionCheck()) { goto error; } TRACE("Notify Nfc Service"); e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block); }break; case phLibNfc_eSE_EvtFieldOn: { TRACE("> SE EVT_FIELD_ON"); TRACE("Notify Nfc Service"); e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldActivated); }break; case phLibNfc_eSE_EvtFieldOff: { TRACE("> SE EVT_FIELD_OFF"); TRACE("Notify Nfc Service"); e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeFieldDeactivated); }break; default: { TRACE("Unknown SE event"); }break; } } else { LOGE("SE transaction notification error"); goto error; } /* Function finished, now clean and return */ goto clean_and_return; error: /* In case of error, just discard the notification */ LOGE("Failed to send SE transaction notification"); e->ExceptionClear(); clean_and_return: if(tmp_array != NULL) { e->DeleteLocalRef(tmp_array); } } static void nfc_jni_se_set_mode_callback(void *pContext, phLibNfc_Handle handle, NFCSTATUS status) { struct nfc_jni_callback_data * pContextData = (struct nfc_jni_callback_data*)pContext; LOG_CALLBACK("nfc_jni_se_set_mode_callback", status); pContextData->status = status; sem_post(&pContextData->sem); } /* * NFCManager methods */ static short get_p2p_mode() { char value[PROPERTY_VALUE_MAX]; property_get("debug.nfc.NXP_NFCI_MODE", value, ""); if (value[0]) { short mode; mode = atoi(value); LOGD("debug.nfc.NXP_NFCI_MODE = %X", mode); return mode; } return phNfc_eP2P_ALL; // default } static bool get_p2p_target_disable() { char value[PROPERTY_VALUE_MAX]; property_get("debug.nfc.TARGET_DISABLE", value, ""); if (value[0]) { int mode; mode = atoi(value); LOGD("debug.nfc.TARGET_DISABLE = %d", mode); return mode; } return FALSE; // default } static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat) { NFCSTATUS ret; struct nfc_jni_callback_data cb_data; /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } /* Reset the PN544 ISO XCHG / sw watchdog timeouts */ nfc_jni_reset_timeout_values(); nat->discovery_cfg.NfcIP_Mode = get_p2p_mode(); //initiator nat->discovery_cfg.Duration = 300000; /* in ms */ nat->discovery_cfg.NfcIP_Tgt_Disable = get_p2p_target_disable(); TRACE("****** NFC Config Mode Reader ******"); /* Register for the reader mode */ REENTRANCE_LOCK(); ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { LOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); goto clean_and_return; } TRACE("phLibNfc_RemoteDev_NtfRegister(%s-%s-%s-%s-%s-%s-%s-%s) returned 0x%x\n", nat->registry_info.Jewel==TRUE?"J":"", nat->registry_info.MifareUL==TRUE?"UL":"", nat->registry_info.MifareStd==TRUE?"Mi":"", nat->registry_info.Felica==TRUE?"F":"", nat->registry_info.ISO14443_4A==TRUE?"4A":"", nat->registry_info.ISO14443_4B==TRUE?"4B":"", nat->registry_info.NFC==TRUE?"P2P":"", nat->registry_info.ISO15693==TRUE?"R":"", ret); /* Register for the card emulation mode */ REENTRANCE_LOCK(); ret = phLibNfc_SE_NtfRegister(nfc_jni_transaction_callback,(void *)nat); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { LOGD("pphLibNfc_RemoteDev_NtfRegister returned 0x%02x",ret); goto clean_and_return; } TRACE("phLibNfc_SE_NtfRegister returned 0x%x\n", ret); /* Start Polling loop */ TRACE("****** Start NFC Discovery ******"); REENTRANCE_LOCK(); ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", nat->discovery_cfg.NfcIP_Mode, nat->discovery_cfg.Duration, ret); if(ret != NFCSTATUS_PENDING) { emergency_recovery(nat); } /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } clean_and_return: nfc_cb_data_deinit(&cb_data); } static void nfc_jni_stop_discovery_locked(struct nfc_jni_native_data *nat) { phLibNfc_sADD_Cfg_t discovery_cfg; NFCSTATUS ret; struct nfc_jni_callback_data cb_data; /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } discovery_cfg.PollDevInfo.PollEnabled = 0; discovery_cfg.Duration = 300000; /* in ms */ discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode; discovery_cfg.NfcIP_Tgt_Disable = TRUE; /* Start Polling loop */ TRACE("****** Stop NFC Discovery ******"); REENTRANCE_LOCK(); ret = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG,discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); TRACE("phLibNfc_Mgt_ConfigureDiscovery(%s-%s-%s-%s-%s-%s, %s-%x-%x) returned 0x%08x\n", discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A==TRUE?"3A":"", discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B==TRUE?"3B":"", discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212==TRUE?"F2":"", discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424==TRUE?"F4":"", discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive==TRUE?"NFC":"", discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693==TRUE?"RFID":"", discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation==FALSE?"CE":"", discovery_cfg.NfcIP_Mode, discovery_cfg.Duration, ret); if(ret != NFCSTATUS_PENDING) { emergency_recovery(nat); } /* Wait for callback response */ if(sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } clean_and_return: nfc_cb_data_deinit(&cb_data); } static void com_android_nfc_NfcManager_disableDiscovery(JNIEnv *e, jobject o) { struct nfc_jni_native_data *nat; CONCURRENCY_LOCK(); /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); nfc_jni_stop_discovery_locked(nat); CONCURRENCY_UNLOCK(); } static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o) { NFCSTATUS ret; struct nfc_jni_native_data *nat; CONCURRENCY_LOCK(); nat = nfc_jni_get_nat(e, o); nfc_jni_start_discovery_locked(nat); CONCURRENCY_UNLOCK(); } static void com_android_nfc_NfcManager_doResetTimeouts( JNIEnv *e, jobject o) { CONCURRENCY_LOCK(); nfc_jni_reset_timeout_values(); CONCURRENCY_UNLOCK(); } static void setFelicaTimeout(jint timeout) { // The Felica timeout is configurable in the PN544 upto a maximum of 255 ms. // It can be set to 0 to disable the timeout altogether, in which case we // use the sw watchdog as a fallback. if (timeout <= 255) { phLibNfc_SetFelicaTimeout(timeout); } else { // Disable hw timeout, use sw watchdog for timeout phLibNfc_SetFelicaTimeout(0); phLibNfc_SetHciTimeout(timeout); } } // Calculates ceiling log2 of value static unsigned int log2(int value) { unsigned int ret = 0; bool isPowerOf2 = ((value & (value - 1)) == 0); while ( (value >> ret) > 1 ) ret++; if (!isPowerOf2) ret++; return ret; } static int calcTimeout(int timeout_in_ms) { // The Iso/Mifare Xchg timeout in PN544 is a non-linear function over X // spanning 0 - 4.9s: timeout in seconds = (256 * 16 / 13560000) * 2 ^ X // // We keep the constant part of the formula in a static; note the factor // 1000 off, which is due to the fact that the formula calculates seconds, // but this method gets milliseconds as an argument. static double factor = (256 * 16) / 13560.0; // timeout = (256 * 16 / 13560000) * 2 ^ X // First find the first X for which timeout > requested timeout return (log2(ceil(((double) timeout_in_ms) / factor))); } static void setIsoDepTimeout(jint timeout) { static double factor = (256 * 16) / 13560.0; if (timeout <= 4900) { int value = calcTimeout(timeout); // Then re-compute the actual timeout based on X double actual_timeout = factor * (1 << value); // Set the sw watchdog a bit longer (The PN544 timeout is very accurate, // but it will take some time to get back through the sw layers. // 500 ms should be enough). phLibNfc_SetHciTimeout(ceil(actual_timeout + 500)); value |= 0x10; // bit 4 to enable timeout phLibNfc_SetIsoXchgTimeout(value); } else { // Also note that if we desire a timeout > 4.9s, the Iso Xchg timeout // must be disabled completely, to prevent the PN544 from aborting // the transaction. We reuse the HCI sw watchdog to catch the timeout // in that case. phLibNfc_SetIsoXchgTimeout(0x00); phLibNfc_SetHciTimeout(timeout); } } static void setNfcATimeout(jint timeout) { if (timeout <= 4900) { int value = calcTimeout(timeout); phLibNfc_SetMifareRawTimeout(value); } else { // Disable mifare raw timeout, use HCI sw watchdog instead phLibNfc_SetMifareRawTimeout(0x00); phLibNfc_SetHciTimeout(timeout); } } static bool com_android_nfc_NfcManager_doSetTimeout( JNIEnv *e, jobject o, jint tech, jint timeout) { bool success = false; CONCURRENCY_LOCK(); if (timeout <= 0) { LOGE("Timeout must be positive."); return false; } else { switch (tech) { case TARGET_TYPE_MIFARE_CLASSIC: case TARGET_TYPE_MIFARE_UL: // Intentional fall-through, Mifare UL, Classic // transceive just uses raw 3A frames case TARGET_TYPE_ISO14443_3A: setNfcATimeout(timeout); success = true; break; case TARGET_TYPE_ISO14443_4: setIsoDepTimeout(timeout); success = true; break; case TARGET_TYPE_FELICA: setFelicaTimeout(timeout); success = true; break; default: LOGW("doSetTimeout: Timeout not supported for tech %d", tech); success = false; } } CONCURRENCY_UNLOCK(); return success; } static jboolean com_android_nfc_NfcManager_init_native_struc(JNIEnv *e, jobject o) { NFCSTATUS status; struct nfc_jni_native_data *nat = NULL; jclass cls; jobject obj; jfieldID f; TRACE("****** Init Native Structure ******"); /* Initialize native structure */ nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data)); if(nat == NULL) { LOGD("malloc of nfc_jni_native_data failed"); return FALSE; } memset(nat, 0, sizeof(*nat)); e->GetJavaVM(&(nat->vm)); nat->env_version = e->GetVersion(); nat->manager = e->NewGlobalRef(o); cls = e->GetObjectClass(o); f = e->GetFieldID(cls, "mNative", "I"); e->SetIntField(o, f, (jint)nat); /* Initialize native cached references */ cached_NfcManager_notifyNdefMessageListeners = e->GetMethodID(cls, "notifyNdefMessageListeners","(Lcom/android/nfc/nxp/NativeNfcTag;)V"); cached_NfcManager_notifyTransactionListeners = e->GetMethodID(cls, "notifyTransactionListeners", "([B)V"); cached_NfcManager_notifyLlcpLinkActivation = e->GetMethodID(cls, "notifyLlcpLinkActivation","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); cached_NfcManager_notifyLlcpLinkDeactivated = e->GetMethodID(cls, "notifyLlcpLinkDeactivated","(Lcom/android/nfc/nxp/NativeP2pDevice;)V"); cached_NfcManager_notifyTargetDeselected = e->GetMethodID(cls, "notifyTargetDeselected","()V"); cached_NfcManager_notifySeFieldActivated = e->GetMethodID(cls, "notifySeFieldActivated", "()V"); cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls, "notifySeFieldDeactivated", "()V"); cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls, "notifySeApduReceived", "([B)V"); cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls, "notifySeMifareAccess", "([B)V"); cached_NfcManager_notifySeEmvCardRemoval = e->GetMethodID(cls, "notifySeEmvCardRemoval", "()V"); if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeNfcTag",&(nat->cached_NfcTag)) == -1) { LOGD("Native Structure initialization failed"); return FALSE; } if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeP2pDevice",&(nat->cached_P2pDevice)) == -1) { LOGD("Native Structure initialization failed"); return FALSE; } TRACE("****** Init Native Structure OK ******"); return TRUE; } /* Init/Deinit method */ static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o) { struct nfc_jni_native_data *nat = NULL; int init_result = JNI_FALSE; #ifdef TNFC_EMULATOR_ONLY char value[PROPERTY_VALUE_MAX]; #endif jboolean result; CONCURRENCY_LOCK(); #ifdef TNFC_EMULATOR_ONLY if (!property_get("ro.kernel.qemu", value, 0)) { LOGE("NFC Initialization failed: not running in an emulator\n"); goto clean_and_return; } #endif /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); nat->seId = SMX_SECURE_ELEMENT_ID; nat->lto = 150; // LLCP_LTO nat->miu = 128; // LLCP_MIU nat->wks = 1; // LLCP_WKS nat->opt = 0; // LLCP_OPT nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE; nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE; nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica212 = TRUE; nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableFelica424 = TRUE; nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso15693 = TRUE; nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableNfcActive = TRUE; nat->discovery_cfg.PollDevInfo.PollCfgInfo.DisableCardEmulation = FALSE; nat->registry_info.MifareUL = TRUE; nat->registry_info.MifareStd = TRUE; nat->registry_info.ISO14443_4A = TRUE; nat->registry_info.ISO14443_4B = TRUE; nat->registry_info.Jewel = TRUE; nat->registry_info.Felica = TRUE; nat->registry_info.NFC = TRUE; nat->registry_info.ISO15693 = TRUE; exported_nat = nat; /* Perform the initialization */ init_result = nfc_jni_initialize(nat); clean_and_return: CONCURRENCY_UNLOCK(); /* Convert the result and return */ return (init_result==TRUE)?JNI_TRUE:JNI_FALSE; } static jboolean com_android_nfc_NfcManager_deinitialize(JNIEnv *e, jobject o) { struct timespec ts; NFCSTATUS status; struct nfc_jni_native_data *nat; int bStackReset = FALSE; struct nfc_jni_callback_data cb_data; /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); /* Clear previous configuration */ memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t)); memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t)); /* Create the local semaphore */ if (nfc_cb_data_init(&cb_data, NULL)) { TRACE("phLibNfc_Mgt_DeInitialize()"); REENTRANCE_LOCK(); status = phLibNfc_Mgt_DeInitialize(gHWRef, nfc_jni_deinit_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if (status == NFCSTATUS_PENDING) { TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 5; /* Wait for callback response */ if(sem_timedwait(&cb_data.sem, &ts) == -1) { LOGW("Operation timed out"); bStackReset = TRUE; } if(cb_data.status != NFCSTATUS_SUCCESS) { LOGE("Failed to deinit the stack"); bStackReset = TRUE; } } else { TRACE("phLibNfc_Mgt_DeInitialize() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); bStackReset = TRUE; } nfc_cb_data_deinit(&cb_data); } else { LOGE("Failed to create semaphore (errno=0x%08x)", errno); bStackReset = TRUE; } kill_client(nat); if(bStackReset == TRUE) { /* Complete deinit. failed, try hard restart of NFC */ LOGW("Reseting stack..."); emergency_recovery(nat); } /* Unconfigure driver */ TRACE("phLibNfc_Mgt_UnConfigureDriver()"); REENTRANCE_LOCK(); status = phLibNfc_Mgt_UnConfigureDriver(gHWRef); REENTRANCE_UNLOCK(); if(status != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); } else { LOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status)); } TRACE("NFC Deinitialized"); return TRUE; } /* Secure Element methods */ static jintArray com_android_nfc_NfcManager_doGetSecureElementList(JNIEnv *e, jobject o) { NFCSTATUS ret; jintArray list= NULL; phLibNfc_SE_List_t se_list[PHLIBNFC_MAXNO_OF_SE]; uint8_t i, se_count = PHLIBNFC_MAXNO_OF_SE; TRACE("****** Get Secure Element List ******"); TRACE("phLibNfc_SE_GetSecureElementList()"); REENTRANCE_LOCK(); ret = phLibNfc_SE_GetSecureElementList(se_list, &se_count); REENTRANCE_UNLOCK(); if (ret != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return list; } TRACE("phLibNfc_SE_GetSecureElementList() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); TRACE("Nb SE: %d", se_count); list =e->NewIntArray(se_count); for (i = 0; i < se_count; i++) { if (se_list[i].eSE_Type == phLibNfc_SE_Type_SmartMX) { LOGD("phLibNfc_SE_GetSecureElementList(): SMX detected"); LOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); } else if(se_list[i].eSE_Type == phLibNfc_SE_Type_UICC) { LOGD("phLibNfc_SE_GetSecureElementList(): UICC detected"); LOGD("SE ID #%d: 0x%08x", i, se_list[i].hSecureElement); } e->SetIntArrayRegion(list, i, 1, (jint*)&se_list[i].hSecureElement); } e->DeleteLocalRef(list); return list; } static void com_android_nfc_NfcManager_doSelectSecureElement(JNIEnv *e, jobject o) { NFCSTATUS ret; struct nfc_jni_native_data *nat; struct nfc_jni_callback_data cb_data; CONCURRENCY_LOCK(); /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } TRACE("****** Select Secure Element ******"); TRACE("phLibNfc_SE_SetMode()"); /* Set SE mode - Virtual */ REENTRANCE_LOCK(); ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeVirtual, nfc_jni_se_set_mode_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); if (ret != NFCSTATUS_PENDING) { LOGD("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); goto clean_and_return; } TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Wait for callback response */ if (sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } clean_and_return: nfc_cb_data_deinit(&cb_data); CONCURRENCY_UNLOCK(); } static void com_android_nfc_NfcManager_doDeselectSecureElement(JNIEnv *e, jobject o) { NFCSTATUS ret; struct nfc_jni_native_data *nat; struct nfc_jni_callback_data cb_data; CONCURRENCY_LOCK(); /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); /* Create the local semaphore */ if (!nfc_cb_data_init(&cb_data, NULL)) { goto clean_and_return; } TRACE("****** Deselect Secure Element ******"); TRACE("phLibNfc_SE_SetMode()"); /* Set SE mode - Off */ REENTRANCE_LOCK(); ret = phLibNfc_SE_SetMode(nat->seId, phLibNfc_SE_ActModeOff, nfc_jni_se_set_mode_callback, (void *)&cb_data); REENTRANCE_UNLOCK(); TRACE("phLibNfc_SE_SetMode returned 0x%02x", ret); if (ret != NFCSTATUS_PENDING) { LOGE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); goto clean_and_return; } TRACE("phLibNfc_SE_SetMode() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Wait for callback response */ if (sem_wait(&cb_data.sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } clean_and_return: nfc_cb_data_deinit(&cb_data); CONCURRENCY_UNLOCK(); } /* Llcp methods */ static jboolean com_android_nfc_NfcManager_doCheckLlcp(JNIEnv *e, jobject o) { NFCSTATUS ret; jboolean result = JNI_FALSE; struct nfc_jni_native_data *nat; struct nfc_jni_callback_data *cb_data; CONCURRENCY_LOCK(); /* Memory allocation for cb_data */ cb_data = (struct nfc_jni_callback_data*) malloc (sizeof(nfc_jni_callback_data)); /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); /* Create the local semaphore */ if (!nfc_cb_data_init(cb_data, (void*)nat)) { goto clean_and_return; } /* Check LLCP compliancy */ TRACE("phLibNfc_Llcp_CheckLlcp(hLlcpHandle=0x%08x)", hLlcpHandle); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_CheckLlcp(hLlcpHandle, nfc_jni_checkLlcp_callback, nfc_jni_llcp_linkStatus_callback, (void*)cb_data); REENTRANCE_UNLOCK(); /* In case of a NFCIP return NFCSTATUS_SUCCESS and in case of an another protocol * NFCSTATUS_PENDING. In this case NFCSTATUS_SUCCESS will also cause the callback. */ if(ret != NFCSTATUS_PENDING && ret != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); free(cb_data); goto clean_and_return; } TRACE("phLibNfc_Llcp_CheckLlcp() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Wait for callback response */ if(sem_wait(&cb_data->sem)) { LOGE("Failed to wait for semaphore (errno=0x%08x)", errno); goto clean_and_return; } if(cb_data->status == NFCSTATUS_SUCCESS) { result = JNI_TRUE; } clean_and_return: nfc_cb_data_deinit(cb_data); CONCURRENCY_UNLOCK(); return result; } static jboolean com_android_nfc_NfcManager_doActivateLlcp(JNIEnv *e, jobject o) { NFCSTATUS ret; TRACE("phLibNfc_Llcp_Activate(hRemoteDevice=0x%08x)", hLlcpHandle); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Activate(hLlcpHandle); REENTRANCE_UNLOCK(); if(ret == NFCSTATUS_SUCCESS) { TRACE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return JNI_TRUE; } else { LOGE("phLibNfc_Llcp_Activate() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return JNI_FALSE; } } static jobject com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket(JNIEnv *e, jobject o, jint nSap) { NFCSTATUS ret; jobject connectionlessSocket = NULL; phLibNfc_Handle hLlcpSocket; struct nfc_jni_native_data *nat; jclass clsNativeConnectionlessSocket; jfieldID f; /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); /* Create socket */ TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionLess, ...)"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionLess, NULL, NULL, &hLlcpSocket, nfc_jni_llcp_transport_socket_err_callback, (void*)nat); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { lastErrorStatus = ret; LOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); return NULL; } TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Bind socket */ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { lastErrorStatus = ret; LOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Close socket created */ REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Close(hLlcpSocket); REENTRANCE_UNLOCK(); return NULL; } TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Create new NativeLlcpConnectionlessSocket object */ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpConnectionlessSocket",&(connectionlessSocket)) == -1) { return NULL; } /* Get NativeConnectionless class object */ clsNativeConnectionlessSocket = e->GetObjectClass(connectionlessSocket); if(e->ExceptionCheck()) { return NULL; } /* Set socket handle */ f = e->GetFieldID(clsNativeConnectionlessSocket, "mHandle", "I"); e->SetIntField(connectionlessSocket, f,(jint)hLlcpSocket); TRACE("Connectionless socket Handle = %02x\n",hLlcpSocket); /* Set the miu link of the connectionless socket */ f = e->GetFieldID(clsNativeConnectionlessSocket, "mLinkMiu", "I"); e->SetIntField(connectionlessSocket, f,(jint)PHFRINFC_LLCP_MIU_DEFAULT); TRACE("Connectionless socket Link MIU = %d\n",PHFRINFC_LLCP_MIU_DEFAULT); /* Set socket SAP */ f = e->GetFieldID(clsNativeConnectionlessSocket, "mSap", "I"); e->SetIntField(connectionlessSocket, f,(jint)nSap); TRACE("Connectionless socket SAP = %d\n",nSap); return connectionlessSocket; } static jobject com_android_nfc_NfcManager_doCreateLlcpServiceSocket(JNIEnv *e, jobject o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength) { NFCSTATUS ret; phLibNfc_Handle hLlcpSocket; phLibNfc_Llcp_sSocketOptions_t sOptions; phNfc_sData_t sWorkingBuffer; phNfc_sData_t serviceName; struct nfc_jni_native_data *nat; jobject serviceSocket = NULL; jclass clsNativeLlcpServiceSocket; jfieldID f; /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); /* Set Connection Oriented socket options */ sOptions.miu = miu; sOptions.rw = rw; /* Allocate Working buffer length */ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); /* Create socket */ TRACE("phLibNfc_Llcp_Socket(hRemoteDevice=0x%08x, eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)", hLlcpHandle); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, &sOptions, &sWorkingBuffer, &hLlcpSocket, nfc_jni_llcp_transport_socket_err_callback, (void*)nat); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); lastErrorStatus = ret; return NULL; } TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Bind socket */ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { lastErrorStatus = ret; LOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Close socket created */ ret = phLibNfc_Llcp_Close(hLlcpSocket); return NULL; } TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Service socket */ if (sn == NULL) { serviceName.buffer = NULL; serviceName.length = 0; } else { serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL); serviceName.length = (uint32_t)e->GetStringUTFLength(sn); } TRACE("phLibNfc_Llcp_Listen(hSocket=0x%08x, ...)", hLlcpSocket); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Listen( hLlcpSocket, &serviceName, nfc_jni_llcp_transport_listen_socket_callback, (void*)hLlcpSocket); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); lastErrorStatus = ret; /* Close created socket */ REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Close(hLlcpSocket); REENTRANCE_UNLOCK(); return NULL; } TRACE("phLibNfc_Llcp_Listen() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Create new NativeLlcpServiceSocket object */ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpServiceSocket",&(serviceSocket)) == -1) { LOGE("Llcp Socket object creation error"); return NULL; } /* Get NativeLlcpServiceSocket class object */ clsNativeLlcpServiceSocket = e->GetObjectClass(serviceSocket); if(e->ExceptionCheck()) { LOGE("Llcp Socket get object class error"); return NULL; } /* Set socket handle */ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mHandle", "I"); e->SetIntField(serviceSocket, f,(jint)hLlcpSocket); TRACE("Service socket Handle = %02x\n",hLlcpSocket); /* Set socket linear buffer length */ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalLinearBufferLength", "I"); e->SetIntField(serviceSocket, f,(jint)linearBufferLength); TRACE("Service socket Linear buffer length = %02x\n",linearBufferLength); /* Set socket MIU */ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalMiu", "I"); e->SetIntField(serviceSocket, f,(jint)miu); TRACE("Service socket MIU = %d\n",miu); /* Set socket RW */ f = e->GetFieldID(clsNativeLlcpServiceSocket, "mLocalRw", "I"); e->SetIntField(serviceSocket, f,(jint)rw); TRACE("Service socket RW = %d\n",rw); return serviceSocket; } static jobject com_android_nfc_NfcManager_doCreateLlcpSocket(JNIEnv *e, jobject o, jint nSap, jint miu, jint rw, jint linearBufferLength) { jobject clientSocket = NULL; NFCSTATUS ret; phLibNfc_Handle hLlcpSocket; phLibNfc_Llcp_sSocketOptions_t sOptions; phNfc_sData_t sWorkingBuffer; struct nfc_jni_native_data *nat; jclass clsNativeLlcpSocket; jfieldID f; /* Retrieve native structure address */ nat = nfc_jni_get_nat(e, o); /* Set Connection Oriented socket options */ sOptions.miu = miu; sOptions.rw = rw; /* Allocate Working buffer length */ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength; sWorkingBuffer.buffer = (uint8_t*)malloc(sWorkingBuffer.length); /* Create socket */ TRACE("phLibNfc_Llcp_Socket(eType=phFriNfc_LlcpTransport_eConnectionOriented, ...)"); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Socket(phFriNfc_LlcpTransport_eConnectionOriented, &sOptions, &sWorkingBuffer, &hLlcpSocket, nfc_jni_llcp_transport_socket_err_callback, (void*)nat); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { LOGE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); lastErrorStatus = ret; return NULL; } TRACE("phLibNfc_Llcp_Socket() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Create new NativeLlcpSocket object */ if(nfc_jni_cache_object(e,"com/android/nfc/nxp/NativeLlcpSocket",&(clientSocket)) == -1) { LOGE("Llcp socket object creation error"); return NULL; } /* Get NativeConnectionless class object */ clsNativeLlcpSocket = e->GetObjectClass(clientSocket); if(e->ExceptionCheck()) { LOGE("Get class object error"); return NULL; } /* Test if an SAP number is present */ if(nSap != 0) { /* Bind socket */ TRACE("phLibNfc_Llcp_Bind(hSocket=0x%08x, nSap=0x%02x)", hLlcpSocket, nSap); REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Bind(hLlcpSocket,nSap); REENTRANCE_UNLOCK(); if(ret != NFCSTATUS_SUCCESS) { lastErrorStatus = ret; LOGE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Close socket created */ REENTRANCE_LOCK(); ret = phLibNfc_Llcp_Close(hLlcpSocket); REENTRANCE_UNLOCK(); return NULL; } TRACE("phLibNfc_Llcp_Bind() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret)); /* Set socket SAP */ f = e->GetFieldID(clsNativeLlcpSocket, "mSap", "I"); e->SetIntField(clientSocket, f,(jint)nSap); TRACE("socket SAP = %d\n",nSap); } /* Set socket handle */ f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I"); e->SetIntField(clientSocket, f,(jint)hLlcpSocket); TRACE("socket Handle = %02x\n",hLlcpSocket); /* Set socket MIU */ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I"); e->SetIntField(clientSocket, f,(jint)miu); TRACE("socket MIU = %d\n",miu); /* Set socket RW */ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I"); e->SetIntField(clientSocket, f,(jint)rw); TRACE("socket RW = %d\n",rw); return clientSocket; } static jint com_android_nfc_NfcManager_doGetLastError(JNIEnv *e, jobject o) { TRACE("Last Error Status = 0x%02x",lastErrorStatus); if(lastErrorStatus == NFCSTATUS_BUFFER_TOO_SMALL) { return ERROR_BUFFER_TOO_SMALL; } else if(lastErrorStatus == NFCSTATUS_INSUFFICIENT_RESOURCES) { return ERROR_INSUFFICIENT_RESOURCES; } else { return lastErrorStatus; } } static void com_android_nfc_NfcManager_doAbort(JNIEnv *e, jobject o) { emergency_recovery(NULL); } /* * JNI registration. */ static JNINativeMethod gMethods[] = { {"initializeNativeStructure", "()Z", (void *)com_android_nfc_NfcManager_init_native_struc}, {"initialize", "()Z", (void *)com_android_nfc_NfcManager_initialize}, {"deinitialize", "()Z", (void *)com_android_nfc_NfcManager_deinitialize}, {"enableDiscovery", "()V", (void *)com_android_nfc_NfcManager_enableDiscovery}, {"doGetSecureElementList", "()[I", (void *)com_android_nfc_NfcManager_doGetSecureElementList}, {"doSelectSecureElement", "()V", (void *)com_android_nfc_NfcManager_doSelectSecureElement}, {"doDeselectSecureElement", "()V", (void *)com_android_nfc_NfcManager_doDeselectSecureElement}, {"doCheckLlcp", "()Z", (void *)com_android_nfc_NfcManager_doCheckLlcp}, {"doActivateLlcp", "()Z", (void *)com_android_nfc_NfcManager_doActivateLlcp}, {"doCreateLlcpConnectionlessSocket", "(I)Lcom/android/nfc/nxp/NativeLlcpConnectionlessSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpConnectionlessSocket}, {"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/nxp/NativeLlcpServiceSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpServiceSocket}, {"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/nxp/NativeLlcpSocket;", (void *)com_android_nfc_NfcManager_doCreateLlcpSocket}, {"doGetLastError", "()I", (void *)com_android_nfc_NfcManager_doGetLastError}, {"disableDiscovery", "()V", (void *)com_android_nfc_NfcManager_disableDiscovery}, {"doSetTimeout", "(II)Z", (void *)com_android_nfc_NfcManager_doSetTimeout}, {"doResetTimeouts", "()V", (void *)com_android_nfc_NfcManager_doResetTimeouts}, {"doAbort", "()V", (void *)com_android_nfc_NfcManager_doAbort}, }; int register_com_android_nfc_NativeNfcManager(JNIEnv *e) { nfc_jni_native_monitor_t *nfc_jni_native_monitor; nfc_jni_native_monitor = nfc_jni_init_monitor(); if(nfc_jni_native_monitor == NULL) { LOGE("NFC Manager cannot recover native monitor %x\n", errno); return -1; } return jniRegisterNativeMethods(e, "com/android/nfc/nxp/NativeNfcManager", gMethods, NELEM(gMethods)); } } /* namespace android */