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(®istry_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