diff options
author | anil.hiranniah <anil.hiranniah@nxp.com> | 2021-03-27 10:45:31 +0530 |
---|---|---|
committer | George Chang <georgekgchang@google.com> | 2021-05-18 02:44:45 +0000 |
commit | 167e0ff873df1f7218524ddc8b6a8dd39e38f323 (patch) | |
tree | f493f0a60513b2c6ed5cbc46f03e469955f03fdd | |
parent | 8803e33ec06cd8eaa99d1c78dbaf3079ad826191 (diff) | |
download | secure_element-167e0ff873df1f7218524ddc8b6a8dd39e38f323.tar.gz |
Add SE hal support for SNXXX
Move existing se hal to pn8x/
Add se hal for snxxx in snxxx/
Move existing extns/intf to intf/
Update Android.bp files to build hals for pn8x and snxxx
Bug: 188034640
Test: CTS, VTS, NFC On/OFf,
Data exchange to SE using OMAPI APIs
Merged-In: I8df25d1b743f7bd012ccb021d92880f774581eef
Change-Id: I8df25d1b743f7bd012ccb021d92880f774581eef
110 files changed, 16746 insertions, 225 deletions
diff --git a/Android.bp b/Android.bp index d33252c..435a352 100755..100644 --- a/Android.bp +++ b/Android.bp @@ -1,170 +1,21 @@ -package { - default_applicable_licenses: ["hardware_nxp_secure_element_license"], -} - -// Added automatically by a large-scale-change -// See: http://go/android-license-faq -license { - name: "hardware_nxp_secure_element_license", - visibility: [":__subpackages__"], - license_kinds: [ - "SPDX-license-identifier-Apache-2.0", - ], - // large-scale-change unable to identify any license_text files -} - -cc_library_shared { - - name: "ese_spi_nxp", - defaults: ["hidl_defaults"], - proprietary: true, - - srcs: [ - "libese-spi/p73/lib/phNxpEseDataMgr.cpp", - "libese-spi/p73/lib/phNxpEseProto7816_3.cpp", - "libese-spi/p73/lib/phNxpEse_Api.cpp", - "libese-spi/p73/pal/phNxpEsePal.cpp", - "libese-spi/p73/pal/spi/phNxpEsePal_spi.cpp", - "libese-spi/p73/spm/phNxpEse_Spm.cpp", - "libese-spi/p73/utils/ese_config.cpp", - "libese-spi/p73/utils/config.cpp", - "libese-spi/p73/utils/ringbuffer.cpp", - "libese-spi/src/adaptation/NfcAdaptation.cpp", - ], - - local_include_dirs: [ - "libese-spi/p73/lib", - "libese-spi/p73/pal/spi", - "libese-spi/p73/utils", - "libese-spi/src/include", - ], - export_include_dirs: [ - "extns/impl", - "libese-spi/common/include", - "libese-spi/p73/common", - "libese-spi/p73/inc", - "libese-spi/p73/pal", - ], - - cflags: [ - "-DANDROID", - "-DBUILDCFG=1", - "-DNXP_EXTNS=TRUE", - "-Wall", - "-Werror", - ], - - shared_libs: [ - "android.hardware.nfc@1.0", - "android.hardware.nfc@1.1", - "libcutils", - "libhardware", - "libhidlbase", - "libutils", - "liblog", - "libbase", - "vendor.nxp.nxpese@1.0", - "vendor.nxp.nxpnfc@1.0", - ], -} - -cc_library_shared { - - name: "ls_client", - defaults: ["hidl_defaults"], - proprietary: true, - - srcs: [ - "ls_client/src/LsLib.cpp", - "ls_client/src/LsClient.cpp", - ], - - export_include_dirs: ["ls_client/inc"], - - shared_libs: [ - "ese_spi_nxp", - "libcutils", - "liblog", - "libhidlbase", - "liblog", - "libutils", - "libcrypto" - ], -} - -cc_defaults { - name: "android.hardware.secure_element@1.1_defaults", - relative_install_path: "hw", - proprietary: true, - defaults: ["hidl_defaults"], - srcs: [ - "1.1/NxpEseService.cpp", - "1.1/SecureElement.cpp", - "extns/impl/NxpEse.cpp", - ], - - shared_libs: [ - "android.hardware.secure_element@1.0", - "android.hardware.secure_element@1.1", - "ese_spi_nxp", - "libbase", - "ls_client", - "libcutils", - "libhardware", - "libhidlbase", - "liblog", - "libutils", - "vendor.nxp.nxpese@1.0", - "vendor.nxp.nxpnfc@1.0", - ], -} - -cc_defaults { - name: "android.hardware.secure_element@1.0_defaults", - relative_install_path: "hw", - proprietary: true, - defaults: ["hidl_defaults"], - srcs: [ - "1.0/NxpEseService.cpp", - "1.0/SecureElement.cpp", - "extns/impl/NxpEse.cpp", - ], - - shared_libs: [ - "android.hardware.secure_element@1.0", - "ese_spi_nxp", - "libbase", - "ls_client", - "libcutils", - "libhardware", - "libhidlbase", - "liblog", - "libutils", - "vendor.nxp.nxpese@1.0", - "vendor.nxp.nxpnfc@1.0", - ], -} - -cc_binary { - name: "android.hardware.secure_element@1.0-service", - init_rc: ["1.0/android.hardware.secure_element@1.0-service.rc"], - defaults: ["android.hardware.secure_element@1.0_defaults"], -} - -cc_binary { - name: "android.hardware.secure_element@1.0-service-disabled", - init_rc: ["1.0/android.hardware.secure_element@1.0-service-disabled.rc"], - defaults: ["android.hardware.secure_element@1.0_defaults"], -} - -cc_binary { - name: "android.hardware.secure_element@1.1-service", - init_rc: ["1.1/android.hardware.secure_element@1.1-service.rc"], - defaults: ["android.hardware.secure_element@1.1_defaults"], -} - -cc_binary { - name: "android.hardware.secure_element@1.1-service-disabled", - init_rc: ["1.1/android.hardware.secure_element@1.1-service-disabled.rc"], - defaults: ["android.hardware.secure_element@1.1_defaults"], -} +/****************************************************************************** + * + * Copyright 2021 NXP + * + * 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. + * +*******************************************************************************/ + +subdirs = [ + "snxxx","intf","pn8x", +] diff --git a/extns/intf/nxpese/1.0/Android.bp b/extns/intf/nxpese/1.0/Android.bp deleted file mode 100644 index 013be4f..0000000 --- a/extns/intf/nxpese/1.0/Android.bp +++ /dev/null @@ -1,24 +0,0 @@ -// This file is autogenerated by hidl-gen -Landroidbp. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_nxp_secure_element_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_nxp_secure_element_license"], -} - -hidl_interface { - name: "vendor.nxp.nxpese@1.0", - root: "vendor.nxp.nxpese", - srcs: [ - "INxpEse.hal", - ], - interfaces: [ - "android.hidl.base@1.0", - ], - types: [ - ], - gen_java: true, -} diff --git a/extns/intf/nxpese/Android.bp b/extns/intf/nxpese/Android.bp deleted file mode 100644 index f8abae8..0000000 --- a/extns/intf/nxpese/Android.bp +++ /dev/null @@ -1,12 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "hardware_nxp_secure_element_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["hardware_nxp_secure_element_license"], -} - -hidl_package_root { - name: "vendor.nxp.nxpese", -} diff --git a/intf/nxpese/1.0/Android.bp b/intf/nxpese/1.0/Android.bp new file mode 100644 index 0000000..8e22179 --- /dev/null +++ b/intf/nxpese/1.0/Android.bp @@ -0,0 +1,15 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "vendor.nxp.nxpese@1.0", + root: "vendor.nxp.nxpese", + srcs: [ + "INxpEse.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + types: [ + ], + gen_java: true, +} diff --git a/extns/intf/nxpese/1.0/INxpEse.hal b/intf/nxpese/1.0/INxpEse.hal index 594fdf2..594fdf2 100644 --- a/extns/intf/nxpese/1.0/INxpEse.hal +++ b/intf/nxpese/1.0/INxpEse.hal diff --git a/extns/intf/nxpese/1.0/manifest.xml b/intf/nxpese/1.0/manifest.xml index 79a5c4d..79a5c4d 100644 --- a/extns/intf/nxpese/1.0/manifest.xml +++ b/intf/nxpese/1.0/manifest.xml diff --git a/intf/nxpese/Android.bp b/intf/nxpese/Android.bp new file mode 100644 index 0000000..cdee88e --- /dev/null +++ b/intf/nxpese/Android.bp @@ -0,0 +1,3 @@ +hidl_package_root { + name: "vendor.nxp.nxpese", +} diff --git a/extns/intf/nxpese/current.txt b/intf/nxpese/current.txt index 57fe96e..57fe96e 100644 --- a/extns/intf/nxpese/current.txt +++ b/intf/nxpese/current.txt diff --git a/1.0/NxpEseService.cpp b/pn8x/1.0/NxpEseService.cpp index c305338..2569a07 100755 --- a/1.0/NxpEseService.cpp +++ b/pn8x/1.0/NxpEseService.cpp @@ -25,13 +25,13 @@ #include "SecureElement.h" // Generated HIDL files -using android::hardware::secure_element::V1_0::ISecureElement; -using android::hardware::secure_element::V1_0::implementation::SecureElement; -using android::hardware::configureRpcThreadpool; -using android::hardware::joinRpcThreadpool; using android::OK; using android::sp; using android::status_t; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::secure_element::V1_0::ISecureElement; +using android::hardware::secure_element::V1_0::implementation::SecureElement; using vendor::nxp::nxpese::V1_0::INxpEse; using vendor::nxp::nxpese::V1_0::implementation::NxpEse; diff --git a/1.0/SecureElement.cpp b/pn8x/1.0/SecureElement.cpp index d4cde23..039d872 100644 --- a/1.0/SecureElement.cpp +++ b/pn8x/1.0/SecureElement.cpp @@ -37,8 +37,7 @@ static void onLSCompleted(bool result, std::string reason, void* arg) { } SecureElement::SecureElement() - : mOpenedchannelCount(0), - mOpenedChannels{false, false, false, false} {} + : mOpenedchannelCount(0), mOpenedChannels{false, false, false, false} {} Return<void> SecureElement::init( const sp< diff --git a/1.0/SecureElement.h b/pn8x/1.0/SecureElement.h index a15028a..6c314e4 100755 --- a/1.0/SecureElement.h +++ b/pn8x/1.0/SecureElement.h @@ -31,12 +31,12 @@ namespace secure_element { namespace V1_0 { namespace implementation { -using ::android::hidl::base::V1_0::IBase; +using ::android::sp; using ::android::hardware::hidl_vec; using ::android::hardware::Return; -using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback; using ::android::hardware::Void; -using ::android::sp; +using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback; +using ::android::hidl::base::V1_0::IBase; #ifndef MAX_LOGICAL_CHANNELS #define MAX_LOGICAL_CHANNELS 0x04 diff --git a/1.0/android.hardware.secure_element@1.0-service-disabled.rc b/pn8x/1.0/android.hardware.secure_element@1.0-service-disabled.rc index bb6ea2f..bb6ea2f 100644 --- a/1.0/android.hardware.secure_element@1.0-service-disabled.rc +++ b/pn8x/1.0/android.hardware.secure_element@1.0-service-disabled.rc diff --git a/1.0/android.hardware.secure_element@1.0-service.rc b/pn8x/1.0/android.hardware.secure_element@1.0-service.rc index f1e0966..f1e0966 100644 --- a/1.0/android.hardware.secure_element@1.0-service.rc +++ b/pn8x/1.0/android.hardware.secure_element@1.0-service.rc diff --git a/1.1/NxpEseService.cpp b/pn8x/1.1/NxpEseService.cpp index 595f11e..595f11e 100755 --- a/1.1/NxpEseService.cpp +++ b/pn8x/1.1/NxpEseService.cpp diff --git a/1.1/SecureElement.cpp b/pn8x/1.1/SecureElement.cpp index e4a05df..e4a05df 100644 --- a/1.1/SecureElement.cpp +++ b/pn8x/1.1/SecureElement.cpp diff --git a/1.1/SecureElement.h b/pn8x/1.1/SecureElement.h index d36b03f..d36b03f 100755 --- a/1.1/SecureElement.h +++ b/pn8x/1.1/SecureElement.h diff --git a/1.1/android.hardware.secure_element@1.1-service-disabled.rc b/pn8x/1.1/android.hardware.secure_element@1.1-service-disabled.rc index 6ff981f..6ff981f 100644 --- a/1.1/android.hardware.secure_element@1.1-service-disabled.rc +++ b/pn8x/1.1/android.hardware.secure_element@1.1-service-disabled.rc diff --git a/1.1/android.hardware.secure_element@1.1-service.rc b/pn8x/1.1/android.hardware.secure_element@1.1-service.rc index 8d5ddbe..8d5ddbe 100644 --- a/1.1/android.hardware.secure_element@1.1-service.rc +++ b/pn8x/1.1/android.hardware.secure_element@1.1-service.rc diff --git a/pn8x/Android.bp b/pn8x/Android.bp new file mode 100755 index 0000000..0e83bab --- /dev/null +++ b/pn8x/Android.bp @@ -0,0 +1,155 @@ +cc_library_shared { + + name: "ese_spi_nxp", + defaults: ["hidl_defaults"], + proprietary: true, + + srcs: [ + "libese-spi/p73/lib/phNxpEseDataMgr.cpp", + "libese-spi/p73/lib/phNxpEseProto7816_3.cpp", + "libese-spi/p73/lib/phNxpEse_Api.cpp", + "libese-spi/p73/pal/phNxpEsePal.cpp", + "libese-spi/p73/pal/spi/phNxpEsePal_spi.cpp", + "libese-spi/p73/spm/phNxpEse_Spm.cpp", + "libese-spi/p73/utils/ese_config.cpp", + "libese-spi/p73/utils/config.cpp", + "libese-spi/p73/utils/ringbuffer.cpp", + "libese-spi/src/adaptation/NfcAdaptation.cpp", + ], + + local_include_dirs: [ + "libese-spi/p73/lib", + "libese-spi/p73/pal/spi", + "libese-spi/p73/utils", + "libese-spi/src/include", + ], + export_include_dirs: [ + "extns/impl", + "libese-spi/common/include", + "libese-spi/p73/common", + "libese-spi/p73/inc", + "libese-spi/p73/pal", + ], + + cflags: [ + "-DANDROID", + "-DBUILDCFG=1", + "-DNXP_EXTNS=TRUE", + "-Wall", + "-Werror", + ], + + shared_libs: [ + "android.hardware.nfc@1.0", + "android.hardware.nfc@1.1", + "libcutils", + "libhardware", + "libhidlbase", + "libutils", + "liblog", + "libbase", + "vendor.nxp.nxpese@1.0", + "vendor.nxp.nxpnfc@1.0", + ], +} + +cc_library_shared { + + name: "ls_client", + defaults: ["hidl_defaults"], + proprietary: true, + + srcs: [ + "ls_client/src/LsLib.cpp", + "ls_client/src/LsClient.cpp", + ], + + export_include_dirs: ["ls_client/inc"], + + shared_libs: [ + "ese_spi_nxp", + "libcutils", + "liblog", + "libhidlbase", + "liblog", + "libutils", + "libcrypto" + ], +} + +cc_defaults { + name: "android.hardware.secure_element@1.1_defaults", + relative_install_path: "hw", + proprietary: true, + defaults: ["hidl_defaults"], + srcs: [ + "1.1/NxpEseService.cpp", + "1.1/SecureElement.cpp", + "extns/impl/NxpEse.cpp", + ], + + shared_libs: [ + "android.hardware.secure_element@1.0", + "android.hardware.secure_element@1.1", + "ese_spi_nxp", + "libbase", + "ls_client", + "libcutils", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + "vendor.nxp.nxpese@1.0", + "vendor.nxp.nxpnfc@1.0", + ], +} + +cc_defaults { + name: "android.hardware.secure_element@1.0_defaults", + relative_install_path: "hw", + proprietary: true, + defaults: ["hidl_defaults"], + srcs: [ + "1.0/NxpEseService.cpp", + "1.0/SecureElement.cpp", + "extns/impl/NxpEse.cpp", + ], + + shared_libs: [ + "android.hardware.secure_element@1.0", + "ese_spi_nxp", + "libbase", + "ls_client", + "libcutils", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + "vendor.nxp.nxpese@1.0", + "vendor.nxp.nxpnfc@1.0", + ], +} + +cc_binary { + name: "android.hardware.secure_element@1.0-service", + init_rc: ["1.0/android.hardware.secure_element@1.0-service.rc"], + defaults: ["android.hardware.secure_element@1.0_defaults"], +} + +cc_binary { + name: "android.hardware.secure_element@1.0-service-disabled", + init_rc: ["1.0/android.hardware.secure_element@1.0-service-disabled.rc"], + defaults: ["android.hardware.secure_element@1.0_defaults"], +} + +cc_binary { + name: "android.hardware.secure_element@1.1-service", + init_rc: ["1.1/android.hardware.secure_element@1.1-service.rc"], + defaults: ["android.hardware.secure_element@1.1_defaults"], +} + +cc_binary { + name: "android.hardware.secure_element@1.1-service-disabled", + init_rc: ["1.1/android.hardware.secure_element@1.1-service-disabled.rc"], + defaults: ["android.hardware.secure_element@1.1_defaults"], +} diff --git a/extns/impl/NxpEse.cpp b/pn8x/extns/impl/NxpEse.cpp index ce5b40a..ce5b40a 100644 --- a/extns/impl/NxpEse.cpp +++ b/pn8x/extns/impl/NxpEse.cpp diff --git a/extns/impl/NxpEse.h b/pn8x/extns/impl/NxpEse.h index b6af6e3..5da9b07 100644 --- a/extns/impl/NxpEse.h +++ b/pn8x/extns/impl/NxpEse.h @@ -31,16 +31,16 @@ namespace nxpese { namespace V1_0 { namespace implementation { -using ::android::hidl::base::V1_0::DebugInfo; -using ::android::hidl::base::V1_0::IBase; -using ::vendor::nxp::nxpese::V1_0::INxpEse; +using ::android::sp; using ::android::hardware::hidl_array; using ::android::hardware::hidl_memory; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; -using ::android::sp; +using ::android::hidl::base::V1_0::DebugInfo; +using ::android::hidl::base::V1_0::IBase; +using ::vendor::nxp::nxpese::V1_0::INxpEse; struct NxpEse : public INxpEse { Return<void> ioctl(uint64_t ioctlType, const hidl_vec<uint8_t>& inOutData, diff --git a/extns/impl/hal_nxpese.h b/pn8x/extns/impl/hal_nxpese.h index 50ae9f5..813fff8 100644 --- a/extns/impl/hal_nxpese.h +++ b/pn8x/extns/impl/hal_nxpese.h @@ -118,7 +118,7 @@ typedef union { */ typedef struct { /*context to be used/updated only by users of proxy & stub of Ese.hal - * i.e, EseAdaptation & hardware/interface/Ese. + * i.e., EseAdaptation & hardware/interface/Ese. */ void* context; eseInputData_t data; @@ -152,7 +152,7 @@ typedef union { typedef struct { /*ioctlType, result & context to be used/updated only by users of * proxy & stub of Ese.hal. - * i.e, EseAdaptation & hardware/interface/Ese + * i.e., EseAdaptation & hardware/interface/Ese * These fields shall not be used by libese or halimplementation*/ uint64_t ioctlType; uint32_t result; diff --git a/libese-spi/common/include/phNxpEseFeatures.h b/pn8x/libese-spi/common/include/phNxpEseFeatures.h index f957ba6..f957ba6 100755 --- a/libese-spi/common/include/phNxpEseFeatures.h +++ b/pn8x/libese-spi/common/include/phNxpEseFeatures.h diff --git a/libese-spi/p73/common/phEseStatus.h b/pn8x/libese-spi/p73/common/phEseStatus.h index d4c893d..d4c893d 100755 --- a/libese-spi/p73/common/phEseStatus.h +++ b/pn8x/libese-spi/p73/common/phEseStatus.h diff --git a/libese-spi/p73/inc/phNxpEse_Api.h b/pn8x/libese-spi/p73/inc/phNxpEse_Api.h index fb31af1..fb31af1 100755 --- a/libese-spi/p73/inc/phNxpEse_Api.h +++ b/pn8x/libese-spi/p73/inc/phNxpEse_Api.h diff --git a/libese-spi/p73/lib/phNxpEseDataMgr.cpp b/pn8x/libese-spi/p73/lib/phNxpEseDataMgr.cpp index 0213e18..0213e18 100755 --- a/libese-spi/p73/lib/phNxpEseDataMgr.cpp +++ b/pn8x/libese-spi/p73/lib/phNxpEseDataMgr.cpp diff --git a/libese-spi/p73/lib/phNxpEseDataMgr.h b/pn8x/libese-spi/p73/lib/phNxpEseDataMgr.h index 8a9e203..8a9e203 100755 --- a/libese-spi/p73/lib/phNxpEseDataMgr.h +++ b/pn8x/libese-spi/p73/lib/phNxpEseDataMgr.h diff --git a/libese-spi/p73/lib/phNxpEseProto7816_3.cpp b/pn8x/libese-spi/p73/lib/phNxpEseProto7816_3.cpp index f7a1679..f7a1679 100755 --- a/libese-spi/p73/lib/phNxpEseProto7816_3.cpp +++ b/pn8x/libese-spi/p73/lib/phNxpEseProto7816_3.cpp diff --git a/libese-spi/p73/lib/phNxpEseProto7816_3.h b/pn8x/libese-spi/p73/lib/phNxpEseProto7816_3.h index ee502f3..ee502f3 100755 --- a/libese-spi/p73/lib/phNxpEseProto7816_3.h +++ b/pn8x/libese-spi/p73/lib/phNxpEseProto7816_3.h diff --git a/libese-spi/p73/lib/phNxpEse_Api.cpp b/pn8x/libese-spi/p73/lib/phNxpEse_Api.cpp index 9db2d3b..9db2d3b 100644 --- a/libese-spi/p73/lib/phNxpEse_Api.cpp +++ b/pn8x/libese-spi/p73/lib/phNxpEse_Api.cpp diff --git a/libese-spi/p73/lib/phNxpEse_Internal.h b/pn8x/libese-spi/p73/lib/phNxpEse_Internal.h index ead441d..ead441d 100755 --- a/libese-spi/p73/lib/phNxpEse_Internal.h +++ b/pn8x/libese-spi/p73/lib/phNxpEse_Internal.h diff --git a/libese-spi/p73/libese-nxp-P73.conf b/pn8x/libese-spi/p73/libese-nxp-P73.conf index 84790d3..84790d3 100755 --- a/libese-spi/p73/libese-nxp-P73.conf +++ b/pn8x/libese-spi/p73/libese-nxp-P73.conf diff --git a/libese-spi/p73/pal/phNxpEsePal.cpp b/pn8x/libese-spi/p73/pal/phNxpEsePal.cpp index c15ab51..c15ab51 100755 --- a/libese-spi/p73/pal/phNxpEsePal.cpp +++ b/pn8x/libese-spi/p73/pal/phNxpEsePal.cpp diff --git a/libese-spi/p73/pal/phNxpEsePal.h b/pn8x/libese-spi/p73/pal/phNxpEsePal.h index 59bcbfe..59bcbfe 100755 --- a/libese-spi/p73/pal/phNxpEsePal.h +++ b/pn8x/libese-spi/p73/pal/phNxpEsePal.h diff --git a/libese-spi/p73/pal/spi/phNxpEsePal_spi.cpp b/pn8x/libese-spi/p73/pal/spi/phNxpEsePal_spi.cpp index cb2d4c5..a89a5fd 100755 --- a/libese-spi/p73/pal/spi/phNxpEsePal_spi.cpp +++ b/pn8x/libese-spi/p73/pal/spi/phNxpEsePal_spi.cpp @@ -161,7 +161,7 @@ retry_nfc_access: } ALOGD_IF(ese_debug_enabled, "Opening port=%s\n", pConfig->pDevName); -/* open port */ + /* open port */ retry: nHandle = open((char const*)pConfig->pDevName, O_RDWR); diff --git a/libese-spi/p73/pal/spi/phNxpEsePal_spi.h b/pn8x/libese-spi/p73/pal/spi/phNxpEsePal_spi.h index 1033694..1033694 100755 --- a/libese-spi/p73/pal/spi/phNxpEsePal_spi.h +++ b/pn8x/libese-spi/p73/pal/spi/phNxpEsePal_spi.h diff --git a/libese-spi/p73/spm/phNxpEse_Spm.cpp b/pn8x/libese-spi/p73/spm/phNxpEse_Spm.cpp index f35a891..f35a891 100755 --- a/libese-spi/p73/spm/phNxpEse_Spm.cpp +++ b/pn8x/libese-spi/p73/spm/phNxpEse_Spm.cpp diff --git a/libese-spi/p73/spm/phNxpEse_Spm.h b/pn8x/libese-spi/p73/spm/phNxpEse_Spm.h index 7595cf8..7595cf8 100755 --- a/libese-spi/p73/spm/phNxpEse_Spm.h +++ b/pn8x/libese-spi/p73/spm/phNxpEse_Spm.h diff --git a/libese-spi/p73/utils/config.cpp b/pn8x/libese-spi/p73/utils/config.cpp index 5983d59..5983d59 100644 --- a/libese-spi/p73/utils/config.cpp +++ b/pn8x/libese-spi/p73/utils/config.cpp diff --git a/libese-spi/p73/utils/config.h b/pn8x/libese-spi/p73/utils/config.h index 6a5ccb1..6a5ccb1 100755 --- a/libese-spi/p73/utils/config.h +++ b/pn8x/libese-spi/p73/utils/config.h diff --git a/libese-spi/p73/utils/ese_config.cpp b/pn8x/libese-spi/p73/utils/ese_config.cpp index 4a6b2cc..4a6b2cc 100755 --- a/libese-spi/p73/utils/ese_config.cpp +++ b/pn8x/libese-spi/p73/utils/ese_config.cpp diff --git a/libese-spi/p73/utils/ese_config.h b/pn8x/libese-spi/p73/utils/ese_config.h index fc7cf98..fc7cf98 100755 --- a/libese-spi/p73/utils/ese_config.h +++ b/pn8x/libese-spi/p73/utils/ese_config.h diff --git a/libese-spi/p73/utils/ringbuffer.cpp b/pn8x/libese-spi/p73/utils/ringbuffer.cpp index d7798fd..d7798fd 100755 --- a/libese-spi/p73/utils/ringbuffer.cpp +++ b/pn8x/libese-spi/p73/utils/ringbuffer.cpp diff --git a/libese-spi/p73/utils/ringbuffer.h b/pn8x/libese-spi/p73/utils/ringbuffer.h index d2c310a..d2c310a 100755 --- a/libese-spi/p73/utils/ringbuffer.h +++ b/pn8x/libese-spi/p73/utils/ringbuffer.h diff --git a/libese-spi/src/adaptation/NfcAdaptation.cpp b/pn8x/libese-spi/src/adaptation/NfcAdaptation.cpp index 55745f5..5f45e44 100755 --- a/libese-spi/src/adaptation/NfcAdaptation.cpp +++ b/pn8x/libese-spi/src/adaptation/NfcAdaptation.cpp @@ -24,9 +24,9 @@ #include <pthread.h> using android::sp; +using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; -using android::hardware::hidl_vec; using vendor::nxp::nxpnfc::V1_0::INxpNfc; sp<INxpNfc> NfcAdaptation::mHalNxpNfc = nullptr; diff --git a/libese-spi/src/include/NfcAdaptation.h b/pn8x/libese-spi/src/include/NfcAdaptation.h index db942fa..db942fa 100755 --- a/libese-spi/src/include/NfcAdaptation.h +++ b/pn8x/libese-spi/src/include/NfcAdaptation.h diff --git a/ls_client/inc/LsClient.h b/pn8x/ls_client/inc/LsClient.h index b4fa43e..b4fa43e 100755 --- a/ls_client/inc/LsClient.h +++ b/pn8x/ls_client/inc/LsClient.h diff --git a/ls_client/inc/LsLib.h b/pn8x/ls_client/inc/LsLib.h index b5002cc..b5002cc 100755 --- a/ls_client/inc/LsLib.h +++ b/pn8x/ls_client/inc/LsLib.h diff --git a/ls_client/src/LsClient.cpp b/pn8x/ls_client/src/LsClient.cpp index 4c874a9..8fb4fcd 100755 --- a/ls_client/src/LsClient.cpp +++ b/pn8x/ls_client/src/LsClient.cpp @@ -106,8 +106,7 @@ static std::string dumpLsInfo(LSInfo* info) { << (int)(info->m_status); buff << std::setw(2) << std::setfill('0') << std::hex << (int)(info->m_version); - buff << std::setw(2) << std::setfill('0') << std::hex - << (int)(info->m_mode); + buff << std::setw(2) << std::setfill('0') << std::hex << (int)(info->m_mode); buff << std::setw(2) << std::setfill('0') << std::hex << (int)(info->m_slot1_status); buff << std::setw(2) << std::setfill('0') << std::hex diff --git a/ls_client/src/LsLib.cpp b/pn8x/ls_client/src/LsLib.cpp index c670408..c670408 100755 --- a/ls_client/src/LsLib.cpp +++ b/pn8x/ls_client/src/LsLib.cpp diff --git a/snxxx/1.0/NxpEseService.cpp b/snxxx/1.0/NxpEseService.cpp new file mode 100644 index 0000000..c27b781 --- /dev/null +++ b/snxxx/1.0/NxpEseService.cpp @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * Copyright 2018 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "nxpese@1.0-service" +#include <android-base/stringprintf.h> +#include <android/hardware/secure_element/1.0/ISecureElement.h> +#include <base/logging.h> +#include <vendor/nxp/nxpese/1.0/INxpEse.h> +#include "VirtualISO.h" + +#include <hidl/LegacySupport.h> +#include <string.h> +#include "NxpEse.h" +#include "SecureElement.h" +#include "eSEClient.h" + +// Generated HIDL files +using android::OK; +using android::base::StringPrintf; +using android::hardware::configureRpcThreadpool; +using android::hardware::defaultPassthroughServiceImplementation; +using android::hardware::joinRpcThreadpool; +using android::hardware::registerPassthroughServiceImplementation; +using android::hardware::secure_element::V1_0::ISecureElement; +using android::hardware::secure_element::V1_0::implementation::SecureElement; +using vendor::nxp::nxpese::V1_0::INxpEse; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +using vendor::nxp::virtual_iso::V1_0::implementation::VirtualISO; + +using android::OK; +using android::sp; +using android::status_t; + +int main() { + status_t status; + + char terminalID[5]; + const char* SEterminal = "eSEx"; + bool ret = false; + + android::sp<ISecureElement> se_service = nullptr; + android::sp<INxpEse> nxp_se_service = nullptr; + android::sp<ISecureElement> virtual_iso_service = nullptr; + + ALOGI("Secure Element HAL Service 1.0 is starting."); + se_service = new SecureElement(); + if (se_service == nullptr) { + LOG(ERROR) << StringPrintf( + "Can not create an instance of Secure Element HAL Iface, exiting."); + goto shutdown; + } + configureRpcThreadpool(1, true /*callerWillJoin*/); + + checkEseClientUpdate(); + ret = geteSETerminalId(terminalID); + ALOGI("Terminal val = %s", terminalID); + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + ALOGI("Terminal ID found"); + status = se_service->registerAsService(terminalID); + + if (status != OK) { + LOG(ERROR) << StringPrintf( + "Could not register service for Secure Element HAL Iface (%d).", + status); + goto shutdown; + } + ALOGI("Secure Element Service is ready"); + + ALOGI("NXP Secure Element Extn Service 1.0 is starting."); + nxp_se_service = new NxpEse(); + if (nxp_se_service == nullptr) { + LOG(ERROR) << StringPrintf( + "Can not create an instance of NXP Secure Element Extn " + "Iface,exiting."); + goto shutdown; + } + status = nxp_se_service->registerAsService(); + if (status != OK) { + LOG(ERROR) << StringPrintf( + "Could not register service for Power Secure Element Extn Iface " + "(%d).", + status); + goto shutdown; + } + ALOGI("Secure Element Service is ready"); + } + + ALOGI("Virtual ISO HAL Service 1.0 is starting."); + virtual_iso_service = new VirtualISO(); + if (virtual_iso_service == nullptr) { + LOG(ERROR) << StringPrintf( + "Can not create an instance of Virtual ISO HAL Iface, exiting."); + goto shutdown; + } + ret = geteUICCTerminalId(terminalID); + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + status = virtual_iso_service->registerAsService(terminalID); + if (status != OK) { + LOG(ERROR) << StringPrintf( + "Could not register service for Virtual ISO HAL Iface (%d).", status); + goto shutdown; + } + } + + ALOGI("Virtual ISO: Secure Element Service is ready"); + perform_eSEClientUpdate(); + joinRpcThreadpool(); +// Should not pass this line +shutdown: + // In normal operation, we don't expect the thread pool to exit + LOG(ERROR) << StringPrintf("Secure Element Service is shutting down"); + return 1; +} diff --git a/snxxx/1.0/SecureElement.cpp b/snxxx/1.0/SecureElement.cpp new file mode 100755 index 0000000..61f1e7f --- /dev/null +++ b/snxxx/1.0/SecureElement.cpp @@ -0,0 +1,688 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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 "SecureElement.h" +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include "NxpEse.h" +#include "eSEClient.h" +#include "hal_nxpese.h" +#include "phNxpEse_Apdu_Api.h" +#include "phNxpEse_Api.h" +/* Mutex to synchronize multiple transceive */ + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_0 { +namespace implementation { + +#define LOG_TAG "nxpese@1.0-service" +#define DEFAULT_BASIC_CHANNEL 0x00 +#define INVALID_LEN_SW1 0x64 +#define INVALID_LEN_SW2 0xFF + +typedef struct gsTransceiveBuffer { + phNxpEse_data cmdData; + phNxpEse_data rspData; + hidl_vec<uint8_t>* pRspDataBuff; +} sTransceiveBuffer_t; + +static sTransceiveBuffer_t gsTxRxBuffer; +static hidl_vec<uint8_t> gsRspDataBuff(256); +static android::sp<ISecureElementHalCallback> cCallback; +std::vector<bool> SecureElement::mOpenedChannels; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +SecureElement::SecureElement() + : mMaxChannelCount(0), mOpenedchannelCount(0), mIsEseInitialized(false) {} + +Return<void> SecureElement::init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + LOG(INFO) << "SecureElement::init called here"; + if (ese_update != ESE_UPDATE_COMPLETED) { + cCallback = clientCallback; + clientCallback->onStateChange(false); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setSeCallBack(clientCallback); + return Void(); + // Register + } + if (mIsEseInitialized) { + clientCallback->onStateChange(true); + return Void(); + } + + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + LOG(INFO) << "ESE SPI init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange(true); + cCallback = clientCallback; + } else { + LOG(ERROR) << "eSE-Hal Init failed"; + clientCallback->onStateChange(false); + } + return Void(); +} + +Return<void> SecureElement::getAtr(getAtr_cb _hidl_cb) { + LOG(ERROR) << "Processing ATR....."; + phNxpEse_data atrData; + hidl_vec<uint8_t> response; + ESESTATUS status = ESESTATUS_FAILED; + bool mIsSeHalInitDone = false; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(response); /*Return with empty Vector*/ + return Void(); + } else { + mIsSeHalInitDone = true; + } + } + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "Endpoint set failed"; + } + status = phNxpEse_getAtr(&atrData); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_getAtr failed"; + _hidl_cb(response); /*Return with empty Vector*/ + return Void(); + } else { + response.resize(atrData.len); + memcpy(&response[0], atrData.p_data, atrData.len); + } + + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "Endpoint set failed"; + } + + if (status != ESESTATUS_SUCCESS) { + LOG(INFO) << StringPrintf("ATR Data[BytebyByte]=Look below for %d bytes", + atrData.len); + for (auto i = response.begin(); i != response.end(); ++i) + LOG(INFO) << StringPrintf("0x%x\t", *i); + } + + _hidl_cb(response); + if (atrData.p_data != NULL) { + phNxpEse_free(atrData.p_data); + } + if (mIsSeHalInitDone) { + if (SecureElementStatus::SUCCESS != seHalDeInit()) + LOG(ERROR) << "phNxpEse_getAtr seHalDeInit failed"; + mIsEseInitialized = false; + mIsSeHalInitDone = false; + } + return Void(); +} + +Return<bool> SecureElement::isCardPresent() { return true; } + +Return<void> SecureElement::transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_FAILED; + hidl_vec<uint8_t> result; + phNxpEse_memset(&gsTxRxBuffer.cmdData, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&gsTxRxBuffer.rspData, 0x00, sizeof(phNxpEse_data)); + gsTxRxBuffer.cmdData.len = data.size(); + gsTxRxBuffer.cmdData.p_data = + (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t)); + if (NULL == gsTxRxBuffer.cmdData.p_data) { + LOG(ERROR) << "transmit failed to allocate the Memory!!!"; + /*Return empty hidl_vec*/ + _hidl_cb(result); + return Void(); + } + memcpy(gsTxRxBuffer.cmdData.p_data, data.data(), gsTxRxBuffer.cmdData.len); + LOG(INFO) << "Acquired lock for SPI"; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&gsTxRxBuffer.cmdData, &gsTxRxBuffer.rspData); + + if (status == ESESTATUS_SUCCESS) { + result.resize(gsTxRxBuffer.rspData.len); + memcpy(&result[0], gsTxRxBuffer.rspData.p_data, gsTxRxBuffer.rspData.len); + } else if (status == ESESTATUS_INVALID_RECEIVE_LENGTH) { + uint8_t respBuf[] = {INVALID_LEN_SW1, INVALID_LEN_SW2}; + result.resize(sizeof(respBuf)); + memcpy(&result[0], respBuf, sizeof(respBuf)); + } else { + LOG(ERROR) << "transmit failed!!!"; + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + + _hidl_cb(result); + if (NULL != gsTxRxBuffer.cmdData.p_data) { + phNxpEse_free(gsTxRxBuffer.cmdData.p_data); + gsTxRxBuffer.cmdData.p_data = NULL; + } + if (NULL != gsTxRxBuffer.rspData.p_data) { + phNxpEse_free(gsTxRxBuffer.rspData.p_data); + gsTxRxBuffer.rspData.p_data = NULL; + } + + return Void(); +} + +Return<void> SecureElement::openLogicalChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openLogicalChannel_cb _hidl_cb) { + hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; + + LogicalChannelResponse resApduBuff; + resApduBuff.channelNumber = 0xff; + memset(&resApduBuff, 0x00, sizeof(resApduBuff)); + + LOG(INFO) << "Acquired the lock from SPI openLogicalChannel"; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = manageChannelCommand.size(); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() * + sizeof(uint8_t)); + memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); + + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&cmdApdu, &rspApdu); + if (status != ESESTATUS_SUCCESS) { + resApduBuff.channelNumber = 0xff; + if (NULL != rspApdu.p_data && rspApdu.len > 0) { + if (rspApdu.p_data[0] == 0x64 && rspApdu.p_data[1] == 0xFF) { + sestatus = SecureElementStatus::IOERROR; + } + } + if (SecureElementStatus::IOERROR != sestatus) { + sestatus = SecureElementStatus::FAILED; + } + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A && + rspApdu.p_data[rspApdu.len - 1] == 0x81) { + resApduBuff.channelNumber = 0xff; + sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + resApduBuff.channelNumber = rspApdu.p_data[0]; + mOpenedchannelCount++; + mOpenedChannels[resApduBuff.channelNumber] = true; + sestatus = SecureElementStatus::SUCCESS; + } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) || + (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } + /*Free the allocations*/ + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + if (sestatus != SecureElementStatus::SUCCESS) { + if (mOpenedchannelCount == 0) { + SecureElementStatus deInitStatus = seHalDeInit(); + if (deInitStatus != SecureElementStatus::SUCCESS) { + LOG(INFO) << "seDeInit Failed"; + } + } + /*If manageChanle is failed in any of above cases + send the callback and return*/ + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + return Void(); + } + LOG(INFO) << "openLogicalChannel Sending selectApdu"; + sestatus = SecureElementStatus::IOERROR; + status = ESESTATUS_FAILED; + + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + if ((resApduBuff.channelNumber > 0x03) && + (resApduBuff.channelNumber < 0x14)) { + /* update CLA byte accoridng to GP spec Table 11-12*/ + cpdu.cla = + 0x40 + (resApduBuff.channelNumber - 4); /* Class of instruction */ + } else if ((resApduBuff.channelNumber > 0x00) && + (resApduBuff.channelNumber < 0x04)) { + /* update CLA byte accoridng to GP spec Table 11-11*/ + cpdu.cla = resApduBuff.channelNumber; /* Class of instruction */ + } else { + LOG(ERROR) << StringPrintf("%s: Invalid Channel no: %02x", __func__, + resApduBuff.channelNumber); + resApduBuff.channelNumber = 0xff; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status != ESESTATUS_SUCCESS) { + /*Transceive failed*/ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + resApduBuff.selectResponse.resize(responseLen); + memcpy(&resApduBuff.selectResponse[0], rpdu.pdata, rpdu.len); + resApduBuff.selectResponse[responseLen - 1] = rpdu.sw2; + resApduBuff.selectResponse[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if ((rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) || (rpdu.sw1 == 0x62) || + (rpdu.sw1 == 0x63)) { + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if ((rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) || + (rpdu.sw1 == 0x69 && (rpdu.sw2 == 0x99 || rpdu.sw2 == 0x85))) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(resApduBuff.channelNumber); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } else { + resApduBuff.channelNumber = 0xff; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + + return Void(); +} + +Return<void> SecureElement::openBasicChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openBasicChannel_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + hidl_vec<uint8_t> result; + hidl_vec<uint8_t> ls_aid = {0xA0, 0x00, 0x00, 0x03, 0x96, 0x41, 0x4C, + 0x41, 0x01, 0x43, 0x4F, 0x52, 0x01}; + + LOG(ERROR) << "Acquired the lock in SPI openBasicChannel"; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + cpdu.cla = 0x00; /* Class of instruction */ + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + SecureElementStatus sestatus; + memset(&sestatus, 0x00, sizeof(sestatus)); + + if (status != ESESTATUS_SUCCESS) { + /* Transceive failed */ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + result.resize(responseLen); + memcpy(&result[0], rpdu.pdata, rpdu.len); + result[responseLen - 1] = rpdu.sw2; + result[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if (((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) || (rpdu.sw1 == 0x62) || + (rpdu.sw1 == 0x63)) { + /*Set basic channel reference if it is not set */ + if (!mOpenedChannels[0]) { + mOpenedChannels[0] = true; + mOpenedchannelCount++; + } + + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if ((rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) || + (rpdu.sw1 == 0x69 && (rpdu.sw2 == 0x99 || rpdu.sw2 == 0x85))) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(DEFAULT_BASIC_CHANNEL); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } + } + _hidl_cb(result, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + return Void(); +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +SecureElement::internalCloseChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(ERROR) << "Acquired the lock in SPI internalCloseChannel"; + LOG(INFO) << StringPrintf("mMaxChannelCount = %d, Closing Channel = %d", + mMaxChannelCount, channelNumber); + if (channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d for %d", channelNumber, + mOpenedChannels[channelNumber]); + sestatus = SecureElementStatus::FAILED; + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + if (status != ESESTATUS_SUCCESS) { + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::FAILED; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +SecureElement::closeChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(ERROR) << "Acquired the lock in SPI closeChannel"; + if (channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d for %d", channelNumber, + mOpenedChannels[channelNumber]); + sestatus = SecureElementStatus::FAILED; + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + if (status != ESESTATUS_SUCCESS) { + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::FAILED; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} +void SecureElement::serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) { + LOG(ERROR) << " SecureElement serviceDied!!!"; + mIsEseInitialized = false; + if (seHalDeInit() != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "SE Deinit not successful"; + } +} +ESESTATUS SecureElement::seHalInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + status = phNxpEse_open(initParams); + if (ESESTATUS_SUCCESS == status || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + mIsEseInitialized = true; + LOG(INFO) << "ESE SPI init complete!!!"; + return ESESTATUS_SUCCESS; + } + deInitStatus = phNxpEse_deInit(); + } else { + LOG(INFO) << "ESE SPI init NOT successful"; + status = ESESTATUS_FAILED; + } + if (phNxpEse_close(deInitStatus) != ESESTATUS_SUCCESS) { + LOG(INFO) << "ESE close not successful"; + status = ESESTATUS_FAILED; + } + mIsEseInitialized = false; + } + return status; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +SecureElement::seHalDeInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsDeInitDone = true; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsDeInitDone = false; + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + status = phNxpEse_close(deInitStatus); + if (status == ESESTATUS_SUCCESS && mIsDeInitDone) { + sestatus = SecureElementStatus::SUCCESS; + ; + } else { + LOG(ERROR) << "seHalDeInit: Failed"; + } + mIsEseInitialized = false; + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + + return sestatus; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace secure_element +} // namespace hardware +} // namespace android diff --git a/snxxx/1.0/SecureElement.h b/snxxx/1.0/SecureElement.h new file mode 100644 index 0000000..f46b666 --- /dev/null +++ b/snxxx/1.0/SecureElement.h @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Copyright 2018 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef ANDROID_HARDWARE_SECURE_ELEMENT_V1_0_SECUREELEMENT_H +#define ANDROID_HARDWARE_SECURE_ELEMENT_V1_0_SECUREELEMENT_H + +#include <android-base/stringprintf.h> +#include <android/hardware/secure_element/1.0/ISecureElement.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <pthread.h> +#include "phNxpEse_Api.h" + +class ThreadMutex { + public: + ThreadMutex(); + virtual ~ThreadMutex(); + void lock(); + void unlock(); + operator pthread_mutex_t*() { return &mMutex; } + + private: + pthread_mutex_t mMutex; +}; + +class AutoThreadMutex { + public: + AutoThreadMutex(ThreadMutex& m); + virtual ~AutoThreadMutex(); + operator ThreadMutex&() { return mm; } + operator pthread_mutex_t*() { return (pthread_mutex_t*)mm; } + + private: + ThreadMutex& mm; +}; + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using android::base::StringPrintf; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hidl::base::V1_0::IBase; + +#ifndef MIN_APDU_LENGTH +#define MIN_APDU_LENGTH 0x04 +#endif +#ifndef DEFAULT_BASIC_CHANNEL +#define DEFAULT_BASIC_CHANNEL 0x00 +#endif + +struct SecureElement : public ISecureElement, public hidl_death_recipient { + SecureElement(); + Return<void> init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) override; + Return<void> getAtr(getAtr_cb _hidl_cb) override; + Return<bool> isCardPresent() override; + Return<void> transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) override; + Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openLogicalChannel_cb _hidl_cb) override; + Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openBasicChannel_cb _hidl_cb) override; + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + closeChannel(uint8_t channelNumber) override; + + void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/); + + private: + uint8_t mMaxChannelCount; + uint8_t mOpenedchannelCount = 0; + bool mIsEseInitialized = false; + static std::vector<bool> mOpenedChannels; + static sp<V1_0::ISecureElementHalCallback> mCallbackV1_0; + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + seHalDeInit(); + ESESTATUS seHalInit(); + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + internalCloseChannel(uint8_t channelNumber); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace secure_element +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SECURE_ELEMENT_V1_0_SECUREELEMENT_H diff --git a/snxxx/1.0/VirtualISO.cpp b/snxxx/1.0/VirtualISO.cpp new file mode 100644 index 0000000..e92bce8 --- /dev/null +++ b/snxxx/1.0/VirtualISO.cpp @@ -0,0 +1,612 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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 "VirtualISO.h" +#include <android-base/logging.h> +#include "NxpEse.h" +#include "SecureElement.h" +#include "eSEClient.h" +#include "hal_nxpese.h" +#include "phNxpEse_Apdu_Api.h" +#include "phNxpEse_Api.h" +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +namespace vendor { +namespace nxp { +namespace virtual_iso { +namespace V1_0 { +namespace implementation { + +#define LOG_TAG "nxpVIsoese@1.0-service" + +#define DEFAULT_BASIC_CHANNEL 0x00 + +typedef struct gsTransceiveBuffer { + phNxpEse_data cmdData; + phNxpEse_data rspData; + hidl_vec<uint8_t>* pRspDataBuff; +} sTransceiveBuffer_t; + +static sTransceiveBuffer_t gsTxRxBuffer; +static hidl_vec<uint8_t> gsRspDataBuff(256); +static android::sp<ISecureElementHalCallback> cCallback; +std::vector<bool> VirtualISO::mOpenedChannels; + +VirtualISO::VirtualISO() + : mMaxChannelCount(0), mOpenedchannelCount(0), mIsEseInitialized(false) {} + +Return<void> VirtualISO::init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + LOG(INFO) << "Virtual ISO::init Enter"; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + if (ese_update != ESE_UPDATE_COMPLETED) { + cCallback = clientCallback; + clientCallback->onStateChange(false); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setVirtualISOCallBack(clientCallback); + return Void(); + // Register + } + if (mIsEseInitialized) { + clientCallback->onStateChange(true); + return Void(); + } + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + LOG(INFO) << "VISO init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange(true); + } else { + LOG(ERROR) << "VISO-Hal Init failed"; + clientCallback->onStateChange(false); + } + return Void(); +} + +Return<void> VirtualISO::getAtr(getAtr_cb _hidl_cb) { + hidl_vec<uint8_t> response; + _hidl_cb(response); + return Void(); +} + +Return<bool> VirtualISO::isCardPresent() { return true; } + +Return<void> VirtualISO::transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_FAILED; + hidl_vec<uint8_t> result; + phNxpEse_memset(&gsTxRxBuffer.cmdData, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&gsTxRxBuffer.rspData, 0x00, sizeof(phNxpEse_data)); + gsTxRxBuffer.cmdData.len = data.size(); + gsTxRxBuffer.cmdData.p_data = + (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t)); + if (NULL == gsTxRxBuffer.cmdData.p_data) { + LOG(ERROR) << "transmit failed to allocate the Memory!!!"; + /*Return empty hidl_vec*/ + _hidl_cb(result); + return Void(); + } + memcpy(gsTxRxBuffer.cmdData.p_data, data.data(), gsTxRxBuffer.cmdData.len); + LOG(ERROR) << "Acquired the lock in VISO "; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&gsTxRxBuffer.cmdData, &gsTxRxBuffer.rspData); + + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "transmit failed!!!"; + } else { + result.resize(gsTxRxBuffer.rspData.len); + memcpy(&result[0], gsTxRxBuffer.rspData.p_data, gsTxRxBuffer.rspData.len); + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + + _hidl_cb(result); + if (NULL != gsTxRxBuffer.cmdData.p_data) { + phNxpEse_free(gsTxRxBuffer.cmdData.p_data); + gsTxRxBuffer.cmdData.p_data = NULL; + } + if (NULL != gsTxRxBuffer.rspData.p_data) { + phNxpEse_free(gsTxRxBuffer.rspData.p_data); + gsTxRxBuffer.rspData.p_data = NULL; + } + + return Void(); +} + +Return<void> VirtualISO::openLogicalChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openLogicalChannel_cb _hidl_cb) { + hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; + + LogicalChannelResponse resApduBuff; + + LOG(INFO) << "Acquired the lock in VISO openLogicalChannel"; + + resApduBuff.channelNumber = 0xff; + memset(&resApduBuff, 0x00, sizeof(resApduBuff)); + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = manageChannelCommand.size(); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() * + sizeof(uint8_t)); + memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); + + memset(&sestatus, 0x00, sizeof(sestatus)); + + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&cmdApdu, &rspApdu); + if (status != ESESTATUS_SUCCESS) { + resApduBuff.channelNumber = 0xff; + if (NULL != rspApdu.p_data && rspApdu.len > 0) { + if ((rspApdu.p_data[0] == 0x64 && rspApdu.p_data[1] == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } + } + if (SecureElementStatus::IOERROR != sestatus) { + sestatus = SecureElementStatus::FAILED; + } + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A && + rspApdu.p_data[rspApdu.len - 1] == 0x81) { + resApduBuff.channelNumber = 0xff; + sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + resApduBuff.channelNumber = rspApdu.p_data[0]; + mOpenedchannelCount++; + mOpenedChannels[resApduBuff.channelNumber] = true; + sestatus = SecureElementStatus::SUCCESS; + } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) || + (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } + + /*Free the allocations*/ + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + if (sestatus != SecureElementStatus::SUCCESS) { + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + if (sestatus != SecureElementStatus::SUCCESS) { + LOG(INFO) << "seDeInit Failed"; + } + } + /*If manageChanle is failed in any of above cases + send the callback and return*/ + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + return Void(); + } + LOG(INFO) << "openLogicalChannel Sending selectApdu"; + sestatus = SecureElementStatus::IOERROR; + status = ESESTATUS_FAILED; + + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + if ((resApduBuff.channelNumber > 0x03) && + (resApduBuff.channelNumber < 0x14)) { + /* update CLA byte accoridng to GP spec Table 11-12*/ + cpdu.cla = + 0x40 + (resApduBuff.channelNumber - 4); /* Class of instruction */ + } else if ((resApduBuff.channelNumber > 0x00) && + (resApduBuff.channelNumber < 0x04)) { + /* update CLA byte accoridng to GP spec Table 11-11*/ + cpdu.cla = resApduBuff.channelNumber; /* Class of instruction */ + } else { + LOG(ERROR) << StringPrintf("%s: Invalid Channel no: %02x", __func__, + resApduBuff.channelNumber); + resApduBuff.channelNumber = 0xff; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + if (status != ESESTATUS_SUCCESS) { + /*Transceive failed*/ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + resApduBuff.selectResponse.resize(responseLen); + memcpy(&resApduBuff.selectResponse[0], rpdu.pdata, rpdu.len); + resApduBuff.selectResponse[responseLen - 1] = rpdu.sw2; + resApduBuff.selectResponse[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if (rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) { + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(resApduBuff.channelNumber); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } else { + resApduBuff.channelNumber = 0xff; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + + return Void(); +} + +Return<void> VirtualISO::openBasicChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openBasicChannel_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + hidl_vec<uint8_t> result; + + LOG(INFO) << "Acquired the lock in VISO openBasicChannel"; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + cpdu.cla = 0x00; /* Class of instruction */ + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_SetEndPoint_Cntxt(1); + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + SecureElementStatus sestatus; + memset(&sestatus, 0x00, sizeof(sestatus)); + + if (status != ESESTATUS_SUCCESS) { + /* Transceive failed */ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + result.resize(responseLen); + memcpy(&result[0], rpdu.pdata, rpdu.len); + result[responseLen - 1] = rpdu.sw2; + result[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + /*Set basic channel reference if it is not set */ + if (!mOpenedChannels[0]) { + mOpenedChannels[0] = true; + mOpenedchannelCount++; + } + + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(DEFAULT_BASIC_CHANNEL); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } + } + _hidl_cb(result, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + return Void(); +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::internalCloseChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(ERROR) << "internalCloseChannel Enter"; + LOG(INFO) << StringPrintf("mMaxChannelCount = %d, Closing Channel = %d", + mMaxChannelCount, channelNumber); + if (channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d", channelNumber); + sestatus = SecureElementStatus::FAILED; + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status != ESESTATUS_SUCCESS) { + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::FAILED; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::closeChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(INFO) << "Acquired the lock in VISO closeChannel"; + if (channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d for %d", channelNumber, + mOpenedChannels[channelNumber]); + sestatus = SecureElementStatus::FAILED; + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status != ESESTATUS_SUCCESS) { + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::FAILED; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} +ESESTATUS VirtualISO::seHalInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + status = phNxpEse_open(initParams); + if (ESESTATUS_SUCCESS == status || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + mIsEseInitialized = true; + LOG(INFO) << "VISO init complete!!!"; + return ESESTATUS_SUCCESS; + } + deInitStatus = phNxpEse_deInit(); + } + phNxpEse_close(deInitStatus); + mIsEseInitialized = false; + } + return status; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::seHalDeInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsDeInitDone = true; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsDeInitDone = false; + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + status = phNxpEse_close(deInitStatus); + if (status == ESESTATUS_SUCCESS && mIsDeInitDone) { + sestatus = SecureElementStatus::SUCCESS; + ; + } else { + LOG(ERROR) << "seHalDeInit: Failed"; + } + // Clear all the flags as SPI driver is closed. + mIsEseInitialized = false; + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + return sestatus; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace virtual_iso +} // namespace nxp +} // namespace vendor diff --git a/snxxx/1.0/VirtualISO.h b/snxxx/1.0/VirtualISO.h new file mode 100644 index 0000000..9d7438f --- /dev/null +++ b/snxxx/1.0/VirtualISO.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Copyright 2018 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H +#define VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H + +#include <android-base/stringprintf.h> +#include <android/hardware/secure_element/1.0/ISecureElement.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include "phNxpEse_Api.h" + +namespace vendor { +namespace nxp { +namespace virtual_iso { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using ::android::wp; +using android::base::StringPrintf; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_death_recipient; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_0::ISecureElement; +using ::android::hardware::secure_element::V1_0::LogicalChannelResponse; +using ::android::hardware::secure_element::V1_0::SecureElementStatus; +using ::android::hidl::base::V1_0::IBase; + +#ifndef DEFAULT_BASIC_CHANNEL +#define DEFAULT_BASIC_CHANNEL 0x00 +#endif + +struct VirtualISO : public ISecureElement, public hidl_death_recipient { + VirtualISO(); + Return<void> init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) override; + Return<void> getAtr(getAtr_cb _hidl_cb) override; + Return<bool> isCardPresent() override; + Return<void> transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) override; + Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openLogicalChannel_cb _hidl_cb) override; + Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openBasicChannel_cb _hidl_cb) override; + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + closeChannel(uint8_t channelNumber) override; + + virtual void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) { + // TODO: Implement graceful closure, to close ongoing tx-rx and deinit + // T=1 stack + // close(0); + } + + private: + uint8_t mMaxChannelCount; + uint8_t mOpenedchannelCount = 0; + bool mIsEseInitialized = false; + static std::vector<bool> mOpenedChannels; + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + seHalDeInit(); + ESESTATUS seHalInit(); + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + internalCloseChannel(uint8_t channelNumber); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace virtual_iso +} // namespace nxp +} // namespace vendor + +#endif // VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H diff --git a/snxxx/1.0/android.hardware.secure_element_snxxx@1.0-service.rc b/snxxx/1.0/android.hardware.secure_element_snxxx@1.0-service.rc new file mode 100644 index 0000000..7c6c36e --- /dev/null +++ b/snxxx/1.0/android.hardware.secure_element_snxxx@1.0-service.rc @@ -0,0 +1,4 @@ +service secure_element_hal_service /vendor/bin/hw/android.hardware.secure_element_snxxx@1.0-service + class hal + user secure_element + group secure_element diff --git a/snxxx/1.1/NxpEseService.cpp b/snxxx/1.1/NxpEseService.cpp new file mode 100755 index 0000000..dcb1541 --- /dev/null +++ b/snxxx/1.1/NxpEseService.cpp @@ -0,0 +1,132 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "nxpese@1.1-service" +#include <android/hardware/secure_element/1.1/ISecureElement.h> +#include <log/log.h> +#include <vendor/nxp/nxpese/1.0/INxpEse.h> +#include "VirtualISO.h" + +#include <hidl/LegacySupport.h> +#include <string.h> +#include <regex> +#include "NxpEse.h" +#include "SecureElement.h" +#include "eSEClient.h" + +// Generated HIDL files +using android::OK; +using android::base::StringPrintf; +using android::hardware::configureRpcThreadpool; +using android::hardware::defaultPassthroughServiceImplementation; +using android::hardware::joinRpcThreadpool; +using android::hardware::registerPassthroughServiceImplementation; +using android::hardware::secure_element::V1_1::ISecureElement; +using android::hardware::secure_element::V1_1::implementation::SecureElement; +using vendor::nxp::nxpese::V1_0::INxpEse; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +using vendor::nxp::virtual_iso::V1_0::implementation::VirtualISO; + +using android::OK; +using android::sp; +using android::status_t; + +int main() { + status_t status; + + char terminalID[5]; + const char* SEterminal = "eSEx"; + bool ret = false; + + android::sp<ISecureElement> se_service = nullptr; + android::sp<INxpEse> nxp_se_service = nullptr; + android::sp<ISecureElement> virtual_iso_service = nullptr; + + ALOGI("Secure Element HAL Service 1.1 is starting."); + try { + se_service = new SecureElement(); + if (se_service == nullptr) { + ALOGE("Can not create an instance of Secure Element HAL Iface, exiting."); + goto shutdown; + } + configureRpcThreadpool(1, true /*callerWillJoin*/); + + checkEseClientUpdate(); + ret = geteSETerminalId(terminalID); + ALOGI("Terminal val = %s", terminalID); + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + ALOGI("Terminal ID found"); + status = se_service->registerAsService(terminalID); + + if (status != OK) { + ALOGE("Could not register service for Secure Element HAL Iface (%d).", + status); + goto shutdown; + } + ALOGI("Secure Element Service is ready"); + + ALOGI("NXP Secure Element Extn Service 1.0 is starting."); + nxp_se_service = new NxpEse(); + if (nxp_se_service == nullptr) { + ALOGE( + "Can not create an instance of NXP Secure Element Extn " + "Iface,exiting."); + goto shutdown; + } + status = nxp_se_service->registerAsService(); + if (status != OK) { + ALOGE( + "Could not register service for Power Secure Element Extn Iface " + "(%d).", + status); + goto shutdown; + } + ALOGI("Secure Element Service is ready"); + } + + ALOGI("Virtual ISO HAL Service 1.0 is starting."); + virtual_iso_service = new VirtualISO(); + if (virtual_iso_service == nullptr) { + ALOGE("Can not create an instance of Virtual ISO HAL Iface, exiting."); + goto shutdown; + } + ret = geteUICCTerminalId(terminalID); + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + status = virtual_iso_service->registerAsService(terminalID); + if (status != OK) { + ALOGE("Could not register service for Virtual ISO HAL Iface (%d).", + status); + goto shutdown; + } + } + + ALOGI("Virtual ISO: Secure Element Service is ready"); + perform_eSEClientUpdate(); + joinRpcThreadpool(); + } catch (const std::length_error& e) { + ALOGE("Length Exception occurred = %s ", e.what()); + } catch (const std::__1::ios_base::failure& e) { + ALOGE("ios failure Exception occurred = %s ", e.what()); + } catch (std::__1::regex_error& e) { + ALOGE("Regex Exception occurred = %s ", e.what()); + } +// Should not pass this line +shutdown: + // In normal operation, we don't expect the thread pool to exit + ALOGE("Secure Element Service is shutting down"); + return 1; +} diff --git a/snxxx/1.1/SecureElement.cpp b/snxxx/1.1/SecureElement.cpp new file mode 100755 index 0000000..409811f --- /dev/null +++ b/snxxx/1.1/SecureElement.cpp @@ -0,0 +1,691 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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 "SecureElement.h" +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include "NxpEse.h" +#include "eSEClient.h" +#include "hal_nxpese.h" +#include "phNxpEse_Apdu_Api.h" +#include "phNxpEse_Api.h" +/* Mutex to synchronize multiple transceive */ + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_1 { +namespace implementation { + +#define LOG_TAG "nxpese@1.1-service" +#define DEFAULT_BASIC_CHANNEL 0x00 +#define INVALID_LEN_SW1 0x64 +#define INVALID_LEN_SW2 0xFF + +typedef struct gsTransceiveBuffer { + phNxpEse_data cmdData; + phNxpEse_data rspData; + hidl_vec<uint8_t>* pRspDataBuff; +} sTransceiveBuffer_t; + +static sTransceiveBuffer_t gsTxRxBuffer; +static hidl_vec<uint8_t> gsRspDataBuff(256); +sp<V1_0::ISecureElementHalCallback> SecureElement::mCallbackV1_0 = nullptr; +sp<V1_1::ISecureElementHalCallback> SecureElement::mCallbackV1_1 = nullptr; +std::vector<bool> SecureElement::mOpenedChannels; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +SecureElement::SecureElement() + : mMaxChannelCount(0), mOpenedchannelCount(0), mIsEseInitialized(false) {} + +void SecureElement::NotifySeWaitExtension(phNxpEse_wtxState state) { + if (state == WTX_ONGOING) { + LOG(INFO) << "SecureElement::WTX ongoing"; + } else if (state == WTX_END) { + LOG(INFO) << "SecureElement::WTX ended"; + } +} + +Return<void> SecureElement::init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + initParams.fPtr_WtxNtf = SecureElement::NotifySeWaitExtension; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + LOG(INFO) << "SecureElement::init called here"; + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_0 = clientCallback; + clientCallback->onStateChange(false); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setSeCallBack(clientCallback); + return Void(); + // Register + } + if (mIsEseInitialized) { + clientCallback->onStateChange(true); + return Void(); + } + + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + LOG(INFO) << "ESE SPI init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange(true); + mCallbackV1_0 = clientCallback; + } else { + LOG(ERROR) << "eSE-Hal Init failed"; + clientCallback->onStateChange(false); + } + return Void(); +} + +Return<void> SecureElement::init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + initParams.fPtr_WtxNtf = SecureElement::NotifySeWaitExtension; + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + LOG(INFO) << "SecureElement::init called here"; + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_1 = clientCallback; + clientCallback->onStateChange_1_1(false, "NXP SE update going on"); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setSeCallBack_1_1(clientCallback); + return Void(); + // Register + } + if (mIsEseInitialized) { + clientCallback->onStateChange_1_1(true, "NXP SE HAL init ok"); + return Void(); + } + + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + LOG(INFO) << "ESE SPI init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange_1_1(true, "NXP SE HAL init ok"); + mCallbackV1_1 = clientCallback; + } else { + LOG(ERROR) << "eSE-Hal Init failed"; + clientCallback->onStateChange_1_1(false, "NXP SE HAL init failed"); + } + return Void(); +} + +Return<void> SecureElement::getAtr(getAtr_cb _hidl_cb) { + AutoMutex guard(seHalLock); + LOG(ERROR) << "Processing ATR....."; + phNxpEse_data atrData; + hidl_vec<uint8_t> response; + ESESTATUS status = ESESTATUS_FAILED; + bool mIsSeHalInitDone = false; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(response); /*Return with empty Vector*/ + return Void(); + } else { + mIsSeHalInitDone = true; + } + } + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "Endpoint set failed"; + } + status = phNxpEse_getAtr(&atrData); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_getAtr failed"; + _hidl_cb(response); /*Return with empty Vector*/ + return Void(); + } else { + response.resize(atrData.len); + memcpy(&response[0], atrData.p_data, atrData.len); + } + + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "Endpoint set failed"; + } + + if (status != ESESTATUS_SUCCESS) { + LOG(INFO) << StringPrintf("ATR Data[BytebyByte]=Look below for %d bytes", + atrData.len); + for (auto i = response.begin(); i != response.end(); ++i) + LOG(INFO) << StringPrintf("0x%x\t", *i); + } + + _hidl_cb(response); + if (atrData.p_data != NULL) { + phNxpEse_free(atrData.p_data); + } + if (mIsSeHalInitDone) { + if (SecureElementStatus::SUCCESS != seHalDeInit()) + LOG(ERROR) << "phNxpEse_getAtr seHalDeInit failed"; + mIsEseInitialized = false; + mIsSeHalInitDone = false; + } + return Void(); +} + +Return<bool> SecureElement::isCardPresent() { return true; } + +Return<void> SecureElement::transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) { + AutoMutex guard(seHalLock); + ESESTATUS status = ESESTATUS_FAILED; + hidl_vec<uint8_t> result; + phNxpEse_memset(&gsTxRxBuffer.cmdData, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&gsTxRxBuffer.rspData, 0x00, sizeof(phNxpEse_data)); + gsTxRxBuffer.cmdData.len = (uint32_t)data.size(); + gsTxRxBuffer.cmdData.p_data = + (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t)); + if (NULL == gsTxRxBuffer.cmdData.p_data) { + LOG(ERROR) << "transmit failed to allocate the Memory!!!"; + /*Return empty hidl_vec*/ + _hidl_cb(result); + return Void(); + } + memcpy(gsTxRxBuffer.cmdData.p_data, data.data(), gsTxRxBuffer.cmdData.len); + LOG(INFO) << "Acquired lock for SPI"; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&gsTxRxBuffer.cmdData, &gsTxRxBuffer.rspData); + + if (status == ESESTATUS_SUCCESS) { + result.resize(gsTxRxBuffer.rspData.len); + memcpy(&result[0], gsTxRxBuffer.rspData.p_data, gsTxRxBuffer.rspData.len); + } else if (status == ESESTATUS_INVALID_RECEIVE_LENGTH) { + uint8_t respBuf[] = {INVALID_LEN_SW1, INVALID_LEN_SW2}; + result.resize(sizeof(respBuf)); + memcpy(&result[0], respBuf, sizeof(respBuf)); + } else { + LOG(ERROR) << "transmit failed!!!"; + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + + _hidl_cb(result); + if (NULL != gsTxRxBuffer.cmdData.p_data) { + phNxpEse_free(gsTxRxBuffer.cmdData.p_data); + gsTxRxBuffer.cmdData.p_data = NULL; + } + if (NULL != gsTxRxBuffer.rspData.p_data) { + phNxpEse_free(gsTxRxBuffer.rspData.p_data); + gsTxRxBuffer.rspData.p_data = NULL; + } + + return Void(); +} + +Return<void> SecureElement::openLogicalChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openLogicalChannel_cb _hidl_cb) { + AutoMutex guard(seHalLock); + hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; + + LogicalChannelResponse resApduBuff; + resApduBuff.channelNumber = 0xff; + memset(&resApduBuff, 0x00, sizeof(resApduBuff)); + + LOG(INFO) << "Acquired the lock from SPI openLogicalChannel"; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = (uint32_t)manageChannelCommand.size(); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() * + sizeof(uint8_t)); + memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); + + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&cmdApdu, &rspApdu); + if (status != ESESTATUS_SUCCESS) { + resApduBuff.channelNumber = 0xff; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A && + rspApdu.p_data[rspApdu.len - 1] == 0x81) { + resApduBuff.channelNumber = 0xff; + sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + resApduBuff.channelNumber = rspApdu.p_data[0]; + mOpenedchannelCount++; + mOpenedChannels[resApduBuff.channelNumber] = true; + sestatus = SecureElementStatus::SUCCESS; + } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) || + (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } + /*Free the allocations*/ + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + if (sestatus != SecureElementStatus::SUCCESS) { + if (mOpenedchannelCount == 0) { + SecureElementStatus deInitStatus = seHalDeInit(); + if (deInitStatus != SecureElementStatus::SUCCESS) { + LOG(INFO) << "seDeInit Failed"; + } + } + /*If manageChanle is failed in any of above cases + send the callback and return*/ + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + return Void(); + } + LOG(INFO) << "openLogicalChannel Sending selectApdu"; + sestatus = SecureElementStatus::IOERROR; + status = ESESTATUS_FAILED; + + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + if ((resApduBuff.channelNumber > 0x03) && + (resApduBuff.channelNumber < 0x14)) { + /* update CLA byte accoridng to GP spec Table 11-12*/ + cpdu.cla = + 0x40 + (resApduBuff.channelNumber - 4); /* Class of instruction */ + } else if ((resApduBuff.channelNumber > 0x00) && + (resApduBuff.channelNumber < 0x04)) { + /* update CLA byte accoridng to GP spec Table 11-11*/ + cpdu.cla = resApduBuff.channelNumber; /* Class of instruction */ + } else { + LOG(ERROR) << StringPrintf("%s: Invalid Channel no: %02x", __func__, + resApduBuff.channelNumber); + resApduBuff.channelNumber = 0xff; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = (uint16_t)aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status != ESESTATUS_SUCCESS) { + /*Transceive failed*/ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + resApduBuff.selectResponse.resize(responseLen); + memcpy(&resApduBuff.selectResponse[0], rpdu.pdata, rpdu.len); + resApduBuff.selectResponse[responseLen - 1] = rpdu.sw2; + resApduBuff.selectResponse[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if ((rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) || (rpdu.sw1 == 0x62) || + (rpdu.sw1 == 0x63)) { + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if ((rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) || + (rpdu.sw1 == 0x69 && (rpdu.sw2 == 0x99 || rpdu.sw2 == 0x85))) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(resApduBuff.channelNumber); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } else { + resApduBuff.channelNumber = 0xff; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + + return Void(); +} + +Return<void> SecureElement::openBasicChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openBasicChannel_cb _hidl_cb) { + AutoMutex guard(seHalLock); + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + hidl_vec<uint8_t> result; + hidl_vec<uint8_t> ls_aid = {0xA0, 0x00, 0x00, 0x03, 0x96, 0x41, 0x4C, + 0x41, 0x01, 0x43, 0x4F, 0x52, 0x01}; + + LOG(ERROR) << "Acquired the lock in SPI openBasicChannel"; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + cpdu.cla = 0x00; /* Class of instruction */ + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = (uint16_t)aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + SecureElementStatus sestatus; + memset(&sestatus, 0x00, sizeof(sestatus)); + + if (status != ESESTATUS_SUCCESS) { + /* Transceive failed */ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + result.resize(responseLen); + memcpy(&result[0], rpdu.pdata, rpdu.len); + result[responseLen - 1] = rpdu.sw2; + result[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if (((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) || (rpdu.sw1 == 0x62) || + (rpdu.sw1 == 0x63)) { + /*Set basic channel reference if it is not set */ + if (!mOpenedChannels[0]) { + mOpenedChannels[0] = true; + mOpenedchannelCount++; + } + + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if ((rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) || + (rpdu.sw1 == 0x69 && (rpdu.sw2 == 0x99 || rpdu.sw2 == 0x85))) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(DEFAULT_BASIC_CHANNEL); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } + } + _hidl_cb(result, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + return Void(); +} + +Return<SecureElementStatus> SecureElement::internalCloseChannel( + uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(ERROR) << "Acquired the lock in SPI internalCloseChannel"; + LOG(INFO) << StringPrintf("mMaxChannelCount = %d, Closing Channel = %d", + mMaxChannelCount, channelNumber); + if ((int8_t)channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d", channelNumber); + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + if (status == ESESTATUS_SUCCESS) { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + } + if (channelNumber < mMaxChannelCount) { + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} + +Return<SecureElementStatus> SecureElement::closeChannel(uint8_t channelNumber) { + AutoMutex guard(seHalLock); + return internalCloseChannel(channelNumber); +} + +void SecureElement::serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) { + LOG(ERROR) << " SecureElement serviceDied!!!"; + mIsEseInitialized = false; + if (seHalDeInit() != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "SE Deinit not successful"; + } +} +ESESTATUS SecureElement::seHalInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + initParams.fPtr_WtxNtf = SecureElement::NotifySeWaitExtension; + + status = phNxpEse_open(initParams); + if (ESESTATUS_SUCCESS == status || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + mIsEseInitialized = true; + LOG(INFO) << "ESE SPI init complete!!!"; + return ESESTATUS_SUCCESS; + } + deInitStatus = phNxpEse_deInit(); + } else { + LOG(INFO) << "ESE SPI init NOT successful"; + status = ESESTATUS_FAILED; + } + if (phNxpEse_close(deInitStatus) != ESESTATUS_SUCCESS) { + LOG(INFO) << "ESE close not successful"; + status = ESESTATUS_FAILED; + } + mIsEseInitialized = false; + } + return status; +} + +Return<SecureElementStatus> SecureElement::seHalDeInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsDeInitDone = true; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsDeInitDone = false; + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + status = phNxpEse_close(deInitStatus); + if (status == ESESTATUS_SUCCESS && mIsDeInitDone) { + sestatus = SecureElementStatus::SUCCESS; + ; + } else { + LOG(ERROR) << "seHalDeInit: Failed"; + } + mIsEseInitialized = false; + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + + return sestatus; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace secure_element +} // namespace hardware +} // namespace android diff --git a/snxxx/1.1/SecureElement.h b/snxxx/1.1/SecureElement.h new file mode 100755 index 0000000..5c15da1 --- /dev/null +++ b/snxxx/1.1/SecureElement.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * Copyright 2018-2019 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H +#define ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H + +#include <SyncEvent.h> +#include <android-base/stringprintf.h> +#include <android/hardware/secure_element/1.0/types.h> +#include <android/hardware/secure_element/1.1/ISecureElement.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <pthread.h> +#include "phNxpEse_Api.h" + +class ThreadMutex { + public: + ThreadMutex(); + virtual ~ThreadMutex(); + void lock(); + void unlock(); + operator pthread_mutex_t*() { return &mMutex; } + + private: + pthread_mutex_t mMutex; +}; + +class AutoThreadMutex { + public: + AutoThreadMutex(ThreadMutex& m); + virtual ~AutoThreadMutex(); + operator ThreadMutex&() { return mm; } + operator pthread_mutex_t*() { return (pthread_mutex_t*)mm; } + + private: + ThreadMutex& mm; +}; + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_1 { +namespace implementation { + +using ::android::sp; +using android::base::StringPrintf; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_0::LogicalChannelResponse; +using ::android::hardware::secure_element::V1_0::SecureElementStatus; +using ::android::hardware::secure_element::V1_1::ISecureElement; +using ::android::hidl::base::V1_0::IBase; + +#ifndef MIN_APDU_LENGTH +#define MIN_APDU_LENGTH 0x04 +#endif +#ifndef DEFAULT_BASIC_CHANNEL +#define DEFAULT_BASIC_CHANNEL 0x00 +#endif + +struct SecureElement : public V1_1::ISecureElement, + public hidl_death_recipient { + SecureElement(); + Return<void> init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) override; + Return<void> init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) override; + Return<void> getAtr(getAtr_cb _hidl_cb) override; + Return<bool> isCardPresent() override; + Return<void> transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) override; + Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openLogicalChannel_cb _hidl_cb) override; + Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openBasicChannel_cb _hidl_cb) override; + Return<SecureElementStatus> closeChannel(uint8_t channelNumber) override; + + void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/); + + static void NotifySeWaitExtension(phNxpEse_wtxState state); + + private: + uint8_t mMaxChannelCount; + uint8_t mOpenedchannelCount = 0; + Mutex seHalLock; + bool mIsEseInitialized = false; + static std::vector<bool> mOpenedChannels; + static sp<V1_0::ISecureElementHalCallback> mCallbackV1_0; + static sp<V1_1::ISecureElementHalCallback> mCallbackV1_1; + Return<SecureElementStatus> seHalDeInit(); + ESESTATUS seHalInit(); + Return<SecureElementStatus> internalCloseChannel(uint8_t channelNumber); +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace secure_element +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H diff --git a/snxxx/1.1/VirtualISO.cpp b/snxxx/1.1/VirtualISO.cpp new file mode 100755 index 0000000..aa0355e --- /dev/null +++ b/snxxx/1.1/VirtualISO.cpp @@ -0,0 +1,655 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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 "VirtualISO.h" +#include <android-base/logging.h> +#include "NxpEse.h" +#include "SecureElement.h" +#include "eSEClient.h" +#include "hal_nxpese.h" +#include "phNxpEse_Apdu_Api.h" +#include "phNxpEse_Api.h" + +namespace vendor { +namespace nxp { +namespace virtual_iso { +namespace V1_0 { +namespace implementation { + +#define LOG_TAG "nxpVIsoese@1.1-service" + +#define DEFAULT_BASIC_CHANNEL 0x00 + +using ::android::hardware::secure_element::V1_1::ISecureElement; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; + +typedef struct gsTransceiveBuffer { + phNxpEse_data cmdData; + phNxpEse_data rspData; + hidl_vec<uint8_t>* pRspDataBuff; +} sTransceiveBuffer_t; + +static sTransceiveBuffer_t gsTxRxBuffer; +static hidl_vec<uint8_t> gsRspDataBuff(256); +sp<::android::hardware::secure_element::V1_0::ISecureElementHalCallback> + VirtualISO::mCallbackV1_0 = nullptr; +sp<::android::hardware::secure_element::V1_1::ISecureElementHalCallback> + VirtualISO::mCallbackV1_1 = nullptr; +std::vector<bool> VirtualISO::mOpenedChannels; + +VirtualISO::VirtualISO() + : mMaxChannelCount(0), mOpenedchannelCount(0), mIsEseInitialized(false) {} + +Return<void> VirtualISO::init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + LOG(INFO) << "Virtual ISO::init Enter"; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_0 = clientCallback; + clientCallback->onStateChange(false); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setVirtualISOCallBack(clientCallback); + return Void(); + // Register + } + if (mIsEseInitialized) { + clientCallback->onStateChange(true); + return Void(); + } + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + LOG(INFO) << "VISO init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange(true); + } else { + LOG(ERROR) << "VISO-Hal Init failed"; + clientCallback->onStateChange(false); + } + return Void(); +} + +Return<void> VirtualISO::init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + LOG(INFO) << "Virtual ISO::init Enter"; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_1 = clientCallback; + clientCallback->onStateChange_1_1(false, "NXP SE update going on"); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setVirtualISOCallBack_1_1(clientCallback); + return Void(); + // Register + } + if (mIsEseInitialized) { + clientCallback->onStateChange_1_1(true, "NXP VISIO HAL init ok"); + return Void(); + } + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + LOG(INFO) << "VISO init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange_1_1(true, "NXP VISIO HAL init ok"); + } else { + LOG(ERROR) << "VISO-Hal Init failed"; + clientCallback->onStateChange_1_1(false, "NXP VISIO HAL init failed"); + } + return Void(); +} + +Return<void> VirtualISO::getAtr(getAtr_cb _hidl_cb) { + hidl_vec<uint8_t> response; + _hidl_cb(response); + return Void(); +} + +Return<bool> VirtualISO::isCardPresent() { return true; } + +Return<void> VirtualISO::transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_FAILED; + hidl_vec<uint8_t> result; + phNxpEse_memset(&gsTxRxBuffer.cmdData, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&gsTxRxBuffer.rspData, 0x00, sizeof(phNxpEse_data)); + gsTxRxBuffer.cmdData.len = data.size(); + gsTxRxBuffer.cmdData.p_data = + (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t)); + if (NULL == gsTxRxBuffer.cmdData.p_data) { + LOG(ERROR) << "transmit failed to allocate the Memory!!!"; + /*Return empty hidl_vec*/ + _hidl_cb(result); + return Void(); + } + memcpy(gsTxRxBuffer.cmdData.p_data, data.data(), gsTxRxBuffer.cmdData.len); + LOG(ERROR) << "Acquired the lock in VISO "; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&gsTxRxBuffer.cmdData, &gsTxRxBuffer.rspData); + + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "transmit failed!!!"; + } else { + result.resize(gsTxRxBuffer.rspData.len); + memcpy(&result[0], gsTxRxBuffer.rspData.p_data, gsTxRxBuffer.rspData.len); + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + + _hidl_cb(result); + if (NULL != gsTxRxBuffer.cmdData.p_data) { + phNxpEse_free(gsTxRxBuffer.cmdData.p_data); + gsTxRxBuffer.cmdData.p_data = NULL; + } + if (NULL != gsTxRxBuffer.rspData.p_data) { + phNxpEse_free(gsTxRxBuffer.rspData.p_data); + gsTxRxBuffer.rspData.p_data = NULL; + } + + return Void(); +} + +Return<void> VirtualISO::openLogicalChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openLogicalChannel_cb _hidl_cb) { + hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; + + LogicalChannelResponse resApduBuff; + + LOG(INFO) << "Acquired the lock in VISO openLogicalChannel"; + + resApduBuff.channelNumber = 0xff; + memset(&resApduBuff, 0x00, sizeof(resApduBuff)); + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = manageChannelCommand.size(); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() * + sizeof(uint8_t)); + memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); + + memset(&sestatus, 0x00, sizeof(sestatus)); + + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&cmdApdu, &rspApdu); + if (status != ESESTATUS_SUCCESS) { + resApduBuff.channelNumber = 0xff; + if (NULL != rspApdu.p_data && rspApdu.len > 0) { + if ((rspApdu.p_data[0] == 0x64 && rspApdu.p_data[1] == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } + } + if (SecureElementStatus::IOERROR != sestatus) { + sestatus = SecureElementStatus::FAILED; + } + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A && + rspApdu.p_data[rspApdu.len - 1] == 0x81) { + resApduBuff.channelNumber = 0xff; + sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + resApduBuff.channelNumber = rspApdu.p_data[0]; + mOpenedchannelCount++; + mOpenedChannels[resApduBuff.channelNumber] = true; + sestatus = SecureElementStatus::SUCCESS; + } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) || + (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } + + /*Free the allocations*/ + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + if (sestatus != SecureElementStatus::SUCCESS) { + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + if (sestatus != SecureElementStatus::SUCCESS) { + LOG(INFO) << "seDeInit Failed"; + } + } + /*If manageChanle is failed in any of above cases + send the callback and return*/ + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + return Void(); + } + LOG(INFO) << "openLogicalChannel Sending selectApdu"; + sestatus = SecureElementStatus::IOERROR; + status = ESESTATUS_FAILED; + + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + if ((resApduBuff.channelNumber > 0x03) && + (resApduBuff.channelNumber < 0x14)) { + /* update CLA byte accoridng to GP spec Table 11-12*/ + cpdu.cla = + 0x40 + (resApduBuff.channelNumber - 4); /* Class of instruction */ + } else if ((resApduBuff.channelNumber > 0x00) && + (resApduBuff.channelNumber < 0x04)) { + /* update CLA byte accoridng to GP spec Table 11-11*/ + cpdu.cla = resApduBuff.channelNumber; /* Class of instruction */ + } else { + LOG(ERROR) << StringPrintf("%s: Invalid Channel no: %02x", __func__, + resApduBuff.channelNumber); + resApduBuff.channelNumber = 0xff; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + if (status != ESESTATUS_SUCCESS) { + /*Transceive failed*/ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + resApduBuff.selectResponse.resize(responseLen); + memcpy(&resApduBuff.selectResponse[0], rpdu.pdata, rpdu.len); + resApduBuff.selectResponse[responseLen - 1] = rpdu.sw2; + resApduBuff.selectResponse[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if (rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) { + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(resApduBuff.channelNumber); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } else { + resApduBuff.channelNumber = 0xff; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + + return Void(); +} + +Return<void> VirtualISO::openBasicChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openBasicChannel_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + hidl_vec<uint8_t> result; + + LOG(INFO) << "Acquired the lock in VISO openBasicChannel"; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + cpdu.cla = 0x00; /* Class of instruction */ + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_SetEndPoint_Cntxt(1); + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + SecureElementStatus sestatus; + memset(&sestatus, 0x00, sizeof(sestatus)); + + if (status != ESESTATUS_SUCCESS) { + /* Transceive failed */ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + result.resize(responseLen); + memcpy(&result[0], rpdu.pdata, rpdu.len); + result[responseLen - 1] = rpdu.sw2; + result[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + /*Set basic channel reference if it is not set */ + if (!mOpenedChannels[0]) { + mOpenedChannels[0] = true; + mOpenedchannelCount++; + } + + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(DEFAULT_BASIC_CHANNEL); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } + } + _hidl_cb(result, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + return Void(); +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::internalCloseChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(ERROR) << "internalCloseChannel Enter"; + LOG(INFO) << StringPrintf("mMaxChannelCount = %d, Closing Channel = %d", + mMaxChannelCount, channelNumber); + if ((int8_t)channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d", channelNumber); + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status == ESESTATUS_SUCCESS) { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::closeChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(INFO) << "Acquired the lock in VISO closeChannel"; + if ((int8_t)channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d", channelNumber); + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status == ESESTATUS_SUCCESS) { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + } + + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} +ESESTATUS VirtualISO::seHalInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + status = phNxpEse_open(initParams); + if (ESESTATUS_SUCCESS == status || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + mIsEseInitialized = true; + LOG(INFO) << "VISO init complete!!!"; + return ESESTATUS_SUCCESS; + } + deInitStatus = phNxpEse_deInit(); + } + phNxpEse_close(deInitStatus); + mIsEseInitialized = false; + } + return status; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::seHalDeInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsDeInitDone = true; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsDeInitDone = false; + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + status = phNxpEse_close(deInitStatus); + if (status == ESESTATUS_SUCCESS && mIsDeInitDone) { + sestatus = SecureElementStatus::SUCCESS; + ; + } else { + LOG(ERROR) << "seHalDeInit: Failed"; + } + // Clear all the flags as SPI driver is closed. + mIsEseInitialized = false; + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + return sestatus; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace virtual_iso +} // namespace nxp +} // namespace vendor diff --git a/snxxx/1.1/VirtualISO.h b/snxxx/1.1/VirtualISO.h new file mode 100755 index 0000000..504a535 --- /dev/null +++ b/snxxx/1.1/VirtualISO.h @@ -0,0 +1,105 @@ +/****************************************************************************** + * + * Copyright 2018-2019 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H +#define VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H + +#include <android-base/stringprintf.h> +#include <android/hardware/secure_element/1.0/types.h> +#include <android/hardware/secure_element/1.1/ISecureElement.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include "phNxpEse_Api.h" + +namespace vendor { +namespace nxp { +namespace virtual_iso { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using ::android::wp; +using android::base::StringPrintf; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_death_recipient; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_0::LogicalChannelResponse; +using ::android::hardware::secure_element::V1_0::SecureElementStatus; +using ::android::hardware::secure_element::V1_1::ISecureElement; +using ::android::hidl::base::V1_0::IBase; + +#ifndef MIN_APDU_LENGTH +#define MIN_APDU_LENGTH 0x04 +#endif +#ifndef DEFAULT_BASIC_CHANNEL +#define DEFAULT_BASIC_CHANNEL 0x00 +#endif + +struct VirtualISO : public ISecureElement, public hidl_death_recipient { + VirtualISO(); + Return<void> init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) override; + Return<void> init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) override; + Return<void> getAtr(getAtr_cb _hidl_cb) override; + Return<bool> isCardPresent() override; + Return<void> transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) override; + Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openLogicalChannel_cb _hidl_cb) override; + Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openBasicChannel_cb _hidl_cb) override; + Return<SecureElementStatus> closeChannel(uint8_t channelNumber) override; + + virtual void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) { + // TODO: Implement graceful closure, to close ongoing tx-rx and deinit + // T=1 stack + // close(0); + } + + private: + uint8_t mMaxChannelCount; + uint8_t mOpenedchannelCount = 0; + bool mIsEseInitialized = false; + static std::vector<bool> mOpenedChannels; + static sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback> + mCallbackV1_0; + static sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback> + mCallbackV1_1; + Return<SecureElementStatus> seHalDeInit(); + ESESTATUS seHalInit(); + Return<SecureElementStatus> internalCloseChannel(uint8_t channelNumber); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace virtual_iso +} // namespace nxp +} // namespace vendor + +#endif // VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H diff --git a/snxxx/1.1/android.hardware.secure_element_snxxx@1.1-service.rc b/snxxx/1.1/android.hardware.secure_element_snxxx@1.1-service.rc new file mode 100755 index 0000000..1a29769 --- /dev/null +++ b/snxxx/1.1/android.hardware.secure_element_snxxx@1.1-service.rc @@ -0,0 +1,4 @@ +service vendor.secure_element_hal_service /vendor/bin/hw/android.hardware.secure_element_snxxx@1.1-service + class hal + user secure_element + group secure_element diff --git a/snxxx/1.2/NxpEseService.cpp b/snxxx/1.2/NxpEseService.cpp new file mode 100755 index 0000000..7e9559a --- /dev/null +++ b/snxxx/1.2/NxpEseService.cpp @@ -0,0 +1,145 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "nxpese@1.2-service" +#include <android/hardware/secure_element/1.2/ISecureElement.h> +#include <log/log.h> +#include <vendor/nxp/nxpese/1.0/INxpEse.h> +#include "VirtualISO.h" + +#include <hidl/LegacySupport.h> +#include <string.h> +#include <regex> +#include "NxpEse.h" +#include "SecureElement.h" +#ifdef NXP_BOOTTIME_UPDATE +#include "eSEClient.h" +#endif + +// Generated HIDL files +using android::OK; +using android::base::StringPrintf; +using android::hardware::configureRpcThreadpool; +using android::hardware::defaultPassthroughServiceImplementation; +using android::hardware::joinRpcThreadpool; +using android::hardware::registerPassthroughServiceImplementation; +using android::hardware::secure_element::V1_2::ISecureElement; +using android::hardware::secure_element::V1_2::implementation::SecureElement; +using vendor::nxp::nxpese::V1_0::INxpEse; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +using vendor::nxp::virtual_iso::V1_0::implementation::VirtualISO; + +using android::OK; +using android::sp; +using android::status_t; + +int main() { + status_t status; + + char terminalID[5] = "eSE1"; + const char* SEterminal = "eSEx"; + bool ret = false; + + android::sp<ISecureElement> se_service = nullptr; + android::sp<INxpEse> nxp_se_service = nullptr; + android::sp<ISecureElement> virtual_iso_service = nullptr; + + ALOGI("Secure Element HAL Service 1.2 is starting."); + try { + se_service = new SecureElement(); + if (se_service == nullptr) { + ALOGE("Can not create an instance of Secure Element HAL Iface, exiting."); + goto shutdown; + } + configureRpcThreadpool(1, true /*callerWillJoin*/); + +#ifdef NXP_BOOTTIME_UPDATE + checkEseClientUpdate(); + ret = geteSETerminalId(terminalID); +#else + ret = true; +#endif + ALOGI("Terminal val = %s", terminalID); + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + ALOGI("Terminal ID found"); + status = se_service->registerAsService(terminalID); + + if (status != OK) { + ALOGE("Could not register service for Secure Element HAL Iface (%d).", + status); + goto shutdown; + } + ALOGI("Secure Element Service is ready"); + + ALOGI("NXP Secure Element Extn Service 1.0 is starting."); + nxp_se_service = new NxpEse(); + if (nxp_se_service == nullptr) { + ALOGE( + "Can not create an instance of NXP Secure Element Extn " + "Iface,exiting."); + goto shutdown; + } + status = nxp_se_service->registerAsService(); + if (status != OK) { + ALOGE( + "Could not register service for Power Secure Element Extn Iface " + "(%d).", + status); + goto shutdown; + } + ALOGI("Secure Element Service is ready"); + } + + ALOGI("Virtual ISO HAL Service 1.0 is starting."); + virtual_iso_service = new VirtualISO(); + if (virtual_iso_service == nullptr) { + ALOGE("Can not create an instance of Virtual ISO HAL Iface, exiting."); + goto shutdown; + } +#ifdef NXP_BOOTTIME_UPDATE + ret = geteUICCTerminalId(terminalID); +#else + strncpy(terminalID, "eSE2", 4); + ret = true; +#endif + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + status = virtual_iso_service->registerAsService(terminalID); + if (status != OK) { + ALOGE("Could not register service for Virtual ISO HAL Iface (%d).", + status); + } else { + ALOGI("Virtual ISO: Secure Element Service is ready"); + } + } + +#ifdef NXP_BOOTTIME_UPDATE + perform_eSEClientUpdate(); +#endif + joinRpcThreadpool(); + } catch (const std::length_error& e) { + ALOGE("Length Exception occurred = %s ", e.what()); + } catch (const std::__1::ios_base::failure& e) { + ALOGE("ios failure Exception occurred = %s ", e.what()); + } catch (std::__1::regex_error& e) { + ALOGE("Regex Exception occurred = %s ", e.what()); + } +// Should not pass this line +shutdown: + // In normal operation, we don't expect the thread pool to exit + ALOGE("Secure Element Service is shutting down"); + return 1; +} diff --git a/snxxx/1.2/OsuHal/inc/OsuHalExtn.h b/snxxx/1.2/OsuHal/inc/OsuHalExtn.h new file mode 100644 index 0000000..6630d7a --- /dev/null +++ b/snxxx/1.2/OsuHal/inc/OsuHalExtn.h @@ -0,0 +1,80 @@ +/****************************************************************************** + * + * Copyright 2020 NXP + * + * 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. + * + ******************************************************************************/ + +#pragma once +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <string.h> +#include "phNxpEse_Api.h" + +using ::android::hardware::hidl_vec; +#define OSU_PROP_CLA 0x80 +#define OSU_PROP_INS 0xDF +#define OSU_PROP_RST_P1 0xEF + +#define ISO7816_BASIC_CHANNEL 0x00 +#define ISO7816_CLA_OFFSET 0 +#define ISO7816_INS_OFFSET 1 +#define ISO7816_P1_OFFSET 2 +#define ISO7816_P2_OFFSET 3 +#define ISO7816_LC_OFFSET 4 +#define ISO7816_EXTENDED_LC_VALUE 0 +#define ISO7816_SHORT_APDU_HEADER 5 +#define ISO7816_EXTENDED_APDU_HEADER 7 +#define ISO7816_CLA_CHN_MASK 0x03 +#define IS_OSU_MODE(...) (OsuHalExtn::getInstance().isOsuMode(__VA_ARGS__)) + +class OsuHalExtn { + public: + typedef enum { + NON_OSU_MODE, // Normal Mode : All HAL APIs allowed + OSU_PROP_MODE, // OSU mode : Only OSU JAR command allowed + OSU_GP_MODE, // OSU Mode : GP command in the OSU mode + OSU_RST_MODE, // OSU mode : Proprietary HARD reset + OSU_BLOCKED_MODE, // OSU mode : Command not allowed return error + } OsuApduMode; + + typedef enum { + INIT, + OPENBASIC, + OPENLOGICAL, + TRANSMIT, + CLOSE, + RESET, + } SecureElementAPI; + + static OsuHalExtn& getInstance(); + + OsuApduMode isOsuMode(const hidl_vec<uint8_t>& evt, uint8_t type, + phNxpEse_data* pCmdData = nullptr); + bool isOsuMode(uint8_t type, uint8_t channel = 0xFF); + virtual ~OsuHalExtn(); + OsuHalExtn() noexcept; + void checkAndUpdateOsuMode(); + unsigned long int getOSUMaxWtxCount(); + + private: + bool isAppOSUMode; + bool isJcopOSUMode; + static const hidl_vec<uint8_t> osu_aid[10]; + OsuApduMode checkTransmit(uint8_t* input, size_t length, uint32_t* outLength); + bool isOsuMode(); +}; diff --git a/snxxx/1.2/OsuHal/src/OsuHalExtn.cpp b/snxxx/1.2/OsuHal/src/OsuHalExtn.cpp new file mode 100644 index 0000000..8fcffb7 --- /dev/null +++ b/snxxx/1.2/OsuHal/src/OsuHalExtn.cpp @@ -0,0 +1,273 @@ +/****************************************************************************** + * + * Copyright 2020-2021 NXP + * + * 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 "OsuHalExtn.h" +#include <ese_config.h> + +#define LOG_TAG "OsuHalExtn" +#include <log/log.h> + +#define DEFAULT_MAX_WTX_COUNT 60 + +const static hidl_vec<uint8_t> OSU_AID = {0x4F, 0x70, 0x80, 0x13, 0x04, + 0xDE, 0xAD, 0xBE, 0xEF}; +const static uint8_t defaultSelectAid[] = {0x00, 0xA4, 0x04, 0x00, 0x00}; + +/******************************************************************************* +** +** Function: OsuHalExtn::isOsuMode +** +** Description: Check, update and return current mode for below SE HAL API +** requests openBasicChannel() and transmit() +** +** Returns: OsuApduMode(NON_OSU_MODE, OSU_PROP_MODE, OSU_RST_MODE, +** OSU_BLOCKED_MODE, OSU_GP_MODE) +** +*******************************************************************************/ +OsuHalExtn::OsuApduMode OsuHalExtn::isOsuMode(const hidl_vec<uint8_t>& evt, + uint8_t type, + phNxpEse_data* pCmdData) { + OsuApduMode osuSubState = (isAppOSUMode ? OSU_PROP_MODE : NON_OSU_MODE); + + switch (type) { + case OPENBASIC: + /* + * update & return OSU_PROP_MODE if OpenBasicChannel AID request matches + * OSU_AID + */ + if (!memcmp(&evt[0], &OSU_AID[0], OSU_AID.size())) { + isAppOSUMode = true; + osuSubState = OSU_PROP_MODE; + ALOGD("Dedicated mode is set !!!!!!!!!!!!!!!!!"); + } else if (isOsuMode()) { + // OpenBasic channel requests with non OSU_AID are not allowed/blocked + osuSubState = OSU_BLOCKED_MODE; + ALOGE("Non OSU AID Not allowed"); + } + break; + case TRANSMIT: + memcpy(pCmdData->p_data, evt.data(), evt.size()); + if (isOsuMode()) { + /* + * Process transmit request(unwrap APDU, proprietary actions) in OSU + * mode + */ + osuSubState = + checkTransmit(pCmdData->p_data, evt.size(), &pCmdData->len); + } else { + pCmdData->len = evt.size(); + osuSubState = NON_OSU_MODE; + } + break; + } + return osuSubState; +} + +/******************************************************************************* +** +** Function: OsuHalExtn::isOsuMode +** +** Description: Check, update and return current mode for below SE HAL API +** requests init(), openLogicalChannel() and closeChannel() +** +** Returns: true(OSU)/false(normal) +** +*******************************************************************************/ +bool OsuHalExtn::isOsuMode(uint8_t type, uint8_t channel) { + switch (type) { + case INIT: + checkAndUpdateOsuMode(); + break; + case OPENLOGICAL: + // No action, only return current mode + break; + case CLOSE: + /* + * If in OSU mode close basic channel is called + * clear osu APP and update JCOP mode + */ + if (channel == ISO7816_BASIC_CHANNEL && isOsuMode()) { + if (phNxpEse_doResetProtection(false) != ESESTATUS_SUCCESS) { + ALOGE("Disable Reset Protection Failed"); + } + phNxpEse_setWtxCountLimit(RESET_APP_WTX_COUNT); + isAppOSUMode = false; + ALOGD("Setting to normal mode!!!"); + } + break; + } + return isOsuMode(); +} + +/******************************************************************************* +** +** Function: OsuHalExtn::checkAndUpdateOsuMode +** +** Description: Check and update current JCOP mode OSU/Normal +** +** Returns: None +** +*******************************************************************************/ +void OsuHalExtn::checkAndUpdateOsuMode() { + isJcopOSUMode = (phNxpEse_GetOsMode() == OSU_MODE); +} + +/******************************************************************************* +** +** Function: OsuHalExtn::getInstance +** +** Description: get class singleton object +** +** Returns: OsuHalExtn +** +*******************************************************************************/ +OsuHalExtn& OsuHalExtn::getInstance() { + static OsuHalExtn manager; + return manager; +} + +/******************************************************************************* +** +** Function: OsuHalExtn::OsuHalExtn() +** +** Description: class constructor +** +** Returns: none +** +*******************************************************************************/ +OsuHalExtn::OsuHalExtn() noexcept { + isAppOSUMode = false; + isJcopOSUMode = false; +} + +/******************************************************************************* +** +** Function: OsuHalExtn::~OsuHalExtn() +** +** Description: class destructor +** +** Returns: none +** +*******************************************************************************/ +OsuHalExtn::~OsuHalExtn() {} + +/******************************************************************************* +** +** Function: OsuHalExtn::isOsuMode() +** +** Description: Returns current JCOP mode +** +** Returns: true(OSU)/false(Normal) +** +*******************************************************************************/ +bool OsuHalExtn::isOsuMode() { return (isAppOSUMode || isJcopOSUMode); } + +/******************************************************************************* +** +** Function: OsuHalExtn::checkTransmit +** +** Description: Process transmit request in OSU mode +** 1) Unwrap proprietary APDU's to native commands +** 2) Block unexpected command request in OSU Mode +** 3) Perform hard reset on receiving proprietary reset APDU +** +** Returns: OsuApduMode +** +*******************************************************************************/ +OsuHalExtn::OsuApduMode OsuHalExtn::checkTransmit(uint8_t* input, size_t length, + uint32_t* outLength) { + OsuHalExtn::OsuApduMode halMode = NON_OSU_MODE; + + /* + * 1) Transmit request on logical channels(ISO7816_CLA_CHN_MASK)shall be + * blocked in OSU mode + * 2) Empty/Default GP card manager select from OMAPI shall + * be blocked in OSU Mode + */ + if (((*input & ISO7816_CLA_CHN_MASK) != ISO7816_BASIC_CHANNEL) || + (isJcopOSUMode && (length == ISO7816_SHORT_APDU_HEADER && + !memcmp(input, defaultSelectAid, length)))) { + phNxpEse_free(input); + input = nullptr; + halMode = OSU_BLOCKED_MODE; + } else if ((*input == OSU_PROP_CLA) && + (*(input + ISO7816_INS_OFFSET) == OSU_PROP_INS) && + (*(input + ISO7816_P1_OFFSET) != OSU_PROP_RST_P1)) { + /* + * 1) Unwrap GP command to native commands + * 2) Check APDU type short/extended before unwrapping + */ + ALOGD("checkTransmit in OSU_PROP_MODE"); + if (*(input + ISO7816_LC_OFFSET) != 0) { + if (length > ISO7816_SHORT_APDU_HEADER) { + *outLength = length - ISO7816_SHORT_APDU_HEADER; + memcpy(input, input + ISO7816_SHORT_APDU_HEADER, + length - ISO7816_SHORT_APDU_HEADER); + } else { + *outLength = 0; + ALOGE("checkTransmit input data length is incorrect"); + } + } else { + if (length > ISO7816_EXTENDED_APDU_HEADER) { + *outLength = length - ISO7816_EXTENDED_APDU_HEADER; + memcpy(input, input + ISO7816_EXTENDED_APDU_HEADER, + length - ISO7816_EXTENDED_APDU_HEADER); + } else { + *outLength = 0; + ALOGE("checkTransmit input data length is incorrect"); + } + } + halMode = OSU_PROP_MODE; + } else if ((*input == OSU_PROP_CLA) && + (*(input + ISO7816_INS_OFFSET) == OSU_PROP_INS) && + (*(input + ISO7816_P1_OFFSET) == OSU_PROP_RST_P1)) { + // eSE hard reset on receiving proprietary reset APDU + ALOGD("checkTransmit in OSU_PROP_RST_INS"); + if (phNxpEse_SetEndPoint_Cntxt(0) != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SetEndPoint_Cntxt failed!!!"); + } + phNxpEse_resetJcopUpdate(); + if (phNxpEse_ResetEndPoint_Cntxt(0) != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_ResetEndPoint_Cntxt failed!!!"); + } + // Update mode after eSE reset + checkAndUpdateOsuMode(); + phNxpEse_free(input); + input = nullptr; + halMode = OSU_RST_MODE; + } else { + // Process remaining OSU commands + *outLength = length; + halMode = OSU_GP_MODE; + } + return halMode; +} + +/******************************************************************************* +** +** Function: OsuHalExtn::getOSUMaxWtxCount +** +** Description: Read OSU_MAX_WTX_COUNT from config file allowed when in OSU +** mode +** +** Returns: Return maximum WTX count +** +*******************************************************************************/ +unsigned long int OsuHalExtn::getOSUMaxWtxCount() { + return EseConfig::getUnsigned(NAME_NXP_OSU_MAX_WTX_COUNT, + DEFAULT_MAX_WTX_COUNT); +} diff --git a/snxxx/1.2/SecureElement.cpp b/snxxx/1.2/SecureElement.cpp new file mode 100755 index 0000000..4c6756d --- /dev/null +++ b/snxxx/1.2/SecureElement.cpp @@ -0,0 +1,832 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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 "SecureElement.h" +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include "NxpEse.h" +#include "hal_nxpese.h" +#include "phNxpEse_Apdu_Api.h" +#include "phNxpEse_Api.h" +#ifdef NXP_BOOTTIME_UPDATE +#include "eSEClient.h" +#endif +/* Mutex to synchronize multiple transceive */ + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_2 { +namespace implementation { + +#define LOG_TAG "nxpese@1.2-service" +#define DEFAULT_BASIC_CHANNEL 0x00 +#define INVALID_LEN_SW1 0x64 +#define INVALID_LEN_SW2 0xFF + +typedef struct gsTransceiveBuffer { + phNxpEse_data cmdData; + phNxpEse_data rspData; + hidl_vec<uint8_t>* pRspDataBuff; +} sTransceiveBuffer_t; + +static sTransceiveBuffer_t gsTxRxBuffer; +static hidl_vec<uint8_t> gsRspDataBuff(256); +sp<V1_0::ISecureElementHalCallback> SecureElement::mCallbackV1_0 = nullptr; +sp<V1_1::ISecureElementHalCallback> SecureElement::mCallbackV1_1 = nullptr; +std::vector<bool> SecureElement::mOpenedChannels; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +SecureElement::SecureElement() + : mMaxChannelCount(0), mOpenedchannelCount(0), mIsEseInitialized(false) {} + +void SecureElement::NotifySeWaitExtension(phNxpEse_wtxState state) { + if (state == WTX_ONGOING) { + LOG(INFO) << "SecureElement::WTX ongoing"; + } else if (state == WTX_END) { + LOG(INFO) << "SecureElement::WTX ended"; + } +} + +Return<void> SecureElement::init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + initParams.fPtr_WtxNtf = SecureElement::NotifySeWaitExtension; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + LOG(INFO) << "SecureElement::init called here"; +#ifdef NXP_BOOTTIME_UPDATE + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_0 = clientCallback; + clientCallback->onStateChange(false); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setSeCallBack(clientCallback); + return Void(); + // Register + } +#endif + if (mIsEseInitialized) { + clientCallback->onStateChange(true); + return Void(); + } + + phNxpEse_setWtxCountLimit(OsuHalExtn::getInstance().getOSUMaxWtxCount()); + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + /*update OS mode during first init*/ + IS_OSU_MODE(OsuHalExtn::getInstance().INIT, 0); + + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + LOG(INFO) << "ESE SPI init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + phNxpEse_setWtxCountLimit(RESET_APP_WTX_COUNT); + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange(true); + mCallbackV1_0 = clientCallback; + } else { + LOG(ERROR) << "eSE-Hal Init failed"; + clientCallback->onStateChange(false); + } + return Void(); +} + +Return<void> SecureElement::init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + initParams.fPtr_WtxNtf = SecureElement::NotifySeWaitExtension; + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } + LOG(INFO) << "SecureElement::init called here"; +#ifdef NXP_BOOTTIME_UPDATE + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_1 = clientCallback; + clientCallback->onStateChange_1_1(false, "NXP SE update going on"); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setSeCallBack_1_1(clientCallback); + return Void(); + // Register + } +#endif + if (mIsEseInitialized) { + clientCallback->onStateChange_1_1(true, "NXP SE HAL init ok"); + return Void(); + } + + phNxpEse_setWtxCountLimit(OsuHalExtn::getInstance().getOSUMaxWtxCount()); + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + /*update OS mode during first init*/ + IS_OSU_MODE(OsuHalExtn::getInstance().INIT, 0); + + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + LOG(INFO) << "ESE SPI init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + phNxpEse_setWtxCountLimit(RESET_APP_WTX_COUNT); + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange_1_1(true, "NXP SE HAL init ok"); + mCallbackV1_1 = clientCallback; + } else { + LOG(ERROR) << "eSE-Hal Init failed"; + clientCallback->onStateChange_1_1(false, "NXP SE HAL init failed"); + } + return Void(); +} + +Return<void> SecureElement::getAtr(getAtr_cb _hidl_cb) { + AutoMutex guard(seHalLock); + LOG(ERROR) << "Processing ATR....."; + phNxpEse_data atrData; + hidl_vec<uint8_t> response; + ESESTATUS status = ESESTATUS_FAILED; + bool mIsSeHalInitDone = false; + + if (IS_OSU_MODE(OsuHalExtn::getInstance().OPENLOGICAL) >= + OsuHalExtn::getInstance().OSU_PROP_MODE) { + LOG(ERROR) << "%s: Not allowed in dedicated mode!!!" << __func__; + _hidl_cb(response); + return Void(); + } + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(response); /*Return with empty Vector*/ + return Void(); + } else { + mIsSeHalInitDone = true; + } + } + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "Endpoint set failed"; + } + status = phNxpEse_getAtr(&atrData); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_getAtr failed"; + _hidl_cb(response); /*Return with empty Vector*/ + return Void(); + } else { + response.resize(atrData.len); + memcpy(&response[0], atrData.p_data, atrData.len); + } + + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "Endpoint set failed"; + } + + if (status != ESESTATUS_SUCCESS) { + LOG(INFO) << StringPrintf("ATR Data[BytebyByte]=Look below for %d bytes", + atrData.len); + for (auto i = response.begin(); i != response.end(); ++i) + LOG(INFO) << StringPrintf("0x%x\t", *i); + } + + _hidl_cb(response); + if (atrData.p_data != NULL) { + phNxpEse_free(atrData.p_data); + } + if (mIsSeHalInitDone) { + if (SecureElementStatus::SUCCESS != seHalDeInit()) + LOG(ERROR) << "phNxpEse_getAtr seHalDeInit failed"; + mIsEseInitialized = false; + mIsSeHalInitDone = false; + } + return Void(); +} + +Return<bool> SecureElement::isCardPresent() { return true; } + +Return<void> SecureElement::transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) { + AutoMutex guard(seHalLock); + ESESTATUS status = ESESTATUS_FAILED; + hidl_vec<uint8_t> result; + phNxpEse_memset(&gsTxRxBuffer.cmdData, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&gsTxRxBuffer.rspData, 0x00, sizeof(phNxpEse_data)); + gsTxRxBuffer.cmdData.len = (uint32_t)data.size(); + gsTxRxBuffer.cmdData.p_data = + (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t)); + if (NULL == gsTxRxBuffer.cmdData.p_data) { + LOG(ERROR) << "transmit failed to allocate the Memory!!!"; + /*Return empty hidl_vec*/ + _hidl_cb(result); + return Void(); + } + OsuHalExtn::OsuApduMode mode = IS_OSU_MODE( + data, OsuHalExtn::getInstance().TRANSMIT, &gsTxRxBuffer.cmdData); + if (mode == OsuHalExtn::getInstance().OSU_BLOCKED_MODE) { + LOG(ERROR) << "Not allowed in dedicated mode!!!"; + /*Return empty hidl_vec*/ + _hidl_cb(result); + return Void(); + } else if (mode == OsuHalExtn::getInstance().OSU_RST_MODE) { + uint8_t sw[2] = {0x90, 0x00}; + result.resize(sizeof(sw)); + memcpy(&result[0], sw, sizeof(sw)); + _hidl_cb(result); + return Void(); + } else { + // continue with normal processing + } + // memcpy(gsTxRxBuffer.cmdData.p_data, data.data(), gsTxRxBuffer.cmdData.len); + LOG(INFO) << "Acquired lock for SPI"; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&gsTxRxBuffer.cmdData, &gsTxRxBuffer.rspData); + + if (status == ESESTATUS_SUCCESS) { + result.resize(gsTxRxBuffer.rspData.len); + memcpy(&result[0], gsTxRxBuffer.rspData.p_data, gsTxRxBuffer.rspData.len); + } else if (status == ESESTATUS_INVALID_RECEIVE_LENGTH) { + uint8_t respBuf[] = {INVALID_LEN_SW1, INVALID_LEN_SW2}; + result.resize(sizeof(respBuf)); + memcpy(&result[0], respBuf, sizeof(respBuf)); + } else { + LOG(ERROR) << "transmit failed!!!"; + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + + _hidl_cb(result); + if (NULL != gsTxRxBuffer.cmdData.p_data) { + phNxpEse_free(gsTxRxBuffer.cmdData.p_data); + gsTxRxBuffer.cmdData.p_data = NULL; + } + if (NULL != gsTxRxBuffer.rspData.p_data) { + phNxpEse_free(gsTxRxBuffer.rspData.p_data); + gsTxRxBuffer.rspData.p_data = NULL; + } + + return Void(); +} + +Return<void> SecureElement::openLogicalChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openLogicalChannel_cb _hidl_cb) { + AutoMutex guard(seHalLock); + hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; + + LogicalChannelResponse resApduBuff; + resApduBuff.channelNumber = 0xff; + memset(&resApduBuff, 0x00, sizeof(resApduBuff)); + + LOG(INFO) << "Acquired the lock from SPI openLogicalChannel"; + + if (IS_OSU_MODE(OsuHalExtn::getInstance().OPENLOGICAL) >= + OsuHalExtn::getInstance().OSU_PROP_MODE) { + LOG(ERROR) << "%s: Not allowed in dedicated mode!!!" << __func__; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + } + + if (mOpenedChannels.size() == 0x00) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = (uint32_t)manageChannelCommand.size(); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() * + sizeof(uint8_t)); + memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); + + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&cmdApdu, &rspApdu); + if (status != ESESTATUS_SUCCESS) { + resApduBuff.channelNumber = 0xff; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A && + rspApdu.p_data[rspApdu.len - 1] == 0x81) { + resApduBuff.channelNumber = 0xff; + sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + resApduBuff.channelNumber = rspApdu.p_data[0]; + mOpenedchannelCount++; + mOpenedChannels[resApduBuff.channelNumber] = true; + sestatus = SecureElementStatus::SUCCESS; + } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) || + (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } + /*Free the allocations*/ + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + if (sestatus != SecureElementStatus::SUCCESS) { + if (mOpenedchannelCount == 0) { + SecureElementStatus deInitStatus = seHalDeInit(); + if (deInitStatus != SecureElementStatus::SUCCESS) { + LOG(INFO) << "seDeInit Failed"; + } + } + /*If manageChanle is failed in any of above cases + send the callback and return*/ + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + return Void(); + } + LOG(INFO) << "openLogicalChannel Sending selectApdu"; + sestatus = SecureElementStatus::IOERROR; + status = ESESTATUS_FAILED; + + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + if ((resApduBuff.channelNumber > 0x03) && + (resApduBuff.channelNumber < 0x14)) { + /* update CLA byte accoridng to GP spec Table 11-12*/ + cpdu.cla = + 0x40 + (resApduBuff.channelNumber - 4); /* Class of instruction */ + } else if ((resApduBuff.channelNumber > 0x00) && + (resApduBuff.channelNumber < 0x04)) { + /* update CLA byte accoridng to GP spec Table 11-11*/ + cpdu.cla = resApduBuff.channelNumber; /* Class of instruction */ + } else { + LOG(ERROR) << StringPrintf("%s: Invalid Channel no: %02x", __func__, + resApduBuff.channelNumber); + resApduBuff.channelNumber = 0xff; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = (uint16_t)aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status != ESESTATUS_SUCCESS) { + /*Transceive failed*/ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + resApduBuff.selectResponse.resize(responseLen); + memcpy(&resApduBuff.selectResponse[0], rpdu.pdata, rpdu.len); + resApduBuff.selectResponse[responseLen - 1] = rpdu.sw2; + resApduBuff.selectResponse[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if ((rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) || (rpdu.sw1 == 0x62) || + (rpdu.sw1 == 0x63)) { + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if ((rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) || + (rpdu.sw1 == 0x69 && (rpdu.sw2 == 0x99 || rpdu.sw2 == 0x85))) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(resApduBuff.channelNumber); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } else { + resApduBuff.channelNumber = 0xff; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + + return Void(); +} + +Return<void> SecureElement::openBasicChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openBasicChannel_cb _hidl_cb) { + AutoMutex guard(seHalLock); + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + hidl_vec<uint8_t> result; + hidl_vec<uint8_t> ls_aid = {0xA0, 0x00, 0x00, 0x03, 0x96, 0x41, 0x4C, + 0x41, 0x01, 0x43, 0x4F, 0x52, 0x01}; + + LOG(ERROR) << "Acquired the lock in SPI openBasicChannel"; + OsuHalExtn::OsuApduMode mode = + IS_OSU_MODE(aid, OsuHalExtn::getInstance().OPENBASIC); + if (mode == OsuHalExtn::OSU_PROP_MODE) { + uint8_t sw[2] = {0x90, 0x00}; + result.resize(sizeof(sw)); + memcpy(&result[0], sw, 2); + if (mIsEseInitialized) { + /*Close existing sessions if any to start dedicated OSU Mode + * with OSU specific settings in TZ/TEE*/ + if (seHalDeInit() != SecureElementStatus::SUCCESS) { + LOG(INFO) << "seDeInit Failed"; + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + phNxpEse_setWtxCountLimit(OsuHalExtn::getInstance().getOSUMaxWtxCount()); + ESESTATUS status = ESESTATUS_FAILED; + uint8_t retry = 0; + do { + /*For Reset Recovery*/ + status = seHalInit(); + } while (status != ESESTATUS_SUCCESS && retry++ < 1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + phNxpEse_setWtxCountLimit(RESET_APP_WTX_COUNT); + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + if (phNxpEse_doResetProtection(true) != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: Enable Reset Protection Failed!!!" << __func__; + _hidl_cb(result, SecureElementStatus::FAILED); + } else { + _hidl_cb(result, SecureElementStatus::SUCCESS); + } + return Void(); + } else if (mode == OsuHalExtn::OSU_BLOCKED_MODE) { + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } else { + } + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + + if (mOpenedChannels.size() == 0x00) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + } + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + cpdu.cla = 0x00; /* Class of instruction */ + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = (uint16_t)aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + SecureElementStatus sestatus; + memset(&sestatus, 0x00, sizeof(sestatus)); + + if (status != ESESTATUS_SUCCESS) { + /* Transceive failed */ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + result.resize(responseLen); + memcpy(&result[0], rpdu.pdata, rpdu.len); + result[responseLen - 1] = rpdu.sw2; + result[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if (((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) || (rpdu.sw1 == 0x62) || + (rpdu.sw1 == 0x63)) { + /*Set basic channel reference if it is not set */ + if (!mOpenedChannels[0]) { + mOpenedChannels[0] = true; + mOpenedchannelCount++; + } + + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if ((rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) || + (rpdu.sw1 == 0x69 && (rpdu.sw2 == 0x99 || rpdu.sw2 == 0x85))) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(DEFAULT_BASIC_CHANNEL); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } + } + _hidl_cb(result, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + return Void(); +} + +Return<SecureElementStatus> SecureElement::internalCloseChannel( + uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(ERROR) << "Acquired the lock in SPI internalCloseChannel"; + LOG(INFO) << StringPrintf("mMaxChannelCount = %d, Closing Channel = %d", + mMaxChannelCount, channelNumber); + if ((int8_t)channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d", channelNumber); + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + if (status == ESESTATUS_SUCCESS) { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + } + if (channelNumber < mMaxChannelCount) { + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} + +Return<SecureElementStatus> SecureElement::closeChannel(uint8_t channelNumber) { + AutoMutex guard(seHalLock); + if (IS_OSU_MODE(OsuHalExtn::getInstance().CLOSE, channelNumber) == + OsuHalExtn::getInstance().NON_OSU_MODE) { + return internalCloseChannel(channelNumber); + } else { + /*Decrement channel count opened to + * keep in sync with service */ + if (channelNumber < mMaxChannelCount) { + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + } + return SecureElementStatus::SUCCESS; + } +} + +void SecureElement::serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) { + LOG(ERROR) << " SecureElement serviceDied!!!"; + mIsEseInitialized = false; + if (seHalDeInit() != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "SE Deinit not successful"; + } +} +ESESTATUS SecureElement::seHalInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + initParams.fPtr_WtxNtf = SecureElement::NotifySeWaitExtension; + + status = phNxpEse_open(initParams); + if (ESESTATUS_SUCCESS == status || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(0) && + ESESTATUS_SUCCESS == (status = phNxpEse_init(initParams))) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(0)) { + mIsEseInitialized = true; + LOG(INFO) << "ESE SPI init complete!!!"; + return ESESTATUS_SUCCESS; + } + } else { + LOG(INFO) << "ESE SPI init NOT successful"; + status = ESESTATUS_FAILED; + } + deInitStatus = phNxpEse_deInit(); + if (phNxpEse_close(deInitStatus) != ESESTATUS_SUCCESS) { + LOG(INFO) << "ESE close not successful"; + status = ESESTATUS_FAILED; + } + mIsEseInitialized = false; + } + return status; +} + +Return<SecureElementStatus> SecureElement::seHalDeInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsDeInitDone = true; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsDeInitDone = false; + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + status = phNxpEse_close(deInitStatus); + if (status == ESESTATUS_SUCCESS && mIsDeInitDone) { + sestatus = SecureElementStatus::SUCCESS; + ; + } else { + LOG(ERROR) << "seHalDeInit: Failed"; + } + mIsEseInitialized = false; + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + + return sestatus; +} +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +SecureElement::reset() { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + LOG(ERROR) << "%s: Enter" << __func__; + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + } + } + if (status == ESESTATUS_SUCCESS) { + mCallbackV1_1->onStateChange_1_1(false, "reset the SE"); + status = phNxpEse_reset(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: SecureElement reset failed!!" << __func__; + } else { + sestatus = SecureElementStatus::SUCCESS; + if (mOpenedChannels.size() == 0x00) { + mMaxChannelCount = + (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + } + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + mCallbackV1_1->onStateChange_1_1(true, "SE initialized"); + } + } + LOG(ERROR) << "%s: Exit" << __func__; + return sestatus; +} + +} // namespace implementation +} // namespace V1_2 +} // namespace secure_element +} // namespace hardware +} // namespace android diff --git a/snxxx/1.2/SecureElement.h b/snxxx/1.2/SecureElement.h new file mode 100755 index 0000000..8853444 --- /dev/null +++ b/snxxx/1.2/SecureElement.h @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * Copyright 2020 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef ANDROID_HARDWARE_SECURE_ELEMENT_V1_2_SECUREELEMENT_H +#define ANDROID_HARDWARE_SECURE_ELEMENT_V1_2_SECUREELEMENT_H + +#include <SyncEvent.h> +#include <android-base/stringprintf.h> +#include <android/hardware/secure_element/1.0/types.h> +#include <android/hardware/secure_element/1.2/ISecureElement.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <pthread.h> +#include "OsuHalExtn.h" +#include "phNxpEse_Api.h" + +class ThreadMutex { + public: + ThreadMutex(); + virtual ~ThreadMutex(); + void lock(); + void unlock(); + operator pthread_mutex_t*() { return &mMutex; } + + private: + pthread_mutex_t mMutex; +}; + +class AutoThreadMutex { + public: + AutoThreadMutex(ThreadMutex& m); + virtual ~AutoThreadMutex(); + operator ThreadMutex&() { return mm; } + operator pthread_mutex_t*() { return (pthread_mutex_t*)mm; } + + private: + ThreadMutex& mm; +}; + +namespace android { +namespace hardware { +namespace secure_element { +namespace V1_2 { +namespace implementation { + +using ::android::sp; +using android::base::StringPrintf; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_0::LogicalChannelResponse; +using ::android::hardware::secure_element::V1_0::SecureElementStatus; +using ::android::hardware::secure_element::V1_2::ISecureElement; +using ::android::hidl::base::V1_0::IBase; + +#ifndef MIN_APDU_LENGTH +#define MIN_APDU_LENGTH 0x04 +#endif +#ifndef DEFAULT_BASIC_CHANNEL +#define DEFAULT_BASIC_CHANNEL 0x00 +#endif + +struct SecureElement : public V1_2::ISecureElement, + public hidl_death_recipient { + SecureElement(); + Return<void> init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) override; + Return<void> init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) override; + Return<void> getAtr(getAtr_cb _hidl_cb) override; + Return<bool> isCardPresent() override; + Return<void> transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) override; + Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openLogicalChannel_cb _hidl_cb) override; + Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openBasicChannel_cb _hidl_cb) override; + Return<SecureElementStatus> closeChannel(uint8_t channelNumber) override; + + void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/); + + static void NotifySeWaitExtension(phNxpEse_wtxState state); + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + reset(); + + private: + uint8_t mMaxChannelCount; + uint8_t mOpenedchannelCount = 0; + Mutex seHalLock; + bool mIsEseInitialized = false; + static std::vector<bool> mOpenedChannels; + static sp<V1_0::ISecureElementHalCallback> mCallbackV1_0; + static sp<V1_1::ISecureElementHalCallback> mCallbackV1_1; + Return<SecureElementStatus> seHalDeInit(); + ESESTATUS seHalInit(); + Return<SecureElementStatus> internalCloseChannel(uint8_t channelNumber); +}; + +} // namespace implementation +} // namespace V1_2 +} // namespace secure_element +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H diff --git a/snxxx/1.2/VirtualISO.cpp b/snxxx/1.2/VirtualISO.cpp new file mode 100755 index 0000000..4550605 --- /dev/null +++ b/snxxx/1.2/VirtualISO.cpp @@ -0,0 +1,704 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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 "VirtualISO.h" +#include <android-base/logging.h> +#include "SecureElement.h" +#include "phNxpEse_Apdu_Api.h" +#include "phNxpEse_Api.h" +#ifdef NXP_BOOTTIME_UPDATE +#include "eSEClient.h" +#endif +#include "NxpEse.h" +#include "hal_nxpese.h" + +namespace vendor { +namespace nxp { +namespace virtual_iso { +namespace V1_0 { +namespace implementation { + +#define LOG_TAG "nxpVIsoese@1.2-service" + +#define DEFAULT_BASIC_CHANNEL 0x00 + +using ::android::hardware::secure_element::V1_2::ISecureElement; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; + +typedef struct gsTransceiveBuffer { + phNxpEse_data cmdData; + phNxpEse_data rspData; + hidl_vec<uint8_t>* pRspDataBuff; +} sTransceiveBuffer_t; + +static sTransceiveBuffer_t gsTxRxBuffer; +static hidl_vec<uint8_t> gsRspDataBuff(256); +sp<::android::hardware::secure_element::V1_0::ISecureElementHalCallback> + VirtualISO::mCallbackV1_0 = nullptr; +sp<::android::hardware::secure_element::V1_1::ISecureElementHalCallback> + VirtualISO::mCallbackV1_1 = nullptr; +std::vector<bool> VirtualISO::mOpenedChannels; + +VirtualISO::VirtualISO() + : mMaxChannelCount(0), mOpenedchannelCount(0), mIsEseInitialized(false) {} + +Return<void> VirtualISO::init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + LOG(INFO) << "Virtual ISO::init Enter"; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } +#ifdef NXP_BOOTTIME_UPDATE + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_0 = clientCallback; + clientCallback->onStateChange(false); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setVirtualISOCallBack(clientCallback); + return Void(); + // Register + } +#endif + if (mIsEseInitialized) { + clientCallback->onStateChange(true); + return Void(); + } + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + LOG(INFO) << "VISO init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange(true); + } else { + LOG(ERROR) << "VISO-Hal Init failed"; + clientCallback->onStateChange(false); + } + return Void(); +} + +Return<void> VirtualISO::init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsInitDone = false; + phNxpEse_initParams initParams; + LOG(INFO) << "Virtual ISO::init Enter"; + gsTxRxBuffer.pRspDataBuff = &gsRspDataBuff; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (clientCallback == nullptr) { + return Void(); + } else { + clientCallback->linkToDeath(this, 0 /*cookie*/); + } +#ifdef NXP_BOOTTIME_UPDATE + if (ese_update != ESE_UPDATE_COMPLETED) { + mCallbackV1_1 = clientCallback; + clientCallback->onStateChange_1_1(false, "NXP SE update going on"); + LOG(INFO) << "ESE JCOP Download in progress"; + NxpEse::setVirtualISOCallBack_1_1(clientCallback); + return Void(); + // Register + } +#endif + if (mIsEseInitialized) { + clientCallback->onStateChange_1_1(true, "NXP VISIO HAL init ok"); + return Void(); + } + status = phNxpEse_open(initParams); + if (status == ESESTATUS_SUCCESS || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + LOG(INFO) << "VISO init complete!!!"; + mIsInitDone = true; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsInitDone = false; + } + status = phNxpEse_close(deInitStatus); + } + if (status == ESESTATUS_SUCCESS && mIsInitDone) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + clientCallback->onStateChange_1_1(true, "NXP VISIO HAL init ok"); + } else { + LOG(ERROR) << "VISO-Hal Init failed"; + clientCallback->onStateChange_1_1(false, "NXP VISIO HAL init failed"); + } + return Void(); +} + +Return<void> VirtualISO::getAtr(getAtr_cb _hidl_cb) { + hidl_vec<uint8_t> response; + _hidl_cb(response); + return Void(); +} + +Return<bool> VirtualISO::isCardPresent() { return true; } + +Return<void> VirtualISO::transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_FAILED; + hidl_vec<uint8_t> result; + phNxpEse_memset(&gsTxRxBuffer.cmdData, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&gsTxRxBuffer.rspData, 0x00, sizeof(phNxpEse_data)); + gsTxRxBuffer.cmdData.len = data.size(); + gsTxRxBuffer.cmdData.p_data = + (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t)); + if (NULL == gsTxRxBuffer.cmdData.p_data) { + LOG(ERROR) << "transmit failed to allocate the Memory!!!"; + /*Return empty hidl_vec*/ + _hidl_cb(result); + return Void(); + } + memcpy(gsTxRxBuffer.cmdData.p_data, data.data(), gsTxRxBuffer.cmdData.len); + LOG(ERROR) << "Acquired the lock in VISO "; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&gsTxRxBuffer.cmdData, &gsTxRxBuffer.rspData); + + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "transmit failed!!!"; + } else { + result.resize(gsTxRxBuffer.rspData.len); + memcpy(&result[0], gsTxRxBuffer.rspData.p_data, gsTxRxBuffer.rspData.len); + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + + _hidl_cb(result); + if (NULL != gsTxRxBuffer.cmdData.p_data) { + phNxpEse_free(gsTxRxBuffer.cmdData.p_data); + gsTxRxBuffer.cmdData.p_data = NULL; + } + if (NULL != gsTxRxBuffer.rspData.p_data) { + phNxpEse_free(gsTxRxBuffer.rspData.p_data); + gsTxRxBuffer.rspData.p_data = NULL; + } + + return Void(); +} + +Return<void> VirtualISO::openLogicalChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openLogicalChannel_cb _hidl_cb) { + hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01}; + + LogicalChannelResponse resApduBuff; + + LOG(INFO) << "Acquired the lock in VISO openLogicalChannel"; + + resApduBuff.channelNumber = 0xff; + memset(&resApduBuff, 0x00, sizeof(resApduBuff)); + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + } + + if (mOpenedChannels.size() == 0x00) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + } + + SecureElementStatus sestatus = SecureElementStatus::IOERROR; + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_data cmdApdu; + phNxpEse_data rspApdu; + + phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data)); + + cmdApdu.len = manageChannelCommand.size(); + cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() * + sizeof(uint8_t)); + memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len); + + memset(&sestatus, 0x00, sizeof(sestatus)); + + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_Transceive(&cmdApdu, &rspApdu); + if (status != ESESTATUS_SUCCESS) { + resApduBuff.channelNumber = 0xff; + if (NULL != rspApdu.p_data && rspApdu.len > 0) { + if ((rspApdu.p_data[0] == 0x64 && rspApdu.p_data[1] == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } + } + if (SecureElementStatus::IOERROR != sestatus) { + sestatus = SecureElementStatus::FAILED; + } + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A && + rspApdu.p_data[rspApdu.len - 1] == 0x81) { + resApduBuff.channelNumber = 0xff; + sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE; + } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + resApduBuff.channelNumber = rspApdu.p_data[0]; + mOpenedchannelCount++; + mOpenedChannels[resApduBuff.channelNumber] = true; + sestatus = SecureElementStatus::SUCCESS; + } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) || + (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) && + rspApdu.p_data[rspApdu.len - 1] == 0x00) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } + + /*Free the allocations*/ + phNxpEse_free(cmdApdu.p_data); + phNxpEse_free(rspApdu.p_data); + + if (sestatus != SecureElementStatus::SUCCESS) { + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + if (sestatus != SecureElementStatus::SUCCESS) { + LOG(INFO) << "seDeInit Failed"; + } + } + /*If manageChanle is failed in any of above cases + send the callback and return*/ + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + return Void(); + } + LOG(INFO) << "openLogicalChannel Sending selectApdu"; + sestatus = SecureElementStatus::IOERROR; + status = ESESTATUS_FAILED; + + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + if ((resApduBuff.channelNumber > 0x03) && + (resApduBuff.channelNumber < 0x14)) { + /* update CLA byte accoridng to GP spec Table 11-12*/ + cpdu.cla = + 0x40 + (resApduBuff.channelNumber - 4); /* Class of instruction */ + } else if ((resApduBuff.channelNumber > 0x00) && + (resApduBuff.channelNumber < 0x04)) { + /* update CLA byte accoridng to GP spec Table 11-11*/ + cpdu.cla = resApduBuff.channelNumber; /* Class of instruction */ + } else { + LOG(ERROR) << StringPrintf("%s: Invalid Channel no: %02x", __func__, + resApduBuff.channelNumber); + resApduBuff.channelNumber = 0xff; + _hidl_cb(resApduBuff, SecureElementStatus::IOERROR); + return Void(); + } + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + if (status != ESESTATUS_SUCCESS) { + /*Transceive failed*/ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + resApduBuff.selectResponse.resize(responseLen); + memcpy(&resApduBuff.selectResponse[0], rpdu.pdata, rpdu.len); + resApduBuff.selectResponse[responseLen - 1] = rpdu.sw2; + resApduBuff.selectResponse[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if (rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) { + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(resApduBuff.channelNumber); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } else { + resApduBuff.channelNumber = 0xff; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + _hidl_cb(resApduBuff, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + + return Void(); +} + +Return<void> VirtualISO::openBasicChannel(const hidl_vec<uint8_t>& aid, + uint8_t p2, + openBasicChannel_cb _hidl_cb) { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + hidl_vec<uint8_t> result; + + LOG(INFO) << "Acquired the lock in VISO openBasicChannel"; + + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + _hidl_cb(result, SecureElementStatus::IOERROR); + return Void(); + } + } + + if (mOpenedChannels.size() == 0x00) { + mMaxChannelCount = (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + } + + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + + cpdu.cla = 0x00; /* Class of instruction */ + cpdu.ins = 0xA4; /* Instruction code */ + cpdu.p1 = 0x04; /* Instruction parameter 1 */ + cpdu.p2 = p2; /* Instruction parameter 2 */ + cpdu.lc = aid.size(); + cpdu.le_type = 0x01; + cpdu.pdata = (uint8_t*)phNxpEse_memalloc(aid.size() * sizeof(uint8_t)); + memcpy(cpdu.pdata, aid.data(), cpdu.lc); + cpdu.le = 256; + + rpdu.len = 0x02; + rpdu.pdata = (uint8_t*)phNxpEse_memalloc(cpdu.le * sizeof(uint8_t)); + + status = phNxpEse_SetEndPoint_Cntxt(1); + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + SecureElementStatus sestatus; + memset(&sestatus, 0x00, sizeof(sestatus)); + + if (status != ESESTATUS_SUCCESS) { + /* Transceive failed */ + if (rpdu.len > 0 && (rpdu.sw1 == 0x64 && rpdu.sw2 == 0xFF)) { + sestatus = SecureElementStatus::IOERROR; + } else { + sestatus = SecureElementStatus::FAILED; + } + } else { + /*Status word to be passed as part of response + So include additional length*/ + uint16_t responseLen = rpdu.len + 2; + result.resize(responseLen); + memcpy(&result[0], rpdu.pdata, rpdu.len); + result[responseLen - 1] = rpdu.sw2; + result[responseLen - 2] = rpdu.sw1; + + /*Status is success*/ + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + /*Set basic channel reference if it is not set */ + if (!mOpenedChannels[0]) { + mOpenedChannels[0] = true; + mOpenedchannelCount++; + } + + sestatus = SecureElementStatus::SUCCESS; + } + /*AID provided doesn't match any applet on the secure element*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x82) { + sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR; + } + /*Operation provided by the P2 parameter is not permitted by the applet.*/ + else if (rpdu.sw1 == 0x6A && rpdu.sw2 == 0x86) { + sestatus = SecureElementStatus::UNSUPPORTED_OPERATION; + } else { + sestatus = SecureElementStatus::FAILED; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (sestatus != SecureElementStatus::SUCCESS) { + SecureElementStatus closeChannelStatus = + internalCloseChannel(DEFAULT_BASIC_CHANNEL); + if (closeChannelStatus != SecureElementStatus::SUCCESS) { + LOG(ERROR) << "%s: closeChannel Failed" << __func__; + } + } + _hidl_cb(result, sestatus); + phNxpEse_free(cpdu.pdata); + phNxpEse_free(rpdu.pdata); + return Void(); +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::internalCloseChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(ERROR) << "internalCloseChannel Enter"; + LOG(INFO) << StringPrintf("mMaxChannelCount = %d, Closing Channel = %d", + mMaxChannelCount, channelNumber); + if ((int8_t)channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d", channelNumber); + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status == ESESTATUS_SUCCESS) { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + } + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::closeChannel(uint8_t channelNumber) { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + phNxpEse_7816_cpdu_t cpdu; + phNxpEse_7816_rpdu_t rpdu; + + LOG(INFO) << "Acquired the lock in VISO closeChannel"; + if ((int8_t)channelNumber < DEFAULT_BASIC_CHANNEL || + channelNumber >= mMaxChannelCount) { + LOG(ERROR) << StringPrintf("invalid channel!!! %d", channelNumber); + } else if (channelNumber > DEFAULT_BASIC_CHANNEL) { + phNxpEse_memset(&cpdu, 0x00, sizeof(phNxpEse_7816_cpdu_t)); + phNxpEse_memset(&rpdu, 0x00, sizeof(phNxpEse_7816_rpdu_t)); + cpdu.cla = channelNumber; /* Class of instruction */ + cpdu.ins = 0x70; /* Instruction code */ + cpdu.p1 = 0x80; /* Instruction parameter 1 */ + cpdu.p2 = channelNumber; /* Instruction parameter 2 */ + cpdu.lc = 0x00; + cpdu.le = 0x9000; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + status = phNxpEse_7816_Transceive(&cpdu, &rpdu); + + if (status == ESESTATUS_SUCCESS) { + if ((rpdu.sw1 == 0x90) && (rpdu.sw2 == 0x00)) { + sestatus = SecureElementStatus::SUCCESS; + } + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + } + if (mOpenedChannels[channelNumber]) { + mOpenedChannels[channelNumber] = false; + mOpenedchannelCount--; + } + } + + /*If there are no channels remaining close secureElement*/ + if (mOpenedchannelCount == 0) { + sestatus = seHalDeInit(); + } else { + sestatus = SecureElementStatus::SUCCESS; + } + return sestatus; +} +ESESTATUS VirtualISO::seHalInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + status = phNxpEse_open(initParams); + if (ESESTATUS_SUCCESS == status || ESESTATUS_BUSY == status) { + if (ESESTATUS_SUCCESS == phNxpEse_SetEndPoint_Cntxt(1) && + ESESTATUS_SUCCESS == phNxpEse_init(initParams)) { + if (ESESTATUS_SUCCESS == phNxpEse_ResetEndPoint_Cntxt(1)) { + mIsEseInitialized = true; + LOG(INFO) << "VISO init complete!!!"; + return ESESTATUS_SUCCESS; + } + deInitStatus = phNxpEse_deInit(); + } + phNxpEse_close(deInitStatus); + mIsEseInitialized = false; + } + return status; +} + +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::seHalDeInit() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + bool mIsDeInitDone = true; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + deInitStatus = phNxpEse_deInit(); + if (ESESTATUS_SUCCESS != deInitStatus) mIsDeInitDone = false; + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "phNxpEse_SetEndPoint_Cntxt failed!!!"; + mIsDeInitDone = false; + } + status = phNxpEse_close(deInitStatus); + if (status == ESESTATUS_SUCCESS && mIsDeInitDone) { + sestatus = SecureElementStatus::SUCCESS; + ; + } else { + LOG(ERROR) << "seHalDeInit: Failed"; + } + // Clear all the flags as SPI driver is closed. + mIsEseInitialized = false; + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + return sestatus; +} +Return<::android::hardware::secure_element::V1_0::SecureElementStatus> +VirtualISO::reset() { + ESESTATUS status = ESESTATUS_SUCCESS; + SecureElementStatus sestatus = SecureElementStatus::FAILED; + LOG(ERROR) << "%s: Enter" << __func__; + if (!mIsEseInitialized) { + ESESTATUS status = seHalInit(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: seHalInit Failed!!!" << __func__; + } + } + if (status == ESESTATUS_SUCCESS) { + mCallbackV1_1->onStateChange_1_1(false, "reset the SE"); + status = phNxpEse_reset(); + if (status != ESESTATUS_SUCCESS) { + LOG(ERROR) << "%s: SecureElement reset failed!!" << __func__; + } else { + sestatus = SecureElementStatus::SUCCESS; + if (mOpenedChannels.size() == 0x00) { + mMaxChannelCount = + (GET_CHIP_OS_VERSION() >= OS_VERSION_6_2) ? 0x0C : 0x04; + mOpenedChannels.resize(mMaxChannelCount, false); + } + for (uint8_t xx = 0; xx < mMaxChannelCount; xx++) { + mOpenedChannels[xx] = false; + } + mOpenedchannelCount = 0; + mCallbackV1_1->onStateChange_1_1(true, "SE initialized"); + } + } + LOG(ERROR) << "%s: Exit" << __func__; + return sestatus; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace virtual_iso +} // namespace nxp +} // namespace vendor diff --git a/snxxx/1.2/VirtualISO.h b/snxxx/1.2/VirtualISO.h new file mode 100755 index 0000000..b664fa0 --- /dev/null +++ b/snxxx/1.2/VirtualISO.h @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H +#define VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H + +#include <android-base/stringprintf.h> +#include <android/hardware/secure_element/1.0/types.h> +#include <android/hardware/secure_element/1.2/ISecureElement.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include "phNxpEse_Api.h" + +namespace vendor { +namespace nxp { +namespace virtual_iso { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using ::android::wp; +using android::base::StringPrintf; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_death_recipient; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_0::LogicalChannelResponse; +using ::android::hardware::secure_element::V1_0::SecureElementStatus; +using ::android::hardware::secure_element::V1_2::ISecureElement; +using ::android::hidl::base::V1_0::IBase; + +#ifndef DEFAULT_BASIC_CHANNEL +#define DEFAULT_BASIC_CHANNEL 0x00 +#endif + +struct VirtualISO : public ISecureElement, public hidl_death_recipient { + VirtualISO(); + Return<void> init( + const sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback>& + clientCallback) override; + Return<void> init_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) override; + Return<void> getAtr(getAtr_cb _hidl_cb) override; + Return<bool> isCardPresent() override; + Return<void> transmit(const hidl_vec<uint8_t>& data, + transmit_cb _hidl_cb) override; + Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openLogicalChannel_cb _hidl_cb) override; + Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2, + openBasicChannel_cb _hidl_cb) override; + Return<SecureElementStatus> closeChannel(uint8_t channelNumber) override; + Return<::android::hardware::secure_element::V1_0::SecureElementStatus> + reset(); + virtual void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) { + // TODO: Implement graceful closure, to close ongoing tx-rx and deinit + // T=1 stack + // close(0); + } + + private: + uint8_t mMaxChannelCount; + uint8_t mOpenedchannelCount = 0; + bool mIsEseInitialized = false; + static std::vector<bool> mOpenedChannels; + static sp< + ::android::hardware::secure_element::V1_0::ISecureElementHalCallback> + mCallbackV1_0; + static sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback> + mCallbackV1_1; + Return<SecureElementStatus> seHalDeInit(); + ESESTATUS seHalInit(); + Return<SecureElementStatus> internalCloseChannel(uint8_t channelNumber); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace virtual_iso +} // namespace nxp +} // namespace vendor + +#endif // VENDOR_NXP_VIRTUAL_ISO_V1_0_SECUREELEMENT_H diff --git a/snxxx/1.2/android.hardware.secure_element_snxxx@1.2-service.rc b/snxxx/1.2/android.hardware.secure_element_snxxx@1.2-service.rc new file mode 100755 index 0000000..3625cce --- /dev/null +++ b/snxxx/1.2/android.hardware.secure_element_snxxx@1.2-service.rc @@ -0,0 +1,4 @@ +service vendor.secure_element_hal_service /vendor/bin/hw/android.hardware.secure_element_snxxx@1.2-service + class hal + user secure_element + group secure_element diff --git a/snxxx/Android.bp b/snxxx/Android.bp new file mode 100755 index 0000000..c7cd477 --- /dev/null +++ b/snxxx/Android.bp @@ -0,0 +1,64 @@ + +cc_binary { + relative_install_path: "hw", + name: "android.hardware.secure_element_snxxx@1.2-service", + init_rc: ["1.2/android.hardware.secure_element_snxxx@1.2-service.rc"], + proprietary: true, + defaults: ["hidl_defaults"], + srcs: [ + "1.2/NxpEseService.cpp", + "1.2/SecureElement.cpp", + "1.2/VirtualISO.cpp", + "extns/impl/NxpEse.cpp", + "1.2/OsuHal/src/OsuHalExtn.cpp", + ], + + shared_libs: [ + "android.hardware.secure_element@1.0", + "android.hardware.secure_element@1.1", + "android.hardware.secure_element@1.2", + "ese_spi_nxp_snxxx", + "libbase", + "libcutils", + "libdl", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + "libchrome", + "vendor.nxp.nxpese@1.0", + "vendor.nxp.nxpnfc@2.0", + "android.hardware.nfc@1.0", + "android.hardware.nfc@1.1", + ], + + local_include_dirs: [ + "libese-spi/common/include", + "libese-spi/p73/common", + "libese-spi/p73/inc", + "libese-spi/p73/lib", + "libese-spi/p73/pal", + "libese-spi/p73/pal/spi", + "libese-spi/p73/utils", + "libese-spi/p73/spm", + "libese-spi/src/include", + "1.2/OsuHal/inc", + "extns/impl", + ], + + cflags: [ + "-DANDROID", + "-DJCOP_VER_3_1=1", + "-DJCOP_VER_3_2=2", + "-DJCOP_VER_3_3=3", + "-DJCOP_VER_4_0=4", + "-DJCOP_VER_5_x=5", + "-DBUILDCFG=1", + "-DNXP_EXTNS=TRUE", + "-DNFC_NXP_ESE_VER=JCOP_VER_5_x", + "-Wall", + "-Werror", + "-fexceptions", + ], + +} diff --git a/snxxx/ese-clients/inc/eSEClient.h b/snxxx/ese-clients/inc/eSEClient.h new file mode 100644 index 0000000..425cada --- /dev/null +++ b/snxxx/ese-clients/inc/eSEClient.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * + * Copyright 2018-2020 NXP + * + * 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 <android/hardware/secure_element/1.0/ISecureElementHalCallback.h> +#include "../../../secure_element_extns/inc/eSEClientIntf.h" +#include "phNxpEse_Api.h" + +#ifndef ESE_UPDATE_2_H_ +#define ESE_UPDATE_2_H_ + +extern ese_update_state_t ese_update; +using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback; + +void checkEseClientUpdate(); + +SESTATUS perform_eSEClientUpdate(); + +void eSEClientUpdate_SE_Thread(); + +void seteSEClientState(uint8_t state); +typedef enum { + ESE = 0, + EUICC = 1, +} SEDomainID; + +#endif /* ESE_UPDATE_2_H_ */ diff --git a/snxxx/ese-clients/src/eSEClient.cpp b/snxxx/ese-clients/src/eSEClient.cpp new file mode 100644 index 0000000..f87e80c --- /dev/null +++ b/snxxx/ese-clients/src/eSEClient.cpp @@ -0,0 +1,484 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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 "eSEClient.h" +#include <IChannel.h> +#include <JcDnld.h> +#include <LsClient.h> +#include <dirent.h> +#include <ese_config.h> +#include <log/log.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <vendor/nxp/nxpnfc/2.0/INxpNfc.h> +#include "NfcAdaptation.h" +#include "NxpEse.h" +#include "hal_nxpese.h" +#include "phNxpEse_Apdu_Api.h" +#include "phNxpEse_Spm.h" + +using android::sp; +using android::hardware::hidl_vec; +using android::hardware::Void; +using vendor::nxp::nxpese::V1_0::implementation::NxpEse; +using vendor::nxp::nxpnfc::V2_0::INxpNfc; +sp<INxpNfc> mHalNxpNfc = nullptr; + +void seteSEClientState(uint8_t state); + +IChannel_t Ch; +se_extns_entry se_intf; +void* eSEClientUpdate_ThreadHandler(void* data); +void* eSEClientUpdate_Thread(void* data); +void* eSEUpdate_SE_SeqHandler(void* data); +void eSEClientUpdate_Thread(); +SESTATUS ESE_ChannelInit(IChannel* ch); +SESTATUS handleJcopOsDownload(); +void* LSUpdate_Thread(void* data); +uint8_t performLSUpdate(); +SESTATUS initializeEse(phNxpEse_initMode mode, SEDomainID Id); +ese_update_state_t ese_update = ESE_UPDATE_COMPLETED; +SESTATUS eSEUpdate_SeqHandler(); +int16_t SE_Open() { return SESTATUS_SUCCESS; } + +void SE_Reset() { phNxpEse_coldReset(); } + +bool SE_Transmit(uint8_t* xmitBuffer, int32_t xmitBufferSize, + uint8_t* recvBuffer, int32_t recvBufferMaxSize, + int32_t& recvBufferActualSize, int32_t timeoutMillisec) { + phNxpEse_data cmdData; + phNxpEse_data rspData; + + cmdData.len = xmitBufferSize; + cmdData.p_data = xmitBuffer; + + recvBufferMaxSize++; + timeoutMillisec++; + if (phNxpEse_Transceive(&cmdData, &rspData) != ESESTATUS_SUCCESS) { + ALOGE("%s: Ese Transceive failed", __FUNCTION__); + } + recvBufferActualSize = rspData.len; + + if (rspData.p_data != NULL && rspData.len) { + memcpy(&recvBuffer[0], rspData.p_data, rspData.len); + } + + ALOGE("%s: size = 0x%x ", __FUNCTION__, recvBufferActualSize); + return true; +} + +void SE_JcopDownLoadReset() { phNxpEse_resetJcopUpdate(); } + +bool SE_Close(int16_t mHandle) { + if (mHandle != 0) + return true; + else + return false; +} +uint8_t SE_getInterfaceInfo() { return INTF_SE; } + +/*************************************************************************** +** +** Function: checkEseClientUpdate +** +** Description: Check the initial condition + and interafce for eSE Client update for LS and JCOP download +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +void checkEseClientUpdate() { + ALOGD("%s enter: ", __func__); + checkeSEClientRequired(ESE_INTF_SPI); + se_intf.isJcopUpdateRequired = getJcopUpdateRequired(); + se_intf.isLSUpdateRequired = getLsUpdateRequired(); + se_intf.sJcopUpdateIntferface = getJcopUpdateIntf(); + se_intf.sLsUpdateIntferface = getLsUpdateIntf(); + if ((se_intf.isJcopUpdateRequired && se_intf.sJcopUpdateIntferface) || + (se_intf.isLSUpdateRequired && se_intf.sLsUpdateIntferface)) + seteSEClientState(ESE_UPDATE_STARTED); +} + +/*************************************************************************** +** +** Function: perform_eSEClientUpdate +** +** Description: Perform LS and JCOP download during hal service init +** +** Returns: SUCCESS / SESTATUS_FAILED +** +*******************************************************************************/ +SESTATUS perform_eSEClientUpdate() { + ALOGD("%s enter: ", __func__); + + eSEClientUpdate_Thread(); + return SESTATUS_SUCCESS; +} + +SESTATUS ESE_ChannelInit(IChannel* ch) { + ch->open = SE_Open; + ch->close = SE_Close; + ch->transceive = SE_Transmit; + ch->transceiveRaw = SE_Transmit; + ch->doeSE_Reset = SE_Reset; + ch->doeSE_JcopDownLoadReset = SE_JcopDownLoadReset; + ch->getInterfaceInfo = SE_getInterfaceInfo; + return SESTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function: eSEClientUpdate_Thread +** +** Description: Perform eSE update +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +void eSEClientUpdate_Thread() { + SESTATUS status = SESTATUS_FAILED; + pthread_t thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&thread, &attr, &eSEClientUpdate_ThreadHandler, NULL) != + 0) { + ALOGD("Thread creation failed"); + status = SESTATUS_FAILED; + } else { + status = SESTATUS_SUCCESS; + ALOGD("Thread creation success"); + } + pthread_attr_destroy(&attr); +} +/******************************************************************************* +** +** Function: eSEClientUpdate_Thread +** +** Description: Perform eSE update +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +void eSEClientUpdate_SE_Thread() { + SESTATUS status = SESTATUS_FAILED; + pthread_t thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&thread, &attr, &eSEUpdate_SE_SeqHandler, NULL) != 0) { + ALOGD("Thread creation failed"); + status = SESTATUS_FAILED; + } else { + status = SESTATUS_SUCCESS; + ALOGD("Thread creation success"); + } + pthread_attr_destroy(&attr); +} +/******************************************************************************* +** +** Function: eSEClientUpdate_ThreadHandler +** +** Description: Perform JCOP Download +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +void* eSEUpdate_SE_SeqHandler(void* data) { + (void)data; + ALOGD("%s Enter\n", __func__); + eSEUpdate_SeqHandler(); + ALOGD("%s Exit eSEUpdate_SE_SeqHandler\n", __func__); + return NULL; +} +/******************************************************************************* +** +** Function: eSEClientUpdate_ThreadHandler +** +** Description: Perform JCOP Download +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +void* eSEClientUpdate_ThreadHandler(void* data) { + (void)data; + int cnt = 0; + + ALOGD("%s Enter\n", __func__); + while (((mHalNxpNfc == nullptr) && (cnt < 3))) { + mHalNxpNfc = INxpNfc::tryGetService(); + if (mHalNxpNfc == nullptr) ALOGD(": Failed to retrieve the NXP NFC HAL!"); + if (mHalNxpNfc != nullptr) { + ALOGD("INxpNfc::getService() returned %p (%s)", mHalNxpNfc.get(), + (mHalNxpNfc->isRemote() ? "remote" : "local")); + } + usleep(100 * 1000); + cnt++; + } + + if (mHalNxpNfc != nullptr) { + if (!se_intf.isJcopUpdateRequired && mHalNxpNfc->isJcopUpdateRequired()) { + se_intf.isJcopUpdateRequired = true; + ALOGD(" se_intf.isJcopUpdateRequired = %d", se_intf.isJcopUpdateRequired); + } + if (!se_intf.isLSUpdateRequired && mHalNxpNfc->isLsUpdateRequired()) { + se_intf.isLSUpdateRequired = true; + ALOGD("se_intf.isLSUpdateRequired = %d", se_intf.isLSUpdateRequired); + } + } + + if (se_intf.isJcopUpdateRequired) { + if (se_intf.sJcopUpdateIntferface == ESE_INTF_NFC) { + seteSEClientState(ESE_JCOP_UPDATE_REQUIRED); + return NULL; + } else if (se_intf.sJcopUpdateIntferface == ESE_INTF_SPI) { + seteSEClientState(ESE_JCOP_UPDATE_REQUIRED); + } + } + + if ((ESE_JCOP_UPDATE_REQUIRED != ese_update) && + (se_intf.isLSUpdateRequired)) { + if (se_intf.sLsUpdateIntferface == ESE_INTF_NFC) { + seteSEClientState(ESE_LS_UPDATE_REQUIRED); + return NULL; + } else if (se_intf.sLsUpdateIntferface == ESE_INTF_SPI) { + seteSEClientState(ESE_LS_UPDATE_REQUIRED); + } + } + + if ((ese_update == ESE_JCOP_UPDATE_REQUIRED) || + (ese_update == ESE_LS_UPDATE_REQUIRED)) + eSEUpdate_SeqHandler(); + + ALOGD("%s Exit eSEClientUpdate_Thread\n", __func__); + return NULL; +} + +/******************************************************************************* +** +** Function: handleJcopOsDownload +** +** Description: Perform JCOP update +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +SESTATUS handleJcopOsDownload() { + SESTATUS status = SESTATUS_FAILED; + uint8_t retstat; + status = initializeEse(ESE_MODE_OSU, ESE); + if (status == SESTATUS_SUCCESS) { + retstat = JCDNLD_Init(&Ch); + if (retstat != STATUS_SUCCESS) { + ALOGE("%s: JCDND initialization failed", __FUNCTION__); + if (phNxpEse_ResetEndPoint_Cntxt(0) != ESESTATUS_SUCCESS) { + ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__); + } + phNxpEse_close(ESESTATUS_SUCCESS); + return status; + } else { + retstat = JCDNLD_StartDownload(); + if (retstat != SESTATUS_SUCCESS) { + ALOGE("%s: JCDNLD_StartDownload failed", __FUNCTION__); + } + } + JCDNLD_DeInit(); + if (phNxpEse_ResetEndPoint_Cntxt(0) != ESESTATUS_SUCCESS) { + ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__); + } + phNxpEse_close(ESESTATUS_SUCCESS); + } + status = SESTATUS_SUCCESS; + return status; +} + +/******************************************************************************* +** +** Function: performLSUpdate +** +** Description: Perform LS update +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +uint8_t performLSUpdate() { + const char* SEterminal = "eSEx"; + bool ret = false; + char terminalID[5]; + uint8_t status = SESTATUS_FAILED; + bool isSEPresent = false; + bool isVISOPresent = false; + ret = geteSETerminalId(terminalID); + ALOGI("performLSUpdate Terminal val = %s", terminalID); + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + isSEPresent = true; + } + ret = geteUICCTerminalId(terminalID); + if ((ret) && (strncmp(SEterminal, terminalID, 3) == 0)) { + isVISOPresent = true; + } + seteSEClientState(ESE_UPDATE_STARTED); + if (isSEPresent) { + ALOGE("%s:On eSE domain ", __FUNCTION__); + status = initializeEse(ESE_MODE_NORMAL, ESE); + ALOGE("%s:On eSE domain ", __FUNCTION__); + if (status == SESTATUS_SUCCESS) { + status = performLSDownload(&Ch); + if (phNxpEse_ResetEndPoint_Cntxt(ESE) != ESESTATUS_SUCCESS) { + ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__); + } + } + phNxpEse_close(ESESTATUS_SUCCESS); + } + if (isVISOPresent) { + ALOGE("%s:On eUICC domain ", __FUNCTION__); + status = initializeEse(ESE_MODE_NORMAL, EUICC); + if (status == SESTATUS_SUCCESS) { + status = performLSDownload(&Ch); + if (phNxpEse_ResetEndPoint_Cntxt(EUICC) != ESESTATUS_SUCCESS) { + ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__); + } + } + phNxpEse_close(ESESTATUS_SUCCESS); + } + return status; +} + +/******************************************************************************* +** +** Function: initializeEse +** +** Description: Open & Initialize libese +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +SESTATUS initializeEse(phNxpEse_initMode mode, SEDomainID Id) { + uint8_t retstat; + SESTATUS status = SESTATUS_FAILED; + phNxpEse_initParams initParams; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + + initParams.initMode = mode; + ALOGE("%s: Mode = %d", __FUNCTION__, mode); + retstat = phNxpEse_open(initParams); + if (retstat != ESESTATUS_SUCCESS) { + return status; + } + retstat = phNxpEse_SetEndPoint_Cntxt(Id); + if (retstat != ESESTATUS_SUCCESS) { + ALOGE("%s: Set SE EndPoint failed", __FUNCTION__); + } + retstat = phNxpEse_init(initParams); + if (retstat != ESESTATUS_SUCCESS) { + if (phNxpEse_ResetEndPoint_Cntxt(Id) != ESESTATUS_SUCCESS) { + ALOGE("%s: Reset SE EndPoint failed", __FUNCTION__); + } + phNxpEse_close(ESESTATUS_SUCCESS); + return status; + } + ESE_ChannelInit(&Ch); + status = SESTATUS_SUCCESS; + return status; +} + +/******************************************************************************* +** +** Function: seteSEClientState +** +** Description: Function to set the eSEUpdate state +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +void seteSEClientState(uint8_t state) { + ALOGE("%s: State = %d", __FUNCTION__, state); + ese_update = (ese_update_state_t)state; +} + +/******************************************************************************* +** +** Function: sendeSEUpdateState +** +** Description: Notify NFC HAL LS / JCOP download state +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +void sendeSEUpdateState(uint8_t state) { + ALOGE("%s: State = %d", __FUNCTION__, state); + phNxpEse_SPM_SetEseClientUpdateState(state); +} + +/******************************************************************************* +** +** Function: eSEUpdate_SeqHandler +** +** Description: ESE client update handler +** +** Returns: SUCCESS of ok +** +*******************************************************************************/ +SESTATUS eSEUpdate_SeqHandler() { + switch (ese_update) { + case ESE_UPDATE_STARTED: + break; + case ESE_JCOP_UPDATE_REQUIRED: + ALOGE("%s: ESE_JCOP_UPDATE_REQUIRED", __FUNCTION__); + if (se_intf.isJcopUpdateRequired) { + if (se_intf.sJcopUpdateIntferface == ESE_INTF_SPI) { + handleJcopOsDownload(); + sendeSEUpdateState(ESE_JCOP_UPDATE_COMPLETED); + setJcopUpdateRequired(false); + } else if (se_intf.sJcopUpdateIntferface == ESE_INTF_NFC) { + return SESTATUS_SUCCESS; + } + } + [[fallthrough]]; + case ESE_JCOP_UPDATE_COMPLETED: + ALOGE("%s: ESE_JCOP_UPDATE_COMPLETED", __FUNCTION__); + [[fallthrough]]; + case ESE_LS_UPDATE_REQUIRED: + if (se_intf.isLSUpdateRequired) { + if (se_intf.sLsUpdateIntferface == ESE_INTF_SPI) { + performLSUpdate(); + sendeSEUpdateState(ESE_LS_UPDATE_COMPLETED); + setLsUpdateRequired(false); + } else if (se_intf.sLsUpdateIntferface == ESE_INTF_NFC) { + seteSEClientState(ESE_LS_UPDATE_REQUIRED); + return SESTATUS_SUCCESS; + } + } + ALOGE("%s: ESE_LS_UPDATE_REQUIRED", __FUNCTION__); + [[fallthrough]]; + case ESE_LS_UPDATE_COMPLETED: + ALOGE("%s: ESE_LS_UPDATE_COMPLETED", __FUNCTION__); + [[fallthrough]]; + case ESE_UPDATE_COMPLETED: + seteSEClientState(ESE_UPDATE_COMPLETED); + sendeSEUpdateState(ESE_UPDATE_COMPLETED); + NxpEse::initSEService(); + NxpEse::initVIrtualISOService(); + ALOGE("%s: ESE_UPDATE_COMPLETED", __FUNCTION__); + break; + } + return SESTATUS_SUCCESS; +} diff --git a/snxxx/extns/impl/NxpEse.cpp b/snxxx/extns/impl/NxpEse.cpp new file mode 100755 index 0000000..c72d162 --- /dev/null +++ b/snxxx/extns/impl/NxpEse.cpp @@ -0,0 +1,224 @@ +/****************************************************************************** + * + * Copyright (C) 2018-2021 NXP Semiconductors + * + * 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 "NxpEse.h" +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include "phNxpEse_Api.h" +#ifdef NXP_BOOTTIME_UPDATE +#include "eSEClient.h" +#endif + +namespace vendor { +namespace nxp { +namespace nxpese { +namespace V1_0 { +namespace implementation { +using android::base::StringPrintf; +// using android::hardware::secure_element::V1_0::implementation::SecureElement; +static android::sp<ISecureElementHalCallback> seCallback; +static android::sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback> + seCallback_1_1; +static android::sp<ISecureElementHalCallback> virtualISOCallback; +static android::sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback> + virtualISOCallback_1_1; +bool isSeHalV1_1 = false; +// Methods from ::vendor::nxp::nxpese::V1_0::INxpEse follow. +Return<void> NxpEse::setSeCallBack( + const android::sp<ISecureElementHalCallback>& clientCallback) { + seCallback = clientCallback; + return Void(); +} + +Return<void> NxpEse::setSeCallBack_1_1( + const sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) { + seCallback_1_1 = clientCallback; + isSeHalV1_1 = true; + return Void(); +} + +Return<void> NxpEse::setVirtualISOCallBack( + const android::sp<ISecureElementHalCallback>& clientCallback) { + virtualISOCallback = clientCallback; + return Void(); +} + +Return<void> NxpEse::setVirtualISOCallBack_1_1( + const android::sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback) { + virtualISOCallback_1_1 = clientCallback; + isSeHalV1_1 = true; + return Void(); +} +void NxpEse::initSEService() { + ESESTATUS status = ESESTATUS_SUCCESS; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (!seCallback && !isSeHalV1_1) return; + + if (!seCallback_1_1 && isSeHalV1_1) return; + + status = phNxpEse_open(initParams); + if (status != ESESTATUS_SUCCESS) { + goto exit; + } + + status = phNxpEse_SetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + goto exit1; + } + status = phNxpEse_init(initParams); + if (status != ESESTATUS_SUCCESS) { + goto exit1; + } + status = phNxpEse_ResetEndPoint_Cntxt(0); + if (status != ESESTATUS_SUCCESS) { + goto exit2; + } + + LOG(INFO) << "ESE SPI init complete !!!"; +exit2: + deInitStatus = phNxpEse_deInit(); +exit1: + status = phNxpEse_close(deInitStatus); +exit: + if (status == ESESTATUS_SUCCESS) { + if (isSeHalV1_1) + seCallback_1_1->onStateChange_1_1(true, "NXP SE HAL init ok"); + else + seCallback->onStateChange(true); + } else { + LOG(ERROR) << "eSE-Hal Init failed"; + if (isSeHalV1_1) + seCallback_1_1->onStateChange_1_1(false, "NXP SE HAL init not ok"); + else + seCallback->onStateChange(false); + } +} + +void NxpEse::initVIrtualISOService() { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_initParams initParams; + ESESTATUS deInitStatus = ESESTATUS_SUCCESS; + memset(&initParams, 0x00, sizeof(phNxpEse_initParams)); + initParams.initMode = ESE_MODE_NORMAL; + initParams.mediaType = ESE_PROTOCOL_MEDIA_SPI_APDU_GATE; + + if (!virtualISOCallback && !isSeHalV1_1) return; + + if (!virtualISOCallback_1_1 && isSeHalV1_1) return; + + status = phNxpEse_SetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + goto exit1; + } + status = phNxpEse_init(initParams); + if (status != ESESTATUS_SUCCESS) { + goto exit1; + } + status = phNxpEse_ResetEndPoint_Cntxt(1); + if (status != ESESTATUS_SUCCESS) { + goto exit2; + } + + LOG(INFO) << "ESE SPI init complete !!!"; +exit2: + deInitStatus = phNxpEse_deInit(); +exit1: + status = phNxpEse_close(deInitStatus); + + if (status == ESESTATUS_SUCCESS) { + if (isSeHalV1_1) + virtualISOCallback_1_1->onStateChange_1_1(true, "NXP SE HAL init ok"); + else + virtualISOCallback->onStateChange(true); + } else { + LOG(ERROR) << "eSE-Hal Init failed"; + if (isSeHalV1_1) + virtualISOCallback_1_1->onStateChange_1_1(false, + "NXP SE HAL init not ok"); + else + virtualISOCallback->onStateChange(false); + } +} +#ifdef NXP_BOOTTIME_UPDATE +Return<void> NxpEse::ioctlHandler(uint64_t ioctlType, + ese_nxp_IoctlInOutData_t& inpOutData) { + switch (ioctlType) { + case HAL_ESE_IOCTL_NFC_JCOP_DWNLD: { + // nfc_nci_IoctlInOutData_t* inpOutData = + // (nfc_nci_IoctlInOutData_t*)inpOutData; + int update_state = inpOutData.inp.data.nxpCmd.p_cmd[0]; + if (update_state == ESE_JCOP_UPDATE_COMPLETED || + update_state == ESE_LS_UPDATE_COMPLETED) { + seteSEClientState(update_state); + eSEClientUpdate_SE_Thread(); + } + } break; + } + return Void(); +} +#endif + +Return<void> NxpEse::ioctl(uint64_t ioctlType, + const hidl_vec<uint8_t>& inOutData, + ioctl_cb _hidl_cb) { + ese_nxp_IoctlInOutData_t inpOutData; + ese_nxp_IoctlInOutData_t* pInOutData = + (ese_nxp_IoctlInOutData_t*)&inOutData[0]; + + /*data from proxy->stub is copied to local data which can be updated by + * underlying HAL implementation since it's an inout argument*/ + memcpy(&inpOutData, pInOutData, sizeof(ese_nxp_IoctlInOutData_t)); + ESESTATUS status = phNxpEse_spiIoctl(ioctlType, &inpOutData); +#ifdef NXP_BOOTTIME_UPDATE + ioctlHandler(ioctlType, inpOutData); +#endif + /*copy data and additional fields indicating status of ioctl operation + * and context of the caller. Then invoke the corresponding proxy callback*/ + inpOutData.out.ioctlType = ioctlType; + inpOutData.out.result = status; +#ifdef NXP_BOOTTIME_UPDATE + if (ioctlType == HAL_ESE_IOCTL_GET_ESE_UPDATE_STATE) { + inpOutData.out.data.status = + (getJcopUpdateRequired() | (getLsUpdateRequired() << 8)); + } +#endif + hidl_vec<uint8_t> outputData; + outputData.setToExternal((uint8_t*)&inpOutData.out, + sizeof(ese_nxp_ExtnOutputData_t)); + LOG(ERROR) << "GET ESE update state2 = " << inpOutData.out.data.status; + _hidl_cb(outputData); + return Void(); +} + +// Methods from ::android::hidl::base::V1_0::IBase follow. + +} // namespace implementation +} // namespace V1_0 +} // namespace nxpese +} // namespace nxp +} // namespace vendor diff --git a/snxxx/extns/impl/NxpEse.h b/snxxx/extns/impl/NxpEse.h new file mode 100755 index 0000000..8c4ec5f --- /dev/null +++ b/snxxx/extns/impl/NxpEse.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Copyright (C) 2018-2019 NXP Semiconductors + * + * 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. + * + ******************************************************************************/ +#ifndef VENDOR_NXP_NXPNFC_V1_0_NXPNFC_H +#define VENDOR_NXP_NXPNFC_V1_0_NXPNFC_H + +#include <android/hardware/secure_element/1.0/ISecureElementHalCallback.h> +#include <android/hardware/secure_element/1.1/ISecureElement.h> +#include <android/hardware/secure_element/1.1/ISecureElementHalCallback.h> +#include <hardware/hardware.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <vendor/nxp/nxpese/1.0/INxpEse.h> +#include "hal_nxpese.h" +namespace vendor { +namespace nxp { +namespace nxpese { +namespace V1_0 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback; +using ::android::hidl::base::V1_0::DebugInfo; +using ::android::hidl::base::V1_0::IBase; +using ::vendor::nxp::nxpese::V1_0::INxpEse; +struct NxpEse : public INxpEse { + Return<void> ioctl(uint64_t ioctlType, const hidl_vec<uint8_t>& inOutData, + ioctl_cb _hidl_cb) override; + static Return<void> setSeCallBack( + const android::sp<ISecureElementHalCallback>& clientCallback); + static Return<void> setSeCallBack_1_1( + const android::sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback); + static Return<void> setVirtualISOCallBack( + const android::sp<ISecureElementHalCallback>& clientCallback); + static Return<void> setVirtualISOCallBack_1_1( + const android::sp< + ::android::hardware::secure_element::V1_1::ISecureElementHalCallback>& + clientCallback); + static void initSEService(); + static void initVIrtualISOService(); + + private: + Return<void> ioctlHandler(uint64_t ioctlType, + ese_nxp_IoctlInOutData_t& inpOutData); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace nxpese +} // namespace nxp +} // namespace vendor + +#endif // VENDOR_NXP_NXPNFC_V1_0_NXPNFC_H diff --git a/snxxx/extns/impl/hal_nxpese.h b/snxxx/extns/impl/hal_nxpese.h new file mode 100755 index 0000000..e0a183c --- /dev/null +++ b/snxxx/extns/impl/hal_nxpese.h @@ -0,0 +1,169 @@ +/****************************************************************************** + * + * Copyright (C) 2018-2020 NXP Semiconductors + * + * 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. + * + ******************************************************************************/ +#ifndef ANDROID_HARDWARE_HAL_NXPESE_V1_0_H +#define ANDROID_HARDWARE_HAL_NXPESE_V1_0_H + +#define ESE_NXPNFC_HARDWARE_MODULE_ID "ese_nxp.pn54x" + +#define MAX_IOCTL_TRANSCEIVE_CMD_LEN 256 +#define MAX_IOCTL_TRANSCEIVE_RESP_LEN 256 +#define MAX_ATR_INFO_LEN 128 +#define HAL_NFC_IOCTL_FIRST_EVT 0xA0 +enum { + HAL_ESE_IOCTL_P61_IDLE_MODE = 0, + HAL_ESE_IOCTL_P61_WIRED_MODE, + HAL_ESE_IOCTL_P61_PWR_MODE, + HAL_ESE_IOCTL_P61_DISABLE_MODE, + HAL_ESE_IOCTL_P61_ENABLE_MODE, + HAL_ESE_IOCTL_SET_BOOT_MODE, + HAL_ESE_IOCTL_GET_CONFIG_INFO, + HAL_ESE_IOCTL_CHECK_FLASH_REQ, + HAL_ESE_IOCTL_FW_DWNLD, + HAL_ESE_IOCTL_FW_MW_VER_CHECK, + HAL_ESE_IOCTL_DISABLE_HAL_LOG, + HAL_ESE_IOCTL_NXP_TRANSCEIVE, + HAL_ESE_IOCTL_P61_GET_ACCESS, + HAL_ESE_IOCTL_P61_REL_ACCESS, + HAL_ESE_IOCTL_ESE_CHIP_RST, + HAL_ESE_IOCTL_REL_SVDD_WAIT, + HAL_ESE_IOCTL_SET_JCP_DWNLD_ENABLE, + HAL_ESE_IOCTL_SET_JCP_DWNLD_DISABLE, + HAL_ESE_IOCTL_SET_ESE_SERVICE_PID, + HAL_ESE_IOCTL_REL_DWP_WAIT, + HAL_ESE_IOCTL_GET_FEATURE_LIST, + HAL_ESE_IOCTL_RF_STATUS_UPDATE, + HAL_ESE_IOCTL_NFC_JCOP_DWNLD, +#if (NXP_EXTNS == TRUE) + HAL_ESE_IOCTL_GET_ESE_UPDATE_STATE, +#endif +}; + +/* + * Data structures provided below are used of Hal Ioctl calls + */ +/* + * ese_nxp_ExtnCmd_t shall contain data for commands used for transceive command + * in ioctl + */ +typedef struct { + uint16_t cmd_len; + uint8_t p_cmd[MAX_IOCTL_TRANSCEIVE_CMD_LEN]; +} ese_nxp_ExtnCmd_t; + +/* + * ese_nxp_ExtnRsp_t shall contain response for command sent in transceive + * command + */ +typedef struct { + uint16_t rsp_len; + uint8_t p_rsp[MAX_IOCTL_TRANSCEIVE_RESP_LEN]; +} ese_nxp_ExtnRsp_t; +/* + * InputData_t :ioctl has multiple subcommands + * Each command has corresponding input data which needs to be populated in this + */ +typedef union { + uint16_t bootMode; + uint8_t halType; + ese_nxp_ExtnCmd_t nxpCmd; + uint32_t timeoutMilliSec; + long eseServicePid; +} eseInputData_t; +/* + * ese_nxp_ExtnInputData_t :Apart from InputData_t, there are context data + * which is required during callback from stub to proxy. + * To avoid additional copy of data while propagating from libese to Adaptation + * and Esestub to nxphal, common structure is used. As a sideeffect, context + * data is exposed to libese (Not encapsulated). + */ +typedef struct { + /*context to be used/updated only by users of proxy & stub of Ese.hal + * i.e., EseAdaptation & hardware/interface/Ese. + */ + eseInputData_t data; + uint8_t data_source; + long level; +} ese_nxp_ExtnInputData_t; + +/* + * outputData_t :ioctl has multiple commands/responses + * This contains the output types for each ioctl. + */ +typedef union { + uint32_t status; + ese_nxp_ExtnRsp_t nxpRsp; + uint8_t nxpNciAtrInfo[MAX_ATR_INFO_LEN]; + uint32_t p61CurrentState; + uint16_t fwUpdateInf; + uint16_t fwDwnldStatus; + uint16_t fwMwVerStatus; + uint8_t chipType; +} eseOutputData_t; + +typedef union { + uint8_t nfc_jcop_download_state; +} eseIoctlData_t; +extern eseIoctlData_t eseioctldata; + +/* + * ese_nxp_ExtnOutputData_t :Apart from outputData_t, there are other + * information which is required during callback from stub to proxy. For ex + * (context, result of the operation , type of ioctl which was completed). To + * avoid additional copy of data while propagating from libese to Adaptation and + * Esestub to nxphal, common structure is used. As a sideeffect, these data is + * exposed(Not encapsulated). + */ +typedef struct { + /*ioctlType, result & context to be used/updated only by users of + * proxy & stub of Ese.hal. + * i.e., EseAdaptation & hardware/interface/Ese + * These fields shall not be used by libese or halimplementation*/ + uint64_t ioctlType; + uint32_t result; + eseOutputData_t data; +} ese_nxp_ExtnOutputData_t; + +/* + * ese_nxp_IoctlInOutData_t :data structure for input & output + * to be sent for ioctl command. input is populated by client/proxy side + * output is provided from server/stub to client/proxy + */ +typedef struct { + ese_nxp_ExtnInputData_t inp; + ese_nxp_ExtnOutputData_t out; +} ese_nxp_IoctlInOutData_t; + +/* + * nxpese_nxp_device_t :data structure for nxp's extended ese_nxp_device + * Extra features added are + * -ioctl(manage sync between and DWP & SPI) + * -check request for fw download + */ +typedef struct nxpese_nxp_device { + // ese_nxp_device_t nxp_device; + /* + * (*ioctl)() For P61 power management synchronization + * between ESE Wired and SPI. + */ + int (*ioctl)(const struct nxpese_nxp_device* p_dev, long arg, void* p_data); + /* + * (*check_fw_dwnld_flag)() Is called to get FW downlaod request. + */ +} nxpese_nxp_device_t; + +#endif // ANDROID_HARDWARE_HAL_NXPESE_V1_0_H diff --git a/snxxx/libese-spi/Android.bp b/snxxx/libese-spi/Android.bp new file mode 100755 index 0000000..e7c00ba --- /dev/null +++ b/snxxx/libese-spi/Android.bp @@ -0,0 +1,76 @@ +cc_library_shared { + + name: "ese_spi_nxp_snxxx", + defaults: ["hidl_defaults"], + proprietary: true, + + srcs: [ + "p73/lib/phNxpEseDataMgr.cpp", + "p73/lib/phNxpEseProto7816_3.cpp", + "p73/lib/phNxpEse_Apdu_Api.cpp", + "p73/lib/phNxpEse_Api.cpp", + "p73/pal/phNxpEsePal.cpp", + "p73/pal/EseTransportFactory.cpp", + "p73/pal/spi/EseSpiTransport.cpp", + "p73/spm/phNxpEse_Spm.cpp", + "p73/utils/ese_config.cpp", + "p73/utils/config.cpp", + "p73/utils/ringbuffer.cpp", + "src/adaptation/NfcAdaptation.cpp", + "src/adaptation/CondVar.cpp", + "src/adaptation/Mutex.cpp", + ], + + local_include_dirs: [ + "common/include", + "p73/common", + "p73/inc", + "p73/lib", + "p73/pal", + "p73/pal/spi", + "p73/utils", + "src/include", + ], + include_dirs: [ + "hardware/nxp/nfc/snxxx/extns/impl/nxpnfc/2.0", + "hardware/nxp/secure_element/snxxx/extns/impl", +], + + cflags: [ + "-DANDROID", + "-DJCOP_VER_3_1=1", + "-DJCOP_VER_3_2=2", + "-DJCOP_VER_3_3=3", + "-DJCOP_VER_4_0=4", + "-DJCOP_VER_5_x=5", + "-DBUILDCFG=1", + "-DNXP_EXTNS=TRUE", + "-DNFC_NXP_ESE_VER=JCOP_VER_5_x", + "-Wall", + "-Werror", + ], + + shared_libs: [ + "android.hardware.nfc@1.0", + "android.hardware.nfc@1.1", + "android.hardware.secure_element@1.0", + "libcutils", + "libhardware", + "libhidlbase", + "libutils", + "liblog", + "libbase", + "libchrome", + "vendor.nxp.nxpese@1.0", + "vendor.nxp.nxpnfc@2.0", + ], + + product_variables: { + debuggable: { + cflags: [ + "-DDCHECK_ALWAYS_ON" + ], + }, + }, + +} diff --git a/snxxx/libese-spi/common/include/phNxpEseFeatures.h b/snxxx/libese-spi/common/include/phNxpEseFeatures.h new file mode 100644 index 0000000..f6fef6c --- /dev/null +++ b/snxxx/libese-spi/common/include/phNxpEseFeatures.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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. + * + ******************************************************************************/ + +/* + * NXP ESE features macros definitions + */ + +#ifndef NXP_ESE_FEATURES_H +#define NXP_ESE_FEATURES_H + +#define ESE_DEBUG_UTILS_INCLUDED true + +#define NXP_POWER_SCHEME_SUPPORT true +#define NXP_ESE_END_OF_SESSION true + +#define NXP_ESE_WTX_RES_DELAY true +#define NXP_ESE_P73_ISO_RST true + +typedef enum OS_VERSION { + OS_VERSION_DEFAULT = 0, + OS_VERSION_4_0 = 1, + OS_VERSION_5_1 = 2, + OS_VERSION_5_2 = 3, + OS_VERSION_5_2_2 = 4, + OS_VERSION_6_2 = 5, + INVALID_OS_VERSION = 0xFF, +} phNxpEse_OsVersion_t; + +extern phNxpEse_OsVersion_t phNxpEse_getOsVersion(); +extern bool ese_debug_enabled; +#define GET_CHIP_OS_VERSION() phNxpEse_getOsVersion() + +#endif /* end of #ifndef NXP_ESE_FEATURES_H */ diff --git a/snxxx/libese-spi/p73/common/phEseStatus.h b/snxxx/libese-spi/p73/common/phEseStatus.h new file mode 100644 index 0000000..80db0b5 --- /dev/null +++ b/snxxx/libese-spi/p73/common/phEseStatus.h @@ -0,0 +1,222 @@ +/****************************************************************************** + * + * Copyright 2018 - 2019 NXP + * + * 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. + * + ******************************************************************************/ +/** + * \addtogroup ISO7816-3_protocol_lib_common + * + * @{ */ + +#ifndef PHESESTATUS_H +#define PHESESTATUS_H + +/*! Internally required by PHESESTVAL. */ +#define PHESESTSHL8 (8U) + +/*! Required by PHESESTVAL. */ +#define PHESESTBLOWER ((ESESTATUS)(0x00FFU)) + +/*! + * ESE Status Composition Macro + * + * This is the macro which must be used to compose status values. + * + * phEseCompID Component ID, as defined in phEseCompId.h . + * phEseStatus Status values, as defined in phEseStatus.h . + * + * The macro is not required for the ESESTATUS_SUCCESS value. + * This is the only return value to be used directly. + * For all other values it shall be used in assignment and conditional + *statements, e.g.: + * ESESTATUS status = PHESESTVAL(phEseCompID, phEseStatus); ... + * if (status == PHESESTVAL(phEseCompID, phEseStatus)) ... + */ +#define PHESESTVAL(phEseCompID, phEseStatus) \ + (((phEseStatus) == (ESESTATUS_SUCCESS)) \ + ? (ESESTATUS_SUCCESS) \ + : ((((ESESTATUS)(phEseStatus)) & (PHESESTBLOWER)) | \ + (((uint16_t)(phEseCompID)) << (PHESESTSHL8)))) + +/*! + * PHESESTATUS + * Get grp_retval from Status Code + */ +#define PHESESTATUS(phEseStatus) ((phEseStatus)&0x00FFU) + +/** + * \ingroup ISO7816-3_protocol_lib_common + * \brief Ese Channel mode + * + */ +typedef enum { + ESESTATUS_SUCCESS = (0x0000), + + ESESTATUS_FAILED = (0x0001), + + ESESTATUS_IOCTL_FAILED = -1, + + ESESTATUS_INVALID_BUFFER = (0x0002), + + ESESTATUS_BUFFER_TOO_SMALL = (0x0003), + + ESESTATUS_INVALID_CLA = (0x0004), + + ESESTATUS_INVALID_CPDU_TYPE = (0x0005), + + ESESTATUS_INVALID_LE_TYPE = (0x0007), + + ESESTATUS_INVALID_DEVICE = (0x0006), + + ESESTATUS_MORE_FRAME = (0x0008), + + ESESTATUS_LAST_FRAME = (0x0009), + + ESESTATUS_CRC_ERROR = (0x000A), + + ESESTATUS_SOF_ERROR = (0x000B), + + ESESTATUS_INSUFFICIENT_RESOURCES = (0x000C), + + ESESTATUS_PENDING = (0x000D), + + ESESTATUS_BOARD_COMMUNICATION_ERROR = (0x000F), + + ESESTATUS_INVALID_STATE = (0x0011), + + ESESTATUS_NOT_INITIALISED = (0x0031), + + ESESTATUS_ALREADY_INITIALISED = (0x0032), + + ESESTATUS_FEATURE_NOT_SUPPORTED = (0x0033), + + ESESTATUS_PARITY_ERROR = (0x0034), + + ESESTATUS_ALREADY_REGISTERED = (0x0035), + + ESESTATUS_CHAINED_FRAME = (0x0036), + + ESESTATUS_SINGLE_FRAME = (0x0037), + + ESESTATUS_DESELECTED = (0x0038), + + ESESTATUS_RELEASED = (0x0039), + + ESESTATUS_NOT_ALLOWED = (0x003A), + + ESESTATUS_OTHER_ERROR = (0x003C), + + ESESTATUS_DRIVER_BUSY = (0x006D), + + ESESTATUS_DWNLD_BUSY = (0x006E), + + ESESTATUS_BUSY = (0x006F), + + ESESTATUS_INVALID_REMOTE_DEVICE = (0x001D), + + ESESTATUS_READ_FAILED = (0x0014), + + ESESTATUS_WRITE_FAILED = (0x0015), + + ESESTATUS_NO_NDEF_SUPPORT = (0x0016), + + ESESTATUS_RESET_SEQ_COUNTER_FRAME_RESEND = (0x001A), + + ESESTATUS_INVALID_RECEIVE_LENGTH = (0x001B), + + ESESTATUS_INVALID_FORMAT = (0x001C), + + ESESTATUS_INSUFFICIENT_STORAGE = (0x001F), + + ESESTATUS_FRAME_RESEND = (0x0023), + + ESESTATUS_WRITE_TIMEOUT = (0x0024), + + ESESTATUS_RESPONSE_TIMEOUT = (0x0025), + + ESESTATUS_FRAME_RESEND_R_FRAME = (0x0026), + + ESESTATUS_SEND_NEXT_FRAME = (0x0027), + + ESESTATUS_RECOVERY_STARTED = (0x0028), + + ESESTATUS_SEND_R_FRAME = (0x0029), + + ESESTATUS_FRAME_RESEND_RNAK = (0x0030), + + ESESTATUS_FRAME_SEND_R_FRAME = (0x003B), + + ESESTATUS_UNKNOWN_ERROR = (0x00FE), + + ESESTATUS_INVALID_PARAMETER = (0x00FF), + + ESESTATUS_CMD_ABORTED = (0x0002), + + ESESTATUS_NO_TARGET_FOUND = (0x000A), + + ESESTATUS_NO_DEVICE_CONNECTED = (0x000B), + + ESESTATUS_RESYNCH_REQ = (0x000E), + + ESESTATUS_RESYNCH_RES = (0x0010), + + ESESTATUS_IFS_REQ = (0x001E), + + ESESTATUS_IFS_RES = (0x0017), + + ESESTATUS_ABORT_REQ = (0x00F0), + + ESESTATUS_ABORT_RES = (0x00F2), + + ESESTATUS_WTX_REQ = (0x00F5), + + ESESTATUS_WTX_RES = (0x00F6), + + ESESTATUS_RESET_REQ = (0x00F7), + + ESESTATUS_RESET_RES = (0x00F8), + + ESESTATUS_END_APDU_REQ = (0x00F9), + + ESESTATUS_END_APDU_RES = (0x00FA), + + ESESTATUS_SHUTDOWN = (0x0091), + + ESESTATUS_TARGET_LOST = (0x0092), + + ESESTATUS_REJECTED = (0x0093), + + ESESTATUS_TARGET_NOT_CONNECTED = (0x0094), + + ESESTATUS_INVALID_HANDLE = (0x0095), + + ESESTATUS_ABORTED = (0x0096), + + ESESTATUS_COMMAND_NOT_SUPPORTED = (0x0097), + + ESESTATUS_NON_NDEF_COMPLIANT = (0x0098), + + ESESTATUS_NOT_ENOUGH_MEMORY = (0x001F), + + ESESTATUS_INCOMING_CONNECTION = (0x0045), + + ESESTATUS_CONNECTION_SUCCESS = (0x0046), + + ESESTATUS_CONNECTION_FAILED = (0x0047), + + ESESTATUS_TRANSCEIVE_FAILED = (0x0048), +} ESESTATUS; +#endif /* PHESESTATUS_H */ +/** @} */ diff --git a/snxxx/libese-spi/p73/inc/phNxpEse_Apdu_Api.h b/snxxx/libese-spi/p73/inc/phNxpEse_Apdu_Api.h new file mode 100644 index 0000000..1f80f83 --- /dev/null +++ b/snxxx/libese-spi/p73/inc/phNxpEse_Apdu_Api.h @@ -0,0 +1,105 @@ +/****************************************************************************** + * + * Copyright 2018-2019,2021 NXP + * + * 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. + * + ******************************************************************************/ + +/** + * \addtogroup ISO7816-4_application_protocol_implementation + * + * @{ */ + +#ifndef _PHNXPESE_APDU_H +#define _PHNXPESE_APDU_H +#include <phEseStatus.h> + +/** + * \brief 7816-4 APDU command Header Size + * + */ + +#define MIN_HEADER_LEN 4 + +/** + * \ingroup ISO7816-4_application_protocol_implementation + * \brief Command data unit structure params + * + */ +typedef struct phNxpEse_7816_cpdu { + uint8_t cla; /*!< Class of instruction */ + uint8_t ins; /*!< Instruction code */ + uint8_t p1; /*!< Instruction parameter 1 */ + uint8_t p2; /*!< Instruction parameter 2 */ + uint16_t lc; /*!< No of data present in the data field of the command */ + uint8_t cpdu_type; /*!< 0 - short len, 1 = extended len, this field is valid + only if le > 0*/ + uint8_t* pdata; /*!< application data*/ + uint8_t le_type; /*!< 0 - Le absent ,1 - one byte le,2 - two byte le or 3 - 3 + byte le*/ + uint32_t le; /*!< le value field */ +} phNxpEse_7816_cpdu_t; + +/** + * \ingroup ISO7816-4_application_protocol_implementation + * \brief Command data unit structure params + * + */ +typedef phNxpEse_7816_cpdu_t* pphNxpEse_7816_cpdu_t; + +/** + * \ingroup ISO7816-4_application_protocol_implementation + * \brief Response data unit structure params + * + */ +typedef struct phNxpEse_7816_rpdu { + uint8_t sw1; /*!< Status byte most significant byte */ + uint8_t sw2; /*!< Status byte least significant byte */ + uint8_t* pdata; /*!< Buffer allocated by caller*/ + uint16_t len; /*!< Length of the buffer, updated by calling api */ +} phNxpEse_7816_rpdu_t; + +/** + * \ingroup ISO7816-4_application_protocol_implementation + * \brief Response data unit structure params + * + */ +typedef phNxpEse_7816_rpdu_t* pphNxpEse_7816_rpdu_t; + +/** + * \ingroup ISO7816-4_application_protocol_implementation + * \brief This function prepares C-APDU and sends to p61 and receives response + *from the p61. + * also it parses all required fields of the response PDU. + * + * \param[in] pCmd - CMD to p61 + * \param[out] pRsp - RSP from p61(all required memory + *allocated by caller) + * + * \retval ESESTATUS_SUCCESS - On Success #pphNxpEse_7816_rpdu_t all fields are + *filled correctly. + * else proper error code. + * \retval ESESTATUS_INVALID_PARAMETER - If any invalid buffer passed from + *application \n + * \retval ESESTATUS_INSUFFICIENT_RESOURCES - Any problem occurred during + *allocating the memory \n + * \retval ESESTATUS_INVALID_BUFFER - If any invalid buffer received \n + * \retval ESESTATUS_FAILED - Any other error occurred. \n + */ + +ESESTATUS phNxpEse_7816_Transceive(pphNxpEse_7816_cpdu_t pCmd, + pphNxpEse_7816_rpdu_t pRsp); + +#endif /* _PHNXPESE_APDU_H */ +/** @} */ diff --git a/snxxx/libese-spi/p73/inc/phNxpEse_Api.h b/snxxx/libese-spi/p73/inc/phNxpEse_Api.h new file mode 100755 index 0000000..fc9655d --- /dev/null +++ b/snxxx/libese-spi/p73/inc/phNxpEse_Api.h @@ -0,0 +1,459 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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. + * + ******************************************************************************/ + +/** + * \addtogroup spi_libese + * \brief ESE Lib layer interface to application + * @{ */ + +#ifndef _PHNXPSPILIB_API_H_ +#define _PHNXPSPILIB_API_H_ + +#include <phEseStatus.h> +#include <phNxpEsePal.h> + +/** + * \ingroup spi_libese + * \brief Ese data buffer + * + */ +typedef struct phNxpEse_data { + uint32_t len; /*!< length of the buffer */ + uint8_t* p_data; /*!< pointer to a buffer */ +} phNxpEse_data; + +/** + * \ingroup spi_libese + * \brief Ese Channel mode + * + */ +typedef enum { + ESE_MODE_NORMAL = 0, /*!< All wired transaction other OSU */ + ESE_MODE_OSU /*!< Jcop Os update mode */ +} phNxpEse_initMode; + +/** + * \ingroup spi_libese + * \brief Ese logical interface i.e. MediaType + * + */ +typedef enum { + ESE_PROTOCOL_MEDIA_SPI = 0x08, /*!< Media Type - SPI legacy */ + ESE_PROTOCOL_MEDIA_SPI_APDU_GATE = 0xD0 /*!Media Type - APDU Gate */ +} phNxpEse_mediaType; + +typedef enum { + WTX_ONGOING = 1, + WTX_END = 2, +} phNxpEse_wtxState; + +typedef enum phNxpEseProto7816_OsType { + UNKNOWN_MODE = 0, + JCOP_MODE = 0x1, + OSU_MODE = 0x2, +} phNxpEseProto7816_OsType_t; + +#define MODE_JCOP 0x01 +#define MODE_OSU 0x02 +#define RESET_APP_WTX_COUNT 0 + +typedef void(NotifyWtxReq)(phNxpEse_wtxState); +/** + * \ingroup spi_libese + * \brief Ese library init parameters to be set while calling phNxpEse_init + * + */ +typedef struct phNxpEse_initParams { + phNxpEse_initMode initMode; /*!< Ese communication mode */ + phNxpEse_mediaType mediaType; /*!< Logical channel for Ese communication */ + NotifyWtxReq* fPtr_WtxNtf; /*!< Wait extension callback notification*/ +} phNxpEse_initParams; + +/*! + * \brief SEAccess kit MW Android version + */ +#define NXP_ANDROID_VER (9U) + +/*! + * \brief SEAccess kit MW Major version + */ +#define ESELIB_MW_VERSION_MAJ (0x0U) + +/*! + * \brief SEAccess kit MW Minor version + */ +#define ESELIB_MW_VERSION_MIN (0x04) + +/*! + * \brief eSE debugging log Level + */ +extern bool ese_debug_enabled; + +/** + * \ingroup spi_libese + * + * \brief This function is called by Jni/phNxpEse_open during the + * initialization of the ESE. It initializes protocol stack instance + * variables. + * + * \param[in] initParams - init parameters to be set while calling + * phNxpEse_init + * + * \retval This function return ESESTATUS_SUCCESS (0) in case of success + * In case of failure returns other failure value. + * + */ +ESESTATUS phNxpEse_init(phNxpEse_initParams initParams); + +/** + * \ingroup spi_libese + * + * \brief Check if libese has opened + * + * \retval return false if it is close, otherwise true. + * + */ +bool phNxpEse_isOpen(); + +/** + * \ingroup spi_libese + * + * \brief This function is used to communicate from nfc-hal to ese-hal + * + * \param[in] ioctlType - ioctl cmd + *\param[out] p_data - value read out + * + * \retval This function return ESESTATUS_SUCCESS (0) in case of success + * In case of failure returns other failure value. + * + */ +ESESTATUS phNxpEse_spiIoctl(uint64_t ioctlType, void* p_data); +/** + * \ingroup spi_libese + * + * \brief This function is called by hal interface api before any + * communication. It sets the end point variables + * + * \param[in] uEndPoint - select the end point type ( END_POINT_ESE = 0, + * END_POINT_eUICC =1 ). + * + * \retval This function return ESESTATUS_SUCCESS (0) in case of success + * In case of failure returns other failure value. + * + */ +ESESTATUS phNxpEse_SetEndPoint_Cntxt(uint8_t uEndPoint); + +/** + * \ingroup spi_libese + * + * \brief This function is called by hal interface api before any + * communication. It resets the end point variables + * + * \param[in] uEndPoint - select the end point type ( END_POINT_ESE = 0, + * END_POINT_eUICC =1 ). + * + * \retval This function return ESESTATUS_SUCCESS (0) in case of success + * In case of failure returns other failure value. + * + */ +ESESTATUS phNxpEse_ResetEndPoint_Cntxt(uint8_t uEndPoint); + +/** + * \ingroup spi_libese + * \brief This function is called by Jni during the + * initialization of the ESE. It opens the physical connection + * with ESE () and initializes the protocol stack + * + * \param[in] initParams - Initialize with init mode ( normal/osu) and media + * type(SPI- legacy/ APDU type). + * + * \retval ESESTATUS_SUCCESS On Success ESESTATUS_SUCCESS else proper error code + * + */ +ESESTATUS phNxpEse_open(phNxpEse_initParams initParams); + +/** + * \ingroup spi_libese + * \brief This function is called by Jni during the + * initialization of the ESE. It opens the physical connection + * with ESE () and creates required client thread for + * operation. This will get priority access to ESE for timeout period. + * + * \param[in] initParams - Initialize with init mode ( normal/osu) and media + * type(SPI- legacy/ APDU type). + * + * \retval ESESTATUS_SUCCESS On Success ESESTATUS_SUCCESS else proper error code + * + */ +ESESTATUS phNxpEse_openPrioSession(phNxpEse_initParams initParams); + +/** + * \ingroup spi_libese + * \brief This function prepares the C-APDU, send to ESE and then receives the + *response from ESE, + * decode it and returns data. + * + * \param[in] pCmd: Command to ESE + * \param[out] pRsp: Response from ESE (Returned data to be freed + *after copying) + * + * \retval ESESTATUS_SUCCESS On Success ESESTATUS_SUCCESS else proper error code + * + */ + +ESESTATUS phNxpEse_Transceive(phNxpEse_data* pCmd, phNxpEse_data* pRsp); + +/** + * \ingroup spi_libese + * + * \brief This function is called by Jni/phNxpEse_close during the + * de-initialization of the ESE. It de-initializes protocol stack + *instance variables + * + * \retval This function return ESESTATUS_SUCCESS (0) in case of success + * In case of failure returns other failure value. + * + */ +ESESTATUS phNxpEse_deInit(void); + +/** + * \ingroup spi_libese + * \brief This function close the ESE interface and free all resources. + * + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ + +ESESTATUS phNxpEse_close(ESESTATUS deInitStatus = ESESTATUS_SUCCESS); + +/** + * \ingroup spi_libese + * \brief This function reset the ESE interface and free all + * + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_reset(void); + +/** + * \ingroup spi_libese + * \brief This function reset the ESE + * + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_resetJcopUpdate(void); + +/** + * \ingroup spi_libese + * \brief This function reset the P73 through ISO RST pin + * + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_chipReset(void); + +/** + * \ingroup spi_libese + * \brief This function is used to set IFSC size + * + * \param[in] IFS_Size + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_setIfs(uint16_t IFS_Size); + +/** + * \ingroup spi_libese + * \brief This function is used to get the ATR data from ESE + * + * \param[out] pATR + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_getAtr(phNxpEse_data* pATR); + +/** + * \ingroup spi_libese + * \brief This function sends the S-frame to indicate END_OF_APDU + * + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_EndOfApdu(void); + +/** + * \ingroup spi_libese + * \brief This function suspends execution of the calling thread for + * (at least) usec microseconds + * + * \param[in] usec + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_Sleep(uint32_t usec); + +/** + * \ingroup spi_libese + * \brief This function updates destination buffer with val + * data in len size + * + * \param[in] buff - Array to be updated + * \param[in] val - value to be updated + * \param[in] len - length of array to be updated + * + * \retval void + * + */ +void* phNxpEse_memset(void* buff, int val, size_t len); + +/** + * \ingroup spi_libese + * \brief This function copies source buffer to destination buffer + * data in len size + * + * \param[in] dest - Destination array to be updated + * \param[in] src - Source array to be updated + * \param[in] len - length of array to be updated + * + * \retval void + * + */ +void* phNxpEse_memcpy(void* dest, const void* src, size_t len); + +/** + * \ingroup spi_libese + * \brief This function suspends allocate memory + * + * \param[in] size + * + * \retval allocated memory. + * + */ +void* phNxpEse_memalloc(uint32_t size); + +/** + * \ingroup spi_libese + * \brief This is utility function for runtime heap memory allocation + * + *\param[in] dataType - data type + * \param[in] size - number of bytes to be allocated + * + * \retval void + * + */ +void* phNxpEse_calloc(size_t dataType, size_t size); + +/** + * \ingroup spi_libese + * \brief This is utility function for freeeing heap memory allocated + * + * \param[in] ptr - Address pointer to previous allocation + * + * \retval void + * + */ +void phNxpEse_free(void* ptr); + +/** + * \ingroup spi_libese + * \brief This function performs disable/enable power control + * + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_DisablePwrCntrl(void); + +/** + * \ingroup spi_libese + * \brief This function is used to get the ESE timer status + * + * \param[out] timer_buffer + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_GetEseStatus(phNxpEse_data* timer_buffer); + +/** + * \ingroup spi_libese + * \brief This function power recycles the ESE + * (using prop. FW command) by talking to NFC HAL + * + * Note: + * After cold reset, phNxpEse_init need to be called to + * reset the host AP T=1 stack parameters + * + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_coldReset(void); + +/** + * \ingroup spi_libese + * \brief This function notifies SE hal service if it registers + * + * \param[out] state - WTX_ONGOIGN/WTX_END + * + * \retval void. + * + */ +void phNxpEse_NotifySEWtxRequest(phNxpEse_wtxState state); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to get OS mode(JCOP/OSU) + * + * \retval OS mode(JCOP/OSU). + * + */ +phNxpEseProto7816_OsType_t phNxpEse_GetOsMode(void); + +/** + * \ingroup spi_libese + * \brief This function enable/disable resetprotection + * + * \param[in] flag - indicated enable or disable resetprotection. + * + * \retval ESESTATUS_SUCCESS Always return ESESTATUS_SUCCESS (0). + * + */ +ESESTATUS phNxpEse_doResetProtection(bool flag); + +/** + * \ingroup spi_libese + * \brief This function is used to set the wtx count limit + * + * \param[in] wtxCount - value to set for wtx count limit + * + * \retval void. + * + */ +void phNxpEse_setWtxCountLimit(unsigned long int wtxCount); +/** @} */ +#endif /* _PHNXPSPILIB_API_H_ */ diff --git a/snxxx/libese-spi/p73/lib/phNxpEseDataMgr.cpp b/snxxx/libese-spi/p73/lib/phNxpEseDataMgr.cpp new file mode 100755 index 0000000..1267c07 --- /dev/null +++ b/snxxx/libese-spi/p73/lib/phNxpEseDataMgr.cpp @@ -0,0 +1,165 @@ +/****************************************************************************** + * + * Copyright 2018-2019 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "NxpEseHal" +#include <log/log.h> +#include <phNxpEseDataMgr.h> +#include <phNxpEsePal.h> + +static phNxpEse_sCoreRecvBuff_List_t *head = NULL, *current = NULL; +static uint32_t total_len = 0; + +static ESESTATUS phNxpEse_DeletList(phNxpEse_sCoreRecvBuff_List_t* head); +static ESESTATUS phNxpEse_GetDataFromList(uint32_t* data_len, uint8_t* pbuff); +/****************************************************************************** + * Function phNxpEse_GetData + * + * Description This function update the len and provided buffer + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_GetData(uint32_t* data_len, uint8_t** pbuffer) { + uint32_t total_data_len = 0; + uint8_t* pbuff = NULL; + ESESTATUS status = ESESTATUS_FAILED; + + if (total_len > 0) { + pbuff = (uint8_t*)phNxpEse_memalloc(total_len); + if (NULL != pbuff) { + if (ESESTATUS_SUCCESS == + phNxpEse_GetDataFromList(&total_data_len, pbuff)) { + if (total_data_len == total_len) { + /***** Success Case *****/ + *pbuffer = pbuff; + *data_len = total_data_len; + phNxpEse_DeletList(head); + head = NULL; + current = NULL; + total_len = 0; + status = ESESTATUS_SUCCESS; + } else { + ALOGD_IF(ese_debug_enabled, + "%s Mismatch of len total_data_len %d total_len %d", + __FUNCTION__, total_data_len, total_len); + phNxpEse_free(pbuff); + } + } else { + ALOGE("%s phNxpEse_GetDataFromList failed", __FUNCTION__); + phNxpEse_free(pbuff); + } + } else { + ALOGE("%s Error in malloc ", __FUNCTION__); + status = ESESTATUS_NOT_ENOUGH_MEMORY; + } + } else { + ALOGD_IF(ese_debug_enabled, "%s total_len = %d", __FUNCTION__, total_len); + } + + if (ESESTATUS_SUCCESS != status) { + *pbuffer = NULL; + *data_len = 0; + } + ALOGD_IF(ese_debug_enabled, "%s exit status = %d", __FUNCTION__, status); + return status; +} + +/****************************************************************************** + * Function phNxpEse_StoreDatainList + * + * Description This function stores the received data in linked list + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_StoreDatainList(uint32_t data_len, uint8_t* pbuff) { + phNxpEse_sCoreRecvBuff_List_t* newNode = NULL; + + newNode = (phNxpEse_sCoreRecvBuff_List_t*)phNxpEse_memalloc( + sizeof(phNxpEse_sCoreRecvBuff_List_t)); + if (newNode == NULL) { + ALOGE("%s Error in malloc ", __FUNCTION__); + return ESESTATUS_NOT_ENOUGH_MEMORY; + } + newNode->pNext = NULL; + newNode->tData.wLen = data_len; + phNxpEse_memcpy(newNode->tData.sbuffer, pbuff, data_len); + total_len += data_len; + if (head == NULL) { + head = newNode; + current = newNode; + } else { + current->pNext = newNode; + current = newNode; + } + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEse_GetDataFromList + * + * Description This function copies all linked list data in provided buffer + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +static ESESTATUS phNxpEse_GetDataFromList(uint32_t* data_len, uint8_t* pbuff) { + phNxpEse_sCoreRecvBuff_List_t* new_node; + uint32_t offset = 0; + ALOGD_IF(ese_debug_enabled, "%s Enter ", __FUNCTION__); + if (head == NULL || pbuff == NULL) { + return ESESTATUS_FAILED; + } + + new_node = head; + while (new_node != NULL) { + phNxpEse_memcpy((pbuff + offset), new_node->tData.sbuffer, + new_node->tData.wLen); + offset += new_node->tData.wLen; + new_node = new_node->pNext; + } + *data_len = offset; + ALOGD_IF(ese_debug_enabled, "%s Exit ", __FUNCTION__); + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEse_DeletList + * + * Description This function deletes all nodes from linked list + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +static ESESTATUS phNxpEse_DeletList(phNxpEse_sCoreRecvBuff_List_t* head) { + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_sCoreRecvBuff_List_t *current, *next; + current = head; + + if (head == NULL) { + return ESESTATUS_FAILED; + } + + while (current != NULL) { + next = current->pNext; + phNxpEse_free(current); + current = NULL; + current = next; + } + head = NULL; + return status; +} diff --git a/snxxx/libese-spi/p73/lib/phNxpEseDataMgr.h b/snxxx/libese-spi/p73/lib/phNxpEseDataMgr.h new file mode 100644 index 0000000..77fea80 --- /dev/null +++ b/snxxx/libese-spi/p73/lib/phNxpEseDataMgr.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * Copyright 2018-2019 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef _PHNXPESE_RECVMGR_H_ +#define _PHNXPESE_RECVMGR_H_ +#include <phNxpEse_Internal.h> + +/*! + * \brief eSE Data buffer structure + * + * + */ +typedef struct phNxpEse_DataPacket { + uint8_t sbuffer[MAX_DATA_LEN]; /*!<buffer to be used to store the received + packet */ + uint16_t wLen; /*!<hold the length of the buffer */ +} phNxpEse_DataPacket_t; + +/*! + * \brief eSE data receive buffer linkedlist + * + * + */ +typedef struct phNxpEse_sCoreRecvBuff_List { + phNxpEse_DataPacket_t + tData; /*!<buffer to be used to store the received payload */ + struct phNxpEse_sCoreRecvBuff_List* + pNext; /*!<pointer to the next node present in lined list*/ +} phNxpEse_sCoreRecvBuff_List_t; + +ESESTATUS phNxpEse_GetData(uint32_t* data_len, uint8_t** pbuff); +ESESTATUS phNxpEse_StoreDatainList(uint32_t data_len, uint8_t* pbuff); + +#endif /* PHNXPESE_RECVMGR_H */ diff --git a/snxxx/libese-spi/p73/lib/phNxpEseProto7816_3.cpp b/snxxx/libese-spi/p73/lib/phNxpEseProto7816_3.cpp new file mode 100755 index 0000000..bf1aad2 --- /dev/null +++ b/snxxx/libese-spi/p73/lib/phNxpEseProto7816_3.cpp @@ -0,0 +1,2231 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "NxpEseHal" +#include <log/log.h> +#include <phNxpEseProto7816_3.h> + +/** + * \addtogroup ISO7816-3_protocol_lib + * + * @{ */ + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to reset the 7816 protocol stack instance + * + * + */ +static ESESTATUS phNxpEseProto7816_ResetProtoParams(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called send the data to ESE + *\param[in] data_len - data len + *\param[in] p_data -address to raw data + * + */ +static ESESTATUS phNxpEseProto7816_SendRawFrame(uint32_t data_len, + uint8_t* p_data); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called read the data from the ESE + *\param[in] data_len - data len + *\param[in] pp_data -address to raw data + * + */ +static ESESTATUS phNxpEseProto7816_GetRawFrame(uint32_t* data_len, + uint8_t** pp_data); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called compute the LRC + *\param[in] p_buff - raw data + *\param[in] offset -address to raw data + *\param[in] length - length of data. + *\retval LRC value. + * + */ +static uint8_t phNxpEseProto7816_ComputeLRC(unsigned char* p_buff, + uint32_t offset, uint32_t length); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called compute and compare the + * received LRC of the received data + *\param[in] data_len - raw data + *\param[in] p_data -address to raw data + * + */ +static ESESTATUS phNxpEseProto7816_CheckLRC(uint32_t data_len, uint8_t* p_data); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called to send S-frame with all + * updated 7816-3 headers + *\param[in] sFrameData -S frame APDU + * + */ +static ESESTATUS phNxpEseProto7816_SendSFrame(sFrameInfo_t sFrameData); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called to send I-frame with all + * updated 7816-3 headers + *\param[in] iFrameData -I frame APDU + * + */ +static ESESTATUS phNxpEseProto7816_SendIframe(iFrameInfo_t iFrameData); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called to send R-frame with all + *updated 7816-3 headers + *\param[in] rFrameType -R frame APDU + * + */ +static ESESTATUS phNxpEseProto7816_sendRframe(rFrameTypes_t rFrameType); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called to set the context for first + *I-frame. Not applicable for the first I-frame of the transceive + * + */ +static ESESTATUS phNxpEseProto7816_SetFirstIframeContxt(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called to set the context for next + *I-frame. Not applicable for the first I-frame of the transceive + * + */ +static ESESTATUS phNxpEseProto7816_SetNextIframeContxt(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called to push I-frame data to internal + *structure. \param[in] p_data -raw data buffer \param[in] data_len -data + *length + * + */ +static ESESTATUS phNxpEseProto7816_SaveIframeData(uint8_t* p_data, + uint32_t data_len); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called to do reset the recovery + *pareameters + * + */ +static ESESTATUS phNxpEseProto7816_ResetRecovery(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is called when 7816-3 stack failed to + *recover after PH_PROTO_7816_FRAME_RETRY_COUNT, and the interface has + *to be recovered + * + */ +static ESESTATUS phNxpEseProto7816_RecoverySteps(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is used to + * 1. Identify the received frame + * 2. If the received frame is I-frame with expected sequence + number, store it or else send R-NACK + 3. If the received frame is R-frame, + 3.1 R-ACK with expected seq. number: Send the next + chained I-frame + 3.2 R-ACK with different sequence number: Send the R-Nack + 3.3 R-NACK: Re-send the last frame + 4. If the received frame is S-frame, send back the correct + S-frame response. + *\param[in] p_data -address of data. + *\param[in] data_len -length of the frame + * + */ +static ESESTATUS phNxpEseProto7816_DecodeFrame(uint8_t* p_data, + uint32_t data_len); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is used to + * 1. Check the LRC + * 2. Initiate decoding of received frame of data. + * + */ +static ESESTATUS phNxpEseProto7816_ProcessResponse(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is used to + * 1. Send the raw data received from application after + *computing LRC + * 2. Receive the response data from ESE, decode, process + *and + * store the data. + * + */ +static ESESTATUS TransceiveProcess(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is used to + * 1. Send propreitary S-Frame command for resynch + *T=1 sequence at client + * + */ +static ESESTATUS phNxpEseProto7816_RSync(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to reset the 7816 protocol stack + * + */ +static ESESTATUS phNxpEseProto7816_ResetProtoParams(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to send the spi hard reset command + * + */ +static ESESTATUS phNxpEseProto7816_HardReset(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is to decode the secure timer. + * value from the payload + *\param[in] frameOffset -To get the L of TLV + *\param[in] secureTimer -V of TLV: Retrieve each byte(4 byte) and push it + *to get the secure timer value (unsigned long) \param[in] p_data -pointer to + *data. + * + */ +static void phNxpEseProto7816_DecodeSecureTimer(uint8_t* frameOffset, + unsigned int* secureTimer, + uint8_t* p_data); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is to decode S-frame payload. + *\param[in] p_data -Raw Data IFS. + * + */ +static void phNxpEseProto7816_DecodeSFrameIFSData(uint8_t* p_data); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is to decode S-frame (ATR) payload. + *\param[in] p_data -ATR TLV. + * + */ +static void phNxpEseProto7816_DecodeSFrameATRData(uint8_t* p_data); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is to decode S-frame (secure timer TLV) + *payload. \param[in] p_data -raw data - secure timer TLV. + * + */ +static void phNxpEseProto7816_DecodeSFrameSecureTimerData(uint8_t* p_data); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function is to notify either WTX_ONGOING ot + *WTX_END \param[in] state - Either WTX_ONGOING/WTX_END + * + */ +static void phNxpEseProto7816_CheckAndNotifyWtx(phNxpEse_wtxState state); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This internal function to check Last sent frame is S-Frame + * request and if received block is not S-Frame response + * re-send Last S-frame request + */ +static bool phNxpEseProto7816_ResendLastSFrameReq(void); +/*! + * \brief 7816_3 protocol stack parameter variable instance + */ +static phNxpEseProto7816_t phNxpEseProto7816_3_Var; + +/*! + * \brief 7816_3 protocol stack instance - pointer variable + */ +static phNxpEseProto7816_t phNxpEseProto7816_ptr[MAX_END_POINTS]; + +/****************************************************************************** + * Function phNxpEseProto7816_SendRawFrame + * + * Description This internal function is called send the data to ESE + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_SendRawFrame(uint32_t data_len, + uint8_t* p_data) { + ESESTATUS status = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + status = phNxpEse_WriteFrame(data_len, p_data); + if (ESESTATUS_SUCCESS != status) { + ALOGE("%s Error phNxpEse_WriteFrame\n", __FUNCTION__); + } else { + ALOGD_IF(ese_debug_enabled, "%s phNxpEse_WriteFrame Success \n", + __FUNCTION__); + } + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_GetRawFrame + * + * Description This internal function is called read the data from the ESE + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_GetRawFrame(uint32_t* data_len, + uint8_t** pp_data) { + ESESTATUS status = ESESTATUS_FAILED; + + status = phNxpEse_read(data_len, pp_data); + if (ESESTATUS_SUCCESS != status) { + ALOGE("%s phNxpEse_read failed , status : 0x%x", __FUNCTION__, status); + } + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ComputeLRC + * + * Description This internal function is called compute the LRC + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static uint8_t phNxpEseProto7816_ComputeLRC(unsigned char* p_buff, + uint32_t offset, uint32_t length) { + uint32_t LRC = 0, i = 0; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + for (i = offset; i < length; i++) { + LRC = LRC ^ p_buff[i]; + } + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return (uint8_t)LRC; +} + +/****************************************************************************** + * Function phNxpEseProto7816_CheckLRC + * + * Description This internal function is called compute and compare the + * received LRC of the received data + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_CheckLRC(uint32_t data_len, + uint8_t* p_data) { + ESESTATUS status = ESESTATUS_SUCCESS; + uint8_t calc_crc = 0; + uint8_t recv_crc = 0; + ALOGD_IF(ese_debug_enabled, "Enter %s len %d", __FUNCTION__, data_len); + if (data_len > 0) { + recv_crc = p_data[data_len - 1]; + + /* calculate the CRC after excluding CRC */ + calc_crc = phNxpEseProto7816_ComputeLRC(p_data, 1, (data_len - 1)); + ALOGD_IF(ese_debug_enabled, "Received LRC:0x%x Calculated LRC:0x%x", + recv_crc, calc_crc); + if (recv_crc != calc_crc) { + status = ESESTATUS_FAILED; + ALOGE("%s LRC failed", __FUNCTION__); + } + } else { + status = ESESTATUS_FAILED; + ALOGE("%s LRC failed length = 0", __FUNCTION__); + } + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SendSFrame + * + * Description This internal function is called to send S-frame with all + * updated 7816-3 headers + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_SendSFrame(sFrameInfo_t sFrameData) { + ESESTATUS status = ESESTATUS_FAILED; + uint32_t frame_len = 0; + uint8_t* p_framebuff = NULL; + uint8_t pcb_byte = 0; + uint8_t lenIFS = 0; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + sFrameInfo_t sframeData = sFrameData; + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = SFRAME; + switch (sframeData.sFrameType) { + case RESYNCH_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + return ESESTATUS_FAILED; + } + p_framebuff[2] = 0; + p_framebuff[3] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_RESYNCH; + break; + case IFS_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + lenIFS = 0; + if (IFSC_SIZE_SEND < phNxpEseProto7816_3_Var.currentIFSDSize) { + frame_len += 2; + lenIFS = 2; + } else { + frame_len += 1; + lenIFS = 1; + } + + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + return ESESTATUS_FAILED; + } + p_framebuff[2] = lenIFS; + if (2 == lenIFS) { + p_framebuff[3] = (phNxpEseProto7816_3_Var.currentIFSDSize >> 8); + p_framebuff[4] = + (phNxpEseProto7816_3_Var.currentIFSDSize & EXTENDED_FRAME_MARKER); + } else { + p_framebuff[3] = phNxpEseProto7816_3_Var.currentIFSDSize; + } + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= IFS_REQ; + break; + case INTF_RESET_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + return ESESTATUS_FAILED; + } + p_framebuff[2] = 0; + p_framebuff[3] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_RESET; + break; + case PROP_END_APDU_REQ: + frame_len = + (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN + sframeData.len); + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + return ESESTATUS_FAILED; + } + p_framebuff[2] = sframeData.len; + if (!sframeData.len) + p_framebuff[3] = PH_PROTO_7816_VALUE_ZERO; + else + phNxpEse_memcpy(&(p_framebuff[3]), sframeData.p_data, sframeData.len); + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_END_OF_APDU; + break; + case HARD_RESET_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + return ESESTATUS_FAILED; + } + p_framebuff[2] = 0; + p_framebuff[3] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_HRD_RST_CMD; + break; + case WTX_RSP: + frame_len = (PH_PROTO_7816_HEADER_LEN + 1 + PH_PROTO_7816_CRC_LEN); + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + return ESESTATUS_FAILED; + } + p_framebuff[2] = 0x01; + p_framebuff[3] = 0x01; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_RSP; + pcb_byte |= PH_PROTO_7816_S_WTX; + break; + case ATR_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + return ESESTATUS_FAILED; + } + p_framebuff[2] = 0; + p_framebuff[3] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= ATR_REQ; + break; + default: + ALOGE("Invalid S-block"); + break; + } + if (NULL != p_framebuff) { + /* frame the packet */ + p_framebuff[0] = 0x00; /* NAD Byte */ + p_framebuff[1] = pcb_byte; /* PCB */ + + p_framebuff[frame_len - 1] = + phNxpEseProto7816_ComputeLRC(p_framebuff, 0, (frame_len - 1)); + ALOGD_IF(ese_debug_enabled, "S-Frame PCB: %x\n", p_framebuff[1]); + status = phNxpEseProto7816_SendRawFrame(frame_len, p_framebuff); + phNxpEse_free(p_framebuff); + /*After S-Frame Tx 1 ms sleep before Rx*/ + if ((GET_CHIP_OS_VERSION() != OS_VERSION_4_0) && + (sframeData.sFrameType != PROP_END_APDU_REQ)) { + phNxpEse_Sleep(1 * 1000); + } + } else { + ALOGE("Invalid S-block or malloc for s-block failed"); + } + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_sendRframe + * + * Description This internal function is called to send R-frame with all + * updated 7816-3 headers + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_sendRframe(rFrameTypes_t rFrameType) { + ESESTATUS status = ESESTATUS_FAILED; + uint8_t recv_ack[4] = {0x00, 0x80, 0x00, 0x00}; + if (RNACK == rFrameType) /* R-NACK */ + { + recv_ack[1] = 0x82; + } else /* R-ACK*/ + { + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = RFRAME; + } + recv_ack[1] |= + ((phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo ^ 1) + << 4); + ALOGD_IF(ese_debug_enabled, "%s recv_ack[1]:0x%x", __FUNCTION__, recv_ack[1]); + recv_ack[3] = + phNxpEseProto7816_ComputeLRC(recv_ack, 0x00, (sizeof(recv_ack) - 1)); + status = phNxpEseProto7816_SendRawFrame(sizeof(recv_ack), recv_ack); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SendIframe + * + * Description This internal function is called to send I-frame with all + * updated 7816-3 headers + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_SendIframe(iFrameInfo_t iFrameData) { + ESESTATUS status = ESESTATUS_FAILED; + uint32_t frame_len = 0; + uint8_t* p_framebuff = NULL; + uint8_t pcb_byte = 0; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + if (0 == iFrameData.sendDataLen) { + ALOGE("I frame Len is 0, INVALID"); + return ESESTATUS_FAILED; + } + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = IFRAME; + frame_len = (iFrameData.sendDataLen + PH_PROTO_7816_HEADER_LEN + + PH_PROTO_7816_CRC_LEN + 2); + + p_framebuff = (uint8_t*)phNxpEse_memalloc(frame_len * sizeof(uint8_t)); + if (NULL == p_framebuff) { + ALOGE("Heap allocation failed"); + return ESESTATUS_FAILED; + } + + /* frame the packet */ + p_framebuff[0] = 0x00; /* NAD Byte */ + + if (iFrameData.isChained) { + /* make B6 (M) bit high */ + pcb_byte |= PH_PROTO_7816_CHAINING; + } + + /* Update the send seq no */ + pcb_byte |= + (phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo << 6); + + /* store the pcb byte */ + p_framebuff[1] = pcb_byte; + if (iFrameData.sendDataLen > + IFSC_SIZE_SEND) { /* Case for frame size > 254 bytes */ + p_framebuff[2] = EXTENDED_FRAME_MARKER; + uint8_t mask = (iFrameData.sendDataLen) & EXTENDED_FRAME_MARKER; + p_framebuff[4] = mask; + mask = ((iFrameData.sendDataLen) >> 8) & EXTENDED_FRAME_MARKER; + p_framebuff[3] = mask; + /* store I frame */ + phNxpEse_memcpy(&(p_framebuff[5]), + iFrameData.p_data + iFrameData.dataOffset, + iFrameData.sendDataLen); + } else { /* Case for frame size < 254 bytes */ + /* store I frame length */ + p_framebuff[2] = iFrameData.sendDataLen; + frame_len = frame_len - 2; + /* store I frame */ + phNxpEse_memcpy(&(p_framebuff[3]), + iFrameData.p_data + iFrameData.dataOffset, + iFrameData.sendDataLen); + } + + p_framebuff[frame_len - 1] = + phNxpEseProto7816_ComputeLRC(p_framebuff, 0, (frame_len - 1)); + + status = phNxpEseProto7816_SendRawFrame(frame_len, p_framebuff); + + phNxpEse_free(p_framebuff); + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SetNextIframeContxt + * + * Description This internal function is called to set the context for next + *I-frame. + * Not applicable for the first I-frame of the transceive + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_SetFirstIframeContxt(void) { + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.dataOffset = 0; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo ^ 1; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME; + if (phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen > + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo + .currentDataLenIFS) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = true; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen = + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo + .currentDataLenIFS; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen = + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen - + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo + .currentDataLenIFS; + } else { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen = + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = false; + } + ALOGD_IF(ese_debug_enabled, "I-Frame Data Len: %d Seq. no:%d", + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen, + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo); + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SetNextIframeContxt + * + * Description This internal function is called to set the context for next + *I-frame. + * Not applicable for the first I-frame of the transceive + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_SetNextIframeContxt(void) { + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + /* Expecting to reach here only after first of chained I-frame is sent and + * before the last chained is sent */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME; + + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo ^ 1; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.dataOffset = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.dataOffset + + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.currentDataLenIFS; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.p_data = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.p_data; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.currentDataLenIFS = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.currentDataLenIFS; + + // if chained + if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.totalDataLen > + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo + .currentDataLenIFS) { + ALOGD_IF(ese_debug_enabled, "Process Chained Frame"); + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = true; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo + .currentDataLenIFS; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.totalDataLen - + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo + .currentDataLenIFS; + } else { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.isChained = false; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.totalDataLen; + } + ALOGD_IF(ese_debug_enabled, "I-Frame Data Len: %d", + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.sendDataLen); + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ResetRecovery + * + * Description This internal function is called to do reset the recovery + *pareameters + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_SaveIframeData(uint8_t* p_data, + uint32_t data_len) { + ESESTATUS status = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + ALOGD_IF(ese_debug_enabled, "Data[0]=0x%x len=%d Data[%d]=0x%x", p_data[0], + data_len, data_len - 1, p_data[data_len - 1]); + if (ESESTATUS_SUCCESS != phNxpEse_StoreDatainList(data_len, p_data)) { + ALOGE("%s - Error storing chained data in list", __FUNCTION__); + } else { + status = ESESTATUS_SUCCESS; + } + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ResetRecovery + * + * Description This internal function is called to do reset the recovery + *pareameters + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_ResetRecovery(void) { + phNxpEseProto7816_3_Var.recoveryCounter = 0; + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEseProto7816_RecoverySteps + * + * Description This internal function is called when 7816-3 stack failed to + *recover + * after PH_PROTO_7816_FRAME_RETRY_COUNT, and the interface has + *to be + * recovered + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_RecoverySteps(void) { + if (phNxpEseProto7816_3_Var.recoveryCounter <= GET_FRAME_RETRY_COUNT()) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = + INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_INTF_RST; + } else { /* If recovery fails */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + ALOGE("%s Recovery failed", __FUNCTION__); + } + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEseProto7816_DecodeSecureTimer + * + * Description This internal function is to decode the secure timer. + * value from the payload + * Returns void + * + ******************************************************************************/ +static void phNxpEseProto7816_DecodeSecureTimer(uint8_t* frameOffset, + unsigned int* secureTimer, + uint8_t* p_data) { + uint8_t byteCounter = 0; + uint8_t dataLength = p_data[++(*frameOffset)]; /* To get the L of TLV */ + if (dataLength > 0) { + /* V of TLV: Retrieve each byte(4 byte) and push it to get the secure timer + * value (unsigned long) */ + for (byteCounter = 1; byteCounter <= dataLength; byteCounter++) { + (*frameOffset)++; + *secureTimer = (*secureTimer) << 8; + *secureTimer |= p_data[(*frameOffset)]; + } + } else { + (*frameOffset)++; /* Goto the end of current marker if length is zero */ + } + return; +} + +/****************************************************************************** + * Function phNxpEseProto7816_DecodeSFrameIFSData + * + * Description This internal function is to decode S-frame payload. + * Returns void + * + ******************************************************************************/ +static void phNxpEseProto7816_DecodeSFrameIFSData(uint8_t* p_data) { + uint16_t ifsd_data = 0; + if (p_data[2] == 1) { + ifsd_data = p_data[3]; + } else if (p_data[2] == 2) { + ifsd_data = p_data[3]; + ifsd_data <<= 8; + ifsd_data |= p_data[4]; + } + if (ifsd_data == phNxpEseProto7816_3_Var.currentIFSDSize) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.currentDataLenIFS = + phNxpEseProto7816_3_Var.currentIFSDSize; + ALOGD_IF(ese_debug_enabled, "%s IFS adjustment: Max DataLen=%d \n", + __FUNCTION__, + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo + .currentDataLenIFS); + } else { + ALOGE("%s ERROR IFS adjustment: Max DataLen=%d \n", __FUNCTION__, + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo + .currentDataLenIFS); + } +} + +/****************************************************************************** + * Function phNxpEseProto7816_DecodeSFrameATRData + * + * Description This internal function is to decode S-frame payload. + * Returns void + * + ******************************************************************************/ +static void phNxpEseProto7816_DecodeSFrameATRData(uint8_t* p_data) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC = 0; + /* Default IFSC size */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.defaultDataLenIFSC = + p_data[16]; + // phNxpEse_memcpy(phNxpEseProto7816_3_Var.pAtrData, &p_data[3], p_data[2]); + /* Max IFSC size */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC = + (p_data[18] << 8); + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC |= + (p_data[19]); + if (!p_data[2]) + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC = + IFSC_SIZE_SEND; + + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.atrInfo.len, + &p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET], + sizeof(phNxpEseProto7816_ATR_Info_t)); + + ALOGD_IF( + ese_debug_enabled, + "%s Max DataLen=%d Current DataLen=%d Default DataLen=%d \n", + __FUNCTION__, + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC, + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.currentDataLenIFS, + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo + .defaultDataLenIFSC); + ALOGD_IF(ese_debug_enabled, "ATR Data Follows"); + ALOGD_IF(ese_debug_enabled, "======================"); + ALOGD_IF(ese_debug_enabled, "ATR Length = %d", + phNxpEseProto7816_3_Var.atrInfo.len); + ALOGD_IF(ese_debug_enabled, "Vendor ID = 0x%.2x%.2x%.2x%.2x%.2x", + phNxpEseProto7816_3_Var.atrInfo.vendorID[0], + phNxpEseProto7816_3_Var.atrInfo.vendorID[1], + phNxpEseProto7816_3_Var.atrInfo.vendorID[2], + phNxpEseProto7816_3_Var.atrInfo.vendorID[3], + phNxpEseProto7816_3_Var.atrInfo.vendorID[4]); + ALOGD_IF(ese_debug_enabled, "DLL-IC = supports T%d", + phNxpEseProto7816_3_Var.atrInfo.dll_IC); + ALOGD_IF(ese_debug_enabled, "BGT = %d ms", + (phNxpEseProto7816_3_Var.atrInfo.bgt[0] << 8) | + (phNxpEseProto7816_3_Var.atrInfo.bgt[1])); + ALOGD_IF(ese_debug_enabled, "BWT = %d ms", + phNxpEseProto7816_3_Var.atrInfo.bwt[0] << 8 | + phNxpEseProto7816_3_Var.atrInfo.bwt[1]); + ALOGD_IF(ese_debug_enabled, "Max supported frequency = %d Hz", + phNxpEseProto7816_3_Var.atrInfo.maxFreq[0] << 8 | + phNxpEseProto7816_3_Var.atrInfo.maxFreq[1]); + ALOGD_IF(ese_debug_enabled, "Checksum LRC(0)/CRC(1) supports = 0x%x", + phNxpEseProto7816_3_Var.atrInfo.checksum); + ALOGD_IF(ese_debug_enabled, "DefaultIFSC = %d bytes", + phNxpEseProto7816_3_Var.atrInfo.defaultIFSC); + ALOGD_IF(ese_debug_enabled, "Max IFSC = %d bytes", + phNxpEseProto7816_3_Var.atrInfo.maxIFSC[0] << 8 | + phNxpEseProto7816_3_Var.atrInfo.maxIFSC[1]); + ALOGD_IF(ese_debug_enabled, "Capabilities = 0x%x", + phNxpEseProto7816_3_Var.atrInfo.capabilities[0] << 8 | + phNxpEseProto7816_3_Var.atrInfo.capabilities[1]); + + if (phNxpEseProto7816_3_Var.atrInfo.vendorID[4] >= PH_SE_OS_VERSION_11) { + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.extndAtrInfo.channelNo, + &p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] + + sizeof(phNxpEseProto7816_ATR_Info_t), + sizeof(phNxpEseProto7816_ATR_Info2_t)); + ALOGD_IF(ese_debug_enabled, "Channel Number = 0x%x", + phNxpEseProto7816_3_Var.extndAtrInfo.channelNo); + ALOGD_IF( + ese_debug_enabled, "OS Type = %s", + (phNxpEseProto7816_3_Var.extndAtrInfo.osType == 0x01 ? "JCOP Mode" + : "OSU Mode")); + } + if (phNxpEseProto7816_3_Var.atrInfo.vendorID[PH_PROTO_ATR_RSP_VENDOR_ID_LEN - + 1] >= PH_SE_OS_VERSION_20) { + phNxpEse_setOsVersion(OS_VERSION_6_2); + } else if (phNxpEseProto7816_3_Var.atrInfo + .vendorID[PH_PROTO_ATR_RSP_VENDOR_ID_LEN - 1] >= + PH_SE_OS_VERSION_11) { + phNxpEse_setOsVersion(OS_VERSION_5_2_2); + } else if (phNxpEseProto7816_3_Var.atrInfo + .vendorID[PH_PROTO_ATR_RSP_VENDOR_ID_LEN - 1] == + PH_SE_OS_VERSION_10) { + phNxpEse_setOsVersion(OS_VERSION_5_2); + } else if (phNxpEseProto7816_3_Var.atrInfo + .vendorID[PH_PROTO_ATR_RSP_VENDOR_ID_LEN - 1] == + PH_PROTO_7816_VALUE_ZERO) { + phNxpEse_setOsVersion(OS_VERSION_5_1); + } + + ALOGD_IF(ese_debug_enabled, "======================"); +} + +/****************************************************************************** + * Function phNxpEseProto7816_DecodeSFrameData + * + * Description This internal function is to decode S-frame payload. + * Returns void + * + ******************************************************************************/ +static void phNxpEseProto7816_DecodeSFrameSecureTimerData(uint8_t* p_data) { + uint8_t maxSframeLen = 0, dataType = 0, frameOffset = 0; + frameOffset = PH_PROPTO_7816_FRAME_LENGTH_OFFSET; + maxSframeLen = + p_data[frameOffset] + + frameOffset; /* to be in sync with offset which starts from index 0 */ + + /* Secure Timer specific parser */ + while (maxSframeLen > frameOffset) { + frameOffset += 1; /* To get the Type (TLV) */ + dataType = p_data[frameOffset]; + ALOGD_IF(ese_debug_enabled, "%s frameoffset=%d value=0x%x\n", __FUNCTION__, + frameOffset, p_data[frameOffset]); + switch (dataType) /* Type (TLV) */ + { + case PH_PROPTO_7816_SFRAME_TIMER1: + phNxpEseProto7816_DecodeSecureTimer( + &frameOffset, + &phNxpEseProto7816_3_Var.secureTimerParams.secureTimer1, p_data); + break; + case PH_PROPTO_7816_SFRAME_TIMER2: + phNxpEseProto7816_DecodeSecureTimer( + &frameOffset, + &phNxpEseProto7816_3_Var.secureTimerParams.secureTimer2, p_data); + break; + case PH_PROPTO_7816_SFRAME_TIMER3: + phNxpEseProto7816_DecodeSecureTimer( + &frameOffset, + &phNxpEseProto7816_3_Var.secureTimerParams.secureTimer3, p_data); + break; + default: + frameOffset += + p_data[frameOffset + 1]; /* Goto the end of current marker */ + break; + } + } + ALOGD_IF(ese_debug_enabled, "secure timer t1 = 0x%x t2 = 0x%x t3 = 0x%x", + phNxpEseProto7816_3_Var.secureTimerParams.secureTimer1, + phNxpEseProto7816_3_Var.secureTimerParams.secureTimer2, + phNxpEseProto7816_3_Var.secureTimerParams.secureTimer3); + return; +} + +/****************************************************************************** + * Function phNxpEseProto7816_DecodeFrame + * + * Description This internal function is used to + * 1. Identify the received frame + * 2. If the received frame is I-frame with expected sequence + number, store it or else send R-NACK + 3. If the received frame is R-frame, + 3.1 R-ACK with expected seq. number: Send the next + chained I-frame + 3.2 R-ACK with different sequence number: Sebd the R-Nack + 3.3 R-NACK: Re-send the last frame + 4. If the received frame is S-frame, send back the correct + S-frame response. + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_DecodeFrame(uint8_t* p_data, + uint32_t data_len) { + ESESTATUS status = ESESTATUS_SUCCESS; + uint8_t pcb; + phNxpEseProto7816_PCB_bits_t pcb_bits; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + ALOGD_IF(ese_debug_enabled, "Retry Counter = %d\n", + phNxpEseProto7816_3_Var.recoveryCounter); + pcb = p_data[PH_PROPTO_7816_PCB_OFFSET]; + // memset(&phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.rcvPcbBits, 0x00, + // sizeof(struct PCB_BITS)); + phNxpEse_memset(&pcb_bits, 0x00, sizeof(phNxpEseProto7816_PCB_bits_t)); + phNxpEse_memcpy(&pcb_bits, &pcb, sizeof(uint8_t)); + + if (0x00 == pcb_bits.msb) /* I-FRAME decoded should come here */ + { + if (!phNxpEseProto7816_ResendLastSFrameReq()) { + ALOGD_IF(ese_debug_enabled, "%s I-Frame Received", __FUNCTION__); + phNxpEseProto7816_CheckAndNotifyWtx(WTX_END); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = IFRAME; + if (phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo != + pcb_bits.bit7) // != pcb_bits->bit7) + { + ALOGD_IF(ese_debug_enabled, "%s I-Frame lastRcvdIframeInfo.seqNo:0x%x", + __FUNCTION__, pcb_bits.bit7); + phNxpEseProto7816_ResetRecovery(); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo = 0x00; + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo |= + pcb_bits.bit7; + + if (pcb_bits.bit6) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.isChained = + true; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode = + NO_ERROR; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_ACK; + if (EXTENDED_FRAME_MARKER == p_data[2] && + (data_len > 6)) /* Checking for extended frame prologue */ + { + status = phNxpEseProto7816_SaveIframeData(&p_data[5], data_len - 6); + } else if (data_len > 4) { + status = phNxpEseProto7816_SaveIframeData(&p_data[3], data_len - 4); + } else { + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_NACK; + ALOGD_IF(ese_debug_enabled, "%s Invalid IframeData", __FUNCTION__); + } + } else { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.isChained = + false; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + if (EXTENDED_FRAME_MARKER == p_data[2] && + (data_len > 6)) /* Checking for extended frame prologue */ + { + status = phNxpEseProto7816_SaveIframeData(&p_data[5], data_len - 6); + } else if (data_len > 4) { + status = phNxpEseProto7816_SaveIframeData(&p_data[3], data_len - 4); + } else { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_NACK; + ALOGD_IF(ese_debug_enabled, "%s Invalid IframeData", __FUNCTION__); + } + } + } else { + phNxpEse_Sleep(GET_DELAY_ERROR_RECOVERY()); + if (phNxpEseProto7816_3_Var.recoveryCounter < GET_FRAME_RETRY_COUNT()) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode = + OTHER_ERROR; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_NACK; + phNxpEseProto7816_3_Var.recoveryCounter++; + } else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + } + } + } else if ((0x01 == pcb_bits.msb) && + (0x00 == pcb_bits.bit7)) /* R-FRAME decoded should come here */ + { + ALOGD_IF(ese_debug_enabled, "%s R-Frame Received", __FUNCTION__); + phNxpEseProto7816_CheckAndNotifyWtx(WTX_END); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.seqNo = + 0; // = 0; + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.seqNo |= + pcb_bits.bit5; + + if ((pcb_bits.lsb == 0x00) && (pcb_bits.bit2 == 0x00)) { + if (!phNxpEseProto7816_ResendLastSFrameReq()) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode = + NO_ERROR; + phNxpEseProto7816_ResetRecovery(); + if (phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.seqNo != + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo) { + status = phNxpEseProto7816_SetNextIframeContxt(); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_IFRAME; + } else { + // error handling. + } + } + } /* Error handling 1 : Parity error */ + else if (((pcb_bits.lsb == 0x01) && (pcb_bits.bit2 == 0x00)) || + /* Error handling 2: Other indicated error */ + ((pcb_bits.lsb == 0x00) && (pcb_bits.bit2 == 0x01)) || + /* Error handling 3 : Frame Missing error */ + ((pcb_bits.lsb == 0x01) && (pcb_bits.bit2 == 0x01))) { + phNxpEse_Sleep(GET_DELAY_ERROR_RECOVERY()); + if ((pcb_bits.lsb == 0x00) && (pcb_bits.bit2 == 0x01)) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode = + OTHER_ERROR; + } else if ((pcb_bits.lsb == 0x01) && (pcb_bits.bit2 == 0x00)) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode = + PARITY_ERROR; + } else { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode = + SOF_MISSED_ERROR; + } + if (phNxpEseProto7816_3_Var.recoveryCounter < GET_FRAME_RETRY_COUNT()) { + if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == IFRAME) { + /*Only for R-NACK other issue re sync*/ + if ((pcb_bits.lsb == 0x00) && (pcb_bits.bit2 == 0x01)) { + if (phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo + .seqNo != phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx + .IframeInfo.seqNo && + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo + .isChained == false) { + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_RSYNC; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo + .sFrameType = RESYNCH_REQ; + } else { + /*If R-NACK with sequence no matching then also reissue frame*/ + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx, + &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx, + sizeof(phNxpEseProto7816_NextTx_Info_t)); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + } + } else { + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx, + &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx, + sizeof(phNxpEseProto7816_NextTx_Info_t)); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + } + } else if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == + RFRAME) { + /* Usecase to reach the below case: + I-frame sent first, followed by R-NACK and we receive a R-NACK with + last sent I-frame sequence number*/ + if ((phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo + .seqNo == + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo) && + (phNxpEseProto7816_3_Var.lastSentNonErrorframeType == IFRAME)) { + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx, + &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx, + sizeof(phNxpEseProto7816_NextTx_Info_t)); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + } + /* Usecase to reach the below case: + R-frame sent first, followed by R-NACK and we receive a R-NACK with + next expected I-frame sequence number*/ + else if ((phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo + .seqNo != phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx + .IframeInfo.seqNo) && + (phNxpEseProto7816_3_Var.lastSentNonErrorframeType == + RFRAME)) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode = + NO_ERROR; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_ACK; + } + /* Usecase to reach the below case: + I-frame sent first, followed by R-NACK and we receive a R-NACK with + next expected I-frame sequence number + all the other unexpected + scenarios */ + else { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode = + OTHER_ERROR; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_NACK; + } + } else if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == + SFRAME) { + /* Copy the last S frame sent */ + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx, + &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx, + sizeof(phNxpEseProto7816_NextTx_Info_t)); + } + phNxpEseProto7816_3_Var.recoveryCounter++; + } else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + // resend previously send I frame + } else /* Error handling 4 */ + { + phNxpEse_Sleep(GET_DELAY_ERROR_RECOVERY()); + if (phNxpEseProto7816_3_Var.recoveryCounter < GET_FRAME_RETRY_COUNT()) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode = + UNDEFINED_ERROR; + phNxpEseProto7816_3_Var.recoveryCounter++; + } else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + } + } else if ((0x01 == pcb_bits.msb) && + (0x01 == pcb_bits.bit7)) /* S-FRAME decoded should come here */ + { + ALOGD_IF(ese_debug_enabled, "%s S-Frame Received", __FUNCTION__); + int32_t frameType = (int32_t)(pcb & 0x3F); /*discard upper 2 bits */ + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = SFRAME; + if (frameType != WTX_REQ) { + phNxpEseProto7816_CheckAndNotifyWtx(WTX_END); + } + phNxpEseProto7816_ResetRecovery(); + switch (frameType) { + case RESYNCH_REQ: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + RESYNCH_REQ; + break; + case RESYNCH_RSP: + if (phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo + .errCode == OTHER_ERROR) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo + .sFrameType = RESYNCH_RSP; + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo.errCode = + NO_ERROR; + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx, + &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx, + sizeof(phNxpEseProto7816_NextTx_Info_t)); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo = + PH_PROTO_7816_VALUE_ZERO; + /* Initialized the I-Frame sequence number as boot time, + as R-SYNCH has reset the Jcop seq number */ + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo = + PH_PROTO_7816_VALUE_ONE; + } else { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo + .sFrameType = RESYNCH_RSP; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + } + break; + case IFS_REQ: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + IFS_REQ; + break; + case IFS_RES: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + IFS_RES; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) + phNxpEseProto7816_DecodeSFrameIFSData(p_data); + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + break; + case ABORT_REQ: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + ABORT_REQ; + break; + case ABORT_RES: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + ABORT_RES; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + break; + case WTX_REQ: + phNxpEseProto7816_3_Var.wtx_counter++; + ALOGD_IF(ese_debug_enabled, "%s Wtx_counter value - %lu", __FUNCTION__, + phNxpEseProto7816_3_Var.wtx_counter); + ALOGD_IF(ese_debug_enabled, "%s Wtx_counter wtx_counter_limit - %lu", + __FUNCTION__, phNxpEseProto7816_3_Var.wtx_counter_limit); + /* Previous sent frame is some S-frame but not WTX response S-frame */ + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0 && + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo.sFrameType != + WTX_RSP && + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == SFRAME) { + /* Goto recovery if it + keep coming here for more than recovery counter max. value */ + if (phNxpEseProto7816_3_Var.recoveryCounter < + GET_FRAME_RETRY_COUNT()) { /* Re-transmitting the previous + sent S-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + phNxpEseProto7816_3_Var.recoveryCounter++; + } else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + } else { + /* Checking for WTX counter with max. allowed WTX count */ + if (phNxpEseProto7816_3_Var.wtx_counter == + phNxpEseProto7816_3_Var.wtx_counter_limit) { + phNxpEseProto7816_CheckAndNotifyWtx(WTX_END); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ALOGD_IF(ese_debug_enabled, + "%s Power cycle to eSE max " + "WTX received", + __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + status = ESESTATUS_TRANSCEIVE_FAILED; + } else { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo + .sFrameType = INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo + .sFrameType = INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_INTF_RST; + ALOGD_IF(ese_debug_enabled, + "%s Interface Reset to eSE wtx" + " count reached!!!", + __FUNCTION__); + } + } else { + phNxpEse_Sleep(GET_DELAY_ERROR_RECOVERY()); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo + .sFrameType = WTX_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = + WTX_RSP; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_WTX_RSP; + } + } + break; + case WTX_RSP: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + WTX_RSP; + break; + case INTF_RESET_REQ: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + INTF_RESET_REQ; + break; + case INTF_RESET_RSP: + phNxpEseProto7816_ResetProtoParams(); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + INTF_RESET_RSP; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameATRData(p_data); + } else { + phNxpEse_setOsVersion(OS_VERSION_4_0); + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + break; + case PROP_END_APDU_REQ: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + PROP_END_APDU_REQ; + break; + case PROP_END_APDU_RSP: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + PROP_END_APDU_RSP; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) + phNxpEseProto7816_DecodeSFrameSecureTimerData(p_data); + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + break; + case HARD_RESET_REQ: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + HARD_RESET_REQ; + break; + case HARD_RESET_RSP: + // This is 4ms delay and delay of 1ms in also there in line 1401 before + // next Tx + phNxpEse_Sleep(HARD_RESET_RES_DELAY); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + HARD_RESET_RSP; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + /*Response status either success/fail*/ + if (!p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET + 1]) + status = ESESTATUS_FAILED; + else + status = ESESTATUS_SUCCESS; + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + break; + case ATR_RSP: + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo.sFrameType = + ATR_RSP; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameATRData(p_data); + phNxpEse_StoreDatainList( + p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET], + &p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET + 1]); + } else { + phNxpEse_setOsVersion(OS_VERSION_4_0); + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + break; + default: + ALOGE("%s Wrong S-Frame Received", __FUNCTION__); + break; + } + /*After S-Frame Rx 1 msec delay before next Tx*/ + if ((GET_CHIP_OS_VERSION() != OS_VERSION_4_0) && + (frameType != PROP_END_APDU_RSP)) { + phNxpEse_Sleep(1000); + } + } else { + ALOGD_IF(ese_debug_enabled, "%s Wrong-Frame Received", __FUNCTION__); + } + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ProcessResponse + * + * Description This internal function is used to + * 1. Check the LRC + * 2. Initiate decoding of received frame of data. + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_ProcessResponse(void) { + uint32_t data_len = 0; + uint8_t* p_data = NULL; + ESESTATUS status = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + status = phNxpEseProto7816_GetRawFrame(&data_len, &p_data); + ALOGD_IF(ese_debug_enabled, "%s p_data ----> %p len ----> 0x%x", __FUNCTION__, + p_data, data_len); + if (ESESTATUS_SUCCESS == status) { + /* Resetting the timeout counter */ + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + /* LRC check followed */ + status = phNxpEseProto7816_CheckLRC(data_len, p_data); + if (status == ESESTATUS_SUCCESS) { + /* Resetting the RNACK retry counter */ + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + status = phNxpEseProto7816_DecodeFrame(p_data, data_len); + } else { + ALOGE("%s LRC Check failed", __FUNCTION__); + if (phNxpEseProto7816_3_Var.rnack_retry_counter < + phNxpEseProto7816_3_Var.rnack_retry_limit) { + /*If Last sent Non-error frame is S-Frame*/ + if (!phNxpEseProto7816_ResendLastSFrameReq()) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode = + PARITY_ERROR; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.seqNo = + (!phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo + .seqNo) + << 4; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_NACK; + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + phNxpEse_Sleep(GET_DELAY_ERROR_RECOVERY()); + } + } + phNxpEseProto7816_3_Var.rnack_retry_counter++; + } else { + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + /* Re-transmission failed completely, Going to exit */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + } + } + } else { + ALOGD_IF(ese_debug_enabled, "%s phNxpEseProto7816_GetRawFrame failed", + __FUNCTION__); + if ((SFRAME == phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType) && + ((WTX_RSP == + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo.sFrameType) || + (RESYNCH_RSP == + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo.sFrameType))) { + if (phNxpEseProto7816_3_Var.rnack_retry_counter < + phNxpEseProto7816_3_Var.rnack_retry_limit) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.errCode = + OTHER_ERROR; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo.seqNo = + (!phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo) + << 4; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_R_NACK; + phNxpEseProto7816_3_Var.rnack_retry_counter++; + } else { + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + /* Re-transmission failed completely, Going to exit */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + } + } else { + phNxpEse_Sleep(GET_DELAY_ERROR_RECOVERY()); + /* re transmit the frame */ + if (phNxpEseProto7816_3_Var.timeoutCounter < + PH_PROTO_7816_TIMEOUT_RETRY_COUNT) { + phNxpEseProto7816_3_Var.timeoutCounter++; + ALOGD_IF(ese_debug_enabled, "%s re-transmitting the previous frame", + __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + } else { + /* Re-transmission failed completely, Going to exit */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + status = ESESTATUS_FAILED; + } + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + ALOGD_IF(ese_debug_enabled, "%s calling phNxpEse_StoreDatainList", + __FUNCTION__); + phNxpEse_StoreDatainList(data_len, p_data); + } + } + } + ALOGD_IF(ese_debug_enabled, "Exit %s Status 0x%x", __FUNCTION__, status); + return status; +} + +/****************************************************************************** + * Function TransceiveProcess + * + * Description This internal function is used to + * 1. Send the raw data received from application after + *computing LRC + * 2. Receive the response data from ESE, decode, process + *and + * store the data. + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS TransceiveProcess(void) { + ESESTATUS status = ESESTATUS_FAILED; + sFrameInfo_t sFrameInfo; + memset(&sFrameInfo, 0, sizeof(sFrameInfo_t)); + + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + while (phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState != + IDLE_STATE) { + ALOGD_IF(ese_debug_enabled, "%s nextTransceiveState %x", __FUNCTION__, + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState); + switch (phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState) { + case SEND_IFRAME: + status = phNxpEseProto7816_SendIframe( + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo); + break; + case SEND_R_ACK: + status = phNxpEseProto7816_sendRframe(RACK); + break; + case SEND_R_NACK: + status = phNxpEseProto7816_sendRframe(RNACK); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + phNxpEse_Sleep(GET_DELAY_ERROR_RECOVERY()); + } + break; + case SEND_S_RSYNC: + sFrameInfo.sFrameType = RESYNCH_REQ; + status = phNxpEseProto7816_SendSFrame(sFrameInfo); + break; + case SEND_S_INTF_RST: + sFrameInfo.sFrameType = INTF_RESET_REQ; + status = phNxpEseProto7816_SendSFrame(sFrameInfo); + break; + case SEND_S_IFS_ADJ: + sFrameInfo.sFrameType = IFS_REQ; + status = phNxpEseProto7816_SendSFrame(sFrameInfo); + break; + case SEND_S_EOS: + sFrameInfo.sFrameType = PROP_END_APDU_REQ; + sFrameInfo.len = + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.len; + sFrameInfo.p_data = + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.p_data; + status = phNxpEseProto7816_SendSFrame(sFrameInfo); + break; + case SEND_S_WTX_RSP: + sFrameInfo.sFrameType = WTX_RSP; + status = phNxpEseProto7816_SendSFrame(sFrameInfo); + phNxpEseProto7816_CheckAndNotifyWtx(WTX_ONGOING); + break; + case SEND_S_HRD_RST: + sFrameInfo.sFrameType = HARD_RESET_REQ; + status = phNxpEseProto7816_SendSFrame(sFrameInfo); + break; + case SEND_S_ATR_REQ: + sFrameInfo.sFrameType = ATR_REQ; + status = phNxpEseProto7816_SendSFrame(sFrameInfo); + break; + default: + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + break; + } + if (ESESTATUS_SUCCESS == status) { + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx, + &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx, + sizeof(phNxpEseProto7816_NextTx_Info_t)); + status = phNxpEseProto7816_ProcessResponse(); + } else { + ALOGE("%s Transceive send failed, going to recovery!", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + IDLE_STATE; + } + }; + /*Timeout condition when previously WTX_ONGOING is notified + *WTX_END shall be notified from here */ + phNxpEseProto7816_CheckAndNotifyWtx(WTX_END); + ALOGD_IF(ese_debug_enabled, "Exit %s Status 0x%x", __FUNCTION__, status); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_CheckAndNotifyWtx + * + * Description This function is used to + * 1. Check any WTX received previously + *computing LRC + * 2. Check WTX_counter limit is reached wtx_ntf limit + *and + * 3. Notify if wtx counter is greater than wtx_ntf + * + * Returns None. + * + ******************************************************************************/ +static void phNxpEseProto7816_CheckAndNotifyWtx(phNxpEse_wtxState state) { + if (phNxpEseProto7816_3_Var.wtx_counter) { + if (state == WTX_END) { + if (phNxpEseProto7816_3_Var.wtx_counter >= + phNxpEseProto7816_3_Var.wtx_ntf_limit) { + phNxpEse_NotifySEWtxRequest(WTX_END); + } + phNxpEseProto7816_3_Var.wtx_counter = 0; + } else if (state == WTX_ONGOING) { + if (phNxpEseProto7816_3_Var.wtx_counter == + phNxpEseProto7816_3_Var.wtx_ntf_limit) { + phNxpEse_NotifySEWtxRequest(WTX_ONGOING); + } + } + } +} + +/****************************************************************************** + * Function phNxpEseProto7816_Transceive + * + * Description This function is used to + * 1. Send the raw data received from application after + *computing LRC + * 2. Receive the response data from ESE, decode, process + *and + * store the data. + * 3. Get the final complete data and sent back to application + * + * Returns On success return true or else false. + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_Transceive(phNxpEse_data* pCmd, + phNxpEse_data* pRsp) { + ESESTATUS status = ESESTATUS_FAILED; + ESESTATUS wStatus = ESESTATUS_FAILED; + phNxpEse_data pRes; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + if ((NULL == pCmd) || (NULL == pRsp) || + (phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState != + PH_NXP_ESE_PROTO_7816_IDLE)) + return status; + phNxpEse_memset(&pRes, 0x00, sizeof(phNxpEse_data)); + /* Updating the transceive information to the protocol stack */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.p_data = pCmd->p_data; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.totalDataLen = + pCmd->len; + ALOGD_IF(ese_debug_enabled, "Transceive data ptr 0x%p len:%d", pCmd->p_data, + pCmd->len); + status = phNxpEseProto7816_SetFirstIframeContxt(); + status = TransceiveProcess(); + if (ESESTATUS_FAILED == status || ESESTATUS_TRANSCEIVE_FAILED == status) { + /* ESE hard reset to be done */ + ALOGE("Transceive failed, hard reset to proceed"); + wStatus = phNxpEse_GetData(&pRes.len, &pRes.p_data); + if (ESESTATUS_SUCCESS == wStatus) { + ALOGD_IF(ese_debug_enabled, + "%s Data successfully received at 7816, packaging to " + "send upper layers: DataLen = %d", + __FUNCTION__, pRes.len); + } + } else { + // fetch the data info and report to upper layer. + wStatus = phNxpEse_GetData(&pRes.len, &pRes.p_data); + if (ESESTATUS_SUCCESS == wStatus) { + ALOGD_IF(ese_debug_enabled, + "%s Data successfully received at 7816, packaging to " + "send upper layers: DataLen = %d", + __FUNCTION__, pRes.len); + } else + status = ESESTATUS_FAILED; + } + + /* Copy the data to be read by the upper layer via transceive api */ + pRsp->len = pRes.len; + pRsp->p_data = pRes.p_data; + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + phNxpEseProto7816_3_Var.reset_type = RESET_TYPE_NONE; + ALOGD_IF(ese_debug_enabled, "Exit %s Status 0x%x", __FUNCTION__, status); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_RSync + * + * Description This function is used to send the RSync command + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_RSync(void) { + ESESTATUS status = ESESTATUS_FAILED; + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + /* send the end of session s-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = + RESYNCH_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_RSYNC; + status = TransceiveProcess(); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_HardReset + * + * Description This function is used to send the spi hard reset command + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_HardReset(void) { + ESESTATUS status = ESESTATUS_FAILED; + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + /* send the hard reset s-frame command*/ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = + HARD_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_HRD_RST; + status = TransceiveProcess(); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ResetProtoParams + * + * Description This function is used to reset the 7816 protocol stack + *instance + * + * Returns On success return true or else false. + * + ******************************************************************************/ +static ESESTATUS phNxpEseProto7816_ResetProtoParams(void) { + unsigned long int tmpWTXCountlimit = PH_PROTO_7816_VALUE_ZERO; + unsigned long int tmpRNACKCountlimit = PH_PROTO_7816_VALUE_ZERO; + unsigned long int tmpWtxNtfCountlimit = PH_PROTO_7816_VALUE_ZERO; + tmpWTXCountlimit = phNxpEseProto7816_3_Var.wtx_counter_limit; + tmpRNACKCountlimit = phNxpEseProto7816_3_Var.rnack_retry_limit; + tmpWtxNtfCountlimit = phNxpEseProto7816_3_Var.wtx_ntf_limit; + phNxpEse_memset(&phNxpEseProto7816_3_Var, PH_PROTO_7816_VALUE_ZERO, + sizeof(phNxpEseProto7816_t)); + phNxpEseProto7816_3_Var.wtx_counter_limit = tmpWTXCountlimit; + phNxpEseProto7816_3_Var.rnack_retry_limit = tmpRNACKCountlimit; + phNxpEseProto7816_3_Var.wtx_ntf_limit = tmpWtxNtfCountlimit; + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC = + IFSC_SIZE_SEND; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.defaultDataLenIFSC = + IFSC_SIZE_SEND; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.currentDataLenIFS = + IFSC_SIZE_SEND; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.p_data = NULL; + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.maxDataLenIFSC = + IFSC_SIZE_SEND; + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.defaultDataLenIFSC = + IFSC_SIZE_SEND; + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.currentDataLenIFS = + IFSC_SIZE_SEND; + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.p_data = NULL; + /* Initialized with sequence number of the last I-frame sent */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.seqNo = + PH_PROTO_7816_VALUE_ONE; + /* Initialized with sequence number of the last I-frame received */ + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo.seqNo = + PH_PROTO_7816_VALUE_ONE; + /* Initialized with sequence number of the last I-frame received */ + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo.seqNo = + PH_PROTO_7816_VALUE_ONE; + phNxpEseProto7816_3_Var.recoveryCounter = PH_PROTO_7816_VALUE_ZERO; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + phNxpEseProto7816_3_Var.wtx_counter = PH_PROTO_7816_VALUE_ZERO; + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = UNKNOWN; + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEseProto7816_Reset + * + * Description This function is used to reset the 7816 protocol stack + *instance + * + * Returns On success return true or else false. + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_Reset(void) { + ESESTATUS status = ESESTATUS_FAILED; + /* Resetting host protocol instance */ + phNxpEseProto7816_ResetProtoParams(); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + status = phNxpEseProto7816_HardReset(); + if (status == ESESTATUS_SUCCESS) { + /* Updating the ATR information(IFS,..) to 7816 stack */ + phNxpEse_data atrRsp; + phNxpEseProto7816_getAtr(&atrRsp); + phNxpEse_free(atrRsp.p_data); + } + } else { + /* Resynchronising ESE protocol instance */ + status = phNxpEseProto7816_RSync(); + } + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_Open + * + * Description This function is used to open the 7816 protocol stack + *instance + * + * Returns On success return true or else false. + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_Open(phNxpEseProto7816InitParam_t initParam) { + ESESTATUS status = ESESTATUS_FAILED; + status = phNxpEseProto7816_ResetProtoParams(); + ALOGD_IF(ese_debug_enabled, "%s: First open completed, Congratulations", + __FUNCTION__); + /* Update WTX max. limit */ + phNxpEseProto7816_3_Var.wtx_counter_limit = initParam.wtx_counter_limit; + phNxpEseProto7816_3_Var.rnack_retry_limit = initParam.rnack_retry_limit; + phNxpEseProto7816_3_Var.wtx_ntf_limit = initParam.wtx_ntf_limit; + if (initParam.interfaceReset) /* Do interface reset */ + { + status = phNxpEseProto7816_IntfReset(initParam.pSecureTimerParams); + if (ESESTATUS_SUCCESS == status) { + phNxpEse_memcpy(initParam.pSecureTimerParams, + &phNxpEseProto7816_3_Var.secureTimerParams, + sizeof(phNxpEseProto7816SecureTimer_t)); + } + } else /* Initialisation condition to achieve usecases like JCOP download */ + { + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + status = phNxpEseProto7816_HardReset(); + /* Updating the ATR information (Eg: IFS,..) to 7816 stack */ + if (status == ESESTATUS_SUCCESS) { + phNxpEse_data atrRsp; + phNxpEseProto7816_getAtr(&atrRsp); + phNxpEse_free(atrRsp.p_data); + } + } else { + status = phNxpEseProto7816_RSync(); + } + } + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_Close + * + * Description This function is used to close the 7816 protocol stack + *instance + * + * Returns On success return true or else false. + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_Close( + phNxpEseProto7816SecureTimer_t* pSecureTimerParams) { + ESESTATUS status = ESESTATUS_FAILED; + if (phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState != + PH_NXP_ESE_PROTO_7816_IDLE) + return status; + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_DEINIT; + phNxpEseProto7816_3_Var.recoveryCounter = 0; + phNxpEseProto7816_3_Var.wtx_counter = 0; + /* send the end of session s-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = + PROP_END_APDU_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.len = + PH_PROTO_7816_VALUE_ZERO; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_EOS; + status = TransceiveProcess(); + if (ESESTATUS_SUCCESS != status) { + /* reset all the structures */ + ALOGE("%s TransceiveProcess failed ", __FUNCTION__); + if (status == ESESTATUS_TRANSCEIVE_FAILED && + phNxpEseProto7816_3_Var.atrInfo.len > PH_PROTO_7816_VALUE_ZERO) { + if (phNxpEseProto7816_3_Var.atrInfo + .vendorID[PH_PROTO_ATR_RSP_VENDOR_ID_LEN - 1] < + PH_SE_OS_VERSION_10) { + ALOGD_IF(ese_debug_enabled, "%s shall trigger recovery", __FUNCTION__); + status = ESESTATUS_RESPONSE_TIMEOUT; + } + } + } + phNxpEse_memcpy(pSecureTimerParams, + &phNxpEseProto7816_3_Var.secureTimerParams, + sizeof(phNxpEseProto7816SecureTimer_t)); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_CloseAllSessions + * + * Description This function is used to close the 7816 protocol stack + *instance + * + * Returns On success return true or else false. + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_CloseAllSessions(void) { + ESESTATUS status = ESESTATUS_FAILED; + + /*Note:- Below OS version check using ATR shall + * be removed while integrating with TEE/REE as ATR + * information is not available in REE case*/ + + if (phNxpEseProto7816_3_Var.atrInfo.vendorID[PH_PROTO_ATR_RSP_VENDOR_ID_LEN - + 1] >= PH_SE_OS_VERSION_10) { + uint8_t* buffer = (uint8_t*)phNxpEse_memalloc(sizeof(uint8_t)); + if (buffer != NULL) { + buffer[PH_PROTO_7816_VALUE_ZERO] = PH_PROTO_CLOSE_ALL_SESSION_INF; + /* send the end of session s-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = + PROP_END_APDU_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.p_data = buffer; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.len = + PH_PROTO_CLOSE_ALL_SESSION_LEN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_EOS; + status = TransceiveProcess(); + if (ESESTATUS_FAILED == status) { + /* reset all the structures */ + ALOGD_IF(ese_debug_enabled, "%s EndOfSession failed ", __FUNCTION__); + } + phNxpEse_free(buffer); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + } + } else { + ALOGD_IF(ese_debug_enabled, "%s Function not supported ", __FUNCTION__); + status = ESESTATUS_SUCCESS; + } + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_IntfReset + * + * Description This function is used to reset just the current interface + * + * Returns On success return true or else false. + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_IntfReset( + phNxpEseProto7816SecureTimer_t* pSecureTimerParam) { + ESESTATUS status = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = + INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_INTF_RST; + status = TransceiveProcess(); + if (ESESTATUS_FAILED == status) { + /* reset all the structures */ + ALOGE("%s TransceiveProcess failed ", __FUNCTION__); + } + phNxpEse_memcpy(pSecureTimerParam, &phNxpEseProto7816_3_Var.secureTimerParams, + sizeof(phNxpEseProto7816SecureTimer_t)); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SetIfs + * + * Description This function is used to set IFSD value to card + * + * Returns On success return true or else false. + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_SetIfs(uint16_t IFS_Size) { + // phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC = + // IFSC_Size; + ESESTATUS status = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + /* IFSD > IFSC not allowed, card will reject by R-NACK so not sending */ + if (IFS_Size > + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC) { + phNxpEseProto7816_3_Var.currentIFSDSize = + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.maxDataLenIFSC; + /* IFSD is greater than IFSC , set max IFSC as IFSD*/ + ALOGD_IF(ese_debug_enabled, + "%s : IFSD greater than IFSC , set max IFSC as IFSD ", + __FUNCTION__); + } else { + phNxpEseProto7816_3_Var.currentIFSDSize = IFS_Size; + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = IFS_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_IFS_ADJ; + status = TransceiveProcess(); + if (ESESTATUS_FAILED == status) { + /* reset all the structures */ + ALOGE("%s TransceiveProcess failed ", __FUNCTION__); + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_GetIfs + * + * Description This function is used to get current IFS adjusted value wrt + *card + * + * Returns On success return true or else false. + * + ******************************************************************************/ +uint16_t phNxpEseProto7816_GetIfs(void) { + ALOGD_IF( + ese_debug_enabled, "Enter %s current IFSC = %d", __FUNCTION__, + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo.currentDataLenIFS); + return phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo + .currentDataLenIFS; +} + +/****************************************************************************** + * Function phNxpEseProto7816_GetOsMode + * + * Description This function is used to get current OS Mode + * + * Returns 0x01 : JCOP_MODE + * 0x02 : OSU_MODE + * + ******************************************************************************/ +phNxpEseProto7816_OsType_t phNxpEseProto7816_GetOsMode(void) { + phNxpEseProto7816_OsType_t mode = UNKNOWN_MODE; + if (GET_CHIP_OS_VERSION() >= OS_VERSION_5_2_2) { + if (phNxpEseProto7816_3_Var.extndAtrInfo.osType == MODE_JCOP) { + ALOGD_IF(ese_debug_enabled, "Enter %s OS Mode = %s", __FUNCTION__, + "JCOP Mode"); + mode = JCOP_MODE; + } else if (phNxpEseProto7816_3_Var.extndAtrInfo.osType == MODE_OSU) { + ALOGD_IF(ese_debug_enabled, "Enter %s OS Mode = %s", __FUNCTION__, + "OSU Mode"); + mode = OSU_MODE; + } else { + ALOGD_IF(ese_debug_enabled, "Enter %s OS Mode = %s", __FUNCTION__, + "UNKNOWN Mode"); + mode = UNKNOWN_MODE; + } + } else { + ALOGE("%s function not supported", __FUNCTION__); + } + return mode; +} + +/****************************************************************************** + * Function phNxpEseProto7816_getAtr + * + * Description This function is used to get the ATR data from ESE + * + * Returns On success return true or else false + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_getAtr(phNxpEse_data* pATRRsp) { + ESESTATUS status = ESESTATUS_FAILED; + + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo.sFrameType = ATR_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = + SEND_S_ATR_REQ; + status = TransceiveProcess(); + if (ESESTATUS_FAILED == status) { + /* reset all the structures */ + ALOGD_IF(ese_debug_enabled, "%s TransceiveProcess failed ", __FUNCTION__); + } + + status = phNxpEse_GetData(&(pATRRsp->len), &(pATRRsp->p_data)); + if (ESESTATUS_SUCCESS == status) { + ALOGD_IF(ese_debug_enabled, + "%s Data successfully received at 7816, packaging to " + "send upper layers: DataLen = %d", + __FUNCTION__, pATRRsp->len); + } else + status = ESESTATUS_FAILED; + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = + PH_NXP_ESE_PROTO_7816_IDLE; + ALOGD_IF(ese_debug_enabled, "Exit %s ", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SetEndPoint + * + * Description This function is used to set end point protocol context + * + * Returns Always return TRUE (1). + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_SetEndPoint(uint8_t uEndPoint) { + ESESTATUS status = ESESTATUS_FAILED; + if (uEndPoint == END_POINT_ESE || uEndPoint == END_POINT_EUICC) { + phNxpEseProto7816_3_Var = phNxpEseProto7816_ptr[uEndPoint]; + status = ESESTATUS_SUCCESS; + } else { + /*Do nothing return fail*/ + } + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ResetEndPoint + * + * Description This function is used to set end point protocol context + * + * Returns Always return TRUE (1). + * + ******************************************************************************/ +ESESTATUS phNxpEseProto7816_ResetEndPoint(uint8_t uEndPoint) { + ESESTATUS status = ESESTATUS_FAILED; + if (uEndPoint == END_POINT_ESE || uEndPoint == END_POINT_EUICC) { + phNxpEseProto7816_ptr[uEndPoint] = phNxpEseProto7816_3_Var; + status = ESESTATUS_SUCCESS; + } else { + /*Do nothing return fail*/ + } + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ResendLastSFrameReq + * + * Description This function is used to Resend S-Frame on receiving + * non S-Frame response + * + * Returns If last sent Frame is S-Frame + * return TRUE(S-Frame) otherwise FALSE(Non-S-Frame). + * + ******************************************************************************/ +static bool phNxpEseProto7816_ResendLastSFrameReq(void) { + bool isLastSFrameReq = false; + if (phNxpEseProto7816_3_Var.lastSentNonErrorframeType == SFRAME && + WTX_RSP != + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo.sFrameType) { + ALOGD_IF(ese_debug_enabled, + "%s Unexpected Frame, re-transmitting the previous S-frame", + __FUNCTION__); + phNxpEse_memcpy(&phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx, + &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx, + sizeof(phNxpEseProto7816_NextTx_Info_t)); + isLastSFrameReq = true; + } + return isLastSFrameReq; +} + +/** @} */ diff --git a/snxxx/libese-spi/p73/lib/phNxpEseProto7816_3.h b/snxxx/libese-spi/p73/lib/phNxpEseProto7816_3.h new file mode 100755 index 0000000..8a22daa --- /dev/null +++ b/snxxx/libese-spi/p73/lib/phNxpEseProto7816_3.h @@ -0,0 +1,623 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef _PHNXPESEPROTO7816_3_H_ +#define _PHNXPESEPROTO7816_3_H_ +#include <ese_config.h> +#include <phNxpEseDataMgr.h> +#include <phNxpEseFeatures.h> +#include <phNxpEse_Internal.h> + +/** + * \addtogroup ISO7816-3_protocol_lib + * \brief 7816-3 PROTOCOL STACK + * @{ */ + +/********************* Definitions and structures *****************************/ + +/*! + * \brief S-Frame types used in 7816-3 protocol stack + */ +typedef enum sFrameTypes { + RESYNCH_REQ = 0x00, /*!< Re-synchronisation request between host and ESE */ + RESYNCH_RSP = 0x20, /*!< Re-synchronisation response between host and ESE */ + IFS_REQ = 0x01, /*!< IFSC size request */ + IFS_RES = 0x21, /*!< IFSC size response */ + ABORT_REQ = 0x02, /*!< Abort request */ + ABORT_RES = 0x22, /*!< Abort response */ + WTX_REQ = 0x03, /*!< WTX request */ + WTX_RSP = 0x23, /*!< WTX response */ + INTF_RESET_REQ = 0x04, /*!< Interface reset request */ + INTF_RESET_RSP = 0x24, /*!< Interface reset response */ + PROP_END_APDU_REQ = 0x05, /*!< Proprietary Enf of APDU request */ + PROP_END_APDU_RSP = 0x25, /*!< Proprietary Enf of APDU response */ + HARD_RESET_REQ = 0x06, /*!< Chip reset request */ + HARD_RESET_RSP = 0x26, /*!< Chip reset request */ + ATR_REQ = 0x07, /*!< ATR request */ + ATR_RSP = 0x27, /*!< ATR response */ + INVALID_REQ_RES /*!< Invalid request */ +} sFrameTypes_t; + +/*! + * \brief R-Frame types used in 7816-3 protocol stack + */ +typedef enum rFrameTypes { + RACK = 0x01, /*!< R-frame Acknowledgement frame indicator */ + RNACK = 0x02 /*!< R-frame Negative-Acknowledgement frame indicator */ +} rFrameTypes_t; + +/*! + * \brief R-Frame error types used 7816-3 protocol stack + */ +typedef enum rFrameErrorTypes { + NO_ERROR, /*!< R-frame received with success */ + PARITY_ERROR, /*!< R-frame received with parity error */ + OTHER_ERROR, /*!< R-frame received with Other error */ + SOF_MISSED_ERROR, /*!< R-frame received with frame missing error */ + UNDEFINED_ERROR /*!< R-frame received with some undefined error */ +} rFrameErrorTypes_t; + +/*! + * \brief Frame types used in 7816-3 protocol stack + */ +typedef enum phNxpEseProto7816_FrameTypes { + IFRAME, /*!< Frame type: I-frame */ + SFRAME, /*!< Frame type: S-frame */ + RFRAME, /*!< Frame type: R-frame */ + INVALID, /*!< Frame type: Invalid */ + UNKNOWN /*!< Frame type: Unknown */ +} phNxpEseProto7816_FrameTypes_t; + +/*! + * \brief 7816-3 protocol stack states + */ +typedef enum phNxpEseProto7816_State { + PH_NXP_ESE_PROTO_7816_IDLE, /*!< 7816-3 protocol state: IDLE */ + PH_NXP_ESE_PROTO_7816_TRANSCEIVE, /*!< 7816-3 protocol state: TRANSCEIVE going + on */ + PH_NXP_ESE_PROTO_7816_DEINIT /*!< 7816-3 protocol state: DeInit going on */ +} phNxpEseProto7816_State_t; + +/*! + * \brief 7816-3 protocol transceive states + */ +typedef enum phNxpEseProto7816_TransceiveStates { + IDLE_STATE, /*!< 7816-3 protocol transceive state: IDLE */ + SEND_IFRAME, /*!< 7816-3 protocol transceive state: I-frame to be sent */ + SEND_R_NACK, /*!< 7816-3 protocol transceive state: R-NACK frame to be sent */ + SEND_R_ACK, /*!< 7816-3 protocol transceive state: R-ACK frame to be sent */ + SEND_S_RSYNC, /*!< 7816-3 protocol transceive state: S-frame + re-synchronisation command to be sent */ + SEND_S_INTF_RST, /*!< 7816-3 protocol transceive state: S-frame interface + reset command to be sent */ + SEND_S_EOS, /*!< 7816-3 protocol transceive state: S-frame end of session + command to be sent */ + SEND_S_HRD_RST, /*!< 7816-3 protocol transceive state: S-frame + chip/hard reset command to be sent */ + SEND_S_WTX_REQ, /*!< 7816-3 protocol transceive state: S-frame WTX command to + be sent */ + SEND_S_WTX_RSP, /*!< 7816-3 protocol transceive state: S-frame WTX response to + be sent */ + SEND_S_IFS_ADJ, /*!< 7816-3 protocol transceive state: S-frame IFS adjustment + */ + SEND_S_ATR_REQ, /*!< 7816-3 protocol transceive state: S-frame ATR request */ +} phNxpEseProto7816_TransceiveStates_t; + +/*! + * \brief I-frame information structure for ISO 7816-3 + * + * This structure holds the information of I-frame used for sending + * and receiving the frame packet. + * + */ +typedef struct iFrameInfo { + bool isChained; /*!< I-frame: Indicates if more frames to follow in the same + data packet or not */ + uint8_t* p_data; /*!< I-frame: Actual data (Information field (INF)) */ + + uint8_t seqNo; /*!< I-frame: Sequence number of the I-frame */ + + uint32_t maxDataLenIFSC; /*!< I-frame: Maximum data length to be allowed in a + single I-frame */ + uint32_t defaultDataLenIFSC; /*!< I-frame: Maximum data length to be allowed + in a single I-frame */ + uint32_t currentDataLenIFS; /*!< I-frame: Current data length agreed + between PCD and Card to be allowed in a + single I-frame */ + + uint32_t dataOffset; /*!< I-frame: Offset to the actual data(INF) for the + current frame of the packet */ + uint32_t totalDataLen; /*!< I-frame: Total data left in the packet, used to + set the chained flag/calculating offset */ + uint32_t sendDataLen; /*!< I-frame: the length of the I-frame actual data */ +} iFrameInfo_t; + +/*! + * \brief S-frame information structure for ISO 7816-3 + * + * This structure holds the information of S-frame used for sending + * and receiving the frame packet. + * + */ +typedef struct sFrameInfo { + sFrameTypes_t sFrameType; /*!< S-frame: Type of S-frame cmd/rsp */ + uint8_t* p_data; /*!< S-frame: Actual data (Information field (INF)) */ + uint8_t len; /*!< S-frame: the length of the I-frame actual data */ +} sFrameInfo_t; + +/*! + * \brief R-frame information structure for ISO 7816-3 + * + * This structure holds the information of R-frame used for sending + * and receiving the frame packet. + * + */ +typedef struct rFrameInfo { + uint8_t seqNo; /*!< R-frame: Sequence number of the expected I-frame */ + rFrameErrorTypes_t errCode; /*!< R-frame: Error type */ +} rFrameInfo_t; + +/*! + * \brief ATRInfo: ISO7816 ATR Information bytes + * + * This structure holds ATR information bytes + * + */ +typedef struct phNxpEseProto7816_ATR_Info { + uint8_t len; /*!< ATR: ATR length in bytes */ + uint8_t vendorID[5]; /*!< ATR: VendorID according to ISO7816-5 */ + uint8_t dll_IC; /*!< ATR: Data Link Layer - Interface Character */ + uint8_t bgt[2]; /*!< ATR: Minimum guard time in milliseconds for + T=1 blocks sent in opposite directions */ + uint8_t + bwt[2]; /*!< ATR: Maximum allowed command processing + time in milliseconds before card has sent either + command response or S(WTX) requesting processing time extension */ + uint8_t maxFreq[2]; /*!< ATR: Max supported clock frequency in kHz */ + uint8_t checksum; /*!< ATR: Checksum (0 = LRC / 1 = CRC) */ + uint8_t defaultIFSC; /*!< ATR: Default IFS size */ + uint8_t numChannels; /*!< ATR: Number of logical connections supported */ + uint8_t maxIFSC[2]; /*!< ATR: Maximum size of IFS supported */ + uint8_t capabilities[2]; /*!< ATR: Bitmap to indicate various features + supported by SE Bit-1: SE Data Available Line + supported. Bit-2: SE Data available polarity. 1 - Data + available GPIO will be pulled HIGH when SE response is + ready Bit 3: SE chip reset S-blk command supported + Bit-4: Extended frame length feature supported Bit-5: + Support for more than one logical channel Bit 6 to 16: + Reserved for future use + */ +} phNxpEseProto7816_ATR_Info_t; + +typedef struct phNxpEseProto7816_ATR_Info2 { + uint8_t channelNo; /*!< ATR: Current ongoing channel no */ + uint8_t osType; /*!< ATR: Indicates OS Type + JCOP_OS = 0x01 + UPDATER_OS = 0x02 */ +} phNxpEseProto7816_ATR_Info2_t; + +/*! + * \brief Next/Last Tx information structure holding transceive data + * + * This structure holds the information of the next/last sent + * I-frame/R-frame/S-frame depending on the frame type + * + */ +typedef struct phNxpEseProto7816_NextTx_Info { + iFrameInfo_t + IframeInfo; /*!< Information of the I-frame to be send next or the last + sent I-frame depending on the frame type */ + rFrameInfo_t + RframeInfo; /*!< Information of the R-frame to be send next or the last + sent R-frame depending on the frame type */ + sFrameInfo_t + SframeInfo; /*!< Information of the S-frame to be send next or the last + sent S-frame depending on the frame type */ + phNxpEseProto7816_FrameTypes_t + FrameType; /*!< Frame (I/R/S frames) type to be sent next */ +} phNxpEseProto7816_NextTx_Info_t; + +/*! + * \brief Last sent Tx ransceive data + * + * This structure holds the information of the last sent + * I-frame/R-frame/S-frame + * + */ +typedef phNxpEseProto7816_NextTx_Info_t phNxpEseProto7816_LastTx_Info_t; + +/*! + * \brief Last Rx information structure holding transceive data + * + * This structure holds the information of the next/last sent + * I-frame/R-frame/S-frame + * + */ +typedef struct phNxpEseRx_Cntx { + iFrameInfo_t lastRcvdIframeInfo; /*!< I-frame: Last received frame */ + rFrameInfo_t lastRcvdRframeInfo; /*!< R-frame: Last received frame */ + sFrameInfo_t lastRcvdSframeInfo; /*!< S-frame: Last received frame */ + phNxpEseProto7816_FrameTypes_t + lastRcvdFrameType; /*!< Last received frame type */ +} phNxpEseRx_Cntx_t; + +/*! + * \brief Proprietery: Secure timer value updates + * + * This structure holds the secure timer value + * + */ +typedef struct phNxpEseProto7816SecureTimer { + unsigned int secureTimer1; + unsigned int secureTimer2; + unsigned int secureTimer3; +} phNxpEseProto7816SecureTimer_t; + +/*! + * \brief structure to hold the interface reset parameters + * secure timer(only for PN8xT products) and atr info. + * + */ +typedef struct phNxpEseProto7816_IntfResetParams { + phNxpEseProto7816SecureTimer_t* pSecureTimerParam; + phNxpEse_data* pAtrData; +} phNxpEseProto7816_IntfResetParams_t; +/*! + * \brief 7816-3 protocol stack context structure + * + * This structure holds the complete information of the + * 7816-3 protocol stack context + * + */ +typedef struct phNxpEseProto7816 { + phNxpEseProto7816_LastTx_Info_t + phNxpEseLastTx_Cntx; /*!< Last transmitted frame information */ + phNxpEseProto7816_NextTx_Info_t + phNxpEseNextTx_Cntx; /*!< Next frame to be transmitted */ + phNxpEseRx_Cntx_t phNxpEseRx_Cntx; /*!< Last received frame information */ + phNxpEseProto7816_TransceiveStates_t + phNxpEseProto7816_nextTransceiveState; /*!< Next Transceive state. It + determines the next + action to be done from host */ + phNxpEseProto7816_State_t + phNxpEseProto7816_CurrentState; /*!< Current protocol stack state */ + uint8_t recoveryCounter; /*!< Keeps track of number of error recovery done. + Stack exits after it reaches max. count */ + unsigned long int wtx_counter_limit; /*!< Max. WTX counter limit */ + unsigned long int wtx_counter; /*!< WTX count tracker */ + uint8_t timeoutCounter; /*!< Keeps track of number of timeout happened. Stack + exits after it reaches max. count */ + phNxpEseProto7816_FrameTypes_t + lastSentNonErrorframeType; /*!< Copy of the last sent non-error frame + type: R-ACK, S-frame, I-frame */ + unsigned long int rnack_retry_limit; + unsigned long int rnack_retry_counter; + unsigned long int + wtx_ntf_limit; /*!< Wtx count interval to notify service registered*/ + phNxpEseProto7816SecureTimer_t secureTimerParams; + unsigned long int reset_type; + uint32_t currentIFSDSize; + phNxpEseProto7816_ATR_Info_t atrInfo; + phNxpEseProto7816_ATR_Info2_t extndAtrInfo; +} phNxpEseProto7816_t; + +/*! + * \brief 7816-3 protocol stack init params + * + * This structure holds the parameters to be passed to open 7816-3 protocl stack + *instance + * + */ +typedef struct phNxpEseProto7816InitParam { + unsigned long int wtx_counter_limit; /*!< WTX count limit */ + bool interfaceReset; /*!< INTF reset required or not>*/ + unsigned long int rnack_retry_limit; + phNxpEseProto7816SecureTimer_t* + pSecureTimerParams; /*!< Secure timer value updated here >*/ + unsigned long int + wtx_ntf_limit; /*!< Wtx count interval to notify service registered*/ +} phNxpEseProto7816InitParam_t; + +/*! + * \brief 7816-3 protocol PCB bit level structure + * + * This structure holds the bit level information of PCB byte + * as per 7816-3 protocol + * + */ +typedef struct phNxpEseProto7816_PCB_bits { + uint8_t lsb : 1; /*!< PCB: lsb */ + uint8_t bit2 : 1; /*!< PCB: bit2 */ + uint8_t bit3 : 1; /*!< PCB: bit3 */ + uint8_t bit4 : 1; /*!< PCB: bit4 */ + uint8_t bit5 : 1; /*!< PCB: bit5 */ + uint8_t bit6 : 1; /*!< PCB: bit6 */ + uint8_t bit7 : 1; /*!< PCB: bit7 */ + uint8_t msb : 1; /*!< PCB: msb */ +} phNxpEseProto7816_PCB_bits_t; + +/*! + * \brief Max. size of the frame that can be sent + */ +#define IFSC_SIZE_SEND 254 +/*! + * \brief Delay to be used before sending the next frame, after error reported + * by ESE + */ +#define DELAY_ERROR_RECOVERY_1_MS 1000 + +#define GET_DELAY_ERROR_RECOVERY() \ + ((GET_CHIP_OS_VERSION() != OS_VERSION_4_0) \ + ? (10 * DELAY_ERROR_RECOVERY_1_MS) \ + : (3.5 * DELAY_ERROR_RECOVERY_1_MS)) +/*! + * \brief 7816-3 protocol frame + * header length + */ +#define PH_PROTO_7816_HEADER_LEN 0x03 +/*! + * \brief 7816-3 protocol ext.frame header length + */ +#define PH_PROTO_7816_EXT_HEADER_LEN 0x05 +/*! + * \brief 7816-3 protocol frame CRC length + */ +#define PH_PROTO_7816_CRC_LEN 0x01 +/*! + * \brief 7816-3 Chaining flag bit for masking + */ +#define PH_PROTO_7816_CHAINING 0x20 +/*! + * \brief 7816-3 PCB byte offset + */ +#define PH_PROPTO_7816_PCB_OFFSET 0x01 +/*! + * \brief 7816-3 frame length offset + */ +#define PH_PROPTO_7816_FRAME_LENGTH_OFFSET 0x02 +/*! + * \brief 7816-3 S-frame timer 1 + */ +#define PH_PROPTO_7816_SFRAME_TIMER1 0xF1 +/*! + * \brief 7816-3 S-frame timer 2 + */ +#define PH_PROPTO_7816_SFRAME_TIMER2 0xF2 +/*! + * \brief 7816-3 S-frame timer 3 + */ +#define PH_PROPTO_7816_SFRAME_TIMER3 0xF3 + +/*! + * \brief 7816-3 S-block request command mask + */ +#define PH_PROTO_7816_S_BLOCK_REQ 0xC0 +/*! + * \brief 7816-3 S-block response mask + */ +#define PH_PROTO_7816_S_BLOCK_RSP 0xE0 +/*! + * \brief 7816-3 S-block reset command mask + */ +#define PH_PROTO_7816_S_RESET 0x04 +/*! + * \brief 7816-3 S-block End of APDU cmd mask + */ +#define PH_PROTO_7816_S_END_OF_APDU 0x05 +/*! + * \brief 7816-3 S-block WTX mask + */ +#define PH_PROTO_7816_S_WTX 0x03 +/*! + * \brief 7816-3 S-block re-sync mask + */ +#define PH_PROTO_7816_S_RESYNCH 0x00 +/*! + * \brief 7816-3 S-block hard reset cmd mask + */ +#define PH_PROTO_7816_S_HRD_RST_CMD 0x06 +/*! + * \brief 7816-3 protocol max. error retry counter + */ +#define PH_PROTO_7816_FRAME_RETRY 01 +/*! + * \brief 7816-3 protocol max. error retry counter based on OS version + */ +#define GET_FRAME_RETRY_COUNT() \ + ((GET_CHIP_OS_VERSION() != OS_VERSION_4_0) \ + ? (3 * PH_PROTO_7816_FRAME_RETRY) \ + : (10 * PH_PROTO_7816_FRAME_RETRY)) + +/*! + * \brief 7816-3 protocol max. WTX default count + */ +#define PH_PROTO_WTX_DEFAULT_COUNT 500 +/*! + * \brief 7816-3 protocol max. timeout retry count + */ +#define PH_PROTO_7816_TIMEOUT_RETRY_COUNT 1 +/*! + * \brief 7816-3 to represent magic number zero + */ +#define PH_PROTO_7816_VALUE_ZERO 0x00 +/*! + * \brief 7816-3 to represent magic number one + */ +#define PH_PROTO_7816_VALUE_ONE 0x01 +/*! + * \brief 7816-3 for max retry for CRC error + */ +#define MAX_RNACK_RETRY_LIMIT 0x02 +/*! + * \brief APIs exposed from the 7816-3 protocol layer + */ +#define RESET_TYPE_NONE 0x00 +/*! + * \brief APIs exposed from the 7816-3 protocol layer + */ +#define EXTENDED_FRAME_MARKER 0xFF +/*! + * \brief APIs exposed from the 7816-3 protocol layer + */ +#define PH_PROTO_CLOSE_ALL_SESSION_INF 0x01 +/*! + * \brief APIs exposed from the 7816-3 protocol layer + */ +#define PH_PROTO_CLOSE_ALL_SESSION_LEN 0x01 +/*! + * \brief APIs exposed from the 7816-3 protocol layer + */ +#define PH_PROTO_ATR_RSP_VENDOR_ID_LEN 0x05 +/*! + * \brief APIs exposed from the 7816-3 protocol layer + */ +#define PH_SE_OS_VERSION_10 0x10 +/*! + * \brief APIs exposed from the 7816-3 protocol layer + */ +#define PH_SE_OS_VERSION_11 0x11 +/*! + * \brief OS version on SE for SN220 + */ +#define PH_SE_OS_VERSION_20 0x20 +/*! + * \brief Default wait extension notification interval + */ +#define PH_DEFAULT_WTX_NTF_LIMIT 0x03 +/*! + * \delay for hard reset response + */ +#define HARD_RESET_RES_DELAY 4000 + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to reset just the current interface + * + * \param[in] secureTimerParams - secure timer instance + * + */ +ESESTATUS phNxpEseProto7816_IntfReset( + phNxpEseProto7816SecureTimer_t* secureTimerParams); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to close the 7816 protocol stack instance + * + * \param[in] secureTimerParams - secure timer instance + * + */ +ESESTATUS phNxpEseProto7816_Close( + phNxpEseProto7816SecureTimer_t* secureTimerParams); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to open the 7816 protocol stack instance + * + * \param[in] initParam: Initialization params + * + */ +ESESTATUS phNxpEseProto7816_Open(phNxpEseProto7816InitParam_t initParam); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to + * 1. Send the raw data received from application after + *computing LRC + * 2. Receive the response data from ESE, decode, process + *and + * store the data. + * 3. Get the final complete data and sent back to application + * + * \param[in] pCmd: Command to ESE + * \param[out] pRsp: Response from ESE + * + * + */ +ESESTATUS phNxpEseProto7816_Transceive(phNxpEse_data* pCmd, + phNxpEse_data* pRsp); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to reset the 7816 protocol stack instance + * + * + * + */ +ESESTATUS phNxpEseProto7816_Reset(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to set the max T=1 data send size + * + * \param[in] IFS_Size: Max. size of the I-frame + * + */ +ESESTATUS phNxpEseProto7816_SetIfs(uint16_t IFS_Size); +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to set the endpoint + * + * \param[in] uEndPoint: END_POINT_ESE = 0 (eSE services), END_POINT_EUICC + * =1(UICC services) + * + */ +ESESTATUS phNxpEseProto7816_SetEndPoint(uint8_t uEndPoint); +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to reset the endpoint + * + * \param[in] uEndPoint: END_POINT_ESE = 0 (eSE services), END_POINT_EUICC + * =1(UICC services) + * + */ +ESESTATUS phNxpEseProto7816_ResetEndPoint(uint8_t uEndPoint); +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to get ATR bytes for the application + * + * \param[out] pATRRsp: Response ATR bytes from ESE + * + */ +ESESTATUS phNxpEseProto7816_getAtr(phNxpEse_data* pATRRsp); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to get the max T=1 data send size + * + * \retval Current IFS adjusted value wrt card. + * + */ +uint16_t phNxpEseProto7816_GetIfs(void); + +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to get OS mode(JCOP/OSU) + * + * \retval OS mode(JCOP/OSU). + * + */ +phNxpEseProto7816_OsType_t phNxpEseProto7816_GetOsMode(void); +/** + * \ingroup ISO7816-3_protocol_lib + * \brief This function is used to check eSE is alive/responding + * + * + * + */ +ESESTATUS phNxpEseProto7816_CloseAllSessions(void); +/** @} */ +#endif /* _PHNXPESEPROTO7816_3_H_ */ diff --git a/snxxx/libese-spi/p73/lib/phNxpEse_Apdu_Api.cpp b/snxxx/libese-spi/p73/lib/phNxpEse_Apdu_Api.cpp new file mode 100755 index 0000000..9a01370 --- /dev/null +++ b/snxxx/libese-spi/p73/lib/phNxpEse_Apdu_Api.cpp @@ -0,0 +1,270 @@ +/****************************************************************************** + * + * Copyright 2018-2019,2021 NXP + * + * 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. + * + ******************************************************************************/ +/** + * \addtogroup ISO7816-4_application_protocol_implementation + * + * @{ */ +#define LOG_TAG "NxpEseHal" +#include <log/log.h> +#include <phNxpEse_Apdu_Api.h> +#include <phNxpEse_Api.h> + +static ESESTATUS phNxpEse_7816_FrameCmd(pphNxpEse_7816_cpdu_t pCmd, + uint8_t** pcmd_data, uint32_t* cmd_len); + +/****************************************************************************** + * Function phNxpEse_7816_Transceive + * + * Description This function prepares C-APDU and sends to p61 and receives + * response from the p61. also it parses all required fields of + * the response PDU. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_7816_Transceive(pphNxpEse_7816_cpdu_t pCmd, + pphNxpEse_7816_rpdu_t pRsp) { + ESESTATUS status = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, " %s Enter \n", __FUNCTION__); + + uint32_t cmd_len = 0; + uint8_t* pCmd_data = NULL; + phNxpEse_data pCmdTrans; + phNxpEse_data pRspTrans; + phNxpEse_memset(&pCmdTrans, 0x00, sizeof(phNxpEse_data)); + phNxpEse_memset(&pRspTrans, 0x00, sizeof(phNxpEse_data)); + + if (NULL == pCmd || NULL == pRsp) { + ALOGE(" %s Invalid prameter \n", __FUNCTION__); + status = ESESTATUS_INVALID_PARAMETER; + } else if (pCmd->cpdu_type > 1) { + ALOGE(" %s Invalid cpdu type \n", __FUNCTION__); + status = ESESTATUS_INVALID_CPDU_TYPE; + } else if (0 < pCmd->le_type && NULL == pRsp->pdata) { + /* if response is requested, but no valid res buffer + * provided by application */ + ALOGE(" %s Invalid response buffer \n", __FUNCTION__); + status = ESESTATUS_INVALID_BUFFER; + } else { + status = phNxpEse_7816_FrameCmd(pCmd, &pCmd_data, &cmd_len); + if (ESESTATUS_SUCCESS == status) { + pCmdTrans.len = cmd_len; + pCmdTrans.p_data = pCmd_data; + status = phNxpEse_Transceive(&pCmdTrans, &pRspTrans); + if (ESESTATUS_SUCCESS != status) { + ALOGE(" %s phNxpEse_Transceive Failed \n", __FUNCTION__); + if ((pRspTrans.len > 0) && (pRspTrans.p_data != NULL)) { + pRsp->sw2 = *(pRspTrans.p_data + (pRspTrans.len - 1)); + pRspTrans.len--; + pRsp->sw1 = *(pRspTrans.p_data + (pRspTrans.len - 1)); + pRspTrans.len--; + pRsp->len = pRspTrans.len; + } + } else { + if ((pRspTrans.len > 0) && (pRspTrans.p_data != NULL)) { + pRsp->sw2 = *(pRspTrans.p_data + (pRspTrans.len - 1)); + pRspTrans.len--; + pRsp->sw1 = *(pRspTrans.p_data + (pRspTrans.len - 1)); + pRspTrans.len--; + pRsp->len = pRspTrans.len; + ALOGD_IF(ese_debug_enabled, "pRsp->len %d", pRsp->len); + if (pRspTrans.len > 0 && NULL != pRsp->pdata) { + phNxpEse_memcpy(pRsp->pdata, pRspTrans.p_data, pRspTrans.len); + status = ESESTATUS_SUCCESS; + } else if (pRspTrans.len == 0) { + status = ESESTATUS_SUCCESS; + } else { + /* if application response buffer is null and data is present */ + ALOGE("Invalid Res buffer"); + status = ESESTATUS_FAILED; + } + ALOGD_IF(ese_debug_enabled, "Freeing memory pRspTrans.p_data "); + phNxpEse_free(pRspTrans.p_data); + pRspTrans.p_data = NULL; + pRspTrans.len = 0; + } else { + ALOGE("pRspTrans.len error = %d", pRspTrans.len); + status = ESESTATUS_FAILED; + } + } + if (pCmd_data != NULL) { + ALOGD_IF(ese_debug_enabled, "Freeing memory pCmd_data"); + phNxpEse_free(pCmd_data); + } + } + } + ALOGD_IF(ese_debug_enabled, " %s Exit status 0x%x \n", __FUNCTION__, status); + return status; +} + +/** + * \ingroup ISO7816-4_application_protocol_implementation + * \brief Frames ISO7816-4 command. + * pCmd: 7816 command structure. + * pcmd_data: command buffer pointer. + * + * \param[in] pCmd- Structure pointer passed from + *application + * \param[in] **pcmd_data - Hold the allocated memory buffer for + *command. + * \param[in] *cmd_len - Hold the buffer length, update by this + *function + * + * \retval ESESTATUS_SUCCESS on Success else proper error code + * + */ + +static ESESTATUS phNxpEse_7816_FrameCmd(pphNxpEse_7816_cpdu_t pCmd, + uint8_t** pcmd_data, + uint32_t* cmd_len) { + uint32_t cmd_total_len = MIN_HEADER_LEN; /* header is always 4 bytes */ + uint8_t* pbuff = NULL; + uint32_t index = 0; + uint8_t lc_len = 0; + uint8_t le_len = 0; + + ALOGD_IF(ese_debug_enabled, "%s pCmd->lc = %d, pCmd->le_type = %d", + __FUNCTION__, pCmd->lc, pCmd->le_type); + /* calculate the total buffer length */ + if (pCmd->lc > 0) { + if (pCmd->cpdu_type == 0) { + cmd_total_len += 1; /* 1 byte LC */ + lc_len = 1; + } else { + cmd_total_len += 3; /* 3 byte LC */ + lc_len = 3; + } + + cmd_total_len += pCmd->lc; /* add data length */ + if (pCmd->pdata == NULL) { + ALOGE("%s Invalide data buffer from application ", __FUNCTION__); + return ESESTATUS_INVALID_BUFFER; + } + } else { + lc_len = 0; + ALOGD_IF(ese_debug_enabled, "%s lc (data) field is not present %d", + __FUNCTION__, pCmd->lc); + } + + if (pCmd->le_type > 0) { + if (pCmd->le_type == 1) { + cmd_total_len += 1; /* 1 byte LE */ + le_len = 1; + } else if ((pCmd->le_type == 2 || pCmd->le_type == 3)) { + /* extended le */ + if ((pCmd->le_type == 3) && (lc_len == 0)) { + /* if data field not present, than only LE would be three bytes */ + cmd_total_len += 3; /* 3 byte LE */ + le_len = 3; + } else if ((pCmd->le_type == 2) && (lc_len != 0)) { + /* if data field present, LE would be two bytes */ + cmd_total_len += 2; /* 2 byte LE */ + le_len = 2; + } else { + ALOGE("%s wrong LE type %d", __FUNCTION__, pCmd->le_type); + cmd_total_len += pCmd->le_type; + le_len = pCmd->le_type; + } + } else { + ALOGE("%s wrong cpdu_type value %d", __FUNCTION__, pCmd->cpdu_type); + return ESESTATUS_INVALID_CPDU_TYPE; + } + } else { + le_len = 0; + ALOGD_IF(ese_debug_enabled, "%s le field is not present", __FUNCTION__); + } + ALOGD_IF(ese_debug_enabled, "%s cmd_total_len = %d, le_len = %d, lc_len = %d", + __FUNCTION__, cmd_total_len, le_len, lc_len); + + pbuff = (uint8_t*)phNxpEse_calloc(cmd_total_len, sizeof(uint8_t)); + if (pbuff == NULL) { + ALOGE("%s Error allocating memory", __FUNCTION__); + return ESESTATUS_INSUFFICIENT_RESOURCES; + } + *cmd_len = cmd_total_len; + *pcmd_data = pbuff; + index = 0; + + *(pbuff + index) = pCmd->cla; + index++; + + *(pbuff + index) = pCmd->ins; + index++; + + *(pbuff + index) = pCmd->p1; + index++; + + *(pbuff + index) = pCmd->p2; + index++; + + /* lc_len can be 0, 1 or 3 bytes */ + if (lc_len > 0) { + if (lc_len == 1) { + *(pbuff + index) = pCmd->lc; + index++; + } else { + /* extended cmd buffer*/ + *(pbuff + index) = 0x00; /* three byte lc */ + index++; + *(pbuff + index) = ((pCmd->lc & 0xFF00) >> 8); + index++; + *(pbuff + index) = (pCmd->lc & 0x00FF); + index++; + } + /* copy the lc bytes data */ + phNxpEse_memcpy((pbuff + index), pCmd->pdata, pCmd->lc); + index += pCmd->lc; + } + /* le_len can be 0, 1, 2 or 3 bytes */ + if (le_len > 0) { + if (le_len == 1) { + if (pCmd->le == 256) { + /* if le is 256 assign max value*/ + *(pbuff + index) = 0x00; + } else { + *(pbuff + index) = (uint8_t)pCmd->le; + } + index++; + } else { + if (pCmd->le == 65536) { + if (le_len == 3) { + /* assign max value */ + *(pbuff + index) = 0x00; /* three byte le */ + index++; + } + *(pbuff + index) = 0x00; + index++; + *(pbuff + index) = 0x00; + index++; + } else { + if (le_len == 3) { + *(pbuff + index) = 0x00; /* three byte le */ + index++; + } + *(pbuff + index) = ((pCmd->le & 0x0000FF00) >> 8); + index++; + *(pbuff + index) = (pCmd->le & 0x000000FF); + index++; + } + } + } + ALOGD_IF(ese_debug_enabled, "Exit %s cmd_total_len = %d, index = %d", + __FUNCTION__, index, cmd_total_len); + return ESESTATUS_SUCCESS; +} +/** @} */ diff --git a/snxxx/libese-spi/p73/lib/phNxpEse_Api.cpp b/snxxx/libese-spi/p73/lib/phNxpEse_Api.cpp new file mode 100755 index 0000000..a5b63d7 --- /dev/null +++ b/snxxx/libese-spi/p73/lib/phNxpEse_Api.cpp @@ -0,0 +1,1950 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "NxpEseHal" +#include <log/log.h> + +#include <EseTransport.h> +#include <cutils/properties.h> +#include <ese_config.h> +#include <phNxpEseFeatures.h> +#include <phNxpEsePal.h> +#include <phNxpEseProto7816_3.h> +#include <phNxpEse_Internal.h> + +#define RECEIVE_PACKET_SOF 0xA5 +#define CHAINED_PACKET_WITHSEQN 0x60 +#define CHAINED_PACKET_WITHOUTSEQN 0x20 +#define PH_PAL_ESE_PRINT_PACKET_TX(data, len) \ + ({ phPalEse_print_packet("SEND", data, len); }) +#define PH_PAL_ESE_PRINT_PACKET_RX(data, len) \ + ({ phPalEse_print_packet("RECV", data, len); }) +/* 32K(0x8000) Datasize + 10(0xA) Byte Max Header Size + 1 byte negative + * testcase support */ +#define MAX_SUPPORTED_DATA_SIZE 0x800B +static int phNxpEse_readPacket(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToRead); +static int phNxpEse_readPacket_legacy(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToRead); + +static ESESTATUS phNxpEse_checkJcopDwnldState(void); +static ESESTATUS phNxpEse_setJcopDwnldState(phNxpEse_JcopDwnldState state); +static ESESTATUS phNxpEse_checkFWDwnldStatus(void); +static void phNxpEse_GetMaxTimer(unsigned long* pMaxTimer); +static unsigned char* phNxpEse_GgetTimerTlvBuffer(unsigned char* timer_buffer, + unsigned int value); +static __inline bool phNxpEse_isColdResetRequired(phNxpEse_initMode mode, + ESESTATUS status); +static int poll_sof_chained_delay = 0; +static phNxpEse_OsVersion_t sOsVersion = INVALID_OS_VERSION; +/* To Overwrite the value of wtx_counter_limit from config file*/ +static unsigned long int app_wtx_cnt = RESET_APP_WTX_COUNT; + +/*********************** Global Variables *************************************/ + +/* ESE Context structure */ +phNxpEse_Context_t nxpese_ctxt; +bool ese_debug_enabled = false; + +/****************************************************************************** + * Function phNxpEse_SetEndPoint_Cntxt + * + * Description This function is called set the SE endpoint + * + * Returns None + * + ******************************************************************************/ + +ESESTATUS phNxpEse_SetEndPoint_Cntxt(uint8_t uEndPoint) { + ESESTATUS status = ESESTATUS_FAILED; + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + status = phNxpEseProto7816_SetEndPoint(uEndPoint); + if (status == ESESTATUS_SUCCESS) { + nxpese_ctxt.nadInfo.nadRx = nadInfoRx_ptr[uEndPoint]; + nxpese_ctxt.nadInfo.nadTx = nadInfoTx_ptr[uEndPoint]; + nxpese_ctxt.endPointInfo = uEndPoint; + } + ALOGD_IF(ese_debug_enabled, "%s: Enpoint=%d", __FUNCTION__, uEndPoint); + } else { + ALOGE("%s- Function not supported", __FUNCTION__); + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_ResetEndPoint_Cntxt + * + * Description This function is called to reset the SE endpoint + * + * Returns None + * + ******************************************************************************/ +ESESTATUS phNxpEse_ResetEndPoint_Cntxt(uint8_t uEndPoint) { + ESESTATUS status = ESESTATUS_FAILED; + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + status = phNxpEseProto7816_ResetEndPoint(uEndPoint); + } else { + ALOGE("%s- Function not supported", __FUNCTION__); + } + return status; +} +/****************************************************************************** + * Function phNxpLog_InitializeLogLevel + * + * Description This function is called during phNxpEse_init to initialize + * debug log level. + * + * Returns None + * + ******************************************************************************/ + +void phNxpLog_InitializeLogLevel() { + ese_debug_enabled = + (EseConfig::getUnsigned(NAME_SE_DEBUG_ENABLED, 0) != 0) ? true : false; + + char valueStr[PROPERTY_VALUE_MAX] = {0}; + int len = property_get("vendor.ese.debug_enabled", valueStr, ""); + if (len > 0) { + // let Android property override .conf variable + unsigned debug_enabled = 0; + sscanf(valueStr, "%u", &debug_enabled); + ese_debug_enabled = (debug_enabled == 0) ? false : true; + } + + ALOGD_IF(ese_debug_enabled, "%s: level=%u", __func__, ese_debug_enabled); +} + +/****************************************************************************** + * Function phNxpEse_init + * + * Description This function is called by Jni/phNxpEse_open during the + * initialization of the ESE. It initializes protocol stack + *instance variable + * + * Returns This function return ESESTATUS_SUCCESS (0) in case of + *success In case of failure returns other failure value. + * + ******************************************************************************/ +ESESTATUS phNxpEse_init(phNxpEse_initParams initParams) { + ESESTATUS wConfigStatus = ESESTATUS_FAILED; + unsigned long int num, ifsd_value = 0; + unsigned long maxTimer = 0; + uint8_t retry = 0; + phNxpEseProto7816InitParam_t protoInitParam; + phNxpEse_memset(&protoInitParam, 0x00, sizeof(phNxpEseProto7816InitParam_t)); + /* STATUS_OPEN */ + nxpese_ctxt.EseLibStatus = ESE_STATUS_OPEN; + + if (app_wtx_cnt > RESET_APP_WTX_COUNT) { + protoInitParam.wtx_counter_limit = app_wtx_cnt; + ALOGD_IF(ese_debug_enabled, "Wtx_counter limit from app setting - %lu", + protoInitParam.wtx_counter_limit); + } else { + protoInitParam.wtx_counter_limit = EseConfig::getUnsigned( + NAME_NXP_WTX_COUNT_VALUE, PH_PROTO_WTX_DEFAULT_COUNT); + ALOGD_IF(ese_debug_enabled, "Wtx_counter read from config file - %lu", + protoInitParam.wtx_counter_limit); + } + if (EseConfig::hasKey(NAME_RNACK_RETRY_DELAY)) { + num = EseConfig::getUnsigned(NAME_RNACK_RETRY_DELAY); + nxpese_ctxt.invalidFrame_Rnack_Delay = num; + ALOGD_IF(ese_debug_enabled, "Rnack retry_delay read from config file - %lu", + num); + } else { + nxpese_ctxt.invalidFrame_Rnack_Delay = 7000; + } + if (EseConfig::hasKey(NAME_NXP_MAX_RNACK_RETRY)) { + protoInitParam.rnack_retry_limit = + EseConfig::getUnsigned(NAME_NXP_MAX_RNACK_RETRY); + } else { + protoInitParam.rnack_retry_limit = MAX_RNACK_RETRY_LIMIT; + } + if (ESE_MODE_NORMAL == + initParams.initMode) /* TZ/Normal wired mode should come here*/ + { + if (EseConfig::hasKey(NAME_NXP_SPI_INTF_RST_ENABLE)) { + protoInitParam.interfaceReset = + (EseConfig::getUnsigned(NAME_NXP_SPI_INTF_RST_ENABLE) == 1) ? true + : false; + } else { + protoInitParam.interfaceReset = true; + } + } else /* OSU mode, no interface reset is required */ + { + if (phNxpEse_doResetProtection(true)) { + ALOGE("%s Reset Potection failed. returning...", __FUNCTION__); + return ESESTATUS_FAILED; + } + protoInitParam.interfaceReset = false; + } + if (EseConfig::hasKey(NAME_NXP_WTX_NTF_COUNT)) { + num = EseConfig::getUnsigned(NAME_NXP_WTX_NTF_COUNT); + protoInitParam.wtx_ntf_limit = num; + ALOGD_IF(ese_debug_enabled, "Wtx_ntf limit from config file - %lu", + protoInitParam.wtx_ntf_limit); + } else { + protoInitParam.wtx_ntf_limit = PH_DEFAULT_WTX_NTF_LIMIT; + } + nxpese_ctxt.fPtr_WtxNtf = initParams.fPtr_WtxNtf; + /* Sharing lib context for fetching secure timer values */ + protoInitParam.pSecureTimerParams = + (phNxpEseProto7816SecureTimer_t*)&nxpese_ctxt.secureTimerParams; + + ALOGD_IF(ese_debug_enabled, + "%s secureTimer1 0x%x secureTimer2 0x%x secureTimer3 0x%x", + __FUNCTION__, nxpese_ctxt.secureTimerParams.secureTimer1, + nxpese_ctxt.secureTimerParams.secureTimer2, + nxpese_ctxt.secureTimerParams.secureTimer3); + + phNxpEse_GetMaxTimer(&maxTimer); +#ifdef SPM_INTEGRATED + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + wConfigStatus = phNxpEse_SPM_DisablePwrControl(maxTimer); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("%s phNxpEse_SPM_DisablePwrControl: failed", __FUNCTION__); + } + } +#endif + do { + /* T=1 Protocol layer open */ + wConfigStatus = phNxpEseProto7816_Open(protoInitParam); + if (phNxpEse_isColdResetRequired(initParams.initMode, wConfigStatus)) + phNxpEse_SPM_ConfigPwr(SPM_RECOVERY_RESET); + } while (phNxpEse_isColdResetRequired(initParams.initMode, wConfigStatus) && + retry++ < 1); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + if (ESESTATUS_TRANSCEIVE_FAILED == wConfigStatus || + ESESTATUS_FAILED == wConfigStatus) { + nxpese_ctxt.EseLibStatus = ESE_STATUS_RECOVERY; + } + } + + if (ESESTATUS_SUCCESS == wConfigStatus) { + ALOGD_IF(ese_debug_enabled, "phNxpEseProto7816_Open completed >>>>>"); + /* Retrieving the IFS-D value configured in the config file and applying to + * Card */ + if ((nxpese_ctxt.endPointInfo == END_POINT_ESE) && + (EseConfig::hasKey(NAME_NXP_ESE_IFSD_VALUE))) { + ifsd_value = EseConfig::getUnsigned(NAME_NXP_ESE_IFSD_VALUE); + if ((0xFFFF > ifsd_value) && (ifsd_value > 0)) { + ALOGD_IF(ese_debug_enabled, + "phNxpEseProto7816_SetIFS IFS adjustment requested with %ld", + ifsd_value); + phNxpEse_setIfs(ifsd_value); + } else { + ALOGD_IF(ese_debug_enabled, + "phNxpEseProto7816_SetIFS IFS adjustment argument invalid"); + } + } else if ((nxpese_ctxt.endPointInfo == END_POINT_EUICC) && + (EseConfig::hasKey(NAME_NXP_EUICC_IFSD_VALUE))) { + ifsd_value = EseConfig::getUnsigned(NAME_NXP_EUICC_IFSD_VALUE); + if ((0xFFFF > ifsd_value) && (ifsd_value > 0)) { + ALOGD_IF(ese_debug_enabled, + "phNxpEseProto7816_SetIFS IFS adjustment requested with %ld", + ifsd_value); + phNxpEse_setIfs(ifsd_value); + } else { + ALOGD_IF(ese_debug_enabled, + "phNxpEseProto7816_SetIFS IFS adjustment argument invalid"); + } + } + } else { + ALOGE("phNxpEseProto7816_Open failed with status = %x", wConfigStatus); + } + + return wConfigStatus; +} + +/****************************************************************************** + * Function phNxpEse_open + * + * Description This function is called by Jni during the + * initialization of the ESE. It opens the physical connection + * with ESE and creates required NAME_NXP_MAX_RNACK_RETRYclient + * thread for operation. + * Returns This function return ESESTATUS_SUCCESS (0) in case of + * success. In case of failure returns other failure values. + ******************************************************************************/ +ESESTATUS phNxpEse_open(phNxpEse_initParams initParams) { + phPalEse_Config_t tPalConfig; + ESESTATUS wConfigStatus = ESESTATUS_SUCCESS; + unsigned long int num = 0, tpm_enable = 0; + char ese_dev_node[64]; + std::string ese_node; +#ifdef SPM_INTEGRATED + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + spm_state_t current_spm_state = SPM_STATE_INVALID; +#endif + /* initialize trace level */ + phNxpLog_InitializeLogLevel(); + + ALOGD_IF(ese_debug_enabled, "phNxpEse_open Enter"); + /*When spi channel is already opened return status as FAILED*/ + if (nxpese_ctxt.EseLibStatus != ESE_STATUS_CLOSE) { + ALOGD_IF(ese_debug_enabled, "already opened\n"); + return ESESTATUS_BUSY; + } + + phNxpEse_memset(&nxpese_ctxt, 0x00, sizeof(nxpese_ctxt)); + phNxpEse_memset(&tPalConfig, 0x00, sizeof(tPalConfig)); + + ALOGD_IF(ese_debug_enabled, "MW SEAccessKit Version"); + ALOGD_IF(ese_debug_enabled, "Android Version:0x%x", NXP_ANDROID_VER); + ALOGD_IF(ese_debug_enabled, "Major Version:0x%x", ESELIB_MW_VERSION_MAJ); + ALOGD_IF(ese_debug_enabled, "Minor Version:0x%x", ESELIB_MW_VERSION_MIN); + + if (EseConfig::hasKey(NAME_NXP_OS_VERSION)) { + num = EseConfig::getUnsigned(NAME_NXP_OS_VERSION); + ALOGD_IF(ese_debug_enabled, "Chip type read from config file - %lu", num); + sOsVersion = (num == 1) ? OS_VERSION_4_0 + : ((num == 2) ? OS_VERSION_5_1 : OS_VERSION_5_2); + } else { + sOsVersion = OS_VERSION_5_2; + ALOGD_IF(ese_debug_enabled, + "Chip type not defined in config file osVersion- %d", sOsVersion); + } + if (EseConfig::hasKey(NAME_NXP_TP_MEASUREMENT)) { + tpm_enable = EseConfig::getUnsigned(NAME_NXP_TP_MEASUREMENT); + ALOGD_IF( + ese_debug_enabled, + "SPI Throughput measurement enable/disable read from config file - %lu", + tpm_enable); + } else { + ALOGD_IF(ese_debug_enabled, + "SPI Throughput not defined in config file - %lu", tpm_enable); + } +#if (NXP_POWER_SCHEME_SUPPORT == true) + if (EseConfig::hasKey(NAME_NXP_POWER_SCHEME)) { + num = EseConfig::getUnsigned(NAME_NXP_POWER_SCHEME); + nxpese_ctxt.pwr_scheme = num; + ALOGD_IF(ese_debug_enabled, "Power scheme read from config file - %lu", + num); + } else { + nxpese_ctxt.pwr_scheme = PN67T_POWER_SCHEME; + ALOGD_IF(ese_debug_enabled, "Power scheme not defined in config file - %lu", + num); + } +#else + nxpese_ctxt.pwr_scheme = PN67T_POWER_SCHEME; + tpm_enable = 0x00; +#endif + + if (EseConfig::hasKey(NAME_NXP_NAD_POLL_RETRY_TIME)) { + num = EseConfig::getUnsigned(NAME_NXP_NAD_POLL_RETRY_TIME); + nxpese_ctxt.nadPollingRetryTime = num; + } else { + nxpese_ctxt.nadPollingRetryTime = 5; + } + + ALOGD_IF(ese_debug_enabled, "Nad poll retry time in us - %lu us", + nxpese_ctxt.nadPollingRetryTime * GET_WAKE_UP_DELAY() * + NAD_POLLING_SCALER); + + /*Read device node path*/ + ese_node = EseConfig::getString(NAME_NXP_ESE_DEV_NODE, "/dev/pn81a"); + strlcpy(ese_dev_node, ese_node.c_str(), sizeof(ese_dev_node)); + tPalConfig.pDevName = (int8_t*)ese_dev_node; + + /* Initialize PAL layer */ + wConfigStatus = phPalEse_open_and_configure(&tPalConfig); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phPalEse_Init Failed"); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + if (ESESTATUS_DRIVER_BUSY == wConfigStatus) + ALOGE("Ese Driver is Busy!!!"); + } + goto clean_and_return; + } + /* Copying device handle to ESE Lib context*/ + nxpese_ctxt.pDevHandle = tPalConfig.pDevHandle; + if (ESE_PROTOCOL_MEDIA_SPI == initParams.mediaType) { + ALOGD_IF(ese_debug_enabled, + "Inform eSE about the starting of trusted Mode"); + wConfigStatus = + phPalEse_ioctl(phPalEse_e_SetSecureMode, tPalConfig.pDevHandle, 0x01); + if (ESESTATUS_SUCCESS != wConfigStatus) goto clean_and_return_2; + } +#ifdef SPM_INTEGRATED + /* Get the Access of ESE*/ + wSpmStatus = phNxpEse_SPM_Init(nxpese_ctxt.pDevHandle); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_Init Failed"); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_2; + } + wSpmStatus = phNxpEse_SPM_SetPwrScheme(nxpese_ctxt.pwr_scheme); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_SetPwrScheme Failed", __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + wConfigStatus = phNxpEse_checkFWDwnldStatus(); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("Failed to open SPI due to VEN pin used by FW download \n"); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + } + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_GetPwrState Failed", __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } else { + if (((current_spm_state & SPM_STATE_SPI) | + (current_spm_state & SPM_STATE_SPI_PRIO)) && + !(current_spm_state & SPM_STATE_SPI_FAILED)) { + ALOGE(" %s : SPI is already opened...second instance not allowed", + __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + } + if (current_spm_state & SPM_STATE_JCOP_DWNLD) { + ALOGE(" %s : Denying to open JCOP Download in progress", __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + phNxpEse_memcpy(&nxpese_ctxt.initParams, &initParams, + sizeof(phNxpEse_initParams)); + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + /* Updating ESE power state based on the init mode */ + if (ESE_MODE_OSU == nxpese_ctxt.initParams.initMode) { + ALOGD_IF(ese_debug_enabled, "%s Init mode ---->OSU", __FUNCTION__); + wConfigStatus = phNxpEse_checkJcopDwnldState(); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_checkJcopDwnldState failed"); + goto clean_and_return_1; + } + } + } + wSpmStatus = phNxpEse_SPM_ConfigPwr(SPM_POWER_ENABLE); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_ConfigPwr: enabling power Failed"); + if (wSpmStatus == ESESTATUS_BUSY) { + wConfigStatus = ESESTATUS_BUSY; + } else if (wSpmStatus == ESESTATUS_DWNLD_BUSY) { + wConfigStatus = ESESTATUS_DWNLD_BUSY; + } else { + wConfigStatus = ESESTATUS_FAILED; + } + goto clean_and_return; + } else { + ALOGD_IF(ese_debug_enabled, "nxpese_ctxt.spm_power_state true"); + nxpese_ctxt.spm_power_state = true; + } +#endif + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + if (tpm_enable) { + wConfigStatus = phPalEse_ioctl(phPalEse_e_EnableThroughputMeasurement, + nxpese_ctxt.pDevHandle, 0); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phPalEse_IoCtl Failed"); + goto clean_and_return; + } + } + } + ALOGD_IF(ese_debug_enabled, "wConfigStatus %x", wConfigStatus); + return wConfigStatus; + +clean_and_return: +#ifdef SPM_INTEGRATED + wSpmStatus = phNxpEse_SPM_ConfigPwr(SPM_POWER_DISABLE); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_ConfigPwr: disabling power Failed"); + } +clean_and_return_1: + phNxpEse_SPM_DeInit(); +clean_and_return_2: +#endif + if (NULL != nxpese_ctxt.pDevHandle) { + phPalEse_close(nxpese_ctxt.pDevHandle); + phNxpEse_memset(&nxpese_ctxt, 0x00, sizeof(nxpese_ctxt)); + } + nxpese_ctxt.EseLibStatus = ESE_STATUS_CLOSE; + nxpese_ctxt.spm_power_state = false; + return ESESTATUS_FAILED; +} + +/****************************************************************************** + * \ingroup spi_libese + * + * \brief Check if libese has opened + * + * \retval return false if it is close, otherwise true. + ** + ******************************************************************************/ +bool phNxpEse_isOpen() { return nxpese_ctxt.EseLibStatus != ESE_STATUS_CLOSE; } + +/****************************************************************************** + * Function phNxpEse_openPrioSession + * + * Description This function is called by Jni during the + * initialization of the ESE. It opens the physical connection + * with ESE () and creates required client thread for + * operation. This will get priority access to ESE for timeout + duration. + + * Returns This function return ESESTATUS_SUCCESS (0) in case of + success + * In case of failure returns other failure value. + * + ******************************************************************************/ +ESESTATUS phNxpEse_openPrioSession(phNxpEse_initParams initParams) { + phPalEse_Config_t tPalConfig; + ESESTATUS wConfigStatus = ESESTATUS_SUCCESS; + unsigned long int num = 0, tpm_enable = 0; + + /* initialize trace level */ + phNxpLog_InitializeLogLevel(); + ALOGD_IF(ese_debug_enabled, "phNxpEse_openPrioSession Enter"); +#ifdef SPM_INTEGRATED + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + spm_state_t current_spm_state = SPM_STATE_INVALID; +#endif + phNxpEse_memset(&nxpese_ctxt, 0x00, sizeof(nxpese_ctxt)); + phNxpEse_memset(&tPalConfig, 0x00, sizeof(tPalConfig)); + + ALOGD_IF(ese_debug_enabled, "MW SEAccessKit Version"); + ALOGD_IF(ese_debug_enabled, "Android Version:0x%x", NXP_ANDROID_VER); + ALOGD_IF(ese_debug_enabled, "Major Version:0x%x", ESELIB_MW_VERSION_MAJ); + ALOGD_IF(ese_debug_enabled, "Minor Version:0x%x", ESELIB_MW_VERSION_MIN); + +#if (NXP_POWER_SCHEME_SUPPORT == true) + if (EseConfig::hasKey(NAME_NXP_POWER_SCHEME)) { + num = EseConfig::getUnsigned(NAME_NXP_POWER_SCHEME); + nxpese_ctxt.pwr_scheme = num; + ALOGD_IF(ese_debug_enabled, "Power scheme read from config file - %lu", + num); + } else +#endif + { + nxpese_ctxt.pwr_scheme = PN67T_POWER_SCHEME; + ALOGD_IF(ese_debug_enabled, "Power scheme not defined in config file - %lu", + num); + } + if (EseConfig::hasKey(NAME_NXP_TP_MEASUREMENT)) { + tpm_enable = EseConfig::getUnsigned(NAME_NXP_TP_MEASUREMENT); + ALOGD_IF( + ese_debug_enabled, + "SPI Throughput measurement enable/disable read from config file - %lu", + tpm_enable); + } else { + ALOGD_IF(ese_debug_enabled, + "SPI Throughput not defined in config file - %lu", num); + } + + tPalConfig.pDevName = (int8_t*)"/dev/p73"; + + /* Initialize PAL layer */ + wConfigStatus = phPalEse_open_and_configure(&tPalConfig); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phPalEse_Init Failed"); + goto clean_and_return; + } + /* Copying device handle to hal context*/ + nxpese_ctxt.pDevHandle = tPalConfig.pDevHandle; + +#ifdef SPM_INTEGRATED + /* Get the Access of ESE*/ + wSpmStatus = phNxpEse_SPM_Init(nxpese_ctxt.pDevHandle); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_Init Failed"); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_2; + } + wSpmStatus = phNxpEse_SPM_SetPwrScheme(nxpese_ctxt.pwr_scheme); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_SetPwrScheme Failed", __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_GetPwrState Failed", __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } else { + if ((current_spm_state & SPM_STATE_SPI) | + (current_spm_state & SPM_STATE_SPI_PRIO)) { + ALOGE(" %s : SPI is already opened...second instance not allowed", + __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + if (current_spm_state & SPM_STATE_JCOP_DWNLD) { + ALOGE(" %s : Denying to open JCOP Download in progress", __FUNCTION__); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + wConfigStatus = phNxpEse_checkFWDwnldStatus(); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGD_IF(ese_debug_enabled, + "Failed to open SPI due to VEN pin used by FW download \n"); + wConfigStatus = ESESTATUS_FAILED; + goto clean_and_return_1; + } + } + } + phNxpEse_memcpy(&nxpese_ctxt.initParams, &initParams.initMode, + sizeof(phNxpEse_initParams)); + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + /* Updating ESE power state based on the init mode */ + if (ESE_MODE_OSU == nxpese_ctxt.initParams.initMode) { + wConfigStatus = phNxpEse_checkJcopDwnldState(); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_checkJcopDwnldState failed"); + goto clean_and_return_1; + } + } + } + wSpmStatus = phNxpEse_SPM_ConfigPwr(SPM_POWER_PRIO_ENABLE); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_ConfigPwr: enabling power for spi prio Failed"); + if (wSpmStatus == ESESTATUS_BUSY) { + wConfigStatus = ESESTATUS_BUSY; + } else if (wSpmStatus == ESESTATUS_DWNLD_BUSY) { + wConfigStatus = ESESTATUS_DWNLD_BUSY; + } else { + wConfigStatus = ESESTATUS_FAILED; + } + goto clean_and_return; + } else { + ALOGE("nxpese_ctxt.spm_power_state true"); + nxpese_ctxt.spm_power_state = true; + } +#endif + +#ifndef SPM_INTEGRATED + wConfigStatus = + phPalEse_ioctl(phPalEse_e_ResetDevice, nxpese_ctxt.pDevHandle, 2); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phPalEse_IoCtl Failed"); + goto clean_and_return; + } +#endif + wConfigStatus = + phPalEse_ioctl(phPalEse_e_EnableLog, nxpese_ctxt.pDevHandle, 0); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phPalEse_IoCtl Failed"); + goto clean_and_return; + } + wConfigStatus = + phPalEse_ioctl(phPalEse_e_EnablePollMode, nxpese_ctxt.pDevHandle, 1); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phPalEse_IoCtl Failed"); + goto clean_and_return; + } + ALOGD_IF(ese_debug_enabled, "wConfigStatus %x", wConfigStatus); + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + if (tpm_enable) { + wConfigStatus = phPalEse_ioctl(phPalEse_e_EnableThroughputMeasurement, + nxpese_ctxt.pDevHandle, 0); + if (wConfigStatus != ESESTATUS_SUCCESS) { + ALOGE("phPalEse_IoCtl Failed"); + goto clean_and_return; + } + } + } + return wConfigStatus; + +clean_and_return: +#ifdef SPM_INTEGRATED + wSpmStatus = phNxpEse_SPM_ConfigPwr(SPM_POWER_DISABLE); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_ConfigPwr: disabling power Failed"); + } +clean_and_return_1: + phNxpEse_SPM_DeInit(); +clean_and_return_2: +#endif + if (NULL != nxpese_ctxt.pDevHandle) { + phPalEse_close(nxpese_ctxt.pDevHandle); + phNxpEse_memset(&nxpese_ctxt, 0x00, sizeof(nxpese_ctxt)); + } + nxpese_ctxt.EseLibStatus = ESE_STATUS_CLOSE; + nxpese_ctxt.spm_power_state = false; + return ESESTATUS_FAILED; +} + +/****************************************************************************** + * Function phNxpEse_setJcopDwnldState + * + * Description This function is used to check whether JCOP OS + * download can be started or not. + * + * Returns returns ESESTATUS_SUCCESS or ESESTATUS_FAILED + * + ******************************************************************************/ +static ESESTATUS phNxpEse_setJcopDwnldState(phNxpEse_JcopDwnldState state) { + ESESTATUS wConfigStatus = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "phNxpEse_setJcopDwnldState Enter"); + + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + wConfigStatus = phNxpEse_SPM_SetJcopDwnldState(state); + } else { + ALOGE("%s function not supported", __FUNCTION__); + } + return wConfigStatus; +} + +/****************************************************************************** + * Function phNxpEse_checkJcopDwnldState + * + * Description This function is used to check whether JCOP OS + * download can be started or not. + * + * Returns returns ESESTATUS_SUCCESS or ESESTATUS_BUSY + * + ******************************************************************************/ +static ESESTATUS phNxpEse_checkJcopDwnldState(void) { + ALOGD_IF(ese_debug_enabled, "phNxpEse_checkJcopDwnld Enter"); + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + spm_state_t current_spm_state = SPM_STATE_INVALID; + uint8_t ese_dwnld_retry = 0x00; + ESESTATUS status = ESESTATUS_FAILED; + + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus == ESESTATUS_SUCCESS) { + /* Check current_spm_state and update config/Spm status*/ + if ((current_spm_state & SPM_STATE_JCOP_DWNLD) || + (current_spm_state & SPM_STATE_WIRED)) + return ESESTATUS_BUSY; + + status = phNxpEse_setJcopDwnldState(JCP_DWNLD_INIT); + if (status == ESESTATUS_SUCCESS) { + while (ese_dwnld_retry < ESE_JCOP_OS_DWNLD_RETRY_CNT) { + ALOGD_IF(ese_debug_enabled, "ESE_JCOP_OS_DWNLD_RETRY_CNT retry count"); + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus == ESESTATUS_SUCCESS) { + if ((current_spm_state & SPM_STATE_JCOP_DWNLD)) { + status = ESESTATUS_SUCCESS; + break; + } + } else { + status = ESESTATUS_FAILED; + break; + } + phNxpEse_Sleep( + 200000); /*sleep for 200 ms checking for jcop dwnld status*/ + ese_dwnld_retry++; + } + } + } + + ALOGD_IF(ese_debug_enabled, "phNxpEse_checkJcopDwnldState status %x", status); + return status; +} + +/****************************************************************************** + * Function phNxpEse_Transceive + * + * Description This function update the len and provided buffer + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_Transceive(phNxpEse_data* pCmd, phNxpEse_data* pRsp) { + ESESTATUS status = ESESTATUS_FAILED; + + if ((NULL == pCmd) || (NULL == pRsp)) return ESESTATUS_INVALID_PARAMETER; + + if ((pCmd->len == 0) || pCmd->p_data == NULL) { + ALOGE(" phNxpEse_Transceive - Invalid Parameter no data\n"); + return ESESTATUS_INVALID_PARAMETER; + } else if (pCmd->len > MAX_SUPPORTED_DATA_SIZE) { + ALOGE(" phNxpEse_Transceive - Invalid data size \n"); + return ESESTATUS_INVALID_RECEIVE_LENGTH; + } else if ((ESE_STATUS_CLOSE == nxpese_ctxt.EseLibStatus)) { + ALOGE(" %s ESE Not Initialized \n", __FUNCTION__); + return ESESTATUS_NOT_INITIALISED; + } else if ((ESE_STATUS_BUSY == nxpese_ctxt.EseLibStatus)) { + ALOGE(" %s ESE - BUSY \n", __FUNCTION__); + return ESESTATUS_BUSY; + } else if ((ESE_STATUS_RECOVERY == nxpese_ctxt.EseLibStatus)) { + ALOGE(" %s ESE - RECOVERY \n", __FUNCTION__); + return ESESTATUS_RECOVERY_STARTED; + } else { + nxpese_ctxt.EseLibStatus = ESE_STATUS_BUSY; + status = phNxpEseProto7816_Transceive((phNxpEse_data*)pCmd, + (phNxpEse_data*)pRsp); + if (ESESTATUS_SUCCESS != status) { + ALOGE(" %s phNxpEseProto7816_Transceive- Failed \n", __FUNCTION__); + if (ESESTATUS_TRANSCEIVE_FAILED == status) { + /*MAX WTX reached*/ + nxpese_ctxt.EseLibStatus = ESE_STATUS_RECOVERY; + } else { + /*Timeout/ No response*/ + nxpese_ctxt.EseLibStatus = ESE_STATUS_IDLE; + } + } else { + nxpese_ctxt.EseLibStatus = ESE_STATUS_IDLE; + } + nxpese_ctxt.rnack_sent = false; + + ALOGD_IF(ese_debug_enabled, " %s Exit status 0x%x \n", __FUNCTION__, + status); + return status; + } +} +/****************************************************************************** + * Function phNxpEse_coldReset + * + * Description This function power cycles the ESE + * (cold reset by prop. FW command) interface by + * talking to NFC HAL + * + * Note: + * After cold reset, phNxpEse_init need to be called to + * reset the host AP T=1 stack parameters + * + * Returns It returns ESESTATUS_SUCCESS (0) if the operation is + *successful else + * ESESTATUS_FAILED(1) + ******************************************************************************/ +ESESTATUS phNxpEse_coldReset(void) { + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + ALOGD_IF(ese_debug_enabled, " %s Enter \n", __FUNCTION__); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + wSpmStatus = phNxpEse_SPM_ConfigPwr(SPM_RECOVERY_RESET); + } else { + wSpmStatus = ESESTATUS_FAILED; + ALOGE(" %s Function not supported \n", __FUNCTION__); + } + ALOGD_IF(ese_debug_enabled, " %s Exit status 0x%x \n", __FUNCTION__, + wSpmStatus); + return wSpmStatus; +} + +/****************************************************************************** + * Function phNxpEse_reset + * + * Description This function reset the ESE interface and free all + * + * Returns It returns ESESTATUS_SUCCESS (0) if the operation is + *successful else + * ESESTATUS_FAILED(1) + ******************************************************************************/ +ESESTATUS phNxpEse_reset(void) { + ESESTATUS status = ESESTATUS_FAILED; + unsigned long maxTimer = 0; +#ifdef SPM_INTEGRATED + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; +#endif + + /* TBD : Call the ioctl to reset the ESE */ + ALOGD_IF(ese_debug_enabled, " %s Enter \n", __FUNCTION__); + /* Do an interface reset, don't wait to see if JCOP went through a full power + * cycle or not */ + status = phNxpEseProto7816_IntfReset( + (phNxpEseProto7816SecureTimer_t*)&nxpese_ctxt.secureTimerParams); + if (status) { + ALOGE("%s Ese status Failed", __FUNCTION__); + } + + ALOGD_IF(ese_debug_enabled, + "%s secureTimer1 0x%x secureTimer2 0x%x secureTimer3 0x%x", + __FUNCTION__, nxpese_ctxt.secureTimerParams.secureTimer1, + nxpese_ctxt.secureTimerParams.secureTimer2, + nxpese_ctxt.secureTimerParams.secureTimer3); + phNxpEse_GetMaxTimer(&maxTimer); +#ifdef SPM_INTEGRATED + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + status = phNxpEse_SPM_DisablePwrControl(maxTimer); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s phNxpEse_SPM_DisablePwrControl: failed", __FUNCTION__); + } + } + if ((nxpese_ctxt.pwr_scheme == PN67T_POWER_SCHEME) || + (nxpese_ctxt.pwr_scheme == PN80T_LEGACY_SCHEME)) { + wSpmStatus = phNxpEse_SPM_ConfigPwr(SPM_POWER_RESET); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_ConfigPwr: reset Failed"); + } + } +#else + /* if arg ==2 (hard reset) + * if arg ==1 (soft reset) + */ + status = phPalEse_ioctl(phPalEse_e_ResetDevice, nxpese_ctxt.pDevHandle, 2); + if (status != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_reset Failed"); + } +#endif + ALOGD_IF(ese_debug_enabled, " %s Exit \n", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEse_resetJcopUpdate + * + * Description This function reset the ESE interface during JCOP Update + * + * Returns It returns ESESTATUS_SUCCESS (0) if the operation is + *successful else + * ESESTATUS_FAILED(1) + ******************************************************************************/ +ESESTATUS phNxpEse_resetJcopUpdate(void) { + ESESTATUS status = ESESTATUS_SUCCESS; + uint8_t retry = 0; +#ifdef SPM_INTEGRATED + unsigned long int num = 0; +#endif + + /* TBD : Call the ioctl to reset the */ + ALOGD_IF(ese_debug_enabled, " %s Enter \n", __FUNCTION__); + + /* Reset interface after every reset irrespective of + whether JCOP did a full power cycle or not. */ + do { + status = phNxpEseProto7816_Reset(); + if (status != ESESTATUS_SUCCESS) phNxpEse_SPM_ConfigPwr(SPM_RECOVERY_RESET); + } while (status != ESESTATUS_SUCCESS && retry++ < 1); + + /* Retrieving the IFS-D value configured in the config file and applying to + * Card */ + if (EseConfig::hasKey(NAME_NXP_ESE_IFSD_VALUE)) { + unsigned long int ifsd_value = 0; + ifsd_value = EseConfig::getUnsigned(NAME_NXP_ESE_IFSD_VALUE); + if ((0xFFFF > ifsd_value) && (ifsd_value > 0)) { + ALOGD_IF(ese_debug_enabled, + "phNxpEseProto7816_SetIFS IFS adjustment requested with %ld", + ifsd_value); + phNxpEse_setIfs(ifsd_value); + } else { + ALOGD_IF(ese_debug_enabled, + "phNxpEseProto7816_SetIFS IFS adjustment argument invalid"); + } + } +#ifdef SPM_INTEGRATED +#if (NXP_POWER_SCHEME_SUPPORT == true) + if (EseConfig::hasKey(NAME_NXP_POWER_SCHEME)) { + num = EseConfig::getUnsigned(NAME_NXP_POWER_SCHEME); + if ((num == 1) || (num == 2)) { + ALOGD_IF(ese_debug_enabled, " %s Call Config Pwr Reset \n", __FUNCTION__); + status = phNxpEse_SPM_ConfigPwr(SPM_POWER_RESET); + if (status != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_resetJcopUpdate: reset Failed"); + status = ESESTATUS_FAILED; + } + } else if (num == 3) { + ALOGD_IF(ese_debug_enabled, " %s Call eSE Chip Reset \n", __FUNCTION__); + status = phNxpEse_chipReset(); + if (status != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_resetJcopUpdate: chip reset Failed"); + status = ESESTATUS_FAILED; + } + } else { + ALOGD_IF(ese_debug_enabled, " %s Invalid Power scheme \n", __FUNCTION__); + } + } +#else + { + status = phNxpEse_SPM_ConfigPwr(SPM_POWER_RESET); + if (status != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_ConfigPwr: reset Failed"); + status = ESESTATUS_FAILED; + } + } +#endif +#else + /* if arg ==2 (hard reset) + * if arg ==1 (soft reset) + */ + status = phPalEse_ioctl(phPalEse_e_ResetDevice, nxpese_ctxt.pDevHandle, 2); + if (status != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_resetJcopUpdate Failed"); + } +#endif + + ALOGD_IF(ese_debug_enabled, " %s Exit \n", __FUNCTION__); + return status; +} +/****************************************************************************** + * Function phNxpEse_EndOfApdu + * + * Description This function is used to send S-frame to indicate + *END_OF_APDU + * + * Returns It returns ESESTATUS_SUCCESS (0) if the operation is + *successful else + * ESESTATUS_FAILED(1) + * + ******************************************************************************/ +ESESTATUS phNxpEse_EndOfApdu(void) { + ESESTATUS status = ESESTATUS_SUCCESS; +#if (NXP_ESE_END_OF_SESSION == true) + status = phNxpEseProto7816_Close( + (phNxpEseProto7816SecureTimer_t*)&nxpese_ctxt.secureTimerParams); +#endif + return status; +} + +/****************************************************************************** + * Function phNxpEse_chipReset + * + * Description This function is used to reset the ESE. + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +ESESTATUS phNxpEse_chipReset(void) { + ESESTATUS status = ESESTATUS_FAILED; + ESESTATUS bStatus = ESESTATUS_FAILED; + if (nxpese_ctxt.pwr_scheme == PN80T_EXT_PMU_SCHEME) { + bStatus = phNxpEseProto7816_Reset(); + if (!bStatus) { + ALOGE("Inside phNxpEse_chipReset, phNxpEseProto7816_Reset Failed"); + } + status = phPalEse_ioctl(phPalEse_e_ChipRst, nxpese_ctxt.pDevHandle, 6); + if (status != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_chipReset Failed"); + } + } else { + ALOGD_IF(ese_debug_enabled, + "phNxpEse_chipReset is not supported in legacy power scheme"); + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_GetOsMode + * + * Description This function is used to get OS mode(JCOP/OSU) + * + * Returns 0x01 : JCOP_MODE + * 0x02 : OSU_MODE + * + ******************************************************************************/ +phNxpEseProto7816_OsType_t phNxpEse_GetOsMode(void) { + return phNxpEseProto7816_GetOsMode(); +} + +/****************************************************************************** + * Function phNxpEse_isColdResetRequired + * + * Description This function determines whether hard reset recovery is + * required or not on protocol recovery failure. + * Returns TRUE(required)/FALSE(not required). + * + ******************************************************************************/ +static __inline bool phNxpEse_isColdResetRequired(phNxpEse_initMode mode, + ESESTATUS status) { + return (mode == ESE_MODE_OSU && status != ESESTATUS_SUCCESS); +} + +/****************************************************************************** + * Function phNxpEse_doResetProtection + * + * Description This function enables/disables reset protection + * + * Returns SUCCESS(0)/FAIL(-1). + * + ******************************************************************************/ +ESESTATUS phNxpEse_doResetProtection(bool flag) { + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + ALOGD_IF(ese_debug_enabled, " %s Enter \n", __FUNCTION__); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + wSpmStatus = phPalEse_ioctl(phPalEse_e_ResetProtection, + nxpese_ctxt.pDevHandle, flag); + } else { + wSpmStatus = ESESTATUS_FAILED; + ALOGE(" %s Function not supported \n", __FUNCTION__); + } + ALOGD_IF(ese_debug_enabled, " %s Exit status 0x%x \n", __FUNCTION__, + wSpmStatus); + return wSpmStatus; +} + +/****************************************************************************** + * Function phNxpEse_deInit + * + * Description This function de-initializes all the ESE protocol params + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +ESESTATUS phNxpEse_deInit(void) { + ESESTATUS status = ESESTATUS_SUCCESS; + unsigned long maxTimer = 0; + unsigned long num = 0; + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0 && + (ESE_STATUS_RECOVERY == nxpese_ctxt.EseLibStatus) && + ESE_PROTOCOL_MEDIA_SPI != nxpese_ctxt.initParams.mediaType) { + return status; + } + if (nxpese_ctxt.initParams.initMode == ESE_MODE_OSU) { + phNxpEse_doResetProtection(false); + } + /*TODO : to be removed after JCOP fix*/ + if (EseConfig::hasKey(NAME_NXP_VISO_DPD_ENABLED)) { + num = EseConfig::getUnsigned(NAME_NXP_VISO_DPD_ENABLED); + } + if (num == 0 && nxpese_ctxt.nadInfo.nadRx == EUICC_NAD_RX) { + // do nothing + } else { + status = phNxpEseProto7816_Close( + (phNxpEseProto7816SecureTimer_t*)&nxpese_ctxt.secureTimerParams); + if (status == ESESTATUS_SUCCESS) { + ALOGD_IF(ese_debug_enabled, + "%s secureTimer1 0x%x secureTimer2 0x%x secureTimer3 0x%x", + __FUNCTION__, nxpese_ctxt.secureTimerParams.secureTimer1, + nxpese_ctxt.secureTimerParams.secureTimer2, + nxpese_ctxt.secureTimerParams.secureTimer3); + phNxpEse_GetMaxTimer(&maxTimer); +#ifdef SPM_INTEGRATED + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + status = phNxpEse_SPM_DisablePwrControl(maxTimer); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s phNxpEseP61_DisablePwrCntrl: failed", __FUNCTION__); + } + } else { + ALOGD_IF(ese_debug_enabled, "Interface reset for DPD"); + status = phNxpEseProto7816_IntfReset( + (phNxpEseProto7816SecureTimer_t*)&nxpese_ctxt.secureTimerParams); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s IntfReset Failed ", __FUNCTION__); + } + } +#endif + } + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_close + * + * Description This function close the ESE interface and free all + * resources. + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +ESESTATUS phNxpEse_close(ESESTATUS deInitStatus) { + ESESTATUS status = ESESTATUS_SUCCESS; + ALOGD_IF(ese_debug_enabled, "phNxpEse_close Enter"); + if ((ESE_STATUS_CLOSE == nxpese_ctxt.EseLibStatus)) { + ALOGE(" %s ESE Not Initialized \n", __FUNCTION__); + return ESESTATUS_NOT_INITIALISED; + } + +#ifdef SPM_INTEGRATED + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; +#endif + +#ifdef SPM_INTEGRATED + /* Release the Access of */ + wSpmStatus = phNxpEse_SPM_ConfigPwr(SPM_POWER_DISABLE); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_ConfigPwr: disabling power Failed"); + } else { + nxpese_ctxt.spm_power_state = false; + } + + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + if (ESE_MODE_OSU == nxpese_ctxt.initParams.initMode) { + status = phNxpEse_setJcopDwnldState(JCP_SPI_DWNLD_COMPLETE); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s: phNxpEse_setJcopDwnldState failed", __FUNCTION__); + } + } + } else { + if (NULL != nxpese_ctxt.pDevHandle) { + if (ESE_PROTOCOL_MEDIA_SPI == nxpese_ctxt.initParams.mediaType) { + ALOGD_IF(ese_debug_enabled, "Inform eSE that trusted Mode is over"); + status = phPalEse_ioctl(phPalEse_e_SetSecureMode, + nxpese_ctxt.pDevHandle, 0x00); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s: phPalEse_e_SetSecureMode failed", __FUNCTION__); + } + if (ESESTATUS_SUCCESS != phNxpEseProto7816_CloseAllSessions()) { + ALOGD_IF(ese_debug_enabled, "eSE not responding perform hard reset"); + phNxpEse_SPM_ConfigPwr(SPM_RECOVERY_RESET); + } + } else { + if (nxpese_ctxt.EseLibStatus == ESE_STATUS_RECOVERY || + (deInitStatus == ESESTATUS_RESPONSE_TIMEOUT) || + ESESTATUS_SUCCESS != phNxpEseProto7816_CloseAllSessions()) { + ALOGD_IF(ese_debug_enabled, "eSE not responding perform hard reset"); + phNxpEse_SPM_ConfigPwr(SPM_RECOVERY_RESET); + } + } + ALOGD_IF(ese_debug_enabled, "Interface reset for DPD"); + status = phNxpEseProto7816_IntfReset( + (phNxpEseProto7816SecureTimer_t*)&nxpese_ctxt.secureTimerParams); + if (status == ESESTATUS_TRANSCEIVE_FAILED || status == ESESTATUS_FAILED) { + ALOGE("%s IntfReset Failed, perform hard reset", __FUNCTION__); + // max wtx or no response of interface reset after protocol recovery + phNxpEse_SPM_ConfigPwr(SPM_RECOVERY_RESET); + } + } + } + + wSpmStatus = phNxpEse_SPM_DeInit(); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE("phNxpEse_SPM_DeInit Failed"); + } +#endif + if (NULL != nxpese_ctxt.pDevHandle) { + phPalEse_close(nxpese_ctxt.pDevHandle); + phNxpEse_memset(&nxpese_ctxt, 0x00, sizeof(nxpese_ctxt)); + ALOGD_IF(ese_debug_enabled, + "phNxpEse_close - ESE Context deinit completed"); + } + /* Return success always */ + return status; +} + +/****************************************************************************** + * Function phNxpEse_read + * + * Description This function write the data to ESE through physical + * interface (e.g. I2C) using the driver interface. + * Before sending the data to ESE, phNxpEse_write_ext + * is called to check if there is any extension processing + * is required for the SPI packet being sent out. + * + * Returns It returns ESESTATUS_SUCCESS (0) if read successful else + * ESESTATUS_FAILED(1) + * + ******************************************************************************/ +ESESTATUS phNxpEse_read(uint32_t* data_len, uint8_t** pp_data) { + ESESTATUS status = ESESTATUS_SUCCESS; + int ret = -1; + + ALOGD_IF(ese_debug_enabled, "%s Enter ..", __FUNCTION__); + + ret = phNxpEse_readPacket(nxpese_ctxt.pDevHandle, nxpese_ctxt.p_read_buff, + MAX_DATA_LEN); + if (ret < 0) { + ALOGE("PAL Read status error status = %x", status); + *data_len = 2; + *pp_data = nxpese_ctxt.p_read_buff; + status = ESESTATUS_FAILED; + } else { + PH_PAL_ESE_PRINT_PACKET_RX(nxpese_ctxt.p_read_buff, (uint16_t)ret); + *data_len = ret; + *pp_data = nxpese_ctxt.p_read_buff; + status = ESESTATUS_SUCCESS; + } + + ALOGD_IF(ese_debug_enabled, "%s Exit", __FUNCTION__); + return status; +} + +/****************************************************************************** + * Function phNxpEse_readPacket + * + * Description This function Reads requested number of bytes from + * pn547 device into given buffer. + * + * Returns nNbBytesToRead- number of successfully read bytes + * -1 - read operation failure + * + ******************************************************************************/ +static int phNxpEse_readPacket(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToRead) { + bool flushData = false; + int ret = -1; + int sof_counter = 0; /* one read may take 1 ms*/ + int total_count = 0, numBytesToRead = 0, headerIndex = 0; + + ALOGD_IF(ese_debug_enabled, "%s Enter", __FUNCTION__); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + int max_sof_counter = 0; + /*Max retry to get SOF in case of chaining*/ + if (poll_sof_chained_delay == 1) { + /*Wait Max for 1.3 sec before retry/recvoery*/ + /*(max_sof_counter(1300) * 10 us) = 1.3 sec */ + max_sof_counter = ESE_POLL_TIMEOUT * 10; + } + /*Max retry to get SOF in case of Non-chaining*/ + else { + /*wait based on config option */ + /*(nadPollingRetryTime * WAKE_UP_DELAY_SN1xx * NAD_POLLING_SCALER_SN1xx)*/ + max_sof_counter = ((ESE_POLL_TIMEOUT * 1000) / + (nxpese_ctxt.nadPollingRetryTime * + GET_WAKE_UP_DELAY() * NAD_POLLING_SCALER)); + } + if (nxpese_ctxt.rnack_sent) { + phPalEse_sleep(nxpese_ctxt.invalidFrame_Rnack_Delay); + } + ALOGD_IF(ese_debug_enabled, + "read() max_sof_counter: " + "%X ESE_POLL_TIMEOUT %2X", + max_sof_counter, ESE_POLL_TIMEOUT); + do { + ret = -1; + ret = phPalEse_read(pDevHandle, pBuffer, 2); + if (ret < 0) { + /*Polling for read on spi, hence Debug log*/ + ALOGD_IF(ese_debug_enabled, "_spi_read() [HDR]errno : %x ret : %X", + errno, ret); + } else { + if ((pBuffer[0] == nxpese_ctxt.nadInfo.nadRx) || + (pBuffer[0] == RECEIVE_PACKET_SOF)) { + /* Read the HEADR of one byte*/ + ALOGD_IF(ese_debug_enabled, "%s Read HDR SOF + PCB", __FUNCTION__); + numBytesToRead = 1; /*Read only INF LEN*/ + headerIndex = 1; + break; + } else if (((pBuffer[0] == 0x00) || (pBuffer[0] == 0xFF)) && + ((pBuffer[1] == nxpese_ctxt.nadInfo.nadRx) || + (pBuffer[1] == RECEIVE_PACKET_SOF))) { + /* Read the HEADR of Two bytes*/ + ALOGD_IF(ese_debug_enabled, "%s Read HDR only SOF", __FUNCTION__); + pBuffer[0] = pBuffer[1]; + numBytesToRead = 2; /*Read PCB + INF LEN*/ + headerIndex = 0; + break; + } else if (((pBuffer[0] == 0x00) && (pBuffer[1] == 0x00)) || + ((pBuffer[0] == 0xFF) && (pBuffer[1] == 0xFF))) { + // LOG(ERROR) << StringPrintf("_spi_read() Buf[0]: %X Buf[1]: %X", + // pBuffer[0], pBuffer[1]); + } else if (ret >= 0) { /* Corruption happened during the receipt from + Card, go flush out the data */ + ALOGE("_spi_read() Corruption Buf[0]: %X Buf[1]: %X ..len=%d", + pBuffer[0], pBuffer[1], ret); + break; + } + } + /*If it is Chained packet wait for 100 usec*/ + if (poll_sof_chained_delay == 1) { + ALOGD_IF(ese_debug_enabled, "%s Chained Pkt, delay read %dus", + __FUNCTION__, GET_WAKE_UP_DELAY() * CHAINED_PKT_SCALER); + phPalEse_sleep(GET_WAKE_UP_DELAY() * CHAINED_PKT_SCALER); + } else { + /*DLOG_IF(INFO, ese_debug_enabled) + << StringPrintf("%s Normal Pkt, delay read %dus", __FUNCTION__, + WAKE_UP_DELAY_SN1xx * NAD_POLLING_SCALER_SN1xx);*/ + phPalEse_sleep(nxpese_ctxt.nadPollingRetryTime * GET_WAKE_UP_DELAY() * + NAD_POLLING_SCALER); + } + sof_counter++; + } while (sof_counter < max_sof_counter); + + /*SOF Read timeout happened, go for frame retransmission*/ + if (sof_counter == max_sof_counter) { + ret = -1; + } + if (ret < 0) { + /*In case of IO Error*/ + ret = -2; + pBuffer[0] = 0x64; + pBuffer[1] = 0xFF; + } else if ((pBuffer[0] == nxpese_ctxt.nadInfo.nadRx) || + (pBuffer[0] == RECEIVE_PACKET_SOF)) { + ALOGD_IF(ese_debug_enabled, "%s SOF FOUND", __FUNCTION__); + /* Read the HEADR of one/Two bytes based on how two bytes read A5 PCB or + * 00 A5*/ + ret = + phPalEse_read(pDevHandle, &pBuffer[1 + headerIndex], numBytesToRead); + if (ret < 0) { + ALOGE("_spi_read() [HDR]errno : %x ret : %X", errno, ret); + flushData = true; + } else { + if ((pBuffer[1] == CHAINED_PACKET_WITHOUTSEQN) || + (pBuffer[1] == CHAINED_PACKET_WITHSEQN)) { + poll_sof_chained_delay = 1; + ALOGD_IF(ese_debug_enabled, "poll_sof_chained_delay value is %d ", + poll_sof_chained_delay); + } else { + poll_sof_chained_delay = 0; + ALOGD_IF(ese_debug_enabled, "poll_sof_chained_delay value is %d ", + poll_sof_chained_delay); + } + total_count = 3; + uint8_t pcb; + phNxpEseProto7816_PCB_bits_t pcb_bits; + pcb = pBuffer[PH_PROPTO_7816_PCB_OFFSET]; + + phNxpEse_memset(&pcb_bits, 0x00, sizeof(phNxpEseProto7816_PCB_bits_t)); + phNxpEse_memcpy(&pcb_bits, &pcb, sizeof(uint8_t)); + + /*For I-Frame Only*/ + if (0 == pcb_bits.msb) { + if (pBuffer[2] != EXTENDED_FRAME_MARKER) { + nNbBytesToRead = pBuffer[2]; + headerIndex = 3; + } else { + ret = phPalEse_read(pDevHandle, &pBuffer[3], 2); + if (ret < 0) { + ALOGE("_spi_read() [HDR]errno : %x ret : %X", errno, ret); + flushData = true; + } else { + nNbBytesToRead = (pBuffer[3] << 8); + nNbBytesToRead = nNbBytesToRead | pBuffer[4]; + /*If I-Frame received with invalid length respond with RNACK*/ + if ((nNbBytesToRead == 0) || (nNbBytesToRead > MAX_DATA_LEN) || + (nNbBytesToRead > phNxpEseProto7816_GetIfs())) { + ALOGD_IF(ese_debug_enabled, "I-Frame with invalid len == %d", + nNbBytesToRead); + flushData = true; + } else { + ALOGE("_spi_read() [HDR]EXTENDED_FRAME_MARKER, ret=%d", ret); + total_count += 2; + headerIndex = 5; + } + } + } + } else { + /*For Non-IFrame*/ + nNbBytesToRead = (int)pBuffer[2]; + headerIndex = 3; + } + if (!flushData) { + /* Read the Complete data + one byte CRC*/ + ret = phPalEse_read(pDevHandle, &pBuffer[headerIndex], + (nNbBytesToRead + 1)); + if (ret < 0) { + ALOGE("_spi_read() [HDR]errno : %x ret : %X", errno, ret); + ret = -1; + } else { + ret = (total_count + (nNbBytesToRead + 1)); + } + nxpese_ctxt.rnack_sent = false; + } + } + } else { + flushData = true; + } + if (flushData) { + /* Received corrupted frame: + Flushing out data in the Rx buffer so that Card can switch the mode */ + uint16_t ifsd_size = phNxpEseProto7816_GetIfs(); + uint32_t total_frame_size = 0; + ALOGE("_spi_read() corrupted, IFSD size=%d flushing it out!!", ifsd_size); + /* If a non-zero byte is received while polling for NAD byte and the byte + is not a valid NAD byte (0xA5 or 0xB4): 1) Read & discard (without + de-asserting SPI CS line) : a. Max IFSD size + 5 (remaining four + prologue + one LRC bytes) bytes from eSE if max IFS size is greater + than 254 bytes OR b. Max IFSD size + 3 (remaining two prologue + one + LRC bytes) bytes from eSE if max IFS size is less than 255 bytes. + 2) Send R-NACK to request eSE to re-transmit the frame*/ + if (ifsd_size > IFSC_SIZE_SEND) { + total_frame_size = ifsd_size + 4; + } else { + total_frame_size = ifsd_size + 2; + } + nxpese_ctxt.rnack_sent = true; + phPalEse_sleep(nxpese_ctxt.invalidFrame_Rnack_Delay); + ret = phPalEse_read(pDevHandle, &pBuffer[2], total_frame_size); + if (ret < 0) { + ALOGE("_spi_read() [HDR]errno : %x ret : %X", errno, ret); + } else { /* LRC fail expected for this frame to send R-NACK*/ + ALOGD_IF( + ese_debug_enabled, + "_spi_read() SUCCESS ret : %X LRC fail excpected for this frame", + ret); + PH_PAL_ESE_PRINT_PACKET_RX(pBuffer, ret); + } + pBuffer[0] = 0x90; + pBuffer[1] = RECEIVE_PACKET_SOF; + ret = 0x02; + phPalEse_sleep(nxpese_ctxt.invalidFrame_Rnack_Delay); + } + } else { + ret = phNxpEse_readPacket_legacy(pDevHandle, pBuffer, nNbBytesToRead); + } + ALOGD_IF(ese_debug_enabled, "%s Exit ret = %d", __FUNCTION__, ret); + return ret; +} + +/****************************************************************************** + * Function phNxpEse_readPacket_legacy + * + * Description This function Reads requested number of bytes from + * pn547 device into given buffer. + * + * Returns nNbBytesToRead- number of successfully read bytes + * -1 - read operation failure + * + ******************************************************************************/ +static int phNxpEse_readPacket_legacy(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToRead) { + int ret = -1; + int sof_counter = 0; /* one read may take 1 ms*/ + int total_count = 0, numBytesToRead = 0, headerIndex = 0; + do { + sof_counter++; + ret = -1; + ret = phPalEse_read(pDevHandle, pBuffer, 2); + if (ret < 0) { + /*Polling for read on spi, hence Debug log*/ + ALOGD_IF(ese_debug_enabled, "_spi_read() [HDR]errno : %x ret : %X", errno, + ret); + } + if (pBuffer[0] == RECEIVE_PACKET_SOF) { + /* Read the HEADR of one byte*/ + ALOGD_IF(ese_debug_enabled, "%s Read HDR", __FUNCTION__); + numBytesToRead = 1; + headerIndex = 1; + break; + } else if (pBuffer[1] == RECEIVE_PACKET_SOF) { + /* Read the HEADR of Two bytes*/ + ALOGD_IF(ese_debug_enabled, "%s Read HDR", __FUNCTION__); + pBuffer[0] = RECEIVE_PACKET_SOF; + numBytesToRead = 2; + headerIndex = 0; + break; + } + /*If it is Chained packet wait for 100 usec*/ + if (poll_sof_chained_delay == 1) { + ALOGD_IF(ese_debug_enabled, "%s Chained Pkt, delay read %dus", + __FUNCTION__, GET_WAKE_UP_DELAY() * CHAINED_PKT_SCALER); + phPalEse_sleep(GET_WAKE_UP_DELAY() * CHAINED_PKT_SCALER); + } else { + ALOGD_IF(ese_debug_enabled, "%s Normal Pkt, delay read %dus", + __FUNCTION__, GET_WAKE_UP_DELAY() * NAD_POLLING_SCALER); + phPalEse_sleep(GET_WAKE_UP_DELAY() * NAD_POLLING_SCALER); + } + } while (sof_counter < ESE_NAD_POLLING_MAX); + if (pBuffer[0] == RECEIVE_PACKET_SOF) { + ALOGD_IF(ese_debug_enabled, "%s SOF FOUND", __FUNCTION__); + /* Read the HEADR of one/Two bytes based on how two bytes read A5 PCB or + * 00 A5*/ + ret = phPalEse_read(pDevHandle, &pBuffer[1 + headerIndex], numBytesToRead); + if (ret < 0) { + ALOGE("_spi_read() [HDR]errno : %x ret : %X", errno, ret); + } + if ((pBuffer[1] == CHAINED_PACKET_WITHOUTSEQN) || + (pBuffer[1] == CHAINED_PACKET_WITHSEQN)) { + poll_sof_chained_delay = 1; + ALOGD_IF(ese_debug_enabled, "poll_sof_chained_delay value is %d ", + poll_sof_chained_delay); + } else { + poll_sof_chained_delay = 0; + ALOGD_IF(ese_debug_enabled, "poll_sof_chained_delay value is %d ", + poll_sof_chained_delay); + } + total_count = 3; + nNbBytesToRead = (int)pBuffer[2]; + /* Read the Complete data + one byte CRC*/ + ret = phPalEse_read(pDevHandle, &pBuffer[3], (nNbBytesToRead + 1)); + if (ret < 0) { + ALOGE("_spi_read() [HDR]errno : %x ret : %X", errno, ret); + ret = -1; + } else { + ret = (total_count + (nNbBytesToRead + 1)); + } + } else if (ret < 0) { + /*In case of IO Error*/ + ret = -2; + pBuffer[0] = 0x64; + pBuffer[1] = 0xFF; + } else { + ret = -1; + } + return ret; +} + +/****************************************************************************** + * Function phNxpEse_WriteFrame + * + * Description This is the actual function which is being called by + * phNxpEse_write. This function writes the data to ESE. + * It waits till write callback provide the result of write + * process. + * + * Returns It returns ESESTATUS_SUCCESS (0) if write successful else + * ESESTATUS_FAILED(1) + * + ******************************************************************************/ +ESESTATUS phNxpEse_WriteFrame(uint32_t data_len, uint8_t* p_data) { + ESESTATUS status = ESESTATUS_INVALID_PARAMETER; + int32_t dwNoBytesWrRd = 0; + ALOGD_IF(ese_debug_enabled, "Enter %s ", __FUNCTION__); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + /* TODO where to set the nad id */ + p_data[0] = nxpese_ctxt.nadInfo.nadTx; + } else { + p_data[0] = ESE_NAD_TX; + } + /* Create local copy of cmd_data */ + phNxpEse_memcpy(nxpese_ctxt.p_cmd_data, p_data, data_len); + nxpese_ctxt.cmd_len = data_len; + + dwNoBytesWrRd = phPalEse_write(nxpese_ctxt.pDevHandle, nxpese_ctxt.p_cmd_data, + nxpese_ctxt.cmd_len); + if (-1 == dwNoBytesWrRd) { + ALOGE(" - Error in SPI Write.....%d\n", errno); + status = ESESTATUS_FAILED; + } else { + status = ESESTATUS_SUCCESS; + PH_PAL_ESE_PRINT_PACKET_TX(nxpese_ctxt.p_cmd_data, nxpese_ctxt.cmd_len); + } + ALOGD_IF(ese_debug_enabled, "Exit %s status %x\n", __FUNCTION__, status); + return status; +} + +/****************************************************************************** + * Function phNxpEse_getAtr + * + * Description This function retrieves ATR bytes from 7816-3 layer + *Update. + * + * Returns It returns ESESTATUS_SUCCESS (0) if write successful else + * ESESTATUS_FAILED(1 + * + ******************************************************************************/ +ESESTATUS phNxpEse_getAtr(phNxpEse_data* pATR) { + ESESTATUS status = ESESTATUS_FAILED; + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + status = phNxpEseProto7816_getAtr(pATR); + } else { + ALOGE(" %s - Function not supported\n", __FUNCTION__); + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_setIfs + * + * Description This function sets the IFS size to 240/254 support JCOP OS + *Update. + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +ESESTATUS phNxpEse_setIfs(uint16_t IFS_Size) { + phNxpEseProto7816_SetIfs(IFS_Size); + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEse_Sleep + * + * Description This function suspends execution of the calling thread for + * (at least) usec microseconds + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +ESESTATUS phNxpEse_Sleep(uint32_t usec) { + phPalEse_sleep(usec); + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEse_memset + * + * Description This function updates destination buffer with val + * data in len size + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +void* phNxpEse_memset(void* buff, int val, size_t len) { + return phPalEse_memset(buff, val, len); +} + +/****************************************************************************** + * Function phNxpEse_memcpy + * + * Description This function copies source buffer to destination buffer + * data in len size + * + * Returns Return pointer to allocated memory location. + * + ******************************************************************************/ +void* phNxpEse_memcpy(void* dest, const void* src, size_t len) { + return phPalEse_memcpy(dest, src, len); +} + +/****************************************************************************** + * Function phNxpEse_Memalloc + * + * Description This function allocation memory + * + * Returns Return pointer to allocated memory or NULL. + * + ******************************************************************************/ +void* phNxpEse_memalloc(uint32_t size) { + return phPalEse_memalloc(size); + ; +} + +/****************************************************************************** + * Function phNxpEse_calloc + * + * Description This is utility function for runtime heap memory allocation + * + * Returns Return pointer to allocated memory or NULL. + * + ******************************************************************************/ +void* phNxpEse_calloc(size_t datatype, size_t size) { + return phPalEse_calloc(datatype, size); +} + +/****************************************************************************** + * Function phNxpEse_free + * + * Description This function de-allocation memory + * + * Returns void. + * + ******************************************************************************/ +void phNxpEse_free(void* ptr) { return phPalEse_free(ptr); } + +/****************************************************************************** + * Function phNxpEse_GetMaxTimer + * + * Description This function finds out the max. timer value returned from + *JCOP + * + * Returns void. + * + ******************************************************************************/ +static void phNxpEse_GetMaxTimer(unsigned long* pMaxTimer) { + /* Finding the max. of the timer value */ + *pMaxTimer = nxpese_ctxt.secureTimerParams.secureTimer1; + if (*pMaxTimer < nxpese_ctxt.secureTimerParams.secureTimer2) + *pMaxTimer = nxpese_ctxt.secureTimerParams.secureTimer2; + *pMaxTimer = (*pMaxTimer < nxpese_ctxt.secureTimerParams.secureTimer3) + ? (nxpese_ctxt.secureTimerParams.secureTimer3) + : *pMaxTimer; + + /* Converting timer to millisecond from sec */ + *pMaxTimer = SECOND_TO_MILLISECOND(*pMaxTimer); + /* Add extra 5% to the timer */ + *pMaxTimer += + CONVERT_TO_PERCENTAGE(*pMaxTimer, ADDITIONAL_SECURE_TIME_PERCENTAGE); + ALOGD_IF(ese_debug_enabled, "%s Max timer value = %lu", __FUNCTION__, + *pMaxTimer); + return; +} + +/****************************************************************************** + * Function phNxpEseP61_DisablePwrCntrl + * + * Description This function disables eSE GPIO power off/on control + * when enabled + * + * Returns SUCCESS/FAIL. + * + ******************************************************************************/ +ESESTATUS phNxpEse_DisablePwrCntrl(void) { + ESESTATUS status = ESESTATUS_SUCCESS; + unsigned long maxTimer = 0; + ALOGE("%s Enter", __FUNCTION__); + phNxpEse_GetMaxTimer(&maxTimer); + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + status = phNxpEse_SPM_DisablePwrControl(maxTimer); + if (status != ESESTATUS_SUCCESS) { + ALOGE("%s phNxpEseP61_DisablePwrCntrl: failed", __FUNCTION__); + } + } else { + ALOGE("%s phNxpEseP61_DisablePwrCntrl: not supported", __FUNCTION__); + status = ESESTATUS_FAILED; + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_getOsVersion + * + * Description This function returns OS version from config file & + * runtime from ATR response + * + * Returns SUCCESS/FAIL. + * + ******************************************************************************/ +phNxpEse_OsVersion_t phNxpEse_getOsVersion() { return sOsVersion; } + +/****************************************************************************** + * Function phNxpEse_setOsVersion + * + * Description This function sets chip type based on ATR response + * + * Returns None. + * + ******************************************************************************/ +void phNxpEse_setOsVersion(phNxpEse_OsVersion_t chipType) { + sOsVersion = chipType; +} + +/****************************************************************************** + * Function phNxpEse_checkFWDwnldStatus + * + * Description This function is used to check whether FW download + * is completed or not. + * + * Returns returns ESESTATUS_SUCCESS or ESESTATUS_BUSY + * + ******************************************************************************/ +static ESESTATUS phNxpEse_checkFWDwnldStatus(void) { + ALOGD_IF(ese_debug_enabled, "phNxpEse_checkFWDwnldStatus Enter"); + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + spm_state_t current_spm_state = SPM_STATE_INVALID; + uint8_t ese_dwnld_retry = 0x00; + ESESTATUS status = ESESTATUS_FAILED; + + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus == ESESTATUS_SUCCESS) { + /* Check current_spm_state and update config/Spm status*/ + while (ese_dwnld_retry < ESE_FW_DWNLD_RETRY_CNT) { + ALOGD_IF(ese_debug_enabled, "ESE_FW_DWNLD_RETRY_CNT retry count"); + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus == ESESTATUS_SUCCESS) { + if ((current_spm_state & SPM_STATE_DWNLD)) { + status = ESESTATUS_FAILED; + } else { + ALOGE("Exit polling no FW Download .."); + status = ESESTATUS_SUCCESS; + break; + } + } else { + status = ESESTATUS_FAILED; + break; + } + phNxpEse_Sleep(500000); /*sleep for 500 ms checking for fw dwnld status*/ + ese_dwnld_retry++; + } + } + + ALOGD_IF(ese_debug_enabled, "phNxpEse_checkFWDwnldStatus status %x", status); + return status; +} + +/****************************************************************************** + * Function phNxpEse_GetEseStatus(unsigned char *timer_buffer) + * + * Description This function returns the all three timer + * Timeout buffer length should be minimum 18 bytes. Response will be in below + format: + * <0xF1><Len><Timer Value><0xF2><Len><Timer Value><0xF3><Len><Timer Value> + * + * Returns SUCCESS/FAIL. + * ESESTATUS_SUCCESS if 0xF1 or 0xF2 tag timeout >= 0 & 0xF3 == 0 + * ESESTATUS_BUSY if 0xF3 tag timeout > 0 + * ESESTATUS_FAILED if any other error + + ******************************************************************************/ +ESESTATUS phNxpEse_GetEseStatus(phNxpEse_data* timer_buffer) { + ESESTATUS status = ESESTATUS_FAILED; + + phNxpEse_SecureTimer_t secureTimerParams; + uint8_t* temp_timer_buffer = NULL; + ALOGD_IF(ese_debug_enabled, "%s Enter", __FUNCTION__); + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ALOGE("%s function not supported", __FUNCTION__); + return status; + } + if (timer_buffer != NULL) { + timer_buffer->len = + (sizeof(secureTimerParams.secureTimer1) + + sizeof(secureTimerParams.secureTimer2) + + sizeof(secureTimerParams.secureTimer3)) + + PH_PROPTO_7816_FRAME_LENGTH_OFFSET * PH_PROPTO_7816_FRAME_LENGTH_OFFSET; + temp_timer_buffer = (uint8_t*)phNxpEse_memalloc(timer_buffer->len); + timer_buffer->p_data = temp_timer_buffer; + + phNxpEse_memcpy(&secureTimerParams, &nxpese_ctxt.secureTimerParams, + sizeof(phNxpEse_SecureTimer_t)); + + ALOGD_IF( + ese_debug_enabled, + "%s secureTimer1 0x%x secureTimer2 0x%x secureTimer3 0x%x len = %d", + __FUNCTION__, secureTimerParams.secureTimer1, + secureTimerParams.secureTimer2, secureTimerParams.secureTimer3, + timer_buffer->len); + + *temp_timer_buffer++ = PH_PROPTO_7816_SFRAME_TIMER1; + *temp_timer_buffer++ = sizeof(secureTimerParams.secureTimer1); + temp_timer_buffer = phNxpEse_GgetTimerTlvBuffer( + temp_timer_buffer, secureTimerParams.secureTimer1); + if (temp_timer_buffer != NULL) { + *temp_timer_buffer++ = PH_PROPTO_7816_SFRAME_TIMER2; + *temp_timer_buffer++ = sizeof(secureTimerParams.secureTimer2); + temp_timer_buffer = phNxpEse_GgetTimerTlvBuffer( + temp_timer_buffer, secureTimerParams.secureTimer2); + if (temp_timer_buffer != NULL) { + *temp_timer_buffer++ = PH_PROPTO_7816_SFRAME_TIMER3; + *temp_timer_buffer++ = sizeof(secureTimerParams.secureTimer3); + temp_timer_buffer = phNxpEse_GgetTimerTlvBuffer( + temp_timer_buffer, secureTimerParams.secureTimer3); + if (temp_timer_buffer != NULL) { + if (secureTimerParams.secureTimer3 > 0) { + status = ESESTATUS_BUSY; + } else { + status = ESESTATUS_SUCCESS; + } + } + } + } + } else { + ALOGE("%s Invalid timer buffer ", __FUNCTION__); + } + + ALOGD_IF(ese_debug_enabled, "%s Exit status = 0x%x", __FUNCTION__, status); + return status; +} + +static unsigned char* phNxpEse_GgetTimerTlvBuffer(uint8_t* timer_buffer, + unsigned int value) { + short int count = 0, shift = 3; + unsigned int mask = 0x000000FF; + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ALOGE("%s function not supported", __FUNCTION__); + } else { + ALOGD_IF(ese_debug_enabled, "value = %x \n", value); + for (count = 0; count < 4; count++) { + if (timer_buffer != NULL) { + *timer_buffer = (value >> (shift * 8) & mask); + ALOGD_IF(ese_debug_enabled, "*timer_buffer=0x%x shift=0x%x", + *timer_buffer, shift); + timer_buffer++; + shift--; + } else { + break; + } + } + } + return timer_buffer; +} + +/****************************************************************************** + * Function phNxpEse_NotifySEWtxRequest + * + * Description This function notifies SE hal service if it registers + * about WTX ongoing & end status + * + * Returns None + * + ******************************************************************************/ +void phNxpEse_NotifySEWtxRequest(phNxpEse_wtxState state) { + if (nxpese_ctxt.fPtr_WtxNtf) { + (nxpese_ctxt.fPtr_WtxNtf)(state); + } else { + ALOGE("%s function not supported", __FUNCTION__); + } +} + +/****************************************************************************** + * Function phNxpEse_setWtxCountLimit + * + * Description This function sets the counter limit for wtx + * + * Returns None + * + ******************************************************************************/ +void phNxpEse_setWtxCountLimit(unsigned long int wtxCount) { + app_wtx_cnt = wtxCount; +} diff --git a/snxxx/libese-spi/p73/lib/phNxpEse_Internal.h b/snxxx/libese-spi/p73/lib/phNxpEse_Internal.h new file mode 100644 index 0000000..83e5667 --- /dev/null +++ b/snxxx/libese-spi/p73/lib/phNxpEse_Internal.h @@ -0,0 +1,142 @@ +/****************************************************************************** + * + * Copyright 2018-2019 NXP + * + * 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. + * + ******************************************************************************/ +#ifndef _PHNXPSPILIB_H_ +#define _PHNXPSPILIB_H_ + +#include <phNxpEse_Api.h> + +/* Macro to enable SPM Module */ +#define SPM_INTEGRATED +//#undef SPM_INTEGRATED +#ifdef SPM_INTEGRATED +#include "../spm/phNxpEse_Spm.h" +#endif + +/********************* Definitions and structures *****************************/ + +typedef enum { + ESE_STATUS_CLOSE = 0x00, + ESE_STATUS_BUSY, + ESE_STATUS_RECOVERY, + ESE_STATUS_IDLE, + ESE_STATUS_OPEN, +} phNxpEse_LibStatus; + +typedef enum { + PN67T_POWER_SCHEME = 0x01, + PN80T_LEGACY_SCHEME, + PN80T_EXT_PMU_SCHEME, +} phNxpEse_PowerScheme; + +typedef enum { + END_POINT_ESE = 0, /*!< eSE services */ + END_POINT_EUICC, /*!< UICC services*/ + MAX_END_POINTS +} phNxpEse_EndPoint; + +/* Macros definition */ +#define MAX_DATA_LEN 780 +#define SECOND_TO_MILLISECOND(X) X * 1000 +#define CONVERT_TO_PERCENTAGE(X, Y) X* Y / 100 +#define ADDITIONAL_SECURE_TIME_PERCENTAGE 5 +#define ESE_JCOP_OS_DWNLD_RETRY_CNT \ + 10 /* Maximum retry count for ESE JCOP OS Dwonload*/ +#define ESE_FW_DWNLD_RETRY_CNT 10 /* Maximum retry count for FW Dwonload*/ + +/*! + * \brief Secure timer values F1, F2, F3 + * + * + */ +typedef struct phNxpEse_SecureTimer { + unsigned int secureTimer1; /*!< Secure timer 1 value */ + unsigned int secureTimer2; /*!< Secure timer 2 value */ + unsigned int secureTimer3; /*!< Secure timer 3 value */ +} phNxpEse_SecureTimer_t; + +typedef enum nadInfoTx { + ESE_NAD_TX = 0x5A, /*!< R-frame Acknowledgement frame indicator */ + EUICC_NAD_TX = 0x4B /*!< R-frame Negative-Acknowledgement frame indicator */ +} nadInfoTx_t; + +/*! + * \brief R-Frame types used in 7816-3 protocol stack + */ +typedef enum nadInfoRx { + ESE_NAD_RX = 0xA5, /*!< R-frame Acknowledgement frame indicator */ + EUICC_NAD_RX = 0xB4 /*!< R-frame Negative-Acknowledgement frame indicator */ +} nadInfoRx_t; + +/*! + * \brief Node address Info structure + * + * + */ +typedef struct phNxpEseNadInfo { + nadInfoTx_t nadTx; /*!< nod address for tx */ + nadInfoRx_t nadRx; /*!< nod address for rx */ +} phNxpEseNadInfo_t; + +/* JCOP download states */ +typedef enum jcop_dwnld_state { + JCP_DWNLD_IDLE = SPM_STATE_JCOP_DWNLD, /* jcop dwnld is not ongoing*/ + JCP_DWNLD_INIT = 0x8010, /* jcop dwonload init state*/ + JCP_DWNLD_START = 0x8020, /* download started */ + JCP_SPI_DWNLD_COMPLETE = 0x8040, /* jcop download complete in spi interface*/ + JCP_DWP_DWNLD_COMPLETE = 0x8080, /* jcop download complete */ +} phNxpEse_JcopDwnldState; + +/*! + * \brief SPI Control structure + * + * + */ +typedef struct phNxpEse_Context { + void* pDevHandle; /*!<device handle */ + long nadPollingRetryTime; /*!<polling retry for nod address */ + long invalidFrame_Rnack_Delay; /*!<delay before retrying when rnack is + received */ + phNxpEse_LibStatus EseLibStatus; /*!<Indicate if Ese Lib is open or closed */ + phNxpEse_initParams initParams; /*!<init params */ + phNxpEse_SecureTimer_t secureTimerParams; /*!<secure timer params */ + phNxpEseNadInfo_t nadInfo; /*!<nad info */ + uint8_t p_read_buff[MAX_DATA_LEN]; /*!<read buffer */ + uint8_t p_cmd_data[MAX_DATA_LEN]; /*!<cmd buffer */ + uint16_t cmd_len; /*!<cmd buffer length */ + uint8_t pwr_scheme; /*!<eSE power scheme */ + uint8_t endPointInfo; /*!<info end point*/ + bool rnack_sent; /*!<rnack send info */ + bool spm_power_state; /*!<spm_power_state */ + NotifyWtxReq* fPtr_WtxNtf; /*!< Wait extension callback notification*/ +} phNxpEse_Context_t; + +/* Timeout value to wait for response from + Note: Timeout value updated from 1000 to 2000 to fix the JCOP delay (WTX)*/ +#define HAL_EXTNS_WRITE_RSP_TIMEOUT (2000) + +#define SPILIB_CMD_CODE_LEN_BYTE_OFFSET (2U) +#define SPILIB_CMD_CODE_BYTE_LEN (3U) + +static nadInfoTx_t nadInfoTx_ptr[MAX_END_POINTS] = {ESE_NAD_TX, EUICC_NAD_TX}; + +static nadInfoRx_t nadInfoRx_ptr[MAX_END_POINTS] = {ESE_NAD_RX, EUICC_NAD_RX}; +ESESTATUS phNxpEse_WriteFrame(uint32_t data_len, uint8_t* p_data); +ESESTATUS phNxpEse_read(uint32_t* data_len, uint8_t** pp_data); +void phNxpEse_setOsVersion(phNxpEse_OsVersion_t chipType); + +#endif /* _PHNXPSPILIB_H_ */ diff --git a/snxxx/libese-spi/p73/pal/EseTransport.h b/snxxx/libese-spi/p73/pal/EseTransport.h new file mode 100644 index 0000000..2929374 --- /dev/null +++ b/snxxx/libese-spi/p73/pal/EseTransport.h @@ -0,0 +1,139 @@ +/****************************************************************************** + * + * Copyright 2020-2021 NXP + * + * 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. + * + ******************************************************************************/ +#pragma once + +/* Basic type definitions */ +#include <phNxpEsePal.h> + +/*! + * \brief Start of frame marker + */ +#define SEND_PACKET_SOF 0x5A +/*! + * \brief ESE Poll timeout (max 2 seconds) + */ +#define ESE_POLL_TIMEOUT (2 * 1000) +/*! + * \brief ESE Max Poll retry count + */ + +#define ESE_NAD_POLLING_MAX (2000) + +/*! + * \brief ESE wakeup delay in case of write error retry + */ + +#define WAKE_UP_DELAY_USECS 100 + +#define GET_WAKE_UP_DELAY() \ + ((GET_CHIP_OS_VERSION() != OS_VERSION_4_0) ? (WAKE_UP_DELAY_USECS) \ + : (10 * WAKE_UP_DELAY_USECS)) + +/*! + * \brief ESE wakeup delay in case of write error retry + */ + +#define NAD_POLLING_SCALER 1 + +/*! + * \brief ESE wakeup delay in case of write error retry + */ +#define CHAINED_PKT_SCALER 1 +/*! + * \brief Magic type specific to the ESE device driver + */ +#define P61_MAGIC 0xEA + +/*! + * \brief IOCTL number to set ESE PWR + */ +#define P61_SET_PWR _IOW(P61_MAGIC, 0x01, long) +/*! + * \brief IOCTL number to set debug state + */ +#define P61_SET_DBG _IOW(P61_MAGIC, 0x02, long) +/*! + * \brief IOCTL number to enable poll mode + */ +#define P61_SET_POLL _IOW(P61_MAGIC, 0x03, long) +/*! + * \brief SPI Request NFCC to enable p61 power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define P61_SET_SPM_PWR _IOW(P61_MAGIC, 0x04, long) + +/*! + * \brief SPI or DWP can call this ioctl to get the current + * power state of P61 + * + */ +#define P61_GET_SPM_STATUS _IOR(P61_MAGIC, 0x05, long) +/*! + * \brief IOCTL to add throughput measurement source code in device driver + * + */ +#define P61_SET_THROUGHPUT _IOW(P61_MAGIC, 0x06, long) +/*! + * \brief IOCTL to get the ESE access + * + */ +#define P61_GET_ESE_ACCESS _IOW(P61_MAGIC, 0x07, long) +/*! + * \brief IOCTL to set the power scheme + * + */ +#define P61_SET_POWER_SCHEME _IOW(P61_MAGIC, 0x08, long) +/*! + * \brief This function is used to set the ESE jcop + * download state. + */ +#define P61_SET_DWNLD_STATUS _IOW(P61_MAGIC, 0x09, long) + +/*! + * \brief This function is used to set disable ESE GPIO + * state On&Off + */ +#define P61_INHIBIT_PWR_CNTRL _IOW(P61_MAGIC, 0x0A, long) +/*! + * \brief IOCTL to set the GPIO for the eSE to distinguish + * the logical interface + */ +#define ESE_SET_TRUSTED_ACCESS _IOW(P61_MAGIC, 0x0B, long) + +/*! + * \brief IOCTL to perform the eSE COLD_RESET via NFC driver. + */ +#define ESE_PERFORM_COLD_RESET _IOW(P61_MAGIC, 0x0C, long) +/*! + * \brief IOCTL to enable/disable GPIO/COLD reset protection. + */ +#define PERFORM_RESET_PROTECTION _IOW(P61_MAGIC, 0x0D, long) + +class EseTransport { + public: + virtual void Close(void* pDevHandle) = 0; + virtual ESESTATUS OpenAndConfigure(pphPalEse_Config_t pConfig) = 0; + virtual int Read(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToRead) = 0; + virtual int Write(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToWrite) = 0; + virtual ESESTATUS Ioctl(phPalEse_ControlCode_t eControlCode, void* pDevHandle, + long level) = 0; + virtual ~EseTransport(){}; +}; diff --git a/snxxx/libese-spi/p73/pal/EseTransportFactory.cpp b/snxxx/libese-spi/p73/pal/EseTransportFactory.cpp new file mode 100644 index 0000000..d76d987 --- /dev/null +++ b/snxxx/libese-spi/p73/pal/EseTransportFactory.cpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright 2020 NXP + * + * 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 <EseSpiTransport.h> +#include <EseTransportFactory.h> + +EseTransportFactory::EseTransportFactory() {} + +EseTransportFactory& EseTransportFactory::getInstance() { + static EseTransportFactory mTransprtFactoryInstance; + return mTransprtFactoryInstance; +} + +spTransport EseTransportFactory::getTransport(transportIntf transportType) { + spTransport mspTransportInterface; + switch (transportType) { + case SPI: + case UNKNOWN: + mspTransportInterface = std::make_shared<EseSpiTransport>(); + break; + default: + mspTransportInterface = std::make_shared<EseSpiTransport>(); + break; + } + return mspTransportInterface; +} diff --git a/snxxx/libese-spi/p73/pal/EseTransportFactory.h b/snxxx/libese-spi/p73/pal/EseTransportFactory.h new file mode 100644 index 0000000..0a9a876 --- /dev/null +++ b/snxxx/libese-spi/p73/pal/EseTransportFactory.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * Copyright 2020 NXP + * + * 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. + * + ******************************************************************************/ + +#pragma once +#include <EseTransport.h> +#include <memory> + +#define transportFactory (EseTransportFactory::getInstance()) +typedef std::shared_ptr<EseTransport> spTransport; +enum transportIntf { SPI, UNKNOWN }; + +extern spTransport gpTransportObj; +class EseTransportFactory { + /***************************************************************************** + ** + ** Function EseTransportFactory + ** + ** Description Constructor for transportFactory. This will be private to + ** support singleton + ** + ** Parameters none + ** + ** Returns none + ****************************************************************************/ + EseTransportFactory(); + + public: + /***************************************************************************** + ** + ** Function getInstance + ** + ** Description returns the static instance of TransportFactory + ** + ** Parameters none + ** + ** Returns TransportFactory instance + ****************************************************************************/ + static EseTransportFactory& getInstance(); + + /***************************************************************************** + ** + ** Function getTransport + ** + ** Description selects and returns transport channel based on the input + ** parameter + ** + ** Parameters Required transport Type + ** + ** Returns Selected transport channel + ****************************************************************************/ + spTransport getTransport(transportIntf transportType); +}; diff --git a/snxxx/libese-spi/p73/pal/phNxpEsePal.cpp b/snxxx/libese-spi/p73/pal/phNxpEsePal.cpp new file mode 100755 index 0000000..7e23305 --- /dev/null +++ b/snxxx/libese-spi/p73/pal/phNxpEsePal.cpp @@ -0,0 +1,314 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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. + * + ******************************************************************************/ + +/* + * DAL spi port implementation for linux + * + * Project: Trusted ESE Linux + * + */ +#define LOG_TAG "NxpEseHal" +#include <log/log.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include <EseTransportFactory.h> +#include <ese_config.h> +#include <phEseStatus.h> +#include <string.h> + +/*! + * \brief Normal mode header length + */ +#define NORMAL_MODE_HEADER_LEN 3 +/*! + * \brief Normal mode header offset + */ +#define NORMAL_MODE_LEN_OFFSET 2 +/*! + * \brief Start of frame marker + */ +#define SEND_PACKET_SOF 0x5A +/*! + * \brief To enable SPI interface for ESE communication + */ +#define SPI_ENABLED 1 + +spTransport gpTransportObj; + +/******************************************************************************* +** +** Function phPalEse_close +** +** Description Closes PN547 device +** +** Parameters pDevHandle - device handle +** +** Returns None +** +*******************************************************************************/ +void phPalEse_close(void* pDevHandle) { + if (NULL != pDevHandle) { + gpTransportObj->Close(pDevHandle); + } + gpTransportObj = NULL; + return; +} + +/******************************************************************************* +** +** Function phPalEse_open_and_configure +** +** Description Open and configure ESE device +** +** Parameters pConfig - hardware information +** +** Returns ESE status: +** ESESTATUS_SUCCESS - open_and_configure operation +*success +** ESESTATUS_INVALID_DEVICE - device open operation failure +** +*******************************************************************************/ +ESESTATUS phPalEse_open_and_configure(pphPalEse_Config_t pConfig) { + ESESTATUS status = ESESTATUS_FAILED; + if (ESESTATUS_SUCCESS != phPalEse_ConfigTransport()) return ESESTATUS_FAILED; + status = gpTransportObj->OpenAndConfigure(pConfig); + return status; +} + +/******************************************************************************* +** +** Function phPalEse_ConfigTransport +** +** Description Configure Transport channel based on transport type provided +** in config file +** +** Returns ESESTATUS_SUCCESS If transport channel is configured +** ESESTATUS_FAILED If transport channel configuration failed +** +*******************************************************************************/ +ESESTATUS phPalEse_ConfigTransport() { + unsigned long transportType = UNKNOWN; + + transportType = EseConfig::getUnsigned(NAME_NXP_TRANSPORT, UNKNOWN); + ALOGD("phPalEse_ConfigTransport transport type %ld", transportType); + gpTransportObj = transportFactory.getTransport((transportIntf)transportType); + if (gpTransportObj == nullptr) { + return ESESTATUS_FAILED; + } + return ESESTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function phPalEse_read +** +** Description Reads requested number of bytes from pn547 device into given +*buffer +** +** Parameters pDevHandle - valid device handle +** pBuffer - buffer for read data +** nNbBytesToRead - number of bytes requested to be read +** +** Returns numRead - number of successfully read bytes +** -1 - read operation failure +** +*******************************************************************************/ +int phPalEse_read(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToRead) { + int ret = -1; + ret = gpTransportObj->Read(pDevHandle, pBuffer, nNbBytesToRead); + return ret; +} + +/******************************************************************************* +** +** Function phPalEse_write +** +** Description Writes requested number of bytes from given buffer into +*pn547 device +** +** Parameters pDevHandle - valid device handle +** pBuffer - buffer for read data +** nNbBytesToWrite - number of bytes requested to be written +** +** Returns numWrote - number of successfully written bytes +** -1 - write operation failure +** +*******************************************************************************/ +int phPalEse_write(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToWrite) { + int numWrote = 0; + + if (NULL == pDevHandle) { + return -1; + } + numWrote = gpTransportObj->Write(pDevHandle, pBuffer, nNbBytesToWrite); + return numWrote; +} + +/******************************************************************************* +** +** Function phPalEse_ioctl +** +** Description Exposed ioctl by p61 spi driver +** +** Parameters pDevHandle - valid device handle +** level - reset level +** +** Returns 0 - ioctl operation success +** -1 - ioctl operation failure +** +*******************************************************************************/ +ESESTATUS phPalEse_ioctl(phPalEse_ControlCode_t eControlCode, void* pDevHandle, + long level) { + ESESTATUS ret = ESESTATUS_FAILED; + ALOGD_IF(ese_debug_enabled, "phPalEse_spi_ioctl(), ioctl %x , level %lx", + eControlCode, level); + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + if (NULL == pDevHandle) { + return ESESTATUS_IOCTL_FAILED; + } + } + if (pDevHandle == NULL) { + phPalEse_ConfigTransport(); + } + ret = gpTransportObj->Ioctl(eControlCode, pDevHandle, level); + if (pDevHandle == NULL) { + phPalEse_close(pDevHandle); + } + + return ret; +} + +/******************************************************************************* +** +** Function phPalEse_print_packet +** +** Description Print packet +** +** Returns None +** +*******************************************************************************/ +void phPalEse_print_packet(const char* pString, const uint8_t* p_data, + uint16_t len) { + uint32_t i; + char print_buffer[len * 3 + 1]; + + memset(print_buffer, 0, sizeof(print_buffer)); + for (i = 0; i < len; i++) { + snprintf(&print_buffer[i * 2], 3, "%02X", p_data[i]); + } + if (0 == memcmp(pString, "SEND", 0x04)) { + ALOGD_IF(ese_debug_enabled, "NxpEseDataX len = %3d > %s", len, + print_buffer); + } else if (0 == memcmp(pString, "RECV", 0x04)) { + ALOGD_IF(ese_debug_enabled, "NxpEseDataR len = %3d > %s", len, + print_buffer); + } + + return; +} + +/******************************************************************************* +** +** Function phPalEse_sleep +** +** Description This function suspends execution of the calling thread for +** (at least) usec microseconds +** +** Returns None +** +*******************************************************************************/ +void phPalEse_sleep(long usec) { + usleep(usec); + return; +} + +/******************************************************************************* +** +** Function phPalEse_memset +** +** Description +** +** Returns None +** +*******************************************************************************/ + +void* phPalEse_memset(void* buff, int val, size_t len) { + return memset(buff, val, len); +} + +/******************************************************************************* +** +** Function phPalEse_memcpy +** +** Description +** +** Returns None +** +*******************************************************************************/ + +void* phPalEse_memcpy(void* dest, const void* src, size_t len) { + return memcpy(dest, src, len); +} + +/******************************************************************************* +** +** Function phPalEse_memalloc +** +** Description +** +** Returns None +** +*******************************************************************************/ + +void* phPalEse_memalloc(uint32_t size) { return malloc(size); } + +/******************************************************************************* +** +** Function phPalEse_calloc +** +** Description +** +** Returns None +** +*******************************************************************************/ + +void* phPalEse_calloc(size_t datatype, size_t size) { + return calloc(datatype, size); +} + +/******************************************************************************* +** +** Function phPalEse_free +** +** Description +** +** Returns None +** +*******************************************************************************/ +void phPalEse_free(void* ptr) { + if (ptr != NULL) { + free(ptr); + ptr = NULL; + } + return; +} diff --git a/snxxx/libese-spi/p73/pal/phNxpEsePal.h b/snxxx/libese-spi/p73/pal/phNxpEsePal.h new file mode 100644 index 0000000..d6d06cf --- /dev/null +++ b/snxxx/libese-spi/p73/pal/phNxpEsePal.h @@ -0,0 +1,247 @@ +/****************************************************************************** + * + * Copyright 2018-2021 NXP + * + * 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. + * + ******************************************************************************/ + +/** + * \addtogroup eSe_PAL + * \brief PAL implementation + * @{ */ + +#ifndef _PHNXPESE_PAL_H +#define _PHNXPESE_PAL_H + +/* Basic type definitions */ +#include <errno.h> +#include <phEseStatus.h> +#include <phNxpEseFeatures.h> +#include <stdint.h> +/*! + * \brief Value indicates to reset device + */ +#define PH_PALESE_RESETDEVICE (0x00008001) + +/*! + * \ingroup eSe_PAL + * + * \brief Enum definition contains supported ioctl control codes. + * + * phPalEse_IoCtl + */ +typedef enum { + phPalEse_e_Invalid = 0, /*!< Invalid control code */ + phPalEse_e_ResetDevice = PH_PALESE_RESETDEVICE, /*!< Reset the device */ + phPalEse_e_EnableLog, /*!< Enable the spi driver logs */ + phPalEse_e_EnablePollMode, /*!< Enable the polling for SPI */ + phPalEse_e_GetEseAccess, /*!< get the bus access in specified timeout */ + phPalEse_e_ChipRst, /*!< eSE Chip reset using ISO RST pin*/ + phPalEse_e_EnableThroughputMeasurement, /*!< Enable throughput measurement */ + phPalEse_e_SetPowerScheme, /*!< Set power scheme */ + phPalEse_e_GetSPMStatus, /*!< Get SPM(power mgt) status */ + phPalEse_e_DisablePwrCntrl, + phPalEse_e_SetJcopDwnldState, /*!< Set Jcop Download state */ + phPalEse_e_SetClientUpdateState, /*!< Set Jcop Download state */ + phPalEse_e_SetSecureMode, /*!< Set the Trusted SE Mode */ + phPalEse_e_ResetProtection, +} phPalEse_ControlCode_t; /*!< Control code for IOCTL call */ + +/*! + * \ingroup eSe_PAL + * + * \brief PAL Configuration exposed to upper layer. + */ +typedef struct phPalEse_Config { + int8_t* pDevName; + /*!< Port name connected to ESE + * + * Platform specific canonical device name to which ESE is connected. + * + * e.g. On Linux based systems this would be /dev/p73 + */ + + uint32_t dwBaudRate; + /*!< Communication speed between DH and ESE + * + * This is the baudrate of the bus for communication between DH and ESE + */ + + void* pDevHandle; + /*!< Device handle output */ +} phPalEse_Config_t, *pphPalEse_Config_t; /* pointer to phPalEse_Config_t */ + +/* Function declarations */ +/** + * \ingroup eSe_PAL + * \brief This function is used to close the ESE device + * + * \retval None + * + */ +void phPalEse_close(void* pDevHandle); + +/** + * \ingroup eSe_PAL + * \brief Open and configure ESE device + * + * \param[in] pConfig: Config to open the device + * + * \retval ESESTATUS On Success ESESTATUS_SUCCESS else proper error code + * + */ +ESESTATUS phPalEse_open_and_configure(pphPalEse_Config_t pConfig); + +/** + * \ingroup eSe_PAL + * \brief ConfigTransport to get SPI terminal + * + * \retval ESESTATUS On Success ESESTATUS_SUCCESS else proper error code + * + */ +ESESTATUS phPalEse_ConfigTransport(); + +/** + * \ingroup eSe_PAL + * \brief Reads requested number of bytes from ESE into given buffer + * + * \param[in] pDevHandle - valid device handle + **\param[in] pBuffer - buffer for read data + **\param[in] nNbBytesToRead - number of bytes requested to be read + * + * \retval numRead - number of successfully read bytes. + * \retval -1 - read operation failure + * + */ +int phPalEse_read(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToRead); + +/** + * \ingroup eSe_PAL + * \brief Writes requested number of bytes from given buffer into pn547 device + * + * \param[in] pDevHandle - valid device handle + * \param[in] pBuffer - buffer to write + * \param[in] nNbBytesToWrite - number of bytes to write + * + * \retval numWrote - number of successfully written bytes + * \retval -1 - write operation failure + * + */ +int phPalEse_write(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToWrite); + +/** + * \ingroup eSe_PAL + * \brief Exposed ioctl by ESE driver + * + * \param[in] eControlCode - phPalEse_ControlCode_t for the respective + *configs + * \param[in] pDevHandle - valid device handle + * \param[in] level - reset level + * + * \retval 0 - ioctl operation success + * \retval -1 - ioctl operation failure + * + */ +ESESTATUS phPalEse_ioctl(phPalEse_ControlCode_t eControlCode, void* pDevHandle, + long level); + +/** + * \ingroup eSe_PAL + * \brief Print packet data + * + * \param[in] pString - String to be printed + * \param[in] p_data - data to be printed + * \param[in] len - Length of data to be printed + * + * \retval void + * + */ +void phPalEse_print_packet(const char* pString, const uint8_t* p_data, + uint16_t len); + +/** + * \ingroup eSe_PAL + * \brief This function suspends execution of the calling thread for + * (at least) usec microseconds + * + * \param[in] usec - number of micro seconds to sleep + * + * \retval void + * + */ +void phPalEse_sleep(long usec); + +/** + * \ingroup eSe_PAL + * \brief This function updates destination buffer with val + * data in len size + * + * \param[in] buff - Array to be updated + * \param[in] val - value to be updated + * \param[in] len - length of array to be updated + * + * \retval void + * + */ +void* phPalEse_memset(void* buff, int val, size_t len); + +/** + * \ingroup eSe_PAL + * \brief This function copies source buffer to destination buffer + * data in len size + * + * \param[in] dest - Destination array to be updated + * \param[in] src - Source array to be updated + * \param[in] len - length of array to be updated + * + * \retval void + * + */ +void* phPalEse_memcpy(void* dest, const void* src, size_t len); + +/** + * \ingroup eSe_PAL + * \brief This is utility function for runtime heap memory allocation + * + * \param[in] size - number of bytes to be allocated + * + * \retval void + * + */ +void* phPalEse_memalloc(uint32_t size); + +/** + * \ingroup eSe_PAL + * \brief This is utility function for runtime heap memory allocation + * + * \param[in] dataType - type of data + * \param[in] size - number of bytes to be allocated + * \retval void + * + */ +void* phPalEse_calloc(size_t dataType, size_t size); + +/** + * \ingroup eSe_PAL + * \brief This is utility function for freeeing heap memory allocated + * + * \param[in] ptr - Address pointer to previous allocation + * + * \retval void + * + */ +void phPalEse_free(void* ptr); + +/** @} */ +#endif /* _PHNXPESE_PAL_H */ diff --git a/snxxx/libese-spi/p73/pal/spi/EseSpiTransport.cpp b/snxxx/libese-spi/p73/pal/spi/EseSpiTransport.cpp new file mode 100644 index 0000000..859298e --- /dev/null +++ b/snxxx/libese-spi/p73/pal/spi/EseSpiTransport.cpp @@ -0,0 +1,503 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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. + * + ******************************************************************************/ + +/* + * DAL spi port implementation for linux + * + * Project: Trusted ESE Linux + * + */ + +#include "EseSpiTransport.h" + +#define LOG_TAG "NxpEseHal" +#include <log/log.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include <ese_config.h> +#include <hardware/nfc.h> +#include <phEseStatus.h> +#include <phNxpEsePal.h> +#include <string.h> +#include "NfcAdaptation.h" +#include "hal_nxpese.h" +#include "phNxpEse_Api.h" + +#define MAX_RETRY_CNT 10 +#define HAL_NFC_SPI_DWP_SYNC 21 + +extern int omapi_status; + +static int rf_status; +#if (NFC_NXP_ESE_VER == JCOP_VER_5_x) +eseIoctlData_t eseioctldata; +#endif +// Default max retry count for SPI CLT write blocked in secs +static unsigned long int gsMaxSpiWriteRetryCnt = 10; +#if (NFC_NXP_ESE_VER == JCOP_VER_4_0) +static ESESTATUS phNxpEse_spiIoctl_legacy(uint64_t ioctlType, void* p_data); +#endif + +/******************************************************************************* +** +** Function phPalEse_spi_close +** +** Description Closes PN547 device +** +** Parameters pDevHandle - device handle +** +** Returns None +** +*******************************************************************************/ +void EseSpiTransport::Close(void* pDevHandle) { + if (NULL != pDevHandle) { + close((intptr_t)pDevHandle); + } + return; +} + +/******************************************************************************* +** +** Function phNxpEse_spiIoctl +** +** Description Perform cross HAL IOCTL functionality +** +** Parameters ioctlType, input data +** +** Returns SUCCESS/FAIL +** +*******************************************************************************/ +ESESTATUS phNxpEse_spiIoctl(uint64_t ioctlType, void* p_data) { + ESESTATUS status = ESESTATUS_SUCCESS; + if (!p_data) { + ALOGE("halimpl phNxpEse_spiIoctl p_data is null ioctltyp: %ld", + (long)ioctlType); + return ESESTATUS_FAILED; + } +#if (NFC_NXP_ESE_VER == JCOP_VER_5_x) + ese_nxp_IoctlInOutData_t* inpOutData = (ese_nxp_IoctlInOutData_t*)p_data; + switch (ioctlType) { + case HAL_ESE_IOCTL_RF_STATUS_UPDATE: + rf_status = inpOutData->inp.data.nxpCmd.p_cmd[0]; + if (rf_status == 1) { + ALOGD_IF( + ese_debug_enabled, + "******************RF IS ON*************************************"); + } else { + ALOGD_IF( + ese_debug_enabled, + "******************RF IS OFF*************************************"); + } + break; + case HAL_ESE_IOCTL_NFC_JCOP_DWNLD: + + eseioctldata.nfc_jcop_download_state = + inpOutData->inp.data.nxpCmd.p_cmd[0]; + if (eseioctldata.nfc_jcop_download_state == 1) { + ALOGD_IF(ese_debug_enabled, + "******************JCOP Download " + "started*************************************"); + } else { + ALOGD_IF(ese_debug_enabled, + "******************JCOP Download " + "stopped*************************************"); + } + break; + default: + ALOGD_IF(ese_debug_enabled, "Invalid IOCTL type"); + break; + } +#endif +#if (NFC_NXP_ESE_VER == JCOP_VER_4_0) + status = phNxpEse_spiIoctl_legacy(ioctlType, p_data); +#endif + return status; +} +#if (NFC_NXP_ESE_VER == JCOP_VER_4_0) +/******************************************************************************* +** +** Function phNxpEse_spiIoctl_legacy +** +** Description Perform cross HAL IOCTL functionality +** +** Parameters ioctlType, input data +** +** Returns SUCCESS/FAIL +** +*******************************************************************************/ +static ESESTATUS phNxpEse_spiIoctl_legacy(uint64_t ioctlType, void* p_data) { + ese_nxp_IoctlInOutData_t* inpOutData = (ese_nxp_IoctlInOutData_t*)p_data; + switch (ioctlType) { + case HAL_ESE_IOCTL_RF_STATUS_UPDATE: + + rf_status = inpOutData->inp.data.nxpCmd.p_cmd[0]; + if (rf_status == 1) { + ALOGD_IF( + ese_debug_enabled, + "******************RF IS ON*************************************"); + } else { + ALOGD_IF( + ese_debug_enabled, + "******************RF IS OFF*************************************"); + } + break; + default: + ALOGD_IF(ese_debug_enabled, "Invalid IOCTL type"); + break; + } + return ESESTATUS_SUCCESS; +} +#endif + +/******************************************************************************* +** +** Function OpenAndConfigure +** +** Description Open and configure pn547 device +** +** Parameters pConfig - hardware information +** pLinkHandle - device handle +** +** Returns ESE status: +** ESESTATUS_SUCCESS - open_and_configure operation +*success +** ESESTATUS_INVALID_DEVICE - device open operation failure +** +*******************************************************************************/ +ESESTATUS EseSpiTransport::OpenAndConfigure(pphPalEse_Config_t pConfig) { + int nHandle; + int retryCnt = 0; + ALOGD("NxpEse EseSpiTransport::OpenAndConfigure 1"); + if (EseConfig::hasKey(NAME_NXP_SOF_WRITE)) { + mConfigSofWrite = EseConfig::getUnsigned(NAME_NXP_SOF_WRITE); + ALOGD_IF(ese_debug_enabled, "NXP_SOF_WRITE value from config file = %ld", + mConfigSofWrite); + } + if (EseConfig::hasKey(NAME_NXP_SPI_WRITE_TIMEOUT)) { + mConfigSpiWriteTimeout = EseConfig::getUnsigned(NAME_NXP_SPI_WRITE_TIMEOUT); + ALOGD_IF(ese_debug_enabled, + "NXP_SPI_WRITE_TIMEOUT value from config file = %ld", + mConfigSpiWriteTimeout); + } + /* Read eSE cold reset interface from ese config file */ + if (EseConfig::hasKey(NAME_NXP_P61_COLD_RESET_INTERFACE)) { + mConfigColdResetIntf = + EseConfig::getUnsigned(NAME_NXP_P61_COLD_RESET_INTERFACE); + ALOGD_IF(ese_debug_enabled, + "mConfigColdResetIntf value from config file = %ld", + mConfigColdResetIntf); + } else { + mConfigColdResetIntf = 0x01; /* Default interface is NFC HAL */ + ALOGD_IF(ese_debug_enabled, "mConfigColdResetIntf: Default value "); + } + ALOGD_IF(ese_debug_enabled, "Opening port=%s\n", pConfig->pDevName); +/* open port */ +retry: + nHandle = open((char const*)pConfig->pDevName, O_RDWR); + if (nHandle < 0) { + ALOGE("%s : failed errno = 0x%x, retval %x", __FUNCTION__, errno, nHandle); + + if ((errno == -EBUSY) || (errno == EBUSY)) { + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + phPalEse_sleep(100 * 1000); // 100ms delay + return ESESTATUS_DRIVER_BUSY; + } else { + retryCnt++; + ALOGE("Retry open eSE driver, retry cnt : %d", retryCnt); + if (retryCnt < MAX_RETRY_CNT) { + phPalEse_sleep(1000000); + goto retry; + } + } + } + ALOGE("_spi_open() Failed: retval %x", nHandle); + pConfig->pDevHandle = NULL; + return ESESTATUS_INVALID_DEVICE; + } + ALOGD_IF(ese_debug_enabled, "eSE driver opened :: fd = [%d]", nHandle); + pConfig->pDevHandle = (void*)((intptr_t)nHandle); + return ESESTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function Read +** +** Description Reads requested number of bytes from pn547 device into given +*buffer +** +** Parameters pDevHandle - valid device handle +** pBuffer - buffer for read data +** nNbBytesToRead - number of bytes requested to be read +** +** Returns numRead - number of successfully read bytes +** -1 - read operation failure +** +*******************************************************************************/ +int EseSpiTransport::Read(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToRead) { + int ret = -1; + ret = read((intptr_t)pDevHandle, (void*)pBuffer, (nNbBytesToRead)); + return ret; +} + +/******************************************************************************* +** +** Function Write +** +** Description Writes requested number of bytes from given buffer into +*pn547 device +** +** Parameters pDevHandle - valid device handle +** pBuffer - buffer for read data +** nNbBytesToWrite - number of bytes requested to be written +** +** Returns numWrote - number of successfully written bytes +** -1 - write operation failure +** +*******************************************************************************/ +int EseSpiTransport::Write(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToWrite) { + int ret = -1; + int numWrote = 0; + unsigned long int retryCount = 0; + if (NULL == pDevHandle) { + ALOGE("phPalEse_spi_write: received pDevHandle=NULL"); + return -1; + } + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + if (mConfigSofWrite == 1) { + /* Appending SOF for SPI write */ + pBuffer[0] = SEND_PACKET_SOF; + } else { + /* Do Nothing */ + } + } + ALOGE("NXP_SPI_WRITE_TIMEOUT value is... : %ld secs", mConfigSpiWriteTimeout); + if (mConfigSpiWriteTimeout > 0) { + gsMaxSpiWriteRetryCnt = mConfigSpiWriteTimeout; + ALOGE(" spi_write_timeout Wait time ... : %ld", gsMaxSpiWriteRetryCnt); + } else { + /* Do Nothing */ + } + + while (numWrote < nNbBytesToWrite) { + // usleep(5000); + if (rf_status == 0) { + ret = write((intptr_t)pDevHandle, pBuffer + numWrote, + nNbBytesToWrite - numWrote); + } else { + ret = -1; + } + if (ret > 0) { + numWrote += ret; + } else if (ret == 0) { + ALOGE("_spi_write() EOF"); + return -1; + } else { + ALOGE("_spi_write() errno : %x", errno); + ALOGD_IF(ese_debug_enabled, "rf_status value is %d", rf_status); + if ((errno == EINTR || errno == EAGAIN || rf_status == 1) && + (retryCount < gsMaxSpiWriteRetryCnt)) { + /*Configure retry count or timeout here,now its configured for 2*10 + * secs*/ + if (retryCount > gsMaxSpiWriteRetryCnt) { + ret = -1; + break; + } + + retryCount++; + /* 5ms delay to give ESE wake up delay */ + phPalEse_sleep(1000 * (GET_WAKE_UP_DELAY())); + ALOGE("_spi_write() failed. Going to retry, counter:%ld !", retryCount); + continue; + } + return -1; + } + } + return numWrote; +} + +/******************************************************************************* +** +** Function Ioctl +** +** Description Exposed ioctl by p61 spi driver +** +** Parameters pDevHandle - valid device handle +** level - reset level +** +** Returns 0 - ioctl operation success +** -1 - ioctl operation failure +** +*******************************************************************************/ +ESESTATUS EseSpiTransport::Ioctl(phPalEse_ControlCode_t eControlCode, + void* pDevHandle, long level) { + ESESTATUS ret = ESESTATUS_IOCTL_FAILED; + int retioctl = 0x00; +#if (NFC_NXP_ESE_VER == JCOP_VER_5_x) + ese_nxp_IoctlInOutData_t inpOutData; + inpOutData.inp.level = level; + NfcAdaptation& pNfcAdapt = NfcAdaptation::GetInstance(); +#endif + ALOGD_IF(ese_debug_enabled, "phPalEse_spi_ioctl(), ioctl %x , level %lx", + eControlCode, level); + if (NULL == pDevHandle) { + if (GET_CHIP_OS_VERSION() == OS_VERSION_4_0) { + return ESESTATUS_IOCTL_FAILED; + } + } + switch (eControlCode) { + case phPalEse_e_ResetDevice: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_SET_PWR, level); + } + break; + + case phPalEse_e_EnableLog: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_SET_DBG, level); + } + break; + + case phPalEse_e_EnablePollMode: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_SET_POLL, level); + } + break; + case phPalEse_e_SetSecureMode: + ret = + (ESESTATUS)ioctl((intptr_t)pDevHandle, ESE_SET_TRUSTED_ACCESS, level); + if (0x00 <= ret) { + ret = ESESTATUS_SUCCESS; + } + break; + case phPalEse_e_ChipRst: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + if (level == 5) { // SPI driver communication part + if (!mConfigColdResetIntf) { /* Call the driver IOCTL */ + retioctl = + ioctl((intptr_t)pDevHandle, ESE_PERFORM_COLD_RESET, level); + if (0x00 <= retioctl) { + ret = ESESTATUS_SUCCESS; + } + } else { +#if (NFC_NXP_ESE_VER == JCOP_VER_5_x) + // Nfc Driver communication part + ret = pNfcAdapt.resetEse(level); +#else + ret = ESESTATUS_SUCCESS; +#endif + } + } else { + ret = ESESTATUS_SUCCESS; + } + } else { + ret = (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_SET_SPM_PWR, level); + } + break; + case phPalEse_e_ResetProtection: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + retioctl = ioctl((intptr_t)pDevHandle, PERFORM_RESET_PROTECTION, level); + if (0x00 <= retioctl) { + ret = ESESTATUS_SUCCESS; + } else { + ALOGE("phPalEse_e_ResetProtection ioctl failed status :%x !", + retioctl); + } + } + break; + case phPalEse_e_EnableThroughputMeasurement: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_SET_THROUGHPUT, level); + } + break; + + case phPalEse_e_SetPowerScheme: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = + (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_SET_POWER_SCHEME, level); + } + break; + + case phPalEse_e_GetSPMStatus: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_GET_SPM_STATUS, level); + } + break; + + case phPalEse_e_GetEseAccess: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_GET_ESE_ACCESS, level); + } + break; + case phPalEse_e_SetJcopDwnldState: + if (GET_CHIP_OS_VERSION() != OS_VERSION_4_0) { + ret = ESESTATUS_SUCCESS; + } else { + ret = + (ESESTATUS)ioctl((intptr_t)pDevHandle, P61_SET_DWNLD_STATUS, level); + } + break; +#if (NFC_NXP_ESE_VER == JCOP_VER_5_x) + case phPalEse_e_SetClientUpdateState: { + pNfcAdapt.Initialize(); + ALOGD_IF(ese_debug_enabled, + "phPalEse_spi_ioctl state = phPalEse_e_SetJcopDwnldState"); + ese_nxp_IoctlInOutData_t inpOutData; + memset(&inpOutData, 0x00, sizeof(ese_nxp_IoctlInOutData_t)); + inpOutData.inp.data.nxpCmd.cmd_len = 1; + inpOutData.inp.data_source = 1; + uint8_t data = (uint8_t)level; + memcpy(inpOutData.inp.data.nxpCmd.p_cmd, &data, sizeof(data)); + ALOGD_IF(ese_debug_enabled, "Before phPalEse_e_SetClientUpdateState"); + + ret = pNfcAdapt.setEseUpdateState(&inpOutData); + ALOGD_IF(ese_debug_enabled, "After phPalEse_e_SetClientUpdateState"); + } break; +#endif + case phPalEse_e_DisablePwrCntrl: + ret = ESESTATUS_SUCCESS; + break; + default: + ret = ESESTATUS_IOCTL_FAILED; + break; + } + ALOGD_IF(ese_debug_enabled, "Exit phPalEse_spi_ioctl : ret = %d errno = %d", + ret, errno); + return (ESESTATUS)ret; +} diff --git a/snxxx/libese-spi/p73/pal/spi/EseSpiTransport.h b/snxxx/libese-spi/p73/pal/spi/EseSpiTransport.h new file mode 100644 index 0000000..2d252c2 --- /dev/null +++ b/snxxx/libese-spi/p73/pal/spi/EseSpiTransport.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * Copyright 2020 NXP + * + * 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. + * + ******************************************************************************/ + +#pragma once +#include "EseTransport.h" + +class EseSpiTransport : public EseTransport { + public: + void Close(void* pDevHandle); + ESESTATUS OpenAndConfigure(pphPalEse_Config_t pConfig); + int Read(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToRead); + int Write(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToWrite); + ESESTATUS Ioctl(phPalEse_ControlCode_t eControlCode, void* pDevHandle, + long level); + + private: + unsigned long int mConfigSofWrite, mConfigSpiWriteTimeout, + mConfigColdResetIntf; +};
\ No newline at end of file diff --git a/snxxx/libese-spi/p73/spm/phNxpEse_Spm.cpp b/snxxx/libese-spi/p73/spm/phNxpEse_Spm.cpp new file mode 100755 index 0000000..836c24b --- /dev/null +++ b/snxxx/libese-spi/p73/spm/phNxpEse_Spm.cpp @@ -0,0 +1,476 @@ +/****************************************************************************** + * + * Copyright 2018-2019 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "NxpEseHal" +#include <log/log.h> + +#include <errno.h> +#include <fcntl.h> +#include <phNxpEsePal.h> +#include <phNxpEse_Internal.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "phNxpEseFeatures.h" +#include "phNxpEse_Spm.h" + +/*********************** Global Variables *************************************/ + +static void* pEseDeviceHandle = NULL; +#define MAX_ESE_ACCESS_TIME_OUT_MS 2000 /*2 seconds*/ + +/** + * \addtogroup SPI_Power_Management + * + * @{ */ +/****************************************************************************** +\section Introduction Introduction + + * This module provide power request to Pn54x nfc-i2c driver, it cheks if + * wired access is already granted. It should have access to pn54x drive. + * Below are the apis provided by the SPM module. + ******************************************************************************/ +/****************************************************************************** + * Function phNxpEse_SPM_Init + * + * Description This function opens the nfc i2c driver to manage power + * and synchronization for ese secure element. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_Init(void* pDevHandle) { + ESESTATUS status = ESESTATUS_SUCCESS; + pEseDeviceHandle = pDevHandle; + if (NULL == pEseDeviceHandle) { + ALOGE("%s : failed, device handle is null", __FUNCTION__); + status = ESESTATUS_FAILED; + } + ALOGD_IF(ese_debug_enabled, "%s : exit status = %d", __FUNCTION__, status); + + return status; +} + +/****************************************************************************** + * Function phNxpEse_SPM_DeInit + * + * Description This function closes the nfc i2c driver node. + * + * Returns Always returns ESESTATUS_SUCCESS + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_DeInit(void) { + pEseDeviceHandle = NULL; + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEse_SPM_ConfigPwr + * + * Description This function request to the nfc i2c driver + * to enable/disable power to ese. This api should be called + *before + * sending any apdu to ese/once apdu exchange is done. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_ConfigPwr(spm_power_t arg) { + int32_t ret = -1; + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + spm_state_t current_spm_state = SPM_STATE_INVALID; + if (GET_CHIP_OS_VERSION() > OS_VERSION_4_0) { + /*None of the IOCTLs valid except SPM_RECOVERY_RESET*/ + if (arg != SPM_RECOVERY_RESET) { + return ESESTATUS_SUCCESS; + } + } + ret = phPalEse_ioctl(phPalEse_e_ChipRst, pEseDeviceHandle, arg); + switch (arg) { + case SPM_POWER_DISABLE: { + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + wSpmStatus = ESESTATUS_FAILED; + } else { + if (phNxpEse_SPM_RelAccess() != ESESTATUS_SUCCESS) { + ALOGE(" %s phNxpEse_SPM_RelAccess : failed \n", __FUNCTION__); + } + } + } break; + case SPM_POWER_ENABLE: { + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + if (errno == -EBUSY) { + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_GetPwrState Failed", __FUNCTION__); + if (phNxpEse_SPM_RelAccess() != ESESTATUS_SUCCESS) { + ALOGE(" %s phNxpEse_SPM_RelAccess : failed \n", __FUNCTION__); + } + return wSpmStatus; + } else { + if (current_spm_state & SPM_STATE_DWNLD) { + wSpmStatus = ESESTATUS_DWNLD_BUSY; + } else { + wSpmStatus = ESESTATUS_BUSY; + } + } + } else { + wSpmStatus = ESESTATUS_FAILED; + } + if (wSpmStatus != ESESTATUS_SUCCESS) { + if (phNxpEse_SPM_RelAccess() != ESESTATUS_SUCCESS) { + ALOGE(" %s phNxpEse_SPM_RelAccess : failed \n", __FUNCTION__); + } + } + } + } break; + case SPM_POWER_RESET: { + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + if (errno == -EBUSY) { + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_GetPwrState Failed", __FUNCTION__); + return wSpmStatus; + } else { + if (current_spm_state & SPM_STATE_DWNLD) { + wSpmStatus = ESESTATUS_DWNLD_BUSY; + } else { + wSpmStatus = ESESTATUS_BUSY; + } + } + } else { + wSpmStatus = ESESTATUS_FAILED; + } + } + } break; + case SPM_POWER_PRIO_ENABLE: { + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + if (errno == -EBUSY) { + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_GetPwrState Failed", __FUNCTION__); + return wSpmStatus; + } else { + if (current_spm_state & SPM_STATE_DWNLD) { + wSpmStatus = ESESTATUS_DWNLD_BUSY; + } else { + wSpmStatus = ESESTATUS_BUSY; + } + } + + } else { + wSpmStatus = ESESTATUS_FAILED; + } + } + } break; + case SPM_POWER_PRIO_DISABLE: { + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + wSpmStatus = ESESTATUS_FAILED; + } + } break; + case SPM_RECOVERY_RESET: { + } break; + } + return wSpmStatus; +} + +/****************************************************************************** + * Function phNxpEse_SPM_EnablePwr + * + * Description This function request to the nfc i2c driver + * to enable power to ese. This api should be called before + * sending any apdu to ese. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_EnablePwr(void) { + int32_t ret = -1; + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + spm_state_t current_spm_state = SPM_STATE_INVALID; + ALOGD_IF(ese_debug_enabled, "%s : phNxpEse_SPM_EnablePwr is set to = 0x%d", + __FUNCTION__, 0); + ret = phPalEse_ioctl(phPalEse_e_ChipRst, pEseDeviceHandle, 0); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + if (errno == -EBUSY) { + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_GetPwrState Failed", __FUNCTION__); + return wSpmStatus; + } else { + if (current_spm_state == SPM_STATE_DWNLD) { + wSpmStatus = ESESTATUS_DWNLD_BUSY; + } else { + wSpmStatus = ESESTATUS_BUSY; + } + } + + } else { + wSpmStatus = ESESTATUS_FAILED; + } + } + + return wSpmStatus; +} + +/****************************************************************************** + * Function phNxpEse_SPM_DisablePwr + * + * Description This function request to the nfc i2c driver + * to disable power to ese. This api should be called + * once apdu exchange is done. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_DisablePwr(void) { + int32_t ret = -1; + ESESTATUS status = ESESTATUS_SUCCESS; + ALOGD_IF(ese_debug_enabled, "%s : phNxpEse_SPM_DisablePwr is set to = 0x%d", + __FUNCTION__, 1); + ret = phPalEse_ioctl(phPalEse_e_ChipRst, pEseDeviceHandle, 1); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + status = ESESTATUS_FAILED; + } + + return status; +} +/****************************************************************************** + * Function phNxpEse_SPM_SetPwrScheme + * + * Description This function request to the nfc i2c driver + * to set the chip type and power scheme. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_SetPwrScheme(long arg) { + int32_t ret = -1; + ESESTATUS status = ESESTATUS_SUCCESS; + + ALOGD_IF(ese_debug_enabled, "%s : Power scheme is set to = 0x%ld", + __FUNCTION__, arg); + ret = phPalEse_ioctl(phPalEse_e_SetPowerScheme, pEseDeviceHandle, arg); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + status = ESESTATUS_FAILED; + } + + return status; +} + +/****************************************************************************** + * Function phNxpEseP61_SPM_EnableDisablePwrCntrl + * + * Description This function request to the nfc i2c driver + * to set the chip type and power scheme. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_DisablePwrControl(unsigned long arg) { + int32_t ret = -1; + ESESTATUS status = ESESTATUS_SUCCESS; + + ALOGD_IF(ese_debug_enabled, "%s : Inhibit power control is set to = 0x%ld", + __FUNCTION__, arg); + ret = phPalEse_ioctl(phPalEse_e_DisablePwrCntrl, pEseDeviceHandle, arg); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + status = ESESTATUS_FAILED; + } + + return status; +} + +/****************************************************************************** + * Function phNxpEse_SPM_GetState + * + * Description This function gets the current power state of ESE + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_GetState(spm_state_t* current_state) { + int32_t ret = -1; + ESESTATUS status = ESESTATUS_SUCCESS; + spm_state_t ese_current_state = SPM_STATE_INVALID; + + if (current_state == NULL) { + ALOGE("%s : failed Invalid argument", __FUNCTION__); + return ESESTATUS_FAILED; + } + ret = phPalEse_ioctl(phPalEse_e_GetSPMStatus, pEseDeviceHandle, + (unsigned long)&ese_current_state); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + status = ESESTATUS_FAILED; + } else { + *current_state = ese_current_state; /* Current ESE state */ + } + + return status; +} + +/****************************************************************************** + * Function phNxpEse_SPM_SetJcopDwnldState + * + * Description This function is used to set the JCOP OS download state + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_SetJcopDwnldState(long arg) { + int ret = -1; + ESESTATUS status = ESESTATUS_SUCCESS; + + ALOGD_IF(ese_debug_enabled, "%s :phNxpEse_SPM_SetJcopDwnldState = 0x%ld", + __FUNCTION__, arg); + ret = phPalEse_ioctl(phPalEse_e_SetJcopDwnldState, pEseDeviceHandle, arg); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + status = ESESTATUS_FAILED; + } + + return status; +} + +/****************************************************************************** + * Function phNxpEse_SPM_SetEseClientUpdateState + * + * Description This function is used to set the ese Update state + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_SetEseClientUpdateState(long arg) { + int ret = -1; + ESESTATUS status = ESESTATUS_SUCCESS; + + ALOGD_IF(ese_debug_enabled, + "%s :phNxpEse_SPM_SetEseClientUpdateState = 0x%ld", __FUNCTION__, + arg); + ret = phPalEse_ioctl(phPalEse_e_SetClientUpdateState, pEseDeviceHandle, arg); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + status = ESESTATUS_FAILED; + } + + return status; +} + +/****************************************************************************** + * Function phNxpEse_SPM_ResetPwr + * + * Description This function request to the nfc i2c driver + * to reset ese. + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_SPM_ResetPwr(void) { + int32_t ret = -1; + ESESTATUS wSpmStatus = ESESTATUS_SUCCESS; + spm_state_t current_spm_state = SPM_STATE_INVALID; + + /* reset the ese */ + ret = phPalEse_ioctl(phPalEse_e_ChipRst, pEseDeviceHandle, 2); + if (ret < 0) { + ALOGE("%s : failed errno = 0x%x", __FUNCTION__, errno); + if (errno == -EBUSY || errno == EBUSY) { + wSpmStatus = phNxpEse_SPM_GetState(¤t_spm_state); + if (wSpmStatus != ESESTATUS_SUCCESS) { + ALOGE(" %s : phNxpEse_SPM_GetPwrState Failed", __FUNCTION__); + return wSpmStatus; + } else { + if (current_spm_state == SPM_STATE_DWNLD) { + wSpmStatus = ESESTATUS_DWNLD_BUSY; + } else { + wSpmStatus = ESESTATUS_BUSY; + } + } + + } else { + wSpmStatus = ESESTATUS_FAILED; + } + } + + return wSpmStatus; +} + +/******************************************************************************* +** +** Function phTmlEse_get_ese_access +** +** Description +** +** Parameters timeout - timeout to wait for ese access +** +** Returns success or failure +** +*******************************************************************************/ +ESESTATUS phNxpEse_SPM_GetAccess(long timeout) { + ESESTATUS status = ESESTATUS_SUCCESS; + ALOGD_IF(ese_debug_enabled, "phTmlEse_get_ese_access(), timeout %ld", + timeout); +#if ((NFC_NXP_ESE_VER == JCOP_VER_3_1) || (NFC_NXP_ESE_VER == JCOP_VER_3_2)) + int ret = -1; + + ret = phPalEse_ioctl(phPalEse_e_GetEseAccess, pEseDeviceHandle, timeout); + if (ret < 0) { + if (ret == -EBUSY) + status = ESESTATUS_BUSY; + else + status = ESESTATUS_FAILED; + } + ALOGD_IF(ese_debug_enabled, "phTmlEse_get_ese_access(), exit %d", status); +#endif + return status; +} +/******************************************************************************* +** +** Function phNxpEse_SPM_RelAccess +** +** Description +** +** Parameters timeout - Releases the ese access +** +** Returns success or failure +** +*******************************************************************************/ +ESESTATUS phNxpEse_SPM_RelAccess(void) { + ESESTATUS status = ESESTATUS_SUCCESS; +#if ((NFC_NXP_ESE_VER == JCOP_VER_3_1) || (NFC_NXP_ESE_VER == JCOP_VER_3_2)) + int ret = -1; + ALOGD_IF(ese_debug_enabled, "phNxpEse_SPM_RelAccess(): enter"); + + ret = phPalEse_ioctl(phPalEse_e_ChipRst, pEseDeviceHandle, 5); + if (ret < 0) { + status = ESESTATUS_FAILED; + } + ALOGD_IF(ese_debug_enabled, "phNxpEse_SPM_RelAccess(): exit %d", status); +#endif + return status; +} +/** @} */ diff --git a/snxxx/libese-spi/p73/spm/phNxpEse_Spm.h b/snxxx/libese-spi/p73/spm/phNxpEse_Spm.h new file mode 100644 index 0000000..a65d991 --- /dev/null +++ b/snxxx/libese-spi/p73/spm/phNxpEse_Spm.h @@ -0,0 +1,195 @@ +/****************************************************************************** + * + * Copyright 2018-2019 NXP + * + * 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. + * + ******************************************************************************/ + +/** + * \addtogroup SPI_Power_Management + * + * @{ */ + +#ifndef _PHNXPESE_SPM_H +#define _PHNXPESE_SPM_H + +#include <phEseStatus.h> +#include <phNxpEseFeatures.h> +/*! SPI Power Manager (SPM) possible error codes */ +typedef enum spm_power { + SPM_POWER_DISABLE = 0, + SPM_POWER_ENABLE, /*!< SPM power disable */ + SPM_POWER_RESET, /*!< SPM Reset pwer */ + SPM_POWER_PRIO_ENABLE, /*!< SPM prio mode enable */ + SPM_POWER_PRIO_DISABLE, /*!< SPM prio mode disable */ + SPM_RECOVERY_RESET +} spm_power_t; + +/*! SPI Power Manager (SPM) possible states */ +typedef enum spm_state { + SPM_STATE_INVALID = 0x0000, /*!< Nfc i2c driver misbehaving */ + SPM_STATE_IDLE = 0x0100, /*!< ESE is free to use */ + SPM_STATE_WIRED = 0x0200, /*!< p61 is being accessed by DWP (NFCC)*/ + SPM_STATE_SPI = 0x0400, /*!< ESE is being accessed by SPI */ + SPM_STATE_DWNLD = 0x0800, /*!< NFCC fw download is in progress */ + SPM_STATE_SPI_PRIO = 0x1000, /*!< Start of p61 access by SPI on priority*/ + SPM_STATE_SPI_PRIO_END = 0x2000, /*!< End of p61 access by SPI on priority*/ + SPM_STATE_SPI_FAILED = 0x0010, /*SPI open/close failed*/ + SPM_STATE_JCOP_DWNLD = 0x8000 /*!< P73 state JCOP Download*/ +} spm_state_t; + +/** + * \ingroup SPI_Power_Management + * \brief This function opens the nfc i2c driver to manage power + * and synchronization for ese secure element. + * + * \param[in] pDevHandle - Device handle to open. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_Init(void* pDevHandle); + +/** + * \ingroup SPI_Power_Management + * \brief TThis function closes the nfc i2c driver node. + * + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_DeInit(void); + +/** + * \ingroup SPI_Power_Management + * \brief This function request to the nfc i2c driver + * to enable/disable power to ese. This api should be called + *before sending any apdu to ese/once apdu exchange is done. + * + * \param[in] arg -input can be of type spm_power_t. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_ConfigPwr(spm_power_t arg); + +/** + * \ingroup SPI_Power_Management + * \brief This function request to the nfc i2c driver + * to enable power to ese. This api should be called before + * sending any apdu to ese. + * + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_EnablePwr(void); + +/** + * \ingroup SPI_Power_Management + * \brief This function request to the nfc i2c driver + * to disable power to ese. This api should be called + * once apdu exchange is done. + * + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_DisablePwr(void); + +/** + * \ingroup SPI_Power_Management + * \brief This function gets the current power state of ESE + * \param[in] current_state -input is of type spm_state_t. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_GetState(spm_state_t* current_state); + +/** + * \ingroup SPI_Power_Management + * \brief This function request to the nfc i2c driver + * to reset ese. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_ResetPwr(void); + +/** + * \ingroup SPI_Power_Management + * \brief This function request to get access to eSE + * + * \param[in] timeout - timeout to wait for ese access. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_GetAccess(long timeout); + +/** + * \ingroup SPI_Power_Management + * \brief This function set the SPM power state + * + * \param[in] arg - state value. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_SetState(long arg); + +/** + * \ingroup SPI_Power_Management + * \brief phNxpEse_SPM_RelAccess + * + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_RelAccess(void); + +/** + * \ingroup SPI_Power_Management + * \brief This function request to the nfc i2c driver + * to set the chip type and power scheme. + * + * \param[in] arg - set power scheme from config. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_SetPwrScheme(long arg); + +/** + * \ingroup SPI_Power_Management + * \brief This function request to the nfc i2c driver + * to set the chip type and power scheme. + * + * \param[in] arg - arg. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_DisablePwrControl(unsigned long arg); +/** + * \ingroup SPI_Power_Management + * \brief This function is used to set the ese Update state. + * + * \param[in] arg - eSE update status started/completed. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_SetEseClientUpdateState(long arg); + +/** + * \ingroup SPI_Power_Management + * \brief This function is used to set the ese Update state. + * + * \param[in] arg - JCOP update status started/completed.. + * + * \retval -On Success ESESTATUS_SUCCESS else proper error code + */ +ESESTATUS phNxpEse_SPM_SetJcopDwnldState(long arg); + +#endif /* _PHNXPESE_SPM_H */ +/** @} */ diff --git a/snxxx/libese-spi/p73/utils/config.cpp b/snxxx/libese-spi/p73/utils/config.cpp new file mode 100644 index 0000000..a470af8 --- /dev/null +++ b/snxxx/libese-spi/p73/utils/config.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2017 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. + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2019 NXP Semiconductors + * + * 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 "config.h" + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/parseint.h> +#include <android-base/strings.h> + +using namespace ::std; +using namespace ::android::base; + +namespace { + +bool parseBytesString(std::string in, std::vector<uint8_t>& out) { + vector<string> values = Split(in, ":"); + if (values.size() == 0) return false; + for (const string& value : values) { + if (value.length() != 2) return false; + uint8_t tmp = 0; + string hexified = "0x"; + hexified.append(value); + if (!ParseUint(hexified.c_str(), &tmp)) return false; + out.push_back(tmp); + } + return true; +} + +} // namespace + +ConfigValue::ConfigValue() { + value_unsigned_ = 0; + type_ = UNSIGNED; +} + +ConfigValue::Type ConfigValue::getType() const { return type_; } + +std::string ConfigValue::getString() const { + CHECK(type_ == STRING); + return value_string_; +}; + +unsigned ConfigValue::getUnsigned() const { + CHECK(type_ == UNSIGNED); + return value_unsigned_; +}; + +std::vector<uint8_t> ConfigValue::getBytes() const { + CHECK(type_ == BYTES); + return value_bytes_; +}; + +bool ConfigValue::parseFromString(std::string in) { + if (in.length() > 1 && in[0] == '"' && in[in.length() - 1] == '"') { + CHECK(in.length() > 2); // Don't allow empty strings + type_ = STRING; + value_string_ = in.substr(1, in.length() - 2); + return true; + } + + if (in.length() > 1 && in[0] == '{' && in[in.length() - 1] == '}') { + CHECK(in.length() >= 4); // Needs at least one byte + type_ = BYTES; + return parseBytesString(in.substr(1, in.length() - 2), value_bytes_); + } + + unsigned tmp = 0; + if (ParseUint(in.c_str(), &tmp)) { + type_ = UNSIGNED; + value_unsigned_ = tmp; + return true; + } + + return false; +} + +void ConfigFile::parseFromFile(const std::string& file_name) { + string config; + bool config_read = ReadFileToString(file_name, &config); + CHECK(config_read); + LOG(INFO) << "ConfigFile - Parsing file '" << file_name << "'"; + parseFromString(config); +} + +void ConfigFile::parseFromString(const std::string& config) { + stringstream ss(config); + string line; + while (getline(ss, line)) { + line = Trim(line); + if (line.empty()) continue; + if (line.at(0) == '#') continue; + if (line.at(0) == 0) continue; + + auto search = line.find('='); + CHECK(search != string::npos); + + string key(Trim(line.substr(0, search))); + string value_string(Trim(line.substr(search + 1, string::npos))); + + ConfigValue value; + bool value_parsed = value.parseFromString(value_string); + CHECK(value_parsed); + CHECK(!hasKey(key)); + values_.emplace(key, value); + + LOG(INFO) << "ConfigFile - [" << key << "] = " << value_string; + } +} + +bool ConfigFile::hasKey(const std::string& key) { + return values_.count(key) != 0; +} + +ConfigValue& ConfigFile::getValue(const std::string& key) { + CHECK(values_.find(key) != values_.end()); + auto search = values_.find(key); + return search->second; +} + +std::string ConfigFile::getString(const std::string& key) { + return getValue(key).getString(); +} + +unsigned ConfigFile::getUnsigned(const std::string& key) { + return getValue(key).getUnsigned(); +} + +std::vector<uint8_t> ConfigFile::getBytes(const std::string& key) { + return getValue(key).getBytes(); +} + +void ConfigFile::clear() { values_.clear(); } diff --git a/snxxx/libese-spi/p73/utils/config.h b/snxxx/libese-spi/p73/utils/config.h new file mode 100644 index 0000000..115c7fa --- /dev/null +++ b/snxxx/libese-spi/p73/utils/config.h @@ -0,0 +1,76 @@ +/* + * Copyright 2017 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. + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2019 NXP Semiconductors + * + * 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. + * + ******************************************************************************/ +#pragma once + +#include <map> +#include <string> +#include <vector> + +class ConfigValue { + public: + enum Type { UNSIGNED, STRING, BYTES }; + + ConfigValue(); + Type getType() const; + std::string getString() const; + unsigned getUnsigned() const; + std::vector<uint8_t> getBytes() const; + + bool parseFromString(std::string in); + + private: + Type type_; + std::string value_string_; + unsigned value_unsigned_; + std::vector<uint8_t> value_bytes_; +}; + +class ConfigFile { + public: + void parseFromFile(const std::string& file_name); + void parseFromString(const std::string& config); + + bool hasKey(const std::string& key); + std::string getString(const std::string& key); + unsigned getUnsigned(const std::string& key); + std::vector<uint8_t> getBytes(const std::string& key); + + void clear(); + + private: + ConfigValue& getValue(const std::string& key); + + std::map<std::string, ConfigValue> values_; +}; diff --git a/snxxx/libese-spi/p73/utils/ese_config.cpp b/snxxx/libese-spi/p73/utils/ese_config.cpp new file mode 100644 index 0000000..4a6b2cc --- /dev/null +++ b/snxxx/libese-spi/p73/utils/ese_config.cpp @@ -0,0 +1,87 @@ +/****************************************************************************** + * + * Copyright 2018 NXP + * + * 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 "ese_config.h" + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/parseint.h> +#include <android-base/strings.h> + +#include <config.h> + +using namespace ::std; +using namespace ::android::base; + +namespace { + +std::string findConfigPath() { + const vector<string> search_path = {"/odm/etc/", "/vendor/etc/", "/etc/"}; + const string file_name = "libese-nxp.conf"; + + for (string path : search_path) { + path.append(file_name); + struct stat file_stat; + if (stat(path.c_str(), &file_stat) != 0) continue; + if (S_ISREG(file_stat.st_mode)) return path; + } + return ""; +} + +} // namespace + +EseConfig::EseConfig() { + string config_path = findConfigPath(); + CHECK(config_path != ""); + config_.parseFromFile(config_path); +} + +EseConfig& EseConfig::getInstance() { + static EseConfig theInstance; + return theInstance; +} + +bool EseConfig::hasKey(const std::string& key) { + return getInstance().config_.hasKey(key); +} + +std::string EseConfig::getString(const std::string& key) { + return getInstance().config_.getString(key); +} + +std::string EseConfig::getString(const std::string& key, + std::string default_value) { + if (hasKey(key)) return getString(key); + return default_value; +} + +unsigned EseConfig::getUnsigned(const std::string& key) { + return getInstance().config_.getUnsigned(key); +} + +unsigned EseConfig::getUnsigned(const std::string& key, + unsigned default_value) { + if (hasKey(key)) return getUnsigned(key); + return default_value; +} + +std::vector<uint8_t> EseConfig::getBytes(const std::string& key) { + return getInstance().config_.getBytes(key); +} + +void EseConfig::clear() { getInstance().config_.clear(); } diff --git a/snxxx/libese-spi/p73/utils/ese_config.h b/snxxx/libese-spi/p73/utils/ese_config.h new file mode 100755 index 0000000..bba26c8 --- /dev/null +++ b/snxxx/libese-spi/p73/utils/ese_config.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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. + * + ******************************************************************************/ + +#pragma once + +#include <string> +#include <vector> + +#include <config.h> + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define NAME_SE_DEBUG_ENABLED "SE_DEBUG_ENABLED" +#define NAME_NXP_JCOPDL_AT_BOOT_ENABLE "NXP_JCOPDL_AT_BOOT_ENABLE" +#define NAME_NXP_WTX_COUNT_VALUE "NXP_WTX_COUNT_VALUE" +#define NAME_NXP_MAX_RSP_TIMEOUT "NXP_MAX_RSP_TIMEOUT" +#define NAME_NXP_POWER_SCHEME "NXP_POWER_SCHEME" +#define NAME_NXP_SOF_WRITE "NXP_SOF_WRITE" +#define NAME_NXP_TP_MEASUREMENT "NXP_TP_MEASUREMENT" +#define NAME_NXP_SPI_INTF_RST_ENABLE "NXP_SPI_INTF_RST_ENABLE" +#define NAME_NXP_MAX_RNACK_RETRY "NXP_MAX_RNACK_RETRY" +#define NAME_NXP_SPI_WRITE_TIMEOUT "NXP_SPI_WRITE_TIMEOUT" +#define NAME_NXP_ESE_DEV_NODE "NXP_ESE_DEV_NODE" +#define NAME_NXP_VISO_DPD_ENABLED "NXP_VISO_DPD_ENABLED" +#define NAME_NXP_NAD_POLL_RETRY_TIME "NXP_NAD_POLL_RETRY_TIME" +#define NAME_RNACK_RETRY_DELAY "RNACK_RETRY_DELAY" +#define NAME_NXP_P61_JCOP_DEFAULT_INTERFACE "NXP_P61_JCOP_DEFAULT_INTERFACE" +#define NAME_NXP_ESE_IFSD_VALUE "NXP_ESE_IFSD_VALUE" +#define NAME_NXP_EUICC_IFSD_VALUE "NXP_EUICC_IFSD_VALUE" +#define NAME_NXP_P61_COLD_RESET_INTERFACE "NXP_P61_COLD_RESET_INTERFACE" +#define NAME_NXP_OS_VERSION "NXP_OS_VERSION" +#define NAME_NXP_WTX_NTF_COUNT "NXP_WTX_NTF_COUNT" +#define NAME_NXP_OSU_MAX_WTX_COUNT "NXP_OSU_MAX_WTX_COUNT" +#define NAME_NXP_TRANSPORT "NXP_TRANSPORT" +#endif + +class EseConfig { + public: + static bool hasKey(const std::string& key); + static std::string getString(const std::string& key); + static std::string getString(const std::string& key, + std::string default_value); + static unsigned getUnsigned(const std::string& key); + static unsigned getUnsigned(const std::string& key, unsigned default_value); + static std::vector<uint8_t> getBytes(const std::string& key); + static void clear(); + + private: + static EseConfig& getInstance(); + EseConfig(); + + ConfigFile config_; +}; diff --git a/snxxx/libese-spi/p73/utils/ringbuffer.cpp b/snxxx/libese-spi/p73/utils/ringbuffer.cpp new file mode 100644 index 0000000..d7798fd --- /dev/null +++ b/snxxx/libese-spi/p73/utils/ringbuffer.cpp @@ -0,0 +1,116 @@ +/****************************************************************************** + * + * Copyright (C) 2017 Google Inc. + * + * 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 <assert.h> +#include <stdlib.h> + +#include "ringbuffer.h" + +struct ringbuffer_t { + size_t total; + size_t available; + uint8_t* base; + uint8_t* head; + uint8_t* tail; +}; + +ringbuffer_t* ringbuffer_init(const size_t size) { + ringbuffer_t* p = static_cast<ringbuffer_t*>(calloc(1, sizeof(ringbuffer_t))); + + if (p == NULL) return p; + + p->base = static_cast<uint8_t*>(calloc(size, sizeof(uint8_t))); + p->head = p->tail = p->base; + p->total = p->available = size; + + return p; +} + +void ringbuffer_free(ringbuffer_t* rb) { + if (rb != NULL) free(rb->base); + free(rb); +} + +size_t ringbuffer_available(const ringbuffer_t* rb) { + assert(rb); + return rb->available; +} + +size_t ringbuffer_size(const ringbuffer_t* rb) { + assert(rb); + return rb->total - rb->available; +} + +size_t ringbuffer_insert(ringbuffer_t* rb, const uint8_t* p, size_t length) { + assert(rb); + assert(p); + + if (length > ringbuffer_available(rb)) length = ringbuffer_available(rb); + + for (size_t i = 0; i != length; ++i) { + *rb->tail++ = *p++; + if (rb->tail >= (rb->base + rb->total)) rb->tail = rb->base; + } + + rb->available -= length; + return length; +} + +size_t ringbuffer_delete(ringbuffer_t* rb, size_t length) { + assert(rb); + + if (length > ringbuffer_size(rb)) length = ringbuffer_size(rb); + + rb->head += length; + if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total; + + rb->available += length; + return length; +} + +size_t ringbuffer_peek(const ringbuffer_t* rb, off_t offset, uint8_t* p, + size_t length) { + assert(rb); + assert(p); + assert(offset >= 0); + assert((size_t)offset <= ringbuffer_size(rb)); + + uint8_t* b = ((rb->head - rb->base + offset) % rb->total) + rb->base; + const size_t bytes_to_copy = (offset + length > ringbuffer_size(rb)) + ? ringbuffer_size(rb) - offset + : length; + + for (size_t copied = 0; copied < bytes_to_copy; ++copied) { + *p++ = *b++; + if (b >= (rb->base + rb->total)) b = rb->base; + } + + return bytes_to_copy; +} + +size_t ringbuffer_pop(ringbuffer_t* rb, uint8_t* p, size_t length) { + assert(rb); + assert(p); + + const size_t copied = ringbuffer_peek(rb, 0, p, length); + rb->head += copied; + if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total; + + rb->available += copied; + return copied; +} diff --git a/snxxx/libese-spi/p73/utils/ringbuffer.h b/snxxx/libese-spi/p73/utils/ringbuffer.h new file mode 100644 index 0000000..d2c310a --- /dev/null +++ b/snxxx/libese-spi/p73/utils/ringbuffer.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright (C) 2017 Google Inc. + * + * 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. + * + ******************************************************************************/ + +#pragma once + +#include <stdint.h> + +typedef struct ringbuffer_t ringbuffer_t; + +// NOTE: +// None of the functions below are thread safe when it comes to accessing the +// *rb pointer. It is *NOT* possible to insert and pop/delete at the same time. +// Callers must protect the *rb pointer separately. + +// Create a ringbuffer with the specified size +// Returns NULL if memory allocation failed. Resulting pointer must be freed +// using |ringbuffer_free|. +ringbuffer_t* ringbuffer_init(const size_t size); + +// Frees the ringbuffer structure and buffer +// Save to call with NULL. +void ringbuffer_free(ringbuffer_t* rb); + +// Returns remaining buffer size +size_t ringbuffer_available(const ringbuffer_t* rb); + +// Returns size of data in buffer +size_t ringbuffer_size(const ringbuffer_t* rb); + +// Attempts to insert up to |length| bytes of data at |p| into the buffer +// Return actual number of bytes added. Can be less than |length| if buffer +// is full. +size_t ringbuffer_insert(ringbuffer_t* rb, const uint8_t* p, size_t length); + +// Peek |length| number of bytes from the ringbuffer, starting at |offset|, +// into the buffer |p|. Return the actual number of bytes peeked. Can be less +// than |length| if there is less than |length| data available. |offset| must +// be non-negative. +size_t ringbuffer_peek(const ringbuffer_t* rb, off_t offset, uint8_t* p, + size_t length); + +// Does the same as |ringbuffer_peek|, but also advances the ring buffer head +size_t ringbuffer_pop(ringbuffer_t* rb, uint8_t* p, size_t length); + +// Deletes |length| bytes from the ringbuffer starting from the head +// Return actual number of bytes deleted. +size_t ringbuffer_delete(ringbuffer_t* rb, size_t length); diff --git a/snxxx/libese-spi/src/adaptation/CondVar.cpp b/snxxx/libese-spi/src/adaptation/CondVar.cpp new file mode 100755 index 0000000..ad69973 --- /dev/null +++ b/snxxx/libese-spi/src/adaptation/CondVar.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 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. + */ + +/* + * Encapsulate a condition variable for thread synchronization. + */ + +#include "CondVar.h" + +#include <errno.h> +#include <string.h> + +#include <android-base/stringprintf.h> +#include <base/logging.h> + +using android::base::StringPrintf; + +/******************************************************************************* +** +** Function: CondVar +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +CondVar::CondVar() { + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + memset(&mCondition, 0, sizeof(mCondition)); + int const res = pthread_cond_init(&mCondition, &attr); + if (res) { + LOG(ERROR) << StringPrintf("CondVar::CondVar: fail init; error=0x%X", res); + } +} + +/******************************************************************************* +** +** Function: ~CondVar +** +** Description: Cleanup all resources. +** +** Returns: None. +** +*******************************************************************************/ +CondVar::~CondVar() { + int const res = pthread_cond_destroy(&mCondition); + if (res) { + LOG(ERROR) << StringPrintf("CondVar::~CondVar: fail destroy; error=0x%X", + res); + } +} + +/******************************************************************************* +** +** Function: wait +** +** Description: Block the caller and wait for a condition. +** +** Returns: None. +** +*******************************************************************************/ +void CondVar::wait(Mutex& mutex) { + int const res = pthread_cond_wait(&mCondition, mutex.nativeHandle()); + if (res) { + LOG(ERROR) << StringPrintf("CondVar::wait: fail wait; error=0x%X", res); + } +} + +/******************************************************************************* +** +** Function: wait +** +** Description: Block the caller and wait for a condition. +** millisec: Timeout in milliseconds. +** +** Returns: True if wait is successful; false if timeout occurs. +** +*******************************************************************************/ +bool CondVar::wait(Mutex& mutex, long millisec) { + bool retVal = false; + struct timespec absoluteTime; + + if (clock_gettime(CLOCK_MONOTONIC, &absoluteTime) == -1) { + LOG(ERROR) << StringPrintf("CondVar::wait: fail get time; errno=0x%X", + errno); + } else { + absoluteTime.tv_sec += millisec / 1000; + long ns = absoluteTime.tv_nsec + ((millisec % 1000) * 1000000); + if (ns > 1000000000) { + absoluteTime.tv_sec++; + absoluteTime.tv_nsec = ns - 1000000000; + } else + absoluteTime.tv_nsec = ns; + } + + int waitResult = + pthread_cond_timedwait(&mCondition, mutex.nativeHandle(), &absoluteTime); + if ((waitResult != 0) && (waitResult != ETIMEDOUT)) + LOG(ERROR) << StringPrintf("CondVar::wait: fail timed wait; error=0x%X", + waitResult); + retVal = (waitResult == 0); // waited successfully + return retVal; +} + +/******************************************************************************* +** +** Function: notifyOne +** +** Description: Unblock the waiting thread. +** +** Returns: None. +** +*******************************************************************************/ +void CondVar::notifyOne() { + int const res = pthread_cond_signal(&mCondition); + if (res) { + LOG(ERROR) << StringPrintf("CondVar::notifyOne: fail signal; error=0x%X", + res); + } +} diff --git a/snxxx/libese-spi/src/adaptation/Mutex.cpp b/snxxx/libese-spi/src/adaptation/Mutex.cpp new file mode 100755 index 0000000..ef4d5e5 --- /dev/null +++ b/snxxx/libese-spi/src/adaptation/Mutex.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2012 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. + */ + +/* + * Encapsulate a mutex for thread synchronization. + */ + +#include "Mutex.h" + +#include <errno.h> +#include <string.h> + +#include <android-base/stringprintf.h> +#include <base/logging.h> + +using android::base::StringPrintf; + +/******************************************************************************* +** +** Function: Mutex +** +** Description: Initialize member variables. +** +** Returns: None. +** +*******************************************************************************/ +Mutex::Mutex() { + memset(&mMutex, 0, sizeof(mMutex)); + int res = pthread_mutex_init(&mMutex, NULL); + if (res != 0) { + LOG(ERROR) << StringPrintf("Mutex::Mutex: fail init; error=0x%X", res); + } +} + +/******************************************************************************* +** +** Function: ~Mutex +** +** Description: Cleanup all resources. +** +** Returns: None. +** +*******************************************************************************/ +Mutex::~Mutex() { + int res = pthread_mutex_destroy(&mMutex); + if (res != 0) { + LOG(ERROR) << StringPrintf("Mutex::~Mutex: fail destroy; error=0x%X", res); + } +} + +/******************************************************************************* +** +** Function: lock +** +** Description: Block the thread and try lock the mutex. +** +** Returns: None. +** +*******************************************************************************/ +void Mutex::lock() { + int res = pthread_mutex_lock(&mMutex); + if (res != 0) { + LOG(ERROR) << StringPrintf("Mutex::lock: fail lock; error=0x%X", res); + } +} + +/******************************************************************************* +** +** Function: unlock +** +** Description: Unlock a mutex to unblock a thread. +** +** Returns: None. +** +*******************************************************************************/ +void Mutex::unlock() { + int res = pthread_mutex_unlock(&mMutex); + if (res != 0) { + LOG(ERROR) << StringPrintf("Mutex::unlock: fail unlock; error=0x%X", res); + } +} + +/******************************************************************************* +** +** Function: tryLock +** +** Description: Try to lock the mutex. +** +** Returns: True if the mutex is locked. +** +*******************************************************************************/ +bool Mutex::tryLock() { + int res = pthread_mutex_trylock(&mMutex); + if ((res != 0) && (res != EBUSY)) { + LOG(ERROR) << StringPrintf("Mutex::tryLock: error=0x%X", res); + } + return res == 0; +} + +/******************************************************************************* +** +** Function: nativeHandle +** +** Description: Get the handle of the mutex. +** +** Returns: Handle of the mutex. +** +*******************************************************************************/ +pthread_mutex_t* Mutex::nativeHandle() { return &mMutex; } diff --git a/snxxx/libese-spi/src/adaptation/NfcAdaptation.cpp b/snxxx/libese-spi/src/adaptation/NfcAdaptation.cpp new file mode 100644 index 0000000..d746a0c --- /dev/null +++ b/snxxx/libese-spi/src/adaptation/NfcAdaptation.cpp @@ -0,0 +1,258 @@ +/****************************************************************************** + * + * Copyright 2018-2020 NXP + * + * 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. + * + ******************************************************************************/ +#define LOG_TAG "NxpEseHal-NfcAdaptation" +#include "NfcAdaptation.h" +#include <android/hardware/nfc/1.0/types.h> +#include <hwbinder/ProcessState.h> +#include <log/log.h> +#include <pthread.h> + +#undef LOG_TAG +#define LOG_TAG "SpiAdaptation" + +using android::OK; +using android::sp; +using android::status_t; + +using android::hardware::hidl_vec; +using android::hardware::ProcessState; +using android::hardware::Return; +using android::hardware::Void; +using vendor::nxp::nxpnfc::V2_0::INxpNfc; + +sp<INxpNfc> NfcAdaptation::mHalNxpNfc = nullptr; +ThreadMutex NfcAdaptation::sIoctlLock; +NfcAdaptation* NfcAdaptation::mpInstance = NULL; +ThreadMutex NfcAdaptation::sLock; + +int omapi_status; + +void NfcAdaptation::Initialize() { + const char* func = "NfcAdaptation::Initialize"; + ALOGD_IF(ese_debug_enabled, "%s", func); + if (mHalNxpNfc != nullptr) return; + mHalNxpNfc = INxpNfc::tryGetService(); + if (mHalNxpNfc != nullptr) { + ALOGE("%s: INxpNfc::getService() returned %p (%s)", func, mHalNxpNfc.get(), + (mHalNxpNfc->isRemote() ? "remote" : "local")); + } + ALOGD_IF(ese_debug_enabled, "%s: exit", func); +} +/******************************************************************************* +** +** Function: NfcAdaptation::GetInstance() +** +** Description: access class singleton +** +** Returns: pointer to the singleton object +** +*******************************************************************************/ +NfcAdaptation& NfcAdaptation::GetInstance() { + AutoThreadMutex a(sLock); + + if (!mpInstance) mpInstance = new NfcAdaptation; + return *mpInstance; +} +/******************************************************************************* +** +** Function: ThreadMutex::ThreadMutex() +** +** Description: class constructor +** +** Returns: none +** +*******************************************************************************/ +ThreadMutex::ThreadMutex() { + pthread_mutexattr_t mutexAttr; + + pthread_mutexattr_init(&mutexAttr); + pthread_mutex_init(&mMutex, &mutexAttr); + pthread_mutexattr_destroy(&mutexAttr); +} +/******************************************************************************* +** +** Function: ThreadMutex::~ThreadMutex() +** +** Description: class destructor +** +** Returns: none +** +*******************************************************************************/ +ThreadMutex::~ThreadMutex() { pthread_mutex_destroy(&mMutex); } + +/******************************************************************************* +** +** Function: AutoThreadMutex::AutoThreadMutex() +** +** Description: class constructor, automatically lock the mutex +** +** Returns: none +** +*******************************************************************************/ +AutoThreadMutex::AutoThreadMutex(ThreadMutex& m) : mm(m) { mm.lock(); } + +/******************************************************************************* +** +** Function: AutoThreadMutex::~AutoThreadMutex() +** +** Description: class destructor, automatically unlock the mutex +** +** Returns: none +** +*******************************************************************************/ +AutoThreadMutex::~AutoThreadMutex() { mm.unlock(); } + +/******************************************************************************* +** +** Function: ThreadMutex::lock() +** +** Description: lock kthe mutex +** +** Returns: none +** +*******************************************************************************/ +void ThreadMutex::lock() { pthread_mutex_lock(&mMutex); } + +/******************************************************************************* +** +** Function: ThreadMutex::unblock() +** +** Description: unlock the mutex +** +** Returns: none +** +*******************************************************************************/ +void ThreadMutex::unlock() { pthread_mutex_unlock(&mMutex); } + +/******************************************************************************* +** +** Function: NfcAdaptation::NfcAdaptation() +** +** Description: class constructor +** +** Returns: none +** +*******************************************************************************/ +NfcAdaptation::NfcAdaptation() { mCurrentIoctlData = NULL; } + +/******************************************************************************* +** +** Function: NfcAdaptation::~NfcAdaptation() +** +** Description: class destructor +** +** Returns: none +** +*******************************************************************************/ +NfcAdaptation::~NfcAdaptation() { mpInstance = NULL; } + +/******************************************************************************* +** +** Function: NfcAdaptation::resetEse +** +** Description: This function a wrapper function which triggers Ese reset +** +** +** +** Returns: -1 or 0. +** +*******************************************************************************/ +ESESTATUS NfcAdaptation::resetEse(uint64_t level) { + const char* func = "NfcAdaptation::resetEse"; + ESESTATUS result = ESESTATUS_FAILED; + bool ret = 0; + + ALOGD_IF(ese_debug_enabled, "%s : Enter", func); + + if (mHalNxpNfc != nullptr) { + ret = mHalNxpNfc->resetEse(level); + if (ret) { + ALOGE("NfcAdaptation::resetEse mHalNxpNfc completed"); + result = ESESTATUS_SUCCESS; + } else { + ALOGE("NfcAdaptation::resetEse mHalNxpNfc failed"); + } + } + + return result; +} + +/******************************************************************************* +** +** Function: NfcAdaptation::setEseUpdateState +** +** Description: This is a wrapper functions notifies upper layer about +** the jcob download comple +** tion. +** Returns: -1 or 0. +** +*******************************************************************************/ +ESESTATUS NfcAdaptation::setEseUpdateState(void* p_data) { + const char* func = "NfcAdaptation::setEseUpdateState"; + ::android::hardware::nfc::V1_0::NfcData data; + ESESTATUS result = ESESTATUS_FAILED; + bool ret = 0; + + ALOGD_IF(ese_debug_enabled, "%s : Enter", func); + + ese_nxp_IoctlInOutData_t* pInpOutData = (ese_nxp_IoctlInOutData_t*)p_data; + data.setToExternal((uint8_t*)pInpOutData, sizeof(ese_nxp_IoctlInOutData_t)); + + if (mHalNxpNfc != nullptr) { + ret = mHalNxpNfc->setEseUpdateState( + (::vendor::nxp::nxpnfc::V2_0::NxpNfcHalEseState) + pInpOutData->inp.data.nxpCmd.p_cmd[0]); + if (ret) { + ALOGE("NfcAdaptation::setEseUpdateState completed"); + result = ESESTATUS_SUCCESS; + } else { + ALOGE("NfcAdaptation::setEseUpdateState failed"); + } + } + + return result; +} + +/******************************************************************************* +** +** Function: ThreadCondVar::ThreadCondVar() +** +** Description: class constructor +** +** Returns: none +** +*******************************************************************************/ +ThreadCondVar::ThreadCondVar() { + pthread_condattr_t CondAttr; + + pthread_condattr_init(&CondAttr); + pthread_cond_init(&mCondVar, &CondAttr); + + pthread_condattr_destroy(&CondAttr); +} + +/******************************************************************************* +** +** Function: ThreadCondVar::~ThreadCondVar() +** +** Description: class destructor +** +** Returns: none +** +*******************************************************************************/ +ThreadCondVar::~ThreadCondVar() { pthread_cond_destroy(&mCondVar); } diff --git a/snxxx/libese-spi/src/include/CondVar.h b/snxxx/libese-spi/src/include/CondVar.h new file mode 100644 index 0000000..a2be51f --- /dev/null +++ b/snxxx/libese-spi/src/include/CondVar.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 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. + */ + +/* + * Encapsulate a condition variable for thread synchronization. + */ + +#pragma once +#include <pthread.h> +#include "Mutex.h" + +class CondVar { + public: + /******************************************************************************* + ** + ** Function: CondVar + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + CondVar(); + + /******************************************************************************* + ** + ** Function: ~CondVar + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~CondVar(); + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the caller and wait for a condition. + ** + ** Returns: None. + ** + *******************************************************************************/ + void wait(Mutex& mutex); + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the caller and wait for a condition. + ** millisec: Timeout in milliseconds. + ** + ** Returns: True if wait is successful; false if timeout occurs. + ** + *******************************************************************************/ + bool wait(Mutex& mutex, long millisec); + + /******************************************************************************* + ** + ** Function: notifyOne + ** + ** Description: Unblock the waiting thread. + ** + ** Returns: None. + ** + *******************************************************************************/ + void notifyOne(); + + private: + pthread_cond_t mCondition; +}; diff --git a/snxxx/libese-spi/src/include/Mutex.h b/snxxx/libese-spi/src/include/Mutex.h new file mode 100644 index 0000000..bcabf31 --- /dev/null +++ b/snxxx/libese-spi/src/include/Mutex.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2012 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. + */ + +/* + * Encapsulate a mutex for thread synchronization. + */ + +#pragma once +#include <pthread.h> + +class Mutex { + public: + /******************************************************************************* + ** + ** Function: Mutex + ** + ** Description: Initialize member variables. + ** + ** Returns: None. + ** + *******************************************************************************/ + Mutex(); + + /******************************************************************************* + ** + ** Function: ~Mutex + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~Mutex(); + + /******************************************************************************* + ** + ** Function: lock + ** + ** Description: Block the thread and try lock the mutex. + ** + ** Returns: None. + ** + *******************************************************************************/ + void lock(); + + /******************************************************************************* + ** + ** Function: unlock + ** + ** Description: Unlock a mutex to unblock a thread. + ** + ** Returns: None. + ** + *******************************************************************************/ + void unlock(); + + /******************************************************************************* + ** + ** Function: tryLock + ** + ** Description: Try to lock the mutex. + ** + ** Returns: True if the mutex is locked. + ** + *******************************************************************************/ + bool tryLock(); + + /******************************************************************************* + ** + ** Function: nativeHandle + ** + ** Description: Get the handle of the mutex. + ** + ** Returns: Handle of the mutex. + ** + *******************************************************************************/ + pthread_mutex_t* nativeHandle(); + + class Autolock { + public: + inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); } + inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); } + inline ~Autolock() { mLock.unlock(); } + + private: + Mutex& mLock; + }; + + private: + pthread_mutex_t mMutex; +}; + +typedef Mutex::Autolock AutoMutex; diff --git a/snxxx/libese-spi/src/include/NfcAdaptation.h b/snxxx/libese-spi/src/include/NfcAdaptation.h new file mode 100644 index 0000000..18720f6 --- /dev/null +++ b/snxxx/libese-spi/src/include/NfcAdaptation.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Copyright 2020 NXP + * + * 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. + * + ******************************************************************************/ +#pragma once +#include <pthread.h> + +#include <android/hardware/nfc/1.0/types.h> +#include <phEseStatus.h> +#include <phNxpEseFeatures.h> +#include <utils/RefBase.h> +#include <vendor/nxp/nxpnfc/2.0/INxpNfc.h> +#include "hal_nxpese.h" +using vendor::nxp::nxpnfc::V2_0::INxpNfc; + +class ThreadMutex { + public: + ThreadMutex(); + virtual ~ThreadMutex(); + void lock(); + void unlock(); + operator pthread_mutex_t*() { return &mMutex; } + + private: + pthread_mutex_t mMutex; +}; + +class ThreadCondVar : public ThreadMutex { + public: + ThreadCondVar(); + virtual ~ThreadCondVar(); + void signal(); + void wait(); + operator pthread_cond_t*() { return &mCondVar; } + operator pthread_mutex_t*() { + return ThreadMutex::operator pthread_mutex_t*(); + } + + private: + pthread_cond_t mCondVar; +}; + +class AutoThreadMutex { + public: + AutoThreadMutex(ThreadMutex& m); + virtual ~AutoThreadMutex(); + operator ThreadMutex&() { return mm; } + operator pthread_mutex_t*() { return (pthread_mutex_t*)mm; } + + private: + ThreadMutex& mm; +}; + +class NfcAdaptation { + public: + virtual ~NfcAdaptation(); + void Initialize(); + static NfcAdaptation& GetInstance(); + static ESESTATUS resetEse(uint64_t level); + static ESESTATUS setEseUpdateState(void* p_data); + ese_nxp_IoctlInOutData_t* mCurrentIoctlData; + + private: + NfcAdaptation(); + static NfcAdaptation* mpInstance; + static ThreadMutex sLock; + static ThreadMutex sIoctlLock; + ThreadCondVar mCondVar; + static ThreadCondVar mHalIoctlEvent; + static android::sp<INxpNfc> mHalNxpNfc; +}; diff --git a/snxxx/libese-spi/src/include/SyncEvent.h b/snxxx/libese-spi/src/include/SyncEvent.h new file mode 100644 index 0000000..96851ef --- /dev/null +++ b/snxxx/libese-spi/src/include/SyncEvent.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2012 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. + */ + +/* + * Synchronize two or more threads using a condition variable and a mutex. + */ +#pragma once +#include "CondVar.h" +#include "Mutex.h" + +class SyncEvent { + public: + /******************************************************************************* + ** + ** Function: ~SyncEvent + ** + ** Description: Cleanup all resources. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~SyncEvent() {} + + /******************************************************************************* + ** + ** Function: start + ** + ** Description: Start a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + void start() { mMutex.lock(); } + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the thread and wait for the event to occur. + ** + ** Returns: None. + ** + *******************************************************************************/ + void wait() { mCondVar.wait(mMutex); } + + /******************************************************************************* + ** + ** Function: wait + ** + ** Description: Block the thread and wait for the event to occur. + ** millisec: Timeout in milliseconds. + ** + ** Returns: True if wait is successful; false if timeout occurs. + ** + *******************************************************************************/ + bool wait(long millisec) { + bool retVal = mCondVar.wait(mMutex, millisec); + return retVal; + } + + /******************************************************************************* + ** + ** Function: notifyOne + ** + ** Description: Notify a blocked thread that the event has occurred. + ** Unblocks it. + ** + ** Returns: None. + ** + *******************************************************************************/ + void notifyOne() { mCondVar.notifyOne(); } + + /******************************************************************************* + ** + ** Function: end + ** + ** Description: End a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + void end() { mMutex.unlock(); } + + private: + CondVar mCondVar; + Mutex mMutex; +}; + +/*****************************************************************************/ +/*****************************************************************************/ + +/***************************************************************************** +** +** Name: SyncEventGuard +** +** Description: Automatically start and end a synchronization event. +** +*****************************************************************************/ +class SyncEventGuard { + public: + /******************************************************************************* + ** + ** Function: SyncEventGuard + ** + ** Description: Start a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + SyncEventGuard(SyncEvent& event) : mEvent(event) { + event.start(); // automatically start operation + }; + + /******************************************************************************* + ** + ** Function: ~SyncEventGuard + ** + ** Description: End a synchronization operation. + ** + ** Returns: None. + ** + *******************************************************************************/ + ~SyncEventGuard() { + mEvent.end(); // automatically end operation + }; + + private: + SyncEvent& mEvent; +}; |