/* * Copyright (C) 2018 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 "HciEventManager.h" #include <android-base/stringprintf.h> #include <base/logging.h> #include <nativehelper/ScopedLocalRef.h> #include "JavaClassConstants.h" #include "NfcJniUtil.h" #include "nfc_config.h" extern bool nfc_debug_enabled; const char* APP_NAME = "NfcNci"; uint8_t HciEventManager::sEsePipe; uint8_t HciEventManager::sSimPipe; using android::base::StringPrintf; HciEventManager::HciEventManager() : mNativeData(nullptr) {} HciEventManager& HciEventManager::getInstance() { static HciEventManager sHciEventManager; return sHciEventManager; } void HciEventManager::initialize(nfc_jni_native_data* native) { mNativeData = native; tNFA_STATUS nfaStat = NFA_HciRegister(const_cast<char*>(APP_NAME), (tNFA_HCI_CBACK*)&nfaHciCallback, true); if (nfaStat != NFA_STATUS_OK) { LOG(ERROR) << "HCI registration failed; status=" << nfaStat; } sEsePipe = NfcConfig::getUnsigned(NAME_OFF_HOST_ESE_PIPE_ID, 0x16); sSimPipe = NfcConfig::getUnsigned(NAME_OFF_HOST_SIM_PIPE_ID, 0x0A); } void HciEventManager::notifyTransactionListenersOfAid(std::vector<uint8_t> aid, std::vector<uint8_t> data, std::string evtSrc) { if (aid.empty()) { return; } JNIEnv* e = NULL; ScopedAttach attach(mNativeData->vm, &e); CHECK(e); ScopedLocalRef<jobject> aidJavaArray(e, e->NewByteArray(aid.size())); CHECK(aidJavaArray.get()); e->SetByteArrayRegion((jbyteArray)aidJavaArray.get(), 0, aid.size(), (jbyte*)&aid[0]); CHECK(!e->ExceptionCheck()); ScopedLocalRef<jobject> srcJavaString(e, e->NewStringUTF(evtSrc.c_str())); CHECK(srcJavaString.get()); if (data.size() > 0) { ScopedLocalRef<jobject> dataJavaArray(e, e->NewByteArray(data.size())); CHECK(dataJavaArray.get()); e->SetByteArrayRegion((jbyteArray)dataJavaArray.get(), 0, data.size(), (jbyte*)&data[0]); CHECK(!e->ExceptionCheck()); e->CallVoidMethod(mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, aidJavaArray.get(), dataJavaArray.get(), srcJavaString.get()); } else { e->CallVoidMethod(mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, aidJavaArray.get(), NULL, srcJavaString.get()); } } /** * BerTlv has the following format: * * byte1 byte2 byte3 byte4 byte5 byte6 * 00-7F - - - - - * 81 00-FF - - - - * 82 0000-FFFF - - - * 83 000000-FFFFFF - - * 84 00000000-FFFFFFFF - */ std::vector<uint8_t> HciEventManager::getDataFromBerTlv( std::vector<uint8_t> berTlv) { if (berTlv.empty()) { return std::vector<uint8_t>(); } size_t lengthTag = berTlv[0]; DLOG_IF(INFO, nfc_debug_enabled) << "decodeBerTlv: berTlv[0]=" << berTlv[0]; /* As per ISO/IEC 7816, read the first byte to determine the length and * the start index accordingly */ if (lengthTag < 0x80 && berTlv.size() == (lengthTag + 1)) { return std::vector<uint8_t>(berTlv.begin() + 1, berTlv.end()); } else if (lengthTag == 0x81 && berTlv.size() > 2) { size_t length = berTlv[1]; if ((length + 2) == berTlv.size()) { return std::vector<uint8_t>(berTlv.begin() + 2, berTlv.end()); } } else if (lengthTag == 0x82 && berTlv.size() > 3) { size_t length = ((berTlv[1] << 8) | berTlv[2]); if ((length + 3) == berTlv.size()) { return std::vector<uint8_t>(berTlv.begin() + 3, berTlv.end()); } } else if (lengthTag == 0x83 && berTlv.size() > 4) { size_t length = (berTlv[1] << 16) | (berTlv[2] << 8) | berTlv[3]; if ((length + 4) == berTlv.size()) { return std::vector<uint8_t>(berTlv.begin() + 4, berTlv.end()); } } else if (lengthTag == 0x84 && berTlv.size() > 5) { size_t length = (berTlv[1] << 24) | (berTlv[2] << 16) | (berTlv[3] << 8) | berTlv[4]; if ((length + 5) == berTlv.size()) { return std::vector<uint8_t>(berTlv.begin() + 5, berTlv.end()); } } LOG(ERROR) << "Error in TLV length encoding!"; return std::vector<uint8_t>(); } void HciEventManager::nfaHciCallback(tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData) { if (eventData == nullptr) { return; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "event=%d code=%d pipe=%d len=%d", event, eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe, eventData->rcvd_evt.evt_len); std::string evtSrc; if (eventData->rcvd_evt.pipe == sEsePipe) { evtSrc = "eSE1"; } else if (eventData->rcvd_evt.pipe == sSimPipe) { evtSrc = "SIM1"; } else { LOG(ERROR) << "Incorrect Pipe Id"; return; } uint8_t* buff = eventData->rcvd_evt.p_evt_buf; uint32_t buffLength = eventData->rcvd_evt.evt_len; std::vector<uint8_t> event_buff(buff, buff + buffLength); // Check the event and check if it contains the AID if (event == NFA_HCI_EVENT_RCVD_EVT && eventData->rcvd_evt.evt_code == NFA_HCI_EVT_TRANSACTION && buffLength > 3 && event_buff[0] == 0x81) { int aidlen = event_buff[1]; std::vector<uint8_t> aid(event_buff.begin() + 2, event_buff.begin() + aidlen + 2); int32_t berTlvStart = aidlen + 2 + 1; int32_t berTlvLen = buffLength - berTlvStart; std::vector<uint8_t> data; if (berTlvLen > 0 && event_buff[2 + aidlen] == 0x82) { std::vector<uint8_t> berTlv(event_buff.begin() + berTlvStart, event_buff.end()); // BERTLV decoding here, to support extended data length for params. data = getInstance().getDataFromBerTlv(berTlv); } getInstance().notifyTransactionListenersOfAid(aid, data, evtSrc); } } void HciEventManager::finalize() { mNativeData = NULL; }