com_android_nfc_NativeNfcSecureElement.cpp revision 0bd11735e8a28db1692f28abcc3e065abae0e8dd
1/*
2 * Copyright (C) 2010 The Android Open Source Project
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#include <semaphore.h>
18
19#include "com_android_nfc.h"
20
21static sem_t com_android_nfc_jni_secure_element_sem;
22static NFCSTATUS com_android_nfc_jni_cb_status = NFCSTATUS_FAILED;
23static phNfc_sData_t *com_android_nfc_jni_transceive_buffer;
24static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer;
25static phNfc_sRemoteDevInformation_t* SecureElementInfo;
26static int secureElementHandle;
27extern void                 *gHWRef;
28static int SecureElementTech;
29
30namespace android {
31
32static void com_android_nfc_jni_ioctl_callback ( void*            context,
33                                            phNfc_sData_t*   Outparam_Cb,
34                                            NFCSTATUS        status)
35{
36	if (status == NFCSTATUS_SUCCESS )
37	{
38		LOGD("> IOCTL successful");
39	}
40	else
41	{
42		LOGD("> IOCTL error");
43	}
44   com_android_nfc_jni_cb_status = status;
45   com_android_nfc_jni_ioctl_buffer = Outparam_Cb;
46
47   sem_post(&com_android_nfc_jni_secure_element_sem);
48}
49
50static void com_android_nfc_jni_transceive_callback(void *pContext,
51   phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
52{
53   LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status);
54
55   com_android_nfc_jni_cb_status = status;
56   com_android_nfc_jni_transceive_buffer = pResBuffer;
57
58   sem_post(&com_android_nfc_jni_secure_element_sem);
59}
60
61
62static void com_android_nfc_jni_connect_callback(void *pContext,
63                                            phLibNfc_Handle hRemoteDev,
64                                            phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
65{
66   LOG_CALLBACK("com_android_nfc_jni_connect_callback", status);
67
68   com_android_nfc_jni_cb_status = status;
69
70   sem_post(&com_android_nfc_jni_secure_element_sem);
71}
72
73static void com_android_nfc_jni_disconnect_callback(void *pContext,
74                                               phLibNfc_Handle hRemoteDev,
75                                               NFCSTATUS status)
76{
77   LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status);
78
79   com_android_nfc_jni_cb_status = status;
80
81   sem_post(&com_android_nfc_jni_secure_element_sem);
82}
83
84/* Set Secure Element mode callback*/
85static void com_android_nfc_jni_smartMX_setModeCb (void*            pContext,
86							                                phLibNfc_Handle  hSecureElement,
87                                              NFCSTATUS        status)
88{
89	if(status==NFCSTATUS_SUCCESS)
90	{
91		LOGD("SE Set Mode is Successful");
92		LOGD("SE Handle: %lu", hSecureElement);
93	}
94	else
95	{
96    LOGD("SE Set Mode is failed\n ");
97  }
98
99	com_android_nfc_jni_cb_status = status;
100
101   sem_post(&com_android_nfc_jni_secure_element_sem);
102}
103
104static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext,
105                                                                     phLibNfc_RemoteDevList_t *psRemoteDevList,
106                                                                     uint8_t uNofRemoteDev,
107                                                                     NFCSTATUS status)
108{
109   JNIEnv *e;
110   NFCSTATUS ret;
111   int i;
112
113   if(status == NFCSTATUS_DESELECTED)
114   {
115      LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status);
116   }
117   else
118   {
119      LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status);
120      LOGI("Discovered %d tags", uNofRemoteDev);
121
122      if(status == NFCSTATUS_MULTIPLE_PROTOCOLS)
123      {
124         LOGD("Multiple Protocol supported\n");
125
126         LOGD("Secure Element Handle: 0x%08x",psRemoteDevList[1].hTargetDev);
127         secureElementHandle = psRemoteDevList[1].hTargetDev;
128
129         /* Set type name */
130         SecureElementTech = get_technology_type(psRemoteDevList[1].psRemoteDevInfo->RemDevType,
131                                        psRemoteDevList[1].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);
132
133         LOGD("Store Secure Element Info\n");
134         SecureElementInfo = psRemoteDevList->psRemoteDevInfo;
135
136         LOGD("Discovered secure element: tech=%d", SecureElementTech);
137      }
138      else
139      {
140         LOGD("Secure Element Handle: 0x%08x",psRemoteDevList->hTargetDev);
141         secureElementHandle = psRemoteDevList->hTargetDev;
142
143         /* Set type name */
144         SecureElementTech = get_technology_type(psRemoteDevList->psRemoteDevInfo->RemDevType,
145                                         psRemoteDevList->psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);
146
147         LOGD("Store Secure Element Info\n");
148         SecureElementInfo = psRemoteDevList->psRemoteDevInfo;
149
150         LOGD("Discovered secure element: tech=%d", SecureElementTech);
151      }
152   }
153
154   com_android_nfc_jni_cb_status = status;
155   sem_post(&com_android_nfc_jni_secure_element_sem);
156}
157
158
159static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o)
160{
161   NFCSTATUS ret;
162   int semResult;
163
164   phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
165   uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0;
166   phLibNfc_sADD_Cfg_t discovery_cfg;
167   phLibNfc_Registry_Info_t registry_info;
168   phNfc_sData_t			InParam;
169   phNfc_sData_t			OutParam;
170   uint8_t              ExternalRFDetected[3] = {0x00, 0xFC, 0x01};
171   uint8_t					Output_Buff[50];
172   uint8_t              reg_value;
173   uint8_t              mask_value;
174
175   /* Registery */
176   registry_info.MifareUL = TRUE;
177   registry_info.MifareStd = TRUE;
178   registry_info.ISO14443_4A = TRUE;
179   registry_info.ISO14443_4B = TRUE;
180   registry_info.Jewel = TRUE;
181   registry_info.Felica = TRUE;
182   registry_info.NFC = FALSE;
183
184   CONCURRENCY_LOCK();
185
186   LOGD("Open Secure Element");
187
188   /* Test if External RF field is detected */
189	InParam.buffer = ExternalRFDetected;
190	InParam.length = 3;
191	OutParam.buffer = Output_Buff;
192	LOGD("phLibNfc_Mgt_IoCtl()");
193   ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)e);
194   if(ret!=NFCSTATUS_PENDING)
195	{
196      LOGE("IOCTL status error");
197	}
198   semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
199   if (semResult)
200   {
201      LOGE("IOCTL semaphore error");
202      goto clean_and_return;
203   }
204
205   if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
206   {
207      LOGE("READ MEM ERROR");
208      goto clean_and_return;
209   }
210
211   /* Check the value */
212   reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0];
213   mask_value = reg_value & 0x40;
214
215   if(mask_value == 0x40)
216   {
217      LOGD("External RF Field detected");
218      goto clean_and_return;
219   }
220
221   /* Get Secure Element List */
222   LOGD("phLibNfc_SE_GetSecureElementList()");
223   ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE);
224   if (ret == NFCSTATUS_SUCCESS)
225   {
226      LOGD("\n> Number of Secure Element(s) : %d\n", No_SE);
227      /* Display Secure Element information */
228      for (i = 0; i<No_SE; i++)
229      {
230         if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX)
231         {
232           LOGD("> SMX detected");
233           LOGD("> Secure Element Handle : %d\n", SE_List[i].hSecureElement);
234           /* save SMARTMX index */
235           SmartMX_detected = 1;
236           SmartMX_index = i;
237         }
238      }
239
240      if(SmartMX_detected)
241      {
242         REENTRANCE_LOCK();
243         LOGD("phLibNfc_RemoteDev_NtfRegister()");
244         ret = phLibNfc_RemoteDev_NtfRegister(&registry_info, com_android_nfc_jni_open_secure_element_notification_callback, (void *)e);
245         REENTRANCE_UNLOCK();
246         if(ret != NFCSTATUS_SUCCESS)
247         {
248            LOGW("Register Notification error");
249            goto clean_and_return;
250         }
251
252         /* Set wired mode */
253         REENTRANCE_LOCK();
254         LOGD("phLibNfc_SE_SetMode: Wired mode");
255         ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement,
256									         phLibNfc_SE_ActModeWired,
257									         com_android_nfc_jni_smartMX_setModeCb,
258									         (void*)e);
259         REENTRANCE_UNLOCK();
260         if (ret != NFCSTATUS_PENDING )
261         {
262            LOGD("\n> SE Set SmartMX mode ERROR \n" );
263            goto clean_and_return;
264         }
265
266         semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
267         if (semResult)
268         {
269            LOGW("Secure Element opening error");
270            goto clean_and_return;
271         }
272
273         if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
274         {
275            LOGE("SE set mode failed");
276            goto clean_and_return;
277         }
278
279         LOGD("Waiting for notification");
280         semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
281         if (semResult)
282         {
283            LOGW("Secure Element opening error");
284            goto clean_and_return;
285         }
286
287         if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS && com_android_nfc_jni_cb_status != NFCSTATUS_MULTIPLE_PROTOCOLS)
288         {
289            LOGE("SE detection failed");
290            goto clean_and_return;
291         }
292         CONCURRENCY_UNLOCK();
293
294         /* Connect Tag */
295         CONCURRENCY_LOCK();
296         LOGD("phLibNfc_RemoteDev_Connect(SMX)");
297         REENTRANCE_LOCK();
298         ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)e);
299         REENTRANCE_UNLOCK();
300         if(ret != NFCSTATUS_PENDING)
301         {
302            LOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
303            goto clean_and_return;
304         }
305         LOGD("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
306
307         /* Wait for callback response */
308         sem_wait(&com_android_nfc_jni_secure_element_sem);
309
310         /* Connect Status */
311         if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
312         {
313            goto clean_and_return;
314         }
315
316         CONCURRENCY_UNLOCK();
317         /* Return the Handle of the SecureElement */
318         return secureElementHandle;
319      }
320      else
321      {
322         LOGD("phLibNfc_SE_GetSecureElementList(): No SMX detected");
323         goto clean_and_return;
324      }
325  }
326  else
327  {
328      LOGD("phLibNfc_SE_GetSecureElementList(): Error");
329      goto clean_and_return;
330  }
331
332clean_and_return:
333   CONCURRENCY_UNLOCK();
334   return 0;
335}
336
337
338static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle)
339{
340   jclass cls;
341   jfieldID f;
342   NFCSTATUS status;
343   jboolean result = JNI_FALSE;
344   phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
345   uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index=0, SmartMX_detected = 0;
346   uint32_t SmartMX_Handle;
347
348   LOGD("Close Secure element function ");
349
350   CONCURRENCY_LOCK();
351   /* Disconnect */
352   LOGI("Disconnecting from SMX (handle = 0x%x)", handle);
353   REENTRANCE_LOCK();
354   status = phLibNfc_RemoteDev_Disconnect(handle,
355                                          NFC_SMARTMX_RELEASE,
356                                          com_android_nfc_jni_disconnect_callback,
357                                          (void *)e);
358   REENTRANCE_UNLOCK();
359   if(status != NFCSTATUS_PENDING)
360   {
361      LOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
362      goto clean_and_return;
363   }
364   LOGD("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
365
366   /* Wait for callback response */
367   sem_wait(&com_android_nfc_jni_secure_element_sem);
368
369   /* Disconnect Status */
370   if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
371   {
372     LOGE("\n> Disconnect SE ERROR \n" );
373      goto clean_and_return;
374   }
375
376   result = JNI_TRUE;
377
378clean_and_return:
379   CONCURRENCY_UNLOCK();
380   return result;
381}
382
383static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e,
384   jobject o,jint handle, jbyteArray data)
385{
386   uint8_t offset = 0;
387   uint8_t *buf;
388   uint32_t buflen;
389   phLibNfc_sTransceiveInfo_t transceive_info;
390   jbyteArray result = NULL;
391   int res;
392
393   int tech = SecureElementTech;
394   NFCSTATUS status;
395
396   LOGD("Exchange APDU function ");
397
398   CONCURRENCY_LOCK();
399
400   LOGD("Secure Element tech: %d\n", tech);
401
402   buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
403   buflen = (uint32_t)e->GetArrayLength(data);
404
405   /* Prepare transceive info structure */
406   if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL)
407   {
408      offset = 2;
409      transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
410      transceive_info.addr = (uint8_t)buf[1];
411   }
412   else if(tech == TARGET_TYPE_ISO14443_4)
413   {
414      transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw;
415      transceive_info.addr = 0;
416   }
417
418   transceive_info.sSendData.buffer = buf + offset;
419   transceive_info.sSendData.length = buflen - offset;
420   transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
421   transceive_info.sRecvData.length = 1024;
422
423   if(transceive_info.sRecvData.buffer == NULL)
424   {
425      goto clean_and_return;
426   }
427
428   LOGD("phLibNfc_RemoteDev_Transceive(SMX)");
429   REENTRANCE_LOCK();
430   status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info,
431		   com_android_nfc_jni_transceive_callback, (void *)e);
432   REENTRANCE_UNLOCK();
433   if(status != NFCSTATUS_PENDING)
434   {
435      LOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
436      goto clean_and_return;
437   }
438   LOGD("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
439
440   /* Wait for callback response */
441   sem_wait(&com_android_nfc_jni_secure_element_sem);
442
443   if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
444   {
445      goto clean_and_return;
446   }
447
448   /* Copy results back to Java */
449   result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length);
450   if(result != NULL)
451   {
452      e->SetByteArrayRegion(result, 0,
453    		  com_android_nfc_jni_transceive_buffer->length,
454         (jbyte *)com_android_nfc_jni_transceive_buffer->buffer);
455   }
456
457clean_and_return:
458   if(transceive_info.sRecvData.buffer != NULL)
459   {
460      free(transceive_info.sRecvData.buffer);
461   }
462
463   e->ReleaseByteArrayElements(data,
464      (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
465
466   CONCURRENCY_UNLOCK();
467
468   return result;
469}
470
471static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle)
472{
473   LOGD("Get Secure element UID function ");
474   jbyteArray SecureElementUid;
475
476   if(handle == secureElementHandle)
477   {
478      SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength);
479      e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid);
480      return SecureElementUid;
481   }
482   else
483   {
484      return NULL;
485   }
486}
487
488static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle)
489{
490   jintArray techList;
491   LOGD("Get Secure element Type function ");
492
493   if(handle == secureElementHandle)
494   {
495      techList = e->NewIntArray(1);
496      e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech);
497      return techList;
498   }
499   else
500   {
501      return NULL;
502   }
503}
504
505
506/*
507 * JNI registration.
508 */
509static JNINativeMethod gMethods[] =
510{
511   {"doOpenSecureElementConnection", "()I",
512      (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection},
513   {"doDisconnect", "(I)Z",
514      (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect},
515   {"doTransceive", "(I[B)[B",
516      (void *)com_android_nfc_NativeNfcSecureElement_doTransceive},
517   {"doGetUid", "(I)[B",
518      (void *)com_android_nfc_NativeNfcSecureElement_doGetUid},
519   {"doGetTechList", "(I)[I",
520      (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList},
521};
522
523int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e)
524{
525   if(sem_init(&com_android_nfc_jni_secure_element_sem, 0, 0) == -1)
526      return -1;
527
528   return jniRegisterNativeMethods(e,
529      "com/android/nfc/NativeNfcSecureElement",
530      gMethods, NELEM(gMethods));
531}
532
533} // namespace android
534