1 /******************************************************************************
2 *
3 * Copyright 2020-2023 NXP
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #define LOG_TAG "weaver-transport-impl"
20 #include <TransportFactory.h>
21 #include <vector>
22 #include <weaver_transport-impl.h>
23 #include <weaver_utils.h>
24
25 #define MAX_RETRY_COUNT 12
26 #define RETRY_DELAY_INTERVAL_SEC 1
27 #define IS_APPLET_SELECTION_FAILED(resp) \
28 (!resp.empty() && resp[0] == APP_NOT_FOUND_SW1 && \
29 resp[1] == APP_NOT_FOUND_SW2)
30
31 WeaverTransportImpl *WeaverTransportImpl::s_instance = NULL;
32 std::once_flag WeaverTransportImpl::s_instanceFlag;
33
34 /* Applet ID to be use for communication */
35 std::vector<std::vector<uint8_t>> kAppletId;
36
37 /* Interface instance of libese-transport library */
38 static std::unique_ptr<se_transport::TransportFactory> pTransportFactory =
39 nullptr;
40
41 /**
42 * \brief static inline function to get lib-ese-transport interface instance
43 */
44 static inline std::unique_ptr<se_transport::TransportFactory> &
getTransportFactoryInstance()45 getTransportFactoryInstance() {
46 if (pTransportFactory == nullptr) {
47 pTransportFactory = std::unique_ptr<se_transport::TransportFactory>(
48 new se_transport::TransportFactory(false, kAppletId[0]));
49 pTransportFactory->openConnection();
50 }
51 return pTransportFactory;
52 }
53
54 /**
55 * \brief static function to get the singleton instance of WeaverTransportImpl
56 * class
57 *
58 * \retval instance of WeaverTransportImpl.
59 */
getInstance()60 WeaverTransportImpl *WeaverTransportImpl::getInstance() {
61 /* call_once c++11 api which executes the passed function ptr exactly once,
62 * even if called concurrently, from several threads
63 */
64 std::call_once(s_instanceFlag, &WeaverTransportImpl::createInstance);
65 return s_instance;
66 }
67
68 /* Private function to create the instance of self class
69 * Same will be used for std::call_once
70 */
createInstance()71 void WeaverTransportImpl::createInstance() {
72 LOG_D(TAG, "Entry");
73 s_instance = new WeaverTransportImpl;
74 LOG_D(TAG, "Exit");
75 }
76
77 /**
78 * \brief Function to initialize Weaver Transport Interface
79 *
80 * \param[in] aid - applet id to be set to transport interface
81 *
82 * \retval This function return true in case of success
83 * In case of failure returns false.
84 */
Init(std::vector<std::vector<uint8_t>> aid)85 bool WeaverTransportImpl::Init(std::vector<std::vector<uint8_t>> aid) {
86 LOG_D(TAG, "Entry");
87 kAppletId = std::move(aid);
88 LOG_D(TAG, "Exit");
89 return true;
90 }
91
92 /**
93 * \brief Function to open applet connection
94 *
95 * \param[in] data - command for open applet
96 * \param[out] resp - response from applet
97 *
98 * \retval This function return true in case of success
99 * In case of failure returns false.
100 */
OpenApplet(std::vector<uint8_t> data,std::vector<uint8_t> & resp)101 bool WeaverTransportImpl::OpenApplet(std::vector<uint8_t> data,
102 std::vector<uint8_t> &resp) {
103 LOG_D(TAG, "Entry");
104 bool status = true;
105 UNUSED(data);
106 UNUSED(resp);
107 // Since libese_transport opens channel as part of send only so open applet is
108 // not required
109 LOG_D(TAG, "Exit");
110 return status;
111 }
112
113 /**
114 * \brief Function to close applet connection
115 *
116 * \retval This function return true in case of success
117 * In case of failure returns false.
118 */
CloseApplet()119 bool WeaverTransportImpl::CloseApplet() {
120 LOG_D(TAG, "Entry");
121 // Close the Applet Channel if opened
122 bool status = getTransportFactoryInstance()->closeConnection();
123 LOG_D(TAG, "Exit");
124 return status;
125 }
126
127 /**
128 * \brief Private wrapper function to send apdu.
129 * It will try with alternate aids if sending is failed.
130 *
131 * \param[in] data - command to be send to applet
132 * \param[out] resp - response from applet
133 *
134 * \retval This function return true in case of success
135 * In case of failure returns false.
136 */
sendInternal(std::vector<uint8_t> data,std::vector<uint8_t> & resp)137 bool WeaverTransportImpl::sendInternal(std::vector<uint8_t> data,
138 std::vector<uint8_t> &resp) {
139 bool status = false;
140 status =
141 getTransportFactoryInstance()->sendData(data.data(), data.size(), resp);
142 if (!status && IS_APPLET_SELECTION_FAILED(resp)) {
143 LOG_E(TAG, ": send Failed, trying with alternateAids");
144 // If Applet selection failed, try with alternate Aids
145 for (int i = 1; i < kAppletId.size(); i++) {
146 getTransportFactoryInstance()->setAppletAid(kAppletId[i]);
147 status = getTransportFactoryInstance()->sendData(data.data(), data.size(),
148 resp);
149 if (status) {
150 return status;
151 }
152 }
153 if (!status) {
154 // None of alternate Aids success, Revert back to primary AID
155 getTransportFactoryInstance()->setAppletAid(kAppletId[0]);
156 }
157 }
158 return status;
159 }
160
161 /**
162 * \brief Function to send commands to applet
163 *
164 * \param[in] data - command to be send to applet
165 * \param[out] resp - response from applet
166 *
167 * \retval This function return true in case of success
168 * In case of failure returns false.
169 */
Send(std::vector<uint8_t> data,std::vector<uint8_t> & resp)170 bool WeaverTransportImpl::Send(std::vector<uint8_t> data,
171 std::vector<uint8_t> &resp) {
172 LOG_D(TAG, "Entry");
173 int retry = 1;
174 bool status = false;
175 // Opens the channel with aid and transmit the data
176 do {
177 status = sendInternal(data, resp);
178 if (!status) {
179 if (retry > MAX_RETRY_COUNT) {
180 LOG_E(TAG, ": completed max retries exit failure");
181 } else {
182 sleep(RETRY_DELAY_INTERVAL_SEC);
183 LOG_E(TAG, ": retry %d/%d", retry, MAX_RETRY_COUNT);
184 }
185 }
186 } while ((!status) && (retry++ <= MAX_RETRY_COUNT));
187 LOG_D(TAG, "Exit");
188 return status;
189 }
190
191 /**
192 * \brief Function to de-initialize Weaver Transport Interface
193 *
194 * \retval This function return true in case of success
195 * In case of failure returns false.
196 */
DeInit()197 bool WeaverTransportImpl::DeInit() {
198 LOG_D(TAG, "Entry");
199 bool status = CloseApplet();
200 LOG_D(TAG, "Exit");
201 return status;
202 }
203