1 /*
2 * Copyright (C) 2012 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 <android-base/stringprintf.h>
18 #include <base/logging.h>
19 #include <errno.h>
20 #include <malloc.h>
21 #include <nativehelper/ScopedLocalRef.h>
22 #include <nativehelper/ScopedPrimitiveArray.h>
23 #include <semaphore.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <time.h>
27 #include <string>
28 #include "IntervalTimer.h"
29 #include "JavaClassConstants.h"
30 #include "Mutex.h"
31 #include "NfcJniUtil.h"
32 #include "NfcTag.h"
33
34 #include "ndef_utils.h"
35 #include "nfa_api.h"
36 #include "nfa_rw_api.h"
37 #include "nfc_brcm_defs.h"
38 #include "phNxpExtns.h"
39 #include "rw_api.h"
40
41 using android::base::StringPrintf;
42
43 namespace android {
44 extern nfc_jni_native_data* getNative(JNIEnv* e, jobject o);
45 extern bool nfcManager_isNfcActive();
46 } // namespace android
47
48 extern bool gActivated;
49 extern SyncEvent gDeactivatedEvent;
50 extern bool nfc_debug_enabled;
51 extern bool legacy_mfc_reader;
52
53 /*****************************************************************************
54 **
55 ** public variables and functions
56 **
57 *****************************************************************************/
58 namespace android {
59 bool gIsTagDeactivating = false; // flag for nfa callback indicating we are
60 // deactivating for RF interface switch
61 bool gIsSelectingRfInterface =
62 false; // flag for nfa callback indicating we are
63 // selecting for RF interface switch
64 } // namespace android
65
66 /*****************************************************************************
67 **
68 ** private variables and functions
69 **
70 *****************************************************************************/
71 namespace android {
72
73 // Pre-defined tag type values. These must match the values in
74 // framework Ndef.java for Google public NFC API.
75 #define NDEF_UNKNOWN_TYPE (-1)
76 #define NDEF_TYPE1_TAG 1
77 #define NDEF_TYPE2_TAG 2
78 #define NDEF_TYPE3_TAG 3
79 #define NDEF_TYPE4_TAG 4
80 #define NDEF_MIFARE_CLASSIC_TAG 101
81
82 #define STATUS_CODE_TARGET_LOST 146 // this error code comes from the service
83
84 static uint32_t sCheckNdefCurrentSize = 0;
85 static tNFA_STATUS sCheckNdefStatus =
86 0; // whether tag already contains a NDEF message
87 static bool sCheckNdefCapable = false; // whether tag has NDEF capability
88 static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
89 static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP;
90 static tNFA_INTF_TYPE sCurrentActivatedProtocl = NFA_INTERFACE_ISO_DEP;
91 static std::basic_string<uint8_t> sRxDataBuffer;
92 static tNFA_STATUS sRxDataStatus = NFA_STATUS_OK;
93 static bool sWaitingForTransceive = false;
94 static bool sTransceiveRfTimeout = false;
95 static Mutex sRfInterfaceMutex;
96 static uint32_t sReadDataLen = 0;
97 static uint8_t* sReadData = NULL;
98 static bool sIsReadingNdefMessage = false;
99 static SyncEvent sReadEvent;
100 static sem_t sWriteSem;
101 static sem_t sFormatSem;
102 static SyncEvent sTransceiveEvent;
103 static SyncEvent sReconnectEvent;
104 static sem_t sCheckNdefSem;
105 static SyncEvent sPresenceCheckEvent;
106 static sem_t sMakeReadonlySem;
107 static IntervalTimer sSwitchBackTimer; // timer used to tell us to switch back
108 // to ISO_DEP frame interface
109 uint8_t RW_TAG_SLP_REQ[] = {0x50, 0x00};
110 uint8_t RW_DESELECT_REQ[] = {0xC2};
111 static jboolean sWriteOk = JNI_FALSE;
112 static jboolean sWriteWaitingForComplete = JNI_FALSE;
113 static bool sFormatOk = false;
114 static jboolean sConnectOk = JNI_FALSE;
115 static jboolean sConnectWaitingForComplete = JNI_FALSE;
116 static bool sGotDeactivate = false;
117 static uint32_t sCheckNdefMaxSize = 0;
118 static bool sCheckNdefCardReadOnly = false;
119 static jboolean sCheckNdefWaitingForComplete = JNI_FALSE;
120 static bool sIsTagPresent = true;
121 static tNFA_STATUS sMakeReadonlyStatus = NFA_STATUS_FAILED;
122 static jboolean sMakeReadonlyWaitingForComplete = JNI_FALSE;
123 static int sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN;
124 static int sCurrentConnectedTargetProtocol = NFC_PROTOCOL_UNKNOWN;
125 static int sCurrentConnectedHandle = 0;
126 static int reSelect(tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded);
127 static bool switchRfInterface(tNFA_INTF_TYPE rfInterface);
128
129 /*******************************************************************************
130 **
131 ** Function: nativeNfcTag_abortWaits
132 **
133 ** Description: Unblock all thread synchronization objects.
134 **
135 ** Returns: None
136 **
137 *******************************************************************************/
nativeNfcTag_abortWaits()138 void nativeNfcTag_abortWaits() {
139 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
140 {
141 SyncEventGuard g(sReadEvent);
142 sReadEvent.notifyOne();
143 }
144 sem_post(&sWriteSem);
145 sem_post(&sFormatSem);
146 {
147 SyncEventGuard g(sTransceiveEvent);
148 sTransceiveEvent.notifyOne();
149 }
150 {
151 SyncEventGuard g(sReconnectEvent);
152 sReconnectEvent.notifyOne();
153 }
154
155 sem_post(&sCheckNdefSem);
156 {
157 SyncEventGuard guard(sPresenceCheckEvent);
158 sPresenceCheckEvent.notifyOne();
159 }
160 sem_post(&sMakeReadonlySem);
161 sCurrentRfInterface = NFA_INTERFACE_ISO_DEP;
162 sCurrentActivatedProtocl = NFA_INTERFACE_ISO_DEP;
163 sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN;
164 sCurrentConnectedTargetProtocol = NFC_PROTOCOL_UNKNOWN;
165 }
166
167 /*******************************************************************************
168 **
169 ** Function: nativeNfcTag_doReadCompleted
170 **
171 ** Description: Receive the completion status of read operation. Called by
172 ** NFA_READ_CPLT_EVT.
173 ** status: Status of operation.
174 **
175 ** Returns: None
176 **
177 *******************************************************************************/
nativeNfcTag_doReadCompleted(tNFA_STATUS status)178 void nativeNfcTag_doReadCompleted(tNFA_STATUS status) {
179 DLOG_IF(INFO, nfc_debug_enabled)
180 << StringPrintf("%s: status=0x%X; is reading=%u", __func__, status,
181 sIsReadingNdefMessage);
182
183 if (sIsReadingNdefMessage == false)
184 return; // not reading NDEF message right now, so just return
185
186 if (status != NFA_STATUS_OK) {
187 sReadDataLen = 0;
188 if (sReadData) free(sReadData);
189 sReadData = NULL;
190 }
191 SyncEventGuard g(sReadEvent);
192 sReadEvent.notifyOne();
193 }
194
195 /*******************************************************************************
196 **
197 ** Function: nativeNfcTag_setRfInterface
198 **
199 ** Description: Set rf interface.
200 **
201 ** Returns: void
202 **
203 *******************************************************************************/
nativeNfcTag_setRfInterface(tNFA_INTF_TYPE rfInterface)204 void nativeNfcTag_setRfInterface(tNFA_INTF_TYPE rfInterface) {
205 sCurrentRfInterface = rfInterface;
206 }
207
208 /*******************************************************************************
209 **
210 ** Function: nativeNfcTag_setActivatedRfProtocol
211 **
212 ** Description: Set rf Activated Protocol.
213 **
214 ** Returns: void
215 **
216 *******************************************************************************/
nativeNfcTag_setActivatedRfProtocol(tNFA_INTF_TYPE rfProtocol)217 void nativeNfcTag_setActivatedRfProtocol(tNFA_INTF_TYPE rfProtocol) {
218 sCurrentActivatedProtocl = rfProtocol;
219 }
220
221 /*******************************************************************************
222 **
223 ** Function: ndefHandlerCallback
224 **
225 ** Description: Receive NDEF-message related events from stack.
226 ** event: Event code.
227 ** p_data: Event data.
228 **
229 ** Returns: None
230 **
231 *******************************************************************************/
ndefHandlerCallback(tNFA_NDEF_EVT event,tNFA_NDEF_EVT_DATA * eventData)232 static void ndefHandlerCallback(tNFA_NDEF_EVT event,
233 tNFA_NDEF_EVT_DATA* eventData) {
234 DLOG_IF(INFO, nfc_debug_enabled)
235 << StringPrintf("%s: event=%u, eventData=%p", __func__, event, eventData);
236
237 switch (event) {
238 case NFA_NDEF_REGISTER_EVT: {
239 tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg;
240 DLOG_IF(INFO, nfc_debug_enabled)
241 << StringPrintf("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X",
242 __func__, ndef_reg.status, ndef_reg.ndef_type_handle);
243 sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle;
244 } break;
245
246 case NFA_NDEF_DATA_EVT: {
247 DLOG_IF(INFO, nfc_debug_enabled)
248 << StringPrintf("%s: NFA_NDEF_DATA_EVT; data_len = %u", __func__,
249 eventData->ndef_data.len);
250 sReadDataLen = eventData->ndef_data.len;
251 sReadData = (uint8_t*)malloc(sReadDataLen);
252 memcpy(sReadData, eventData->ndef_data.p_data, eventData->ndef_data.len);
253 } break;
254
255 default:
256 LOG(ERROR) << StringPrintf("%s: Unknown event %u ????", __func__, event);
257 break;
258 }
259 }
260
261 /*******************************************************************************
262 **
263 ** Function: nativeNfcTag_doRead
264 **
265 ** Description: Read the NDEF message on the tag.
266 ** e: JVM environment.
267 ** o: Java object.
268 **
269 ** Returns: NDEF message.
270 **
271 *******************************************************************************/
nativeNfcTag_doRead(JNIEnv * e,jobject)272 static jbyteArray nativeNfcTag_doRead(JNIEnv* e, jobject) {
273 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
274 tNFA_STATUS status = NFA_STATUS_FAILED;
275 jbyteArray buf = NULL;
276
277 sReadDataLen = 0;
278 if (sReadData != NULL) {
279 free(sReadData);
280 sReadData = NULL;
281 }
282
283 if (sCheckNdefCurrentSize > 0) {
284 {
285 SyncEventGuard g(sReadEvent);
286 sIsReadingNdefMessage = true;
287 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
288 status = EXTNS_MfcReadNDef();
289 } else {
290 status = NFA_RwReadNDef();
291 }
292 sReadEvent.wait(); // wait for NFA_READ_CPLT_EVT
293 }
294 sIsReadingNdefMessage = false;
295
296 if (sReadDataLen > 0) // if stack actually read data from the tag
297 {
298 DLOG_IF(INFO, nfc_debug_enabled)
299 << StringPrintf("%s: read %u bytes", __func__, sReadDataLen);
300 buf = e->NewByteArray(sReadDataLen);
301 e->SetByteArrayRegion(buf, 0, sReadDataLen, (jbyte*)sReadData);
302 }
303 } else {
304 DLOG_IF(INFO, nfc_debug_enabled)
305 << StringPrintf("%s: create empty buffer", __func__);
306 sReadDataLen = 0;
307 sReadData = (uint8_t*)malloc(1);
308 buf = e->NewByteArray(sReadDataLen);
309 e->SetByteArrayRegion(buf, 0, sReadDataLen, (jbyte*)sReadData);
310 }
311
312 if (sReadData) {
313 free(sReadData);
314 sReadData = NULL;
315 }
316 sReadDataLen = 0;
317
318 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
319 return buf;
320 }
321
322 /*******************************************************************************
323 **
324 ** Function: nativeNfcTag_doWriteStatus
325 **
326 ** Description: Receive the completion status of write operation. Called
327 ** by NFA_WRITE_CPLT_EVT.
328 ** isWriteOk: Status of operation.
329 **
330 ** Returns: None
331 **
332 *******************************************************************************/
nativeNfcTag_doWriteStatus(jboolean isWriteOk)333 void nativeNfcTag_doWriteStatus(jboolean isWriteOk) {
334 if (sWriteWaitingForComplete != JNI_FALSE) {
335 sWriteWaitingForComplete = JNI_FALSE;
336 sWriteOk = isWriteOk;
337 sem_post(&sWriteSem);
338 }
339 }
340
341 /*******************************************************************************
342 **
343 ** Function: nativeNfcTag_formatStatus
344 **
345 ** Description: Receive the completion status of format operation. Called
346 ** by NFA_FORMAT_CPLT_EVT.
347 ** isOk: Status of operation.
348 **
349 ** Returns: None
350 **
351 *******************************************************************************/
nativeNfcTag_formatStatus(bool isOk)352 void nativeNfcTag_formatStatus(bool isOk) {
353 sFormatOk = isOk;
354 sem_post(&sFormatSem);
355 }
356
357 /*******************************************************************************
358 **
359 ** Function: nativeNfcTag_doWrite
360 **
361 ** Description: Write a NDEF message to the tag.
362 ** e: JVM environment.
363 ** o: Java object.
364 ** buf: Contains a NDEF message.
365 **
366 ** Returns: True if ok.
367 **
368 *******************************************************************************/
nativeNfcTag_doWrite(JNIEnv * e,jobject,jbyteArray buf)369 static jboolean nativeNfcTag_doWrite(JNIEnv* e, jobject, jbyteArray buf) {
370 jboolean result = JNI_FALSE;
371 tNFA_STATUS status = 0;
372 const int maxBufferSize = 1024;
373 uint8_t buffer[maxBufferSize] = {0};
374 uint32_t curDataSize = 0;
375
376 ScopedByteArrayRO bytes(e, buf);
377 uint8_t* p_data = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(
378 &bytes[0])); // TODO: const-ness API bug in NFA_RwWriteNDef!
379
380 DLOG_IF(INFO, nfc_debug_enabled)
381 << StringPrintf("%s: enter; len = %zu", __func__, bytes.size());
382
383 /* Create the write semaphore */
384 if (sem_init(&sWriteSem, 0, 0) == -1) {
385 LOG(ERROR) << StringPrintf("%s: semaphore creation failed (errno=0x%08x)",
386 __func__, errno);
387 return JNI_FALSE;
388 }
389
390 sWriteWaitingForComplete = JNI_TRUE;
391 if (sCheckNdefStatus == NFA_STATUS_FAILED) {
392 // if tag does not contain a NDEF message
393 // and tag is capable of storing NDEF message
394 if (sCheckNdefCapable) {
395 DLOG_IF(INFO, nfc_debug_enabled)
396 << StringPrintf("%s: try format", __func__);
397 sem_init(&sFormatSem, 0, 0);
398 sFormatOk = false;
399 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
400 static uint8_t mfc_key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
401 static uint8_t mfc_key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
402
403 status = EXTNS_MfcFormatTag(mfc_key1, sizeof(mfc_key1));
404 if (status != NFA_STATUS_OK) {
405 LOG(ERROR) << StringPrintf("%s: can't format mifare classic tag",
406 __func__);
407 sem_destroy(&sFormatSem);
408 goto TheEnd;
409 }
410
411 if (sFormatOk == false) // if format operation failed
412 {
413 sem_wait(&sFormatSem);
414 sem_destroy(&sFormatSem);
415 sem_init(&sFormatSem, 0, 0);
416 status = EXTNS_MfcFormatTag(mfc_key2, sizeof(mfc_key2));
417 if (status != NFA_STATUS_OK) {
418 LOG(ERROR) << StringPrintf("%s: can't format mifare classic tag",
419 __func__);
420 sem_destroy(&sFormatSem);
421 goto TheEnd;
422 }
423 }
424 } else {
425 status = NFA_RwFormatTag();
426 if (status != NFA_STATUS_OK) {
427 LOG(ERROR) << StringPrintf("%s: can't format mifare classic tag",
428 __func__);
429 sem_destroy(&sFormatSem);
430 goto TheEnd;
431 }
432 }
433 sem_wait(&sFormatSem);
434 sem_destroy(&sFormatSem);
435 if (sFormatOk == false) // if format operation failed
436 goto TheEnd;
437 }
438 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: try write", __func__);
439 status = NFA_RwWriteNDef(p_data, bytes.size());
440 } else if (bytes.size() == 0) {
441 // if (NXP TagWriter wants to erase tag) then create and write an empty ndef
442 // message
443 NDEF_MsgInit(buffer, maxBufferSize, &curDataSize);
444 status = NDEF_MsgAddRec(buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY,
445 NULL, 0, NULL, 0, NULL, 0);
446 DLOG_IF(INFO, nfc_debug_enabled)
447 << StringPrintf("%s: create empty ndef msg; status=%u; size=%u",
448 __func__, status, curDataSize);
449 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
450 status = EXTNS_MfcWriteNDef(buffer, curDataSize);
451 } else {
452 status = NFA_RwWriteNDef(buffer, curDataSize);
453 }
454 } else {
455 DLOG_IF(INFO, nfc_debug_enabled)
456 << StringPrintf("%s: NFA_RwWriteNDef", __func__);
457 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
458 status = EXTNS_MfcWriteNDef(p_data, bytes.size());
459 } else {
460 status = NFA_RwWriteNDef(p_data, bytes.size());
461 }
462 }
463
464 if (status != NFA_STATUS_OK) {
465 LOG(ERROR) << StringPrintf("%s: write/format error=%d", __func__, status);
466 goto TheEnd;
467 }
468
469 /* Wait for write completion status */
470 sWriteOk = false;
471 if (sem_wait(&sWriteSem)) {
472 LOG(ERROR) << StringPrintf("%s: wait semaphore (errno=0x%08x)", __func__,
473 errno);
474 goto TheEnd;
475 }
476
477 result = sWriteOk;
478
479 TheEnd:
480 /* Destroy semaphore */
481 if (sem_destroy(&sWriteSem)) {
482 LOG(ERROR) << StringPrintf("%s: failed destroy semaphore (errno=0x%08x)",
483 __func__, errno);
484 }
485 sWriteWaitingForComplete = JNI_FALSE;
486 DLOG_IF(INFO, nfc_debug_enabled)
487 << StringPrintf("%s: exit; result=%d", __func__, result);
488 return result;
489 }
490
491 /*******************************************************************************
492 **
493 ** Function: nativeNfcTag_doConnectStatus
494 **
495 ** Description: Receive the completion status of connect operation.
496 ** isConnectOk: Status of the operation.
497 **
498 ** Returns: None
499 **
500 *******************************************************************************/
nativeNfcTag_doConnectStatus(jboolean isConnectOk)501 void nativeNfcTag_doConnectStatus(jboolean isConnectOk) {
502 if (EXTNS_GetConnectFlag() == TRUE && legacy_mfc_reader) {
503 EXTNS_MfcActivated();
504 EXTNS_SetConnectFlag(FALSE);
505 return;
506 }
507
508 if (sConnectWaitingForComplete != JNI_FALSE) {
509 sConnectWaitingForComplete = JNI_FALSE;
510 sConnectOk = isConnectOk;
511 SyncEventGuard g(sReconnectEvent);
512 sReconnectEvent.notifyOne();
513 }
514 }
515
516 /*******************************************************************************
517 **
518 ** Function: nativeNfcTag_doDeactivateStatus
519 **
520 ** Description: Receive the completion status of deactivate operation.
521 **
522 ** Returns: None
523 **
524 *******************************************************************************/
nativeNfcTag_doDeactivateStatus(int status)525 void nativeNfcTag_doDeactivateStatus(int status) {
526 if (EXTNS_GetDeactivateFlag() == TRUE && legacy_mfc_reader) {
527 EXTNS_MfcDisconnect();
528 EXTNS_SetDeactivateFlag(FALSE);
529 return;
530 }
531
532 sGotDeactivate = (status == 0);
533
534 SyncEventGuard g(sReconnectEvent);
535 sReconnectEvent.notifyOne();
536 }
537
538 /*******************************************************************************
539 **
540 ** Function: nativeNfcTag_doConnect
541 **
542 ** Description: Connect to the tag in RF field.
543 ** e: JVM environment.
544 ** o: Java object.
545 ** targetHandle: Handle of the tag.
546 **
547 ** Returns: Must return NXP status code, which NFC service expects.
548 **
549 *******************************************************************************/
nativeNfcTag_doConnect(JNIEnv *,jobject,jint targetHandle)550 static jint nativeNfcTag_doConnect(JNIEnv*, jobject, jint targetHandle) {
551 DLOG_IF(INFO, nfc_debug_enabled)
552 << StringPrintf("%s: targetHandle = %d", __func__, targetHandle);
553 int i = targetHandle;
554 NfcTag& natTag = NfcTag::getInstance();
555 int retCode = NFCSTATUS_SUCCESS;
556
557 if (i >= NfcTag::MAX_NUM_TECHNOLOGY) {
558 LOG(ERROR) << StringPrintf("%s: Handle not found", __func__);
559 retCode = NFCSTATUS_FAILED;
560 goto TheEnd;
561 }
562
563 if (natTag.getActivationState() != NfcTag::Active) {
564 LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
565 retCode = NFCSTATUS_FAILED;
566 goto TheEnd;
567 }
568
569 sCurrentConnectedTargetType = natTag.mTechList[i];
570 sCurrentConnectedTargetProtocol = natTag.mTechLibNfcTypes[i];
571 sCurrentConnectedHandle = targetHandle;
572
573 if (sCurrentConnectedTargetProtocol != NFC_PROTOCOL_ISO_DEP &&
574 sCurrentConnectedTargetProtocol != NFC_PROTOCOL_MIFARE) {
575 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
576 "%s() Nfc type = %d, do nothing for non ISO_DEP and non Mifare ",
577 __func__, sCurrentConnectedTargetProtocol);
578 retCode = NFCSTATUS_SUCCESS;
579 goto TheEnd;
580 }
581
582 if (sCurrentConnectedTargetType == TARGET_TYPE_ISO14443_3A ||
583 sCurrentConnectedTargetType == TARGET_TYPE_ISO14443_3B) {
584 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
585 "%s: switching to tech: %d need to switch rf intf to frame", __func__,
586 sCurrentConnectedTargetType);
587 retCode = switchRfInterface(NFA_INTERFACE_FRAME) ? NFA_STATUS_OK
588 : NFA_STATUS_FAILED;
589 } else if (sCurrentConnectedTargetType == TARGET_TYPE_MIFARE_CLASSIC) {
590 retCode = switchRfInterface(NFA_INTERFACE_MIFARE) ? NFA_STATUS_OK
591 : NFA_STATUS_FAILED;
592 } else {
593 retCode = switchRfInterface(NFA_INTERFACE_ISO_DEP) ? NFA_STATUS_OK
594 : NFA_STATUS_FAILED;
595 }
596
597 TheEnd:
598 DLOG_IF(INFO, nfc_debug_enabled)
599 << StringPrintf("%s: exit 0x%X", __func__, retCode);
600 return retCode;
601 }
602
603 /*******************************************************************************
604 **
605 ** Function: reSelect
606 **
607 ** Description: Deactivates the tag and re-selects it with the specified
608 ** rf interface.
609 **
610 ** Returns: status code, 0 on success, 1 on failure,
611 ** 146 (defined in service) on tag lost
612 **
613 *******************************************************************************/
reSelect(tNFA_INTF_TYPE rfInterface,bool fSwitchIfNeeded)614 static int reSelect(tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded) {
615 DLOG_IF(INFO, nfc_debug_enabled)
616 << StringPrintf("%s: enter; rf intf = %d, current intf = %d", __func__,
617 rfInterface, sCurrentRfInterface);
618
619 sRfInterfaceMutex.lock();
620
621 if (fSwitchIfNeeded && (rfInterface == sCurrentRfInterface)) {
622 // already in the requested interface
623 sRfInterfaceMutex.unlock();
624 return 0; // success
625 }
626
627 NfcTag& natTag = NfcTag::getInstance();
628
629 tNFA_STATUS status = NFA_STATUS_OK;
630 int rVal = 1;
631
632 do {
633 // if tag has shutdown, abort this method
634 if (NfcTag::getInstance().isNdefDetectionTimedOut()) {
635 DLOG_IF(INFO, nfc_debug_enabled)
636 << StringPrintf("%s: ndef detection timeout; break", __func__);
637 rVal = STATUS_CODE_TARGET_LOST;
638 break;
639 }
640 if ((sCurrentRfInterface == NFA_INTERFACE_FRAME) &&
641 (NFC_GetNCIVersion() >= NCI_VERSION_2_0)) {
642 {
643 SyncEventGuard g3(sReconnectEvent);
644 if (sCurrentActivatedProtocl == NFA_PROTOCOL_T2T) {
645 status = NFA_SendRawFrame(RW_TAG_SLP_REQ, sizeof(RW_TAG_SLP_REQ), 0);
646 } else if (sCurrentActivatedProtocl == NFA_PROTOCOL_ISO_DEP) {
647 status = NFA_SendRawFrame(RW_DESELECT_REQ,
648 sizeof(RW_DESELECT_REQ), 0);
649 }
650 sReconnectEvent.wait(4);
651 if (status != NFA_STATUS_OK) {
652 LOG(ERROR) << StringPrintf("%s: send error=%d", __func__, status);
653 break;
654 }
655 }
656 }
657
658 {
659 SyncEventGuard g(sReconnectEvent);
660 gIsTagDeactivating = true;
661 sGotDeactivate = false;
662 DLOG_IF(INFO, nfc_debug_enabled)
663 << StringPrintf("%s: deactivate to sleep", __func__);
664 if (NFA_STATUS_OK !=
665 (status = NFA_Deactivate(TRUE))) // deactivate to sleep state
666 {
667 LOG(ERROR) << StringPrintf("%s: deactivate failed, status = %d",
668 __func__, status);
669 break;
670 }
671
672 if (sReconnectEvent.wait(1000) == false) // if timeout occurred
673 {
674 LOG(ERROR) << StringPrintf("%s: timeout waiting for deactivate",
675 __func__);
676 }
677 }
678
679 if (!sGotDeactivate) {
680 rVal = STATUS_CODE_TARGET_LOST;
681 break;
682 }
683
684 if (NfcTag::getInstance().getActivationState() != NfcTag::Sleep) {
685 LOG(ERROR) << StringPrintf("%s: tag is not in sleep", __func__);
686 rVal = STATUS_CODE_TARGET_LOST;
687 break;
688 }
689
690 gIsTagDeactivating = false;
691
692 {
693 SyncEventGuard g2(sReconnectEvent);
694
695 sConnectWaitingForComplete = JNI_TRUE;
696 DLOG_IF(INFO, nfc_debug_enabled)
697 << StringPrintf("%s: select interface %u", __func__, rfInterface);
698 gIsSelectingRfInterface = true;
699 if (NFA_STATUS_OK !=
700 (status = NFA_Select(natTag.mTechHandles[sCurrentConnectedHandle],
701 natTag.mTechLibNfcTypes[sCurrentConnectedHandle],
702 rfInterface))) {
703 LOG(ERROR) << StringPrintf("%s: NFA_Select failed, status = %d",
704 __func__, status);
705 break;
706 }
707
708 sConnectOk = false;
709 if (sReconnectEvent.wait(1000) == false) // if timeout occurred
710 {
711 LOG(ERROR) << StringPrintf("%s: timeout waiting for select", __func__);
712 break;
713 }
714 }
715
716 /*Retry logic in case of core Generic error while selecting a tag*/
717 if (sConnectOk == false) {
718 LOG(ERROR) << StringPrintf("%s: waiting for Card to be activated",
719 __func__);
720 int retry = 0;
721 sConnectWaitingForComplete = JNI_TRUE;
722 do {
723 SyncEventGuard reselectEvent(sReconnectEvent);
724 if (sReconnectEvent.wait(500) == false) { // if timeout occurred
725 LOG(ERROR) << StringPrintf("%s: timeout ", __func__);
726 }
727 retry++;
728 LOG(ERROR) << StringPrintf("%s: waiting for Card to be activated %x %x",
729 __func__, retry, sConnectOk);
730 } while (sConnectOk == false && retry < 3);
731 }
732
733 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
734 "%s: select completed; sConnectOk=%d", __func__, sConnectOk);
735 if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
736 LOG(ERROR) << StringPrintf("%s: tag is not active", __func__);
737 rVal = STATUS_CODE_TARGET_LOST;
738 break;
739 }
740 if (sConnectOk) {
741 rVal = 0; // success
742 sCurrentRfInterface = rfInterface;
743 } else {
744 rVal = 1;
745 }
746 } while (0);
747
748 sConnectWaitingForComplete = JNI_FALSE;
749 gIsTagDeactivating = false;
750 gIsSelectingRfInterface = false;
751 sRfInterfaceMutex.unlock();
752 DLOG_IF(INFO, nfc_debug_enabled)
753 << StringPrintf("%s: exit; status=%d", __func__, rVal);
754 return rVal;
755 }
756
757 /*******************************************************************************
758 **
759 ** Function: switchRfInterface
760 **
761 ** Description: Switch controller's RF interface to frame, ISO-DEP, or
762 *NFC-DEP.
763 ** rfInterface: Type of RF interface.
764 **
765 ** Returns: True if ok.
766 **
767 *******************************************************************************/
switchRfInterface(tNFA_INTF_TYPE rfInterface)768 static bool switchRfInterface(tNFA_INTF_TYPE rfInterface) {
769 NfcTag& natTag = NfcTag::getInstance();
770
771 if (sCurrentConnectedTargetProtocol != NFC_PROTOCOL_ISO_DEP &&
772 sCurrentConnectedTargetProtocol != NFC_PROTOCOL_MIFARE) {
773 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
774 "%s: protocol: %d not ISO_DEP and not Mifare, do nothing", __func__,
775 natTag.mTechLibNfcTypes[0]);
776 return true;
777 }
778
779 DLOG_IF(INFO, nfc_debug_enabled)
780 << StringPrintf("%s: new rf intf = %d, cur rf intf = %d", __func__,
781 rfInterface, sCurrentRfInterface);
782
783 return (0 == reSelect(rfInterface, true));
784 }
785
786 /*******************************************************************************
787 **
788 ** Function: nativeNfcTag_doReconnect
789 **
790 ** Description: Re-connect to the tag in RF field.
791 ** e: JVM environment.
792 ** o: Java object.
793 **
794 ** Returns: Status code.
795 **
796 *******************************************************************************/
nativeNfcTag_doReconnect(JNIEnv *,jobject)797 static jint nativeNfcTag_doReconnect(JNIEnv*, jobject) {
798 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
799 int retCode = NFCSTATUS_SUCCESS;
800 NfcTag& natTag = NfcTag::getInstance();
801
802 if (natTag.getActivationState() != NfcTag::Active) {
803 LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
804 retCode = NFCSTATUS_FAILED;
805 goto TheEnd;
806 }
807
808 // special case for Kovio
809 if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
810 DLOG_IF(INFO, nfc_debug_enabled)
811 << StringPrintf("%s: fake out reconnect for Kovio", __func__);
812 goto TheEnd;
813 }
814
815 // this is only supported for type 2 or 4 (ISO_DEP) tags
816 if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_ISO_DEP)
817 retCode = reSelect(NFA_INTERFACE_ISO_DEP, false);
818 else if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_T2T)
819 retCode = reSelect(NFA_INTERFACE_FRAME, false);
820 else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE)
821 retCode = reSelect(NFA_INTERFACE_MIFARE, false);
822
823 TheEnd:
824 DLOG_IF(INFO, nfc_debug_enabled)
825 << StringPrintf("%s: exit 0x%X", __func__, retCode);
826 return retCode;
827 }
828
829 /*******************************************************************************
830 **
831 ** Function: nativeNfcTag_doHandleReconnect
832 **
833 ** Description: Re-connect to the tag in RF field.
834 ** e: JVM environment.
835 ** o: Java object.
836 ** targetHandle: Handle of the tag.
837 **
838 ** Returns: Status code.
839 **
840 *******************************************************************************/
nativeNfcTag_doHandleReconnect(JNIEnv * e,jobject o,jint targetHandle)841 static jint nativeNfcTag_doHandleReconnect(JNIEnv* e, jobject o,
842 jint targetHandle) {
843 DLOG_IF(INFO, nfc_debug_enabled)
844 << StringPrintf("%s: targetHandle = %d", __func__, targetHandle);
845 return nativeNfcTag_doConnect(e, o, targetHandle);
846 }
847
848 /*******************************************************************************
849 **
850 ** Function: nativeNfcTag_doDisconnect
851 **
852 ** Description: Deactivate the RF field.
853 ** e: JVM environment.
854 ** o: Java object.
855 **
856 ** Returns: True if ok.
857 **
858 *******************************************************************************/
nativeNfcTag_doDisconnect(JNIEnv *,jobject)859 jboolean nativeNfcTag_doDisconnect(JNIEnv*, jobject) {
860 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
861 tNFA_STATUS nfaStat = NFA_STATUS_OK;
862
863 NfcTag::getInstance().resetAllTransceiveTimeouts();
864
865 if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
866 LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
867 goto TheEnd;
868 }
869
870 nfaStat = NFA_Deactivate(FALSE);
871 if (nfaStat != NFA_STATUS_OK)
872 LOG(ERROR) << StringPrintf("%s: deactivate failed; error=0x%X", __func__,
873 nfaStat);
874
875 TheEnd:
876 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
877 return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
878 }
879
880 /*******************************************************************************
881 **
882 ** Function: nativeNfcTag_doTransceiveStatus
883 **
884 ** Description: Receive the completion status of transceive operation.
885 ** status: operation status.
886 ** buf: Contains tag's response.
887 ** bufLen: Length of buffer.
888 **
889 ** Returns: None
890 **
891 *******************************************************************************/
nativeNfcTag_doTransceiveStatus(tNFA_STATUS status,uint8_t * buf,uint32_t bufLen)892 void nativeNfcTag_doTransceiveStatus(tNFA_STATUS status, uint8_t* buf,
893 uint32_t bufLen) {
894 SyncEventGuard g(sTransceiveEvent);
895 DLOG_IF(INFO, nfc_debug_enabled)
896 << StringPrintf("%s: data len=%d", __func__, bufLen);
897
898 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
899 if (EXTNS_GetCallBackFlag() == FALSE) {
900 EXTNS_MfcCallBack(buf, bufLen);
901 return;
902 }
903 }
904
905 if (!sWaitingForTransceive) {
906 LOG(ERROR) << StringPrintf("%s: drop data", __func__);
907 return;
908 }
909 sRxDataStatus = status;
910 if (sRxDataStatus == NFA_STATUS_OK || sRxDataStatus == NFC_STATUS_CONTINUE)
911 sRxDataBuffer.append(buf, bufLen);
912
913 if (sRxDataStatus == NFA_STATUS_OK) sTransceiveEvent.notifyOne();
914 }
915
nativeNfcTag_notifyRfTimeout()916 void nativeNfcTag_notifyRfTimeout() {
917 SyncEventGuard g(sTransceiveEvent);
918 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
919 "%s: waiting for transceive: %d", __func__, sWaitingForTransceive);
920 if (!sWaitingForTransceive) return;
921
922 sTransceiveRfTimeout = true;
923
924 sTransceiveEvent.notifyOne();
925 }
926
927 /*******************************************************************************
928 **
929 ** Function: nativeNfcTag_doTransceive
930 **
931 ** Description: Send raw data to the tag; receive tag's response.
932 ** e: JVM environment.
933 ** o: Java object.
934 ** raw: Not used.
935 ** statusTargetLost: Whether tag responds or times out.
936 **
937 ** Returns: Response from tag.
938 **
939 *******************************************************************************/
nativeNfcTag_doTransceive(JNIEnv * e,jobject o,jbyteArray data,jboolean raw,jintArray statusTargetLost)940 static jbyteArray nativeNfcTag_doTransceive(JNIEnv* e, jobject o,
941 jbyteArray data, jboolean raw,
942 jintArray statusTargetLost) {
943 int timeout =
944 NfcTag::getInstance().getTransceiveTimeout(sCurrentConnectedTargetType);
945 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
946 "%s: enter; raw=%u; timeout = %d", __func__, raw, timeout);
947
948 bool waitOk = false;
949 bool isNack = false;
950 jint* targetLost = NULL;
951 tNFA_STATUS status;
952
953 if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
954 if (statusTargetLost) {
955 targetLost = e->GetIntArrayElements(statusTargetLost, 0);
956 if (targetLost)
957 *targetLost = 1; // causes NFC service to throw TagLostException
958 e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0);
959 }
960 DLOG_IF(INFO, nfc_debug_enabled)
961 << StringPrintf("%s: tag not active", __func__);
962 return NULL;
963 }
964
965 NfcTag& natTag = NfcTag::getInstance();
966
967 // get input buffer and length from java call
968 ScopedByteArrayRO bytes(e, data);
969 uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(
970 &bytes[0])); // TODO: API bug; NFA_SendRawFrame should take const*!
971 size_t bufLen = bytes.size();
972
973 if (statusTargetLost) {
974 targetLost = e->GetIntArrayElements(statusTargetLost, 0);
975 if (targetLost) *targetLost = 0; // success, tag is still present
976 }
977
978 sSwitchBackTimer.kill();
979 ScopedLocalRef<jbyteArray> result(e, NULL);
980 do {
981 {
982 SyncEventGuard g(sTransceiveEvent);
983 sTransceiveRfTimeout = false;
984 sWaitingForTransceive = true;
985 sRxDataStatus = NFA_STATUS_OK;
986 sRxDataBuffer.clear();
987
988 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
989 status = EXTNS_MfcTransceive(buf, bufLen);
990 } else {
991 status = NFA_SendRawFrame(buf, bufLen,
992 NFA_DM_DEFAULT_PRESENCE_CHECK_START_DELAY);
993 }
994
995 if (status != NFA_STATUS_OK) {
996 LOG(ERROR) << StringPrintf("%s: fail send; error=%d", __func__, status);
997 break;
998 }
999 waitOk = sTransceiveEvent.wait(timeout);
1000 }
1001
1002 if (waitOk == false || sTransceiveRfTimeout) // if timeout occurred
1003 {
1004 LOG(ERROR) << StringPrintf("%s: wait response timeout", __func__);
1005 if (targetLost)
1006 *targetLost = 1; // causes NFC service to throw TagLostException
1007 break;
1008 }
1009
1010 if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
1011 LOG(ERROR) << StringPrintf("%s: already deactivated", __func__);
1012 if (targetLost)
1013 *targetLost = 1; // causes NFC service to throw TagLostException
1014 break;
1015 }
1016
1017 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1018 "%s: response %zu bytes", __func__, sRxDataBuffer.size());
1019
1020 if ((natTag.getProtocol() == NFA_PROTOCOL_T2T) &&
1021 natTag.isT2tNackResponse(sRxDataBuffer.data(), sRxDataBuffer.size())) {
1022 isNack = true;
1023 }
1024
1025 if (sRxDataBuffer.size() > 0) {
1026 if (isNack) {
1027 // Some Mifare Ultralight C tags enter the HALT state after it
1028 // responds with a NACK. Need to perform a "reconnect" operation
1029 // to wake it.
1030 DLOG_IF(INFO, nfc_debug_enabled)
1031 << StringPrintf("%s: try reconnect", __func__);
1032 nativeNfcTag_doReconnect(NULL, NULL);
1033 DLOG_IF(INFO, nfc_debug_enabled)
1034 << StringPrintf("%s: reconnect finish", __func__);
1035 } else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1036 uint32_t transDataLen = sRxDataBuffer.size();
1037 uint8_t* transData = (uint8_t*)sRxDataBuffer.data();
1038 bool doReconnect = false;
1039
1040 if (legacy_mfc_reader) {
1041 doReconnect = (EXTNS_CheckMfcResponse(&transData, &transDataLen) ==
1042 NFCSTATUS_FAILED) ? true : false;
1043 } else {
1044 doReconnect =
1045 ((transDataLen == 1) && (transData[0] != 0x00)) ? true : false;
1046 }
1047
1048 if (doReconnect) {
1049 nativeNfcTag_doReconnect(e, o);
1050 } else {
1051 if (transDataLen != 0) {
1052 result.reset(e->NewByteArray(transDataLen));
1053 if (result.get() != NULL) {
1054 e->SetByteArrayRegion(result.get(), 0, transDataLen,
1055 (const jbyte*)transData);
1056 } else
1057 LOG(ERROR) << StringPrintf("%s: Failed to allocate java byte array",
1058 __func__);
1059 }
1060 }
1061 } else {
1062 // marshall data to java for return
1063 result.reset(e->NewByteArray(sRxDataBuffer.size()));
1064 if (result.get() != NULL) {
1065 e->SetByteArrayRegion(result.get(), 0, sRxDataBuffer.size(),
1066 (const jbyte*)sRxDataBuffer.data());
1067 } else
1068 LOG(ERROR) << StringPrintf("%s: Failed to allocate java byte array",
1069 __func__);
1070 } // else a nack is treated as a transceive failure to the upper layers
1071
1072 sRxDataBuffer.clear();
1073 }
1074 } while (0);
1075
1076 sWaitingForTransceive = false;
1077 if (targetLost) e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0);
1078
1079 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1080 return result.release();
1081 }
1082
1083 /*******************************************************************************
1084 **
1085 ** Function: nativeNfcTag_doGetNdefType
1086 **
1087 ** Description: Retrieve the type of tag.
1088 ** e: JVM environment.
1089 ** o: Java object.
1090 ** libnfcType: Type of tag represented by JNI.
1091 ** javaType: Not used.
1092 **
1093 ** Returns: Type of tag represented by NFC Service.
1094 **
1095 *******************************************************************************/
nativeNfcTag_doGetNdefType(JNIEnv *,jobject,jint libnfcType,jint javaType)1096 static jint nativeNfcTag_doGetNdefType(JNIEnv*, jobject, jint libnfcType,
1097 jint javaType) {
1098 DLOG_IF(INFO, nfc_debug_enabled)
1099 << StringPrintf("%s: enter; libnfc type=%d; java type=%d", __func__,
1100 libnfcType, javaType);
1101 jint ndefType = NDEF_UNKNOWN_TYPE;
1102
1103 // For NFA, libnfcType is mapped to the protocol value received
1104 // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event.
1105 if (NFA_PROTOCOL_T1T == libnfcType) {
1106 ndefType = NDEF_TYPE1_TAG;
1107 } else if (NFA_PROTOCOL_T2T == libnfcType) {
1108 ndefType = NDEF_TYPE2_TAG;
1109 } else if (NFA_PROTOCOL_T3T == libnfcType) {
1110 ndefType = NDEF_TYPE3_TAG;
1111 } else if (NFA_PROTOCOL_ISO_DEP == libnfcType) {
1112 ndefType = NDEF_TYPE4_TAG;
1113 } else if (NFC_PROTOCOL_MIFARE == libnfcType) {
1114 ndefType = NDEF_MIFARE_CLASSIC_TAG;
1115 } else {
1116 /* NFA_PROTOCOL_T5T, NFA_PROTOCOL_INVALID and others */
1117 ndefType = NDEF_UNKNOWN_TYPE;
1118 }
1119 DLOG_IF(INFO, nfc_debug_enabled)
1120 << StringPrintf("%s: exit; ndef type=%d", __func__, ndefType);
1121 return ndefType;
1122 }
1123
1124 /*******************************************************************************
1125 **
1126 ** Function: nativeNfcTag_doCheckNdefResult
1127 **
1128 ** Description: Receive the result of checking whether the tag contains a
1129 *NDEF
1130 ** message. Called by the NFA_NDEF_DETECT_EVT.
1131 ** status: Status of the operation.
1132 ** maxSize: Maximum size of NDEF message.
1133 ** currentSize: Current size of NDEF message.
1134 ** flags: Indicate various states.
1135 **
1136 ** Returns: None
1137 **
1138 *******************************************************************************/
nativeNfcTag_doCheckNdefResult(tNFA_STATUS status,uint32_t maxSize,uint32_t currentSize,uint8_t flags)1139 void nativeNfcTag_doCheckNdefResult(tNFA_STATUS status, uint32_t maxSize,
1140 uint32_t currentSize, uint8_t flags) {
1141 // this function's flags parameter is defined using the following macros
1142 // in nfc/include/rw_api.h;
1143 //#define RW_NDEF_FL_READ_ONLY 0x01 /* Tag is read only */
1144 //#define RW_NDEF_FL_FORMATED 0x02 /* Tag formated for NDEF */
1145 //#define RW_NDEF_FL_SUPPORTED 0x04 /* NDEF supported by the tag */
1146 //#define RW_NDEF_FL_UNKNOWN 0x08 /* Unable to find if tag is ndef
1147 // capable/formated/read only */ #define RW_NDEF_FL_FORMATABLE 0x10 /* Tag
1148 // supports format operation */
1149
1150 if (!sCheckNdefWaitingForComplete) {
1151 LOG(ERROR) << StringPrintf("%s: not waiting", __func__);
1152 return;
1153 }
1154
1155 if (flags & RW_NDEF_FL_READ_ONLY)
1156 DLOG_IF(INFO, nfc_debug_enabled)
1157 << StringPrintf("%s: flag read-only", __func__);
1158 if (flags & RW_NDEF_FL_FORMATED)
1159 DLOG_IF(INFO, nfc_debug_enabled)
1160 << StringPrintf("%s: flag formatted for ndef", __func__);
1161 if (flags & RW_NDEF_FL_SUPPORTED)
1162 DLOG_IF(INFO, nfc_debug_enabled)
1163 << StringPrintf("%s: flag ndef supported", __func__);
1164 if (flags & RW_NDEF_FL_UNKNOWN)
1165 DLOG_IF(INFO, nfc_debug_enabled)
1166 << StringPrintf("%s: flag all unknown", __func__);
1167 if (flags & RW_NDEF_FL_FORMATABLE)
1168 DLOG_IF(INFO, nfc_debug_enabled)
1169 << StringPrintf("%s: flag formattable", __func__);
1170
1171 sCheckNdefWaitingForComplete = JNI_FALSE;
1172 sCheckNdefStatus = status;
1173 if (sCheckNdefStatus != NFA_STATUS_OK &&
1174 sCheckNdefStatus != NFA_STATUS_TIMEOUT)
1175 sCheckNdefStatus = NFA_STATUS_FAILED;
1176 sCheckNdefCapable = false; // assume tag is NOT ndef capable
1177 if (sCheckNdefStatus == NFA_STATUS_OK) {
1178 // NDEF content is on the tag
1179 sCheckNdefMaxSize = maxSize;
1180 sCheckNdefCurrentSize = currentSize;
1181 sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1182 sCheckNdefCapable = true;
1183 } else if (sCheckNdefStatus == NFA_STATUS_FAILED) {
1184 // no NDEF content on the tag
1185 sCheckNdefMaxSize = 0;
1186 sCheckNdefCurrentSize = 0;
1187 sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1188 if ((flags & RW_NDEF_FL_UNKNOWN) == 0) // if stack understands the tag
1189 {
1190 if (flags & RW_NDEF_FL_SUPPORTED) // if tag is ndef capable
1191 sCheckNdefCapable = true;
1192 }
1193 } else {
1194 LOG(ERROR) << StringPrintf("%s: unknown status=0x%X", __func__, status);
1195 sCheckNdefMaxSize = 0;
1196 sCheckNdefCurrentSize = 0;
1197 sCheckNdefCardReadOnly = false;
1198 }
1199 sem_post(&sCheckNdefSem);
1200 }
1201
1202 /*******************************************************************************
1203 **
1204 ** Function: nativeNfcTag_doCheckNdef
1205 **
1206 ** Description: Does the tag contain a NDEF message?
1207 ** e: JVM environment.
1208 ** o: Java object.
1209 ** ndefInfo: NDEF info.
1210 **
1211 ** Returns: Status code; 0 is success.
1212 **
1213 *******************************************************************************/
nativeNfcTag_doCheckNdef(JNIEnv * e,jobject o,jintArray ndefInfo)1214 static jint nativeNfcTag_doCheckNdef(JNIEnv* e, jobject o, jintArray ndefInfo) {
1215 tNFA_STATUS status = NFA_STATUS_FAILED;
1216 jint* ndef = NULL;
1217
1218 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1219
1220 // special case for Kovio
1221 if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
1222 DLOG_IF(INFO, nfc_debug_enabled)
1223 << StringPrintf("%s: Kovio tag, no NDEF", __func__);
1224 ndef = e->GetIntArrayElements(ndefInfo, 0);
1225 ndef[0] = 0;
1226 ndef[1] = NDEF_MODE_READ_ONLY;
1227 e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1228 return NFA_STATUS_FAILED;
1229 } else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1230 nativeNfcTag_doReconnect(e, o);
1231 }
1232
1233 /* Create the write semaphore */
1234 if (sem_init(&sCheckNdefSem, 0, 0) == -1) {
1235 LOG(ERROR) << StringPrintf(
1236 "%s: Check NDEF semaphore creation failed (errno=0x%08x)", __func__,
1237 errno);
1238 return JNI_FALSE;
1239 }
1240
1241 if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
1242 LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
1243 goto TheEnd;
1244 }
1245
1246 DLOG_IF(INFO, nfc_debug_enabled)
1247 << StringPrintf("%s: try NFA_RwDetectNDef", __func__);
1248 sCheckNdefWaitingForComplete = JNI_TRUE;
1249
1250 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
1251 status = EXTNS_MfcCheckNDef();
1252 } else {
1253 status = NFA_RwDetectNDef();
1254 }
1255
1256 if (status != NFA_STATUS_OK) {
1257 LOG(ERROR) << StringPrintf("%s: NFA_RwDetectNDef failed, status = 0x%X",
1258 __func__, status);
1259 goto TheEnd;
1260 }
1261
1262 /* Wait for check NDEF completion status */
1263 if (sem_wait(&sCheckNdefSem)) {
1264 LOG(ERROR) << StringPrintf(
1265 "%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __func__,
1266 errno);
1267 goto TheEnd;
1268 }
1269
1270 if (sCheckNdefStatus == NFA_STATUS_OK) {
1271 // stack found a NDEF message on the tag
1272 ndef = e->GetIntArrayElements(ndefInfo, 0);
1273 if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T)
1274 ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize();
1275 else
1276 ndef[0] = sCheckNdefMaxSize;
1277 if (sCheckNdefCardReadOnly)
1278 ndef[1] = NDEF_MODE_READ_ONLY;
1279 else
1280 ndef[1] = NDEF_MODE_READ_WRITE;
1281 e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1282 status = NFA_STATUS_OK;
1283 } else if (sCheckNdefStatus == NFA_STATUS_FAILED) {
1284 // stack did not find a NDEF message on the tag;
1285 ndef = e->GetIntArrayElements(ndefInfo, 0);
1286 if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T)
1287 ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize();
1288 else
1289 ndef[0] = sCheckNdefMaxSize;
1290 if (sCheckNdefCardReadOnly)
1291 ndef[1] = NDEF_MODE_READ_ONLY;
1292 else
1293 ndef[1] = NDEF_MODE_READ_WRITE;
1294 e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1295 status = NFA_STATUS_FAILED;
1296 } else {
1297 DLOG_IF(INFO, nfc_debug_enabled)
1298 << StringPrintf("%s: unknown status 0x%X", __func__, sCheckNdefStatus);
1299 status = sCheckNdefStatus;
1300 }
1301
1302 /* Reconnect Mifare Classic Tag for furture use */
1303 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1304 nativeNfcTag_doReconnect(e, o);
1305 }
1306
1307 TheEnd:
1308 /* Destroy semaphore */
1309 if (sem_destroy(&sCheckNdefSem)) {
1310 LOG(ERROR) << StringPrintf(
1311 "%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __func__,
1312 errno);
1313 }
1314 sCheckNdefWaitingForComplete = JNI_FALSE;
1315 DLOG_IF(INFO, nfc_debug_enabled)
1316 << StringPrintf("%s: exit; status=0x%X", __func__, status);
1317 return status;
1318 }
1319
1320 /*******************************************************************************
1321 **
1322 ** Function: nativeNfcTag_resetPresenceCheck
1323 **
1324 ** Description: Reset variables related to presence-check.
1325 **
1326 ** Returns: None
1327 **
1328 *******************************************************************************/
nativeNfcTag_resetPresenceCheck()1329 void nativeNfcTag_resetPresenceCheck() { sIsTagPresent = true; }
1330
1331 /*******************************************************************************
1332 **
1333 ** Function: nativeNfcTag_doPresenceCheckResult
1334 **
1335 ** Description: Receive the result of presence-check.
1336 ** status: Result of presence-check.
1337 **
1338 ** Returns: None
1339 **
1340 *******************************************************************************/
nativeNfcTag_doPresenceCheckResult(tNFA_STATUS status)1341 void nativeNfcTag_doPresenceCheckResult(tNFA_STATUS status) {
1342 SyncEventGuard guard(sPresenceCheckEvent);
1343 sIsTagPresent = status == NFA_STATUS_OK;
1344 sPresenceCheckEvent.notifyOne();
1345 }
1346
1347 /*******************************************************************************
1348 **
1349 ** Function: nativeNfcTag_doPresenceCheck
1350 **
1351 ** Description: Check if the tag is in the RF field.
1352 ** e: JVM environment.
1353 ** o: Java object.
1354 **
1355 ** Returns: True if tag is in RF field.
1356 **
1357 *******************************************************************************/
nativeNfcTag_doPresenceCheck(JNIEnv *,jobject)1358 static jboolean nativeNfcTag_doPresenceCheck(JNIEnv*, jobject) {
1359 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1360 tNFA_STATUS status = NFA_STATUS_OK;
1361 jboolean isPresent = JNI_FALSE;
1362
1363 // Special case for Kovio. The deactivation would have already occurred
1364 // but was ignored so that normal tag opertions could complete. Now we
1365 // want to process as if the deactivate just happened.
1366 if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
1367 DLOG_IF(INFO, nfc_debug_enabled)
1368 << StringPrintf("%s: Kovio, force deactivate handling", __func__);
1369 tNFA_DEACTIVATED deactivated = {NFA_DEACTIVATE_TYPE_IDLE};
1370 {
1371 SyncEventGuard g(gDeactivatedEvent);
1372 gActivated = false; // guard this variable from multi-threaded access
1373 gDeactivatedEvent.notifyOne();
1374 }
1375
1376 NfcTag::getInstance().setDeactivationState(deactivated);
1377 nativeNfcTag_resetPresenceCheck();
1378 NfcTag::getInstance().connectionEventHandler(NFA_DEACTIVATED_EVT, NULL);
1379 nativeNfcTag_abortWaits();
1380 NfcTag::getInstance().abort();
1381
1382 return JNI_FALSE;
1383 }
1384
1385 if (nfcManager_isNfcActive() == false) {
1386 DLOG_IF(INFO, nfc_debug_enabled)
1387 << StringPrintf("%s: NFC is no longer active.", __func__);
1388 return JNI_FALSE;
1389 }
1390
1391 if (!sRfInterfaceMutex.tryLock()) {
1392 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1393 "%s: tag is being reSelected assume it is present", __func__);
1394 return JNI_TRUE;
1395 }
1396
1397 sRfInterfaceMutex.unlock();
1398
1399 if (NfcTag::getInstance().isActivated() == false) {
1400 DLOG_IF(INFO, nfc_debug_enabled)
1401 << StringPrintf("%s: tag already deactivated", __func__);
1402 return JNI_FALSE;
1403 }
1404 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
1405 status = EXTNS_MfcPresenceCheck();
1406 if (status == NFCSTATUS_SUCCESS) {
1407 return (NFCSTATUS_SUCCESS == EXTNS_GetPresenceCheckStatus()) ? JNI_TRUE
1408 : JNI_FALSE;
1409 }
1410 }
1411
1412 {
1413 SyncEventGuard guard(sPresenceCheckEvent);
1414 status =
1415 NFA_RwPresenceCheck(NfcTag::getInstance().getPresenceCheckAlgorithm());
1416 if (status == NFA_STATUS_OK) {
1417 sPresenceCheckEvent.wait();
1418 isPresent = sIsTagPresent ? JNI_TRUE : JNI_FALSE;
1419 }
1420 }
1421
1422 if (isPresent == JNI_FALSE)
1423 DLOG_IF(INFO, nfc_debug_enabled)
1424 << StringPrintf("%s: tag absent", __func__);
1425 return isPresent;
1426 }
1427
1428 /*******************************************************************************
1429 **
1430 ** Function: nativeNfcTag_doIsNdefFormatable
1431 **
1432 ** Description: Can tag be formatted to store NDEF message?
1433 ** e: JVM environment.
1434 ** o: Java object.
1435 ** libNfcType: Type of tag.
1436 ** uidBytes: Tag's unique ID.
1437 ** pollBytes: Data from activation.
1438 ** actBytes: Data from activation.
1439 **
1440 ** Returns: True if formattable.
1441 **
1442 *******************************************************************************/
nativeNfcTag_doIsNdefFormatable(JNIEnv * e,jobject o,jint,jbyteArray,jbyteArray,jbyteArray)1443 static jboolean nativeNfcTag_doIsNdefFormatable(JNIEnv* e, jobject o,
1444 jint /*libNfcType*/, jbyteArray,
1445 jbyteArray, jbyteArray) {
1446 jboolean isFormattable = JNI_FALSE;
1447 tNFC_PROTOCOL protocol = NfcTag::getInstance().getProtocol();
1448 if (NFA_PROTOCOL_T1T == protocol || NFA_PROTOCOL_T5T == protocol ||
1449 NFC_PROTOCOL_MIFARE == protocol) {
1450 isFormattable = JNI_TRUE;
1451 } else if (NFA_PROTOCOL_T3T == protocol) {
1452 isFormattable = NfcTag::getInstance().isFelicaLite() ? JNI_TRUE : JNI_FALSE;
1453 } else if (NFA_PROTOCOL_T2T == protocol) {
1454 isFormattable = (NfcTag::getInstance().isMifareUltralight() |
1455 NfcTag::getInstance().isInfineonMyDMove() |
1456 NfcTag::getInstance().isKovioType2Tag())
1457 ? JNI_TRUE
1458 : JNI_FALSE;
1459 } else if (NFA_PROTOCOL_ISO_DEP == protocol) {
1460 /**
1461 * Determines whether this is a formatable IsoDep tag - currectly only NXP
1462 * DESFire is supported.
1463 */
1464 uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00};
1465
1466 if (NfcTag::getInstance().isMifareDESFire()) {
1467 /* Identifies as DESfire, use get version cmd to be sure */
1468 jbyteArray versionCmd = e->NewByteArray(5);
1469 e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd);
1470 jbyteArray respBytes =
1471 nativeNfcTag_doTransceive(e, o, versionCmd, JNI_TRUE, NULL);
1472 if (respBytes != NULL) {
1473 // Check whether the response matches a typical DESfire
1474 // response.
1475 // libNFC even does more advanced checking than we do
1476 // here, and will only format DESfire's with a certain
1477 // major/minor sw version and NXP as a manufacturer.
1478 // We don't want to do such checking here, to avoid
1479 // having to change code in multiple places.
1480 // A succesful (wrapped) DESFire getVersion command returns
1481 // 9 bytes, with byte 7 0x91 and byte 8 having status
1482 // code 0xAF (these values are fixed and well-known).
1483 int respLength = e->GetArrayLength(respBytes);
1484 uint8_t* resp = (uint8_t*)e->GetByteArrayElements(respBytes, NULL);
1485 if (respLength == 9 && resp[7] == 0x91 && resp[8] == 0xAF) {
1486 isFormattable = JNI_TRUE;
1487 }
1488 e->ReleaseByteArrayElements(respBytes, (jbyte*)resp, JNI_ABORT);
1489 }
1490 }
1491 }
1492
1493 DLOG_IF(INFO, nfc_debug_enabled)
1494 << StringPrintf("%s: is formattable=%u", __func__, isFormattable);
1495 return isFormattable;
1496 }
1497
1498 /*******************************************************************************
1499 **
1500 ** Function: nativeNfcTag_doIsIsoDepNdefFormatable
1501 **
1502 ** Description: Is ISO-DEP tag formattable?
1503 ** e: JVM environment.
1504 ** o: Java object.
1505 ** pollBytes: Data from activation.
1506 ** actBytes: Data from activation.
1507 **
1508 ** Returns: True if formattable.
1509 **
1510 *******************************************************************************/
nativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv * e,jobject o,jbyteArray pollBytes,jbyteArray actBytes)1511 static jboolean nativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv* e, jobject o,
1512 jbyteArray pollBytes,
1513 jbyteArray actBytes) {
1514 uint8_t uidFake[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
1515 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1516 jbyteArray uidArray = e->NewByteArray(8);
1517 e->SetByteArrayRegion(uidArray, 0, 8, (jbyte*)uidFake);
1518 return nativeNfcTag_doIsNdefFormatable(e, o, 0, uidArray, pollBytes,
1519 actBytes);
1520 }
1521
1522 /*******************************************************************************
1523 **
1524 ** Function: nativeNfcTag_makeMifareNdefFormat
1525 **
1526 ** Description: Format a mifare classic tag so it can store NDEF message.
1527 ** e: JVM environment.
1528 ** o: Java object.
1529 ** key: Key to acces tag.
1530 ** keySize: size of Key.
1531 **
1532 ** Returns: True if ok.
1533 **
1534 *******************************************************************************/
nativeNfcTag_makeMifareNdefFormat(JNIEnv * e,jobject o,uint8_t * key,uint32_t keySize)1535 static jboolean nativeNfcTag_makeMifareNdefFormat(JNIEnv* e, jobject o,
1536 uint8_t* key,
1537 uint32_t keySize) {
1538 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1539 tNFA_STATUS status = NFA_STATUS_OK;
1540
1541 status = nativeNfcTag_doReconnect(e, o);
1542 if (status != NFA_STATUS_OK) {
1543 DLOG_IF(INFO, nfc_debug_enabled)
1544 << StringPrintf("%s: reconnect error, status=%u", __func__, status);
1545 return JNI_FALSE;
1546 }
1547
1548 sem_init(&sFormatSem, 0, 0);
1549 sFormatOk = false;
1550
1551 status = EXTNS_MfcFormatTag(key, keySize);
1552
1553 if (status == NFA_STATUS_OK) {
1554 DLOG_IF(INFO, nfc_debug_enabled)
1555 << StringPrintf("%s: wait for completion", __func__);
1556 sem_wait(&sFormatSem);
1557 status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
1558 } else {
1559 LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, status);
1560 }
1561
1562 sem_destroy(&sFormatSem);
1563 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1564 return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
1565 }
1566
1567 /*******************************************************************************
1568 **
1569 ** Function: nativeNfcTag_doNdefFormat
1570 **
1571 ** Description: Format a tag so it can store NDEF message.
1572 ** e: JVM environment.
1573 ** o: Java object.
1574 ** key: Not used.
1575 **
1576 ** Returns: True if ok.
1577 **
1578 *******************************************************************************/
nativeNfcTag_doNdefFormat(JNIEnv * e,jobject o,jbyteArray)1579 static jboolean nativeNfcTag_doNdefFormat(JNIEnv* e, jobject o, jbyteArray) {
1580 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1581 tNFA_STATUS status = NFA_STATUS_OK;
1582
1583 // Do not try to format if tag is already deactivated.
1584 if (NfcTag::getInstance().isActivated() == false) {
1585 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1586 "%s: tag already deactivated(no need to format)", __func__);
1587 return JNI_FALSE;
1588 }
1589
1590 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
1591 static uint8_t mfc_key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1592 static uint8_t mfc_key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
1593 jboolean result;
1594
1595 result =
1596 nativeNfcTag_makeMifareNdefFormat(e, o, mfc_key1, sizeof(mfc_key1));
1597 if (result == JNI_FALSE) {
1598 result =
1599 nativeNfcTag_makeMifareNdefFormat(e, o, mfc_key2, sizeof(mfc_key2));
1600 }
1601 return result;
1602 }
1603
1604 sem_init(&sFormatSem, 0, 0);
1605 sFormatOk = false;
1606 status = NFA_RwFormatTag();
1607 if (status == NFA_STATUS_OK) {
1608 DLOG_IF(INFO, nfc_debug_enabled)
1609 << StringPrintf("%s: wait for completion", __func__);
1610 sem_wait(&sFormatSem);
1611 status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
1612 } else
1613 LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, status);
1614 sem_destroy(&sFormatSem);
1615
1616 if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_ISO_DEP) {
1617 int retCode = NFCSTATUS_SUCCESS;
1618 retCode = nativeNfcTag_doReconnect(e, o);
1619 }
1620 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1621 return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
1622 }
1623
1624 /*******************************************************************************
1625 **
1626 ** Function: nativeNfcTag_doMakeReadonlyResult
1627 **
1628 ** Description: Receive the result of making a tag read-only. Called by the
1629 ** NFA_SET_TAG_RO_EVT.
1630 ** status: Status of the operation.
1631 **
1632 ** Returns: None
1633 **
1634 *******************************************************************************/
nativeNfcTag_doMakeReadonlyResult(tNFA_STATUS status)1635 void nativeNfcTag_doMakeReadonlyResult(tNFA_STATUS status) {
1636 if (sMakeReadonlyWaitingForComplete != JNI_FALSE) {
1637 sMakeReadonlyWaitingForComplete = JNI_FALSE;
1638 sMakeReadonlyStatus = status;
1639
1640 sem_post(&sMakeReadonlySem);
1641 }
1642 }
1643
1644 /*******************************************************************************
1645 **
1646 ** Function: nativeNfcTag_makeMifareReadonly
1647 **
1648 ** Description: Make the mifare classic tag read-only.
1649 ** e: JVM environment.
1650 ** o: Java object.
1651 ** key: Key to access the tag.
1652 ** keySize: size of Key.
1653 **
1654 ** Returns: True if ok.
1655 **
1656 *******************************************************************************/
nativeNfcTag_makeMifareReadonly(JNIEnv * e,jobject o,uint8_t * key,int32_t keySize)1657 static jboolean nativeNfcTag_makeMifareReadonly(JNIEnv* e, jobject o,
1658 uint8_t* key, int32_t keySize) {
1659 jboolean result = JNI_FALSE;
1660 tNFA_STATUS status = NFA_STATUS_OK;
1661
1662 sMakeReadonlyStatus = NFA_STATUS_FAILED;
1663
1664 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1665
1666 /* Create the make_readonly semaphore */
1667 if (sem_init(&sMakeReadonlySem, 0, 0) == -1) {
1668 LOG(ERROR) << StringPrintf(
1669 "%s: Make readonly semaphore creation failed (errno=0x%08x)", __func__,
1670 errno);
1671 return JNI_FALSE;
1672 }
1673
1674 sMakeReadonlyWaitingForComplete = JNI_TRUE;
1675
1676 status = nativeNfcTag_doReconnect(e, o);
1677 if (status != NFA_STATUS_OK) {
1678 goto TheEnd;
1679 }
1680
1681 status = EXTNS_MfcSetReadOnly(key, keySize);
1682 if (status != NFA_STATUS_OK) {
1683 goto TheEnd;
1684 }
1685 sem_wait(&sMakeReadonlySem);
1686
1687 if (sMakeReadonlyStatus == NFA_STATUS_OK) {
1688 result = JNI_TRUE;
1689 }
1690
1691 TheEnd:
1692 /* Destroy semaphore */
1693 if (sem_destroy(&sMakeReadonlySem)) {
1694 LOG(ERROR) << StringPrintf(
1695 "%s: Failed to destroy read_only semaphore (errno=0x%08x)", __func__,
1696 errno);
1697 }
1698 sMakeReadonlyWaitingForComplete = JNI_FALSE;
1699 return result;
1700 }
1701
1702 /*******************************************************************************
1703 **
1704 ** Function: nativeNfcTag_doMakeReadonly
1705 **
1706 ** Description: Make the tag read-only.
1707 ** e: JVM environment.
1708 ** o: Java object.
1709 ** key: Key to access the tag.
1710 **
1711 ** Returns: True if ok.
1712 **
1713 *******************************************************************************/
nativeNfcTag_doMakeReadonly(JNIEnv * e,jobject o,jbyteArray)1714 static jboolean nativeNfcTag_doMakeReadonly(JNIEnv* e, jobject o, jbyteArray) {
1715 jboolean result = JNI_FALSE;
1716 tNFA_STATUS status;
1717
1718 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1719
1720 if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE && legacy_mfc_reader) {
1721 static uint8_t mfc_key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1722 static uint8_t mfc_key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
1723 result = nativeNfcTag_makeMifareReadonly(e, o, mfc_key1, sizeof(mfc_key1));
1724 if (result == JNI_FALSE) {
1725 result =
1726 nativeNfcTag_makeMifareReadonly(e, o, mfc_key2, sizeof(mfc_key2));
1727 }
1728 return result;
1729 }
1730
1731 /* Create the make_readonly semaphore */
1732 if (sem_init(&sMakeReadonlySem, 0, 0) == -1) {
1733 LOG(ERROR) << StringPrintf(
1734 "%s: Make readonly semaphore creation failed (errno=0x%08x)", __func__,
1735 errno);
1736 return JNI_FALSE;
1737 }
1738
1739 sMakeReadonlyWaitingForComplete = JNI_TRUE;
1740
1741 // Hard-lock the tag (cannot be reverted)
1742 status = NFA_RwSetTagReadOnly(TRUE);
1743 if (status == NFA_STATUS_REJECTED) {
1744 status = NFA_RwSetTagReadOnly(FALSE); // try soft lock
1745 if (status != NFA_STATUS_OK) {
1746 LOG(ERROR) << StringPrintf("%s: fail soft lock, status=%d", __func__,
1747 status);
1748 goto TheEnd;
1749 }
1750 } else if (status != NFA_STATUS_OK) {
1751 LOG(ERROR) << StringPrintf("%s: fail hard lock, status=%d", __func__,
1752 status);
1753 goto TheEnd;
1754 }
1755
1756 /* Wait for check NDEF completion status */
1757 if (sem_wait(&sMakeReadonlySem)) {
1758 LOG(ERROR) << StringPrintf(
1759 "%s: Failed to wait for make_readonly semaphore (errno=0x%08x)",
1760 __func__, errno);
1761 goto TheEnd;
1762 }
1763
1764 if (sMakeReadonlyStatus == NFA_STATUS_OK) {
1765 result = JNI_TRUE;
1766 }
1767
1768 TheEnd:
1769 /* Destroy semaphore */
1770 if (sem_destroy(&sMakeReadonlySem)) {
1771 LOG(ERROR) << StringPrintf(
1772 "%s: Failed to destroy read_only semaphore (errno=0x%08x)", __func__,
1773 errno);
1774 }
1775 sMakeReadonlyWaitingForComplete = JNI_FALSE;
1776 return result;
1777 }
1778
1779 /*******************************************************************************
1780 **
1781 ** Function: nativeNfcTag_registerNdefTypeHandler
1782 **
1783 ** Description: Register a callback to receive NDEF message from the tag
1784 ** from the NFA_NDEF_DATA_EVT.
1785 **
1786 ** Returns: None
1787 **
1788 *******************************************************************************/
1789 // register a callback to receive NDEF message from the tag
1790 // from the NFA_NDEF_DATA_EVT;
nativeNfcTag_registerNdefTypeHandler()1791 void nativeNfcTag_registerNdefTypeHandler() {
1792 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1793 sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1794 NFA_RegisterNDefTypeHandler(TRUE, NFA_TNF_DEFAULT, (uint8_t*)"", 0,
1795 ndefHandlerCallback);
1796 if (legacy_mfc_reader) {
1797 EXTNS_MfcRegisterNDefTypeHandler(ndefHandlerCallback);
1798 }
1799 }
1800
1801 /*******************************************************************************
1802 **
1803 ** Function: nativeNfcTag_deregisterNdefTypeHandler
1804 **
1805 ** Description: No longer need to receive NDEF message from the tag.
1806 **
1807 ** Returns: None
1808 **
1809 *******************************************************************************/
nativeNfcTag_deregisterNdefTypeHandler()1810 void nativeNfcTag_deregisterNdefTypeHandler() {
1811 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1812 NFA_DeregisterNDefTypeHandler(sNdefTypeHandlerHandle);
1813 sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1814 }
1815
1816 /*******************************************************************************
1817 **
1818 ** Function: nativeNfcTag_acquireRfInterfaceMutexLock
1819 **
1820 ** Description: acquire sRfInterfaceMutex
1821 **
1822 ** Returns: None
1823 **
1824 *******************************************************************************/
nativeNfcTag_acquireRfInterfaceMutexLock()1825 void nativeNfcTag_acquireRfInterfaceMutexLock() {
1826 DLOG_IF(INFO, nfc_debug_enabled)
1827 << StringPrintf("%s: try to acquire lock", __func__);
1828 sRfInterfaceMutex.lock();
1829 DLOG_IF(INFO, nfc_debug_enabled)
1830 << StringPrintf("%s: sRfInterfaceMutex lock", __func__);
1831 }
1832
1833 /*******************************************************************************
1834 **
1835 ** Function: nativeNfcTag_releaseRfInterfaceMutexLock
1836 **
1837 ** Description: release the sRfInterfaceMutex
1838 **
1839 ** Returns: None
1840 **
1841 *******************************************************************************/
nativeNfcTag_releaseRfInterfaceMutexLock()1842 void nativeNfcTag_releaseRfInterfaceMutexLock() {
1843 sRfInterfaceMutex.unlock();
1844 DLOG_IF(INFO, nfc_debug_enabled)
1845 << StringPrintf("%s: sRfInterfaceMutex unlock", __func__);
1846 }
1847
1848 /*****************************************************************************
1849 **
1850 ** JNI functions for Android 4.0.3
1851 **
1852 *****************************************************************************/
1853 static JNINativeMethod gMethods[] = {
1854 {"doConnect", "(I)I", (void*)nativeNfcTag_doConnect},
1855 {"doDisconnect", "()Z", (void*)nativeNfcTag_doDisconnect},
1856 {"doReconnect", "()I", (void*)nativeNfcTag_doReconnect},
1857 {"doHandleReconnect", "(I)I", (void*)nativeNfcTag_doHandleReconnect},
1858 {"doTransceive", "([BZ[I)[B", (void*)nativeNfcTag_doTransceive},
1859 {"doGetNdefType", "(II)I", (void*)nativeNfcTag_doGetNdefType},
1860 {"doCheckNdef", "([I)I", (void*)nativeNfcTag_doCheckNdef},
1861 {"doRead", "()[B", (void*)nativeNfcTag_doRead},
1862 {"doWrite", "([B)Z", (void*)nativeNfcTag_doWrite},
1863 {"doPresenceCheck", "()Z", (void*)nativeNfcTag_doPresenceCheck},
1864 {"doIsIsoDepNdefFormatable", "([B[B)Z",
1865 (void*)nativeNfcTag_doIsIsoDepNdefFormatable},
1866 {"doNdefFormat", "([B)Z", (void*)nativeNfcTag_doNdefFormat},
1867 {"doMakeReadonly", "([B)Z", (void*)nativeNfcTag_doMakeReadonly},
1868 };
1869
1870 /*******************************************************************************
1871 **
1872 ** Function: register_com_android_nfc_NativeNfcTag
1873 **
1874 ** Description: Regisgter JNI functions with Java Virtual Machine.
1875 ** e: Environment of JVM.
1876 **
1877 ** Returns: Status of registration.
1878 **
1879 *******************************************************************************/
register_com_android_nfc_NativeNfcTag(JNIEnv * e)1880 int register_com_android_nfc_NativeNfcTag(JNIEnv* e) {
1881 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1882 return jniRegisterNativeMethods(e, gNativeNfcTagClassName, gMethods,
1883 NELEM(gMethods));
1884 }
1885
1886 } /* namespace android */
1887