merge with master
[platform/core/connectivity/smartcard-plugin-uicc.git] / UICCTerminal.cpp
1 /*
2  * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* standard library header */
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <sys/time.h>
22
23 /* SLP library header */
24
25 /* local header */
26 #include "Debug.h"
27 #include "TerminalInterface.h"
28 #include "UICCTerminal.h"
29
30 #ifndef EXPORT_API
31 #define EXPORT_API __attribute__((visibility("default")))
32 #endif
33
34 typedef struct _callback_param_t
35 {
36         void *callback;
37         void *param;
38 }
39 callback_param_t;
40
41 using namespace smartcard_service_api;
42
43 static const char *se_name = "SIM1";
44
45 /* below functions will be called when dlopen or dlclose is called */
46 void __attribute__ ((constructor)) lib_init()
47 {
48 }
49
50 void __attribute__ ((destructor)) lib_fini()
51 {
52 }
53
54 /* below trhee functions must be implemented */
55 extern "C" EXPORT_API const char *get_name()
56 {
57         return se_name;
58 }
59
60 extern "C" EXPORT_API void *create_instance()
61 {
62         return (void *)UICCTerminal::getInstance();
63 }
64
65 extern "C" EXPORT_API void destroy_instance(void *instance)
66 {
67         UICCTerminal *inst = (UICCTerminal *)instance;
68         if (inst == UICCTerminal::getInstance())
69         {
70                 inst->finalize();
71         }
72         else
73         {
74                 SCARD_DEBUG_ERR("instance is invalid : getInstance [%p], instance [%p]", UICCTerminal::getInstance(), instance);
75         }
76 }
77
78 static void _uiccTransmitCallback(TapiHandle *handle, int result, void *data, void *user_data)
79 {
80         TelSimAccessResult_t access_rt = (TelSimAccessResult_t)result;
81         TelSimApduResp_t *apdu = (TelSimApduResp_t *)data;
82         callback_param_t *param = (callback_param_t *)user_data;
83
84         SCARD_DEBUG("APDU response");
85
86         if (param != NULL)
87         {
88                 if (param->callback != NULL)
89                 {
90                         terminalTransmitCallback callback = (terminalTransmitCallback)param->callback;
91
92                         if (apdu != NULL && apdu->apdu_resp_len > 0)
93                         {
94                                 callback(apdu->apdu_resp, apdu->apdu_resp_len, access_rt, param->param);
95                         }
96                         else
97                         {
98                                 callback(NULL, 0, access_rt, param->param);
99                         }
100                 }
101                 else
102                 {
103                         SCARD_DEBUG("there is no callback");
104                 }
105
106                 delete param;
107         }
108         else
109         {
110                 SCARD_DEBUG_ERR("invalid param");
111         }
112 }
113
114 static void _uiccGetATRCallback(TapiHandle *handle, int result, void *data, void *user_data)
115 {
116         TelSimAccessResult_t access_rt = (TelSimAccessResult_t)result;
117         TelSimAtrResp_t *atr  = (TelSimAtrResp_t *)data;
118         callback_param_t *param = (callback_param_t *)user_data;
119
120         SCARD_DEBUG("APDU response");
121
122         if (param != NULL)
123         {
124                 if (param->callback != NULL)
125                 {
126                         terminalGetATRCallback callback = (terminalGetATRCallback)param->callback;
127
128                         if (atr != NULL && atr->atr_resp_len > 0)
129                         {
130                                 callback(atr->atr_resp, atr->atr_resp_len, access_rt, param->param);
131                         }
132                         else
133                         {
134                                 callback(NULL, 0, access_rt, param->param);
135                         }
136                 }
137                 else
138                 {
139                         SCARD_DEBUG("there is no callback");
140                 }
141
142                 delete param;
143         }
144         else
145         {
146                 SCARD_DEBUG_ERR("invalid param");
147         }
148 }
149
150 namespace smartcard_service_api
151 {
152         UICCTerminal::UICCTerminal()
153         {
154                 name = (char *)se_name;
155                 initialize();
156         }
157
158         UICCTerminal::~UICCTerminal()
159         {
160                 finalize();
161         }
162
163         UICCTerminal *UICCTerminal::getInstance()
164         {
165                 static UICCTerminal instance;
166
167                 return &instance;
168         }
169
170         bool UICCTerminal::initialize()
171         {
172                 SCARD_BEGIN();
173
174                 if (initialized == false)
175                 {
176                         char **cpList = NULL;
177
178 //                      cpList = tel_get_cp_name_list();
179
180                         handle = tel_init(NULL);
181                         if (handle != NULL)
182                         {
183                                 int error;
184
185                                 error = tel_register_noti_event(handle, TAPI_NOTI_SIM_STATUS, &UICCTerminal::uiccStatusNotiCallback, this);
186
187                                 initialized = true;
188                         }
189                         else
190                         {
191                                 SCARD_DEBUG_ERR("tel_init failed");
192                         }
193                 }
194
195                 SCARD_END();
196
197                 return initialized;
198         }
199
200         void UICCTerminal::finalize()
201         {
202                 SCARD_BEGIN();
203
204                 if (isInitialized())
205                 {
206                         tel_deregister_noti_event(handle, TAPI_NOTI_SIM_STATUS);
207
208                         tel_deinit(handle);
209
210                         initialized = false;
211                 }
212
213                 SCARD_END();
214         }
215
216         int UICCTerminal::transmitSync(ByteArray command, ByteArray &response)
217         {
218                 int result = -1;
219
220                 SCARD_BEGIN();
221
222                 SCOPE_LOCK(mutex)
223                 {
224                         if (command.getLength() > 0)
225                         {
226                                 TelSimApdu_t apdu_data = { 0, };
227
228                                 apdu_data.apdu = command.getBuffer();
229                                 apdu_data.apdu_len = command.getLength();
230
231                                 syncLock();
232
233                                 result = tel_req_sim_apdu(handle, &apdu_data, &UICCTerminal::uiccTransmitAPDUCallback, this);
234                                 if (result == 0)
235                                 {
236                                         SCARD_DEBUG("tel_req_sim_apdu request is success");
237
238                                         error = 0;
239                                         this->response.releaseBuffer();
240
241                                         result = waitTimedCondition(3);
242
243
244                                         if (result == 0 && error == 0)
245                                         {
246                                                 if (this->response.getLength() > 0)
247                                                 {
248                                                         response = this->response;
249                                                 }
250
251                                                 SCARD_DEBUG("tel_req_sim_apdu success, length [%d]", response.getLength());
252                                         }
253                                         else
254                                         {
255                                                 SCARD_DEBUG_ERR("tel_req_sim_apdu failed, result [%d], cbResult [%d]", result, error);
256                                         }
257                                 }
258                                 else
259                                 {
260                                         SCARD_DEBUG_ERR("tel_req_sim_apdu failed [%d]", result);
261                                 }
262
263                                 syncUnlock();
264                         }
265                         else
266                         {
267                                 SCARD_DEBUG_ERR("apdu is empty");
268                         }
269                 }
270
271                 SCARD_END();
272
273                 return result;
274         }
275
276         int UICCTerminal::getATRSync(ByteArray &atr)
277         {
278                 int result = 0;
279
280                 SCARD_BEGIN();
281
282                 SCOPE_LOCK(mutex)
283                 {
284                         syncLock();
285
286                         result = tel_req_sim_atr(handle, &UICCTerminal::uiccGetAtrCallback, this);
287                         if (result == 0)
288                         {
289                                 SCARD_DEBUG("tel_req_sim_atr request is success");
290
291                                 error = 0;
292                                 this->response.releaseBuffer();
293
294                                 result = waitTimedCondition(3);
295
296                                 if (result == 0 && error == 0)
297                                 {
298                                         if (this->response.getLength() > 0)
299                                         {
300                                                 atr = this->response;
301                                         }
302
303                                         SCARD_DEBUG("tel_req_sim_atr success, length [%d]", response.getLength());
304                                 }
305                                 else
306                                 {
307                                         SCARD_DEBUG_ERR("tel_req_sim_atr failed, result [%d], cbResult [%d]", result, error);
308                                 }
309                         }
310                         else
311                         {
312                                 SCARD_DEBUG_ERR("tel_req_sim_atr failed [%d]", result);
313                         }
314
315                         syncUnlock();
316                 }
317
318                 SCARD_END();
319
320                 return result;
321         }
322
323         int UICCTerminal::transmit(ByteArray command, terminalTransmitCallback callback, void *userParam)
324         {
325                 int result = -1;
326
327                 SCARD_BEGIN();
328
329                 SCOPE_LOCK(mutex)
330                 {
331                         if (command.getLength() > 0)
332                         {
333                                 TelSimApdu_t apdu_data = { 0, };
334                                 callback_param_t *param = NULL;
335
336                                 apdu_data.apdu = command.getBuffer();
337                                 apdu_data.apdu_len = command.getLength();
338
339                                 param = new callback_param_t();
340                                 param->callback = (void *)callback;
341                                 param->param = userParam;
342
343                                 result = tel_req_sim_apdu(handle, &apdu_data, _uiccTransmitCallback, param);
344                                 if (result == 0)
345                                 {
346                                         SCARD_DEBUG("tel_req_sim_apdu request is success");
347                                 }
348                                 else
349                                 {
350                                         SCARD_DEBUG_ERR("tel_req_sim_apdu failed [%d]", result);
351                                 }
352                         }
353                         else
354                         {
355                                 SCARD_DEBUG_ERR("apdu is empty");
356                         }
357                 }
358
359                 SCARD_END();
360
361                 return result;
362         }
363
364         int UICCTerminal::getATR(terminalGetATRCallback callback, void *userParam)
365         {
366                 int result = 0;
367
368                 SCARD_BEGIN();
369
370                 SCOPE_LOCK(mutex)
371                 {
372                         callback_param_t *param = NULL;
373
374                         param = new callback_param_t();
375                         param->callback = (void *)callback;
376                         param->param = userParam;
377
378                         result = tel_req_sim_atr(handle, _uiccGetATRCallback, param);
379                         if (result == 0)
380                         {
381                                 SCARD_DEBUG("tel_req_sim_atr request is success");
382                         }
383                         else
384                         {
385                                 SCARD_DEBUG_ERR("tel_req_sim_atr failed [%d]", result);
386                         }
387                 }
388
389                 SCARD_END();
390
391                 return result;
392         }
393
394         bool UICCTerminal::isSecureElementPresence()
395         {
396                 bool result = false;
397                 int error = 0;
398                 TelSimCardStatus_t state = (TelSimCardStatus_t)0;
399                 int cardChanged = 0;
400
401                 SCARD_BEGIN();
402
403                 error = tel_get_sim_init_info(handle, &state, &cardChanged);
404
405                 SCARD_DEBUG("current sim init state = [%d], error [%d], cardChanged [%d]", state, error, cardChanged);
406
407                 if (error == 0)
408                 {
409                         if (state == TAPI_SIM_STATUS_SIM_INIT_COMPLETED || state == TAPI_SIM_STATUS_SIM_INITIALIZING)
410                         {
411                                 SCARD_DEBUG("sim is initialized");
412
413                                 result = true;
414                         }
415                         else
416                         {
417                                 SCARD_DEBUG_ERR("sim is not initialized");
418                         }
419                 }
420                 else
421                 {
422                         SCARD_DEBUG_ERR("error = [%d]", error);
423                 }
424
425                 SCARD_END();
426
427                 return result;
428         }
429
430         void UICCTerminal::uiccTransmitAPDUCallback(TapiHandle *handle, int result, void *data, void *user_data)
431         {
432                 UICCTerminal *instance = (UICCTerminal *)user_data;
433                 TelSimAccessResult_t access_rt = (TelSimAccessResult_t)result;
434                 TelSimApduResp_t *apdu = (TelSimApduResp_t *)data;
435
436                 SCARD_DEBUG("APDU response");
437
438                 instance->syncLock();
439
440                 instance->error = access_rt;
441
442                 if (instance->error == 0)
443                 {
444                         if (apdu != NULL && apdu->apdu_resp_len > 0)
445                         {
446                                 instance->response.setBuffer(apdu->apdu_resp, apdu->apdu_resp_len);
447                         }
448
449                         SCARD_DEBUG("response : %s", instance->response.toString());
450                 }
451                 else
452                 {
453                         SCARD_DEBUG_ERR("error : event->Status == [%d]", access_rt);
454                 }
455
456                 instance->signalCondition();
457                 instance->syncUnlock();
458         }
459
460         void UICCTerminal::uiccGetAtrCallback(TapiHandle *handle, int result, void *data, void *user_data)
461         {
462                 UICCTerminal *instance = (UICCTerminal *)user_data;
463                 TelSimAccessResult_t access_rt = (TelSimAccessResult_t)result;
464                 TelSimAtrResp_t *atr  = (TelSimAtrResp_t *)data;
465
466                 SCARD_DEBUG("Get ATR response");
467
468                 instance->syncLock();
469
470                 instance->error = access_rt;
471
472                 if (access_rt == 0)
473                 {
474                         if (atr != NULL && atr->atr_resp_len > 0)
475                         {
476                                 instance->response.setBuffer(atr->atr_resp, atr->atr_resp_len);
477                         }
478
479                         SCARD_DEBUG("response : %s", instance->response.toString());
480                 }
481                 else
482                 {
483                         SCARD_DEBUG_ERR("error : event->Status == [%d]", access_rt);
484                 }
485
486                 instance->signalCondition();
487                 instance->syncUnlock();
488         }
489
490         void UICCTerminal::uiccStatusNotiCallback(TapiHandle *handle, const char *noti_id, void *data, void *user_data)
491         {
492                 UICCTerminal *instance = (UICCTerminal *)user_data;
493                 TelSimCardStatus_t *status = (TelSimCardStatus_t *)data;
494
495                 SCARD_DEBUG("TAPI_NOTI_SIM_STATUS");
496
497                 switch (*status)
498                 {
499                 case TAPI_SIM_STATUS_SIM_INIT_COMPLETED :
500                         SCARD_DEBUG("TAPI_SIM_STATUS_SIM_INIT_COMPLETED");
501
502                         if (instance->statusCallback != NULL)
503                         {
504                                 instance->statusCallback((void *)se_name, NOTIFY_SE_AVAILABLE, 0, NULL);
505                         }
506                         break;
507
508                 case TAPI_SIM_STATUS_CARD_REMOVED :
509                         SCARD_DEBUG("TAPI_SIM_STATUS_CARD_REMOVED");
510
511                         if (instance->statusCallback != NULL)
512                         {
513                                 instance->statusCallback((void *)se_name, NOTIFY_SE_NOT_AVAILABLE, 0, NULL);
514                         }
515                         break;
516
517                 default :
518                         SCARD_DEBUG("unknown status [%d]", *status);
519                         break;
520                 }
521         }
522 } /* namespace smartcard_service_api */