1 /******************************************************************************
2  *
3  *  Copyright (C) 2010-2014 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 
20 /******************************************************************************
21  *
22  *  This file contains the implementation for Type 4 tag in Card Emulation
23  *  mode.
24  *
25  ******************************************************************************/
26 #include <string.h>
27 #include "nfc_target.h"
28 #include "bt_types.h"
29 #include "trace_api.h"
30 
31 #if (NFC_INCLUDED == TRUE)
32 #include "nfc_api.h"
33 #include "nfc_int.h"
34 #include "ce_api.h"
35 #include "ce_int.h"
36 #include "tags_int.h"
37 #include "gki.h"
38 
39 #if (CE_TEST_INCLUDED == TRUE) /* test only */
40 BOOLEAN mapping_aid_test_enabled = FALSE;
41 UINT8   ce_test_tag_app_id[T4T_V20_NDEF_TAG_AID_LEN] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
42 #endif
43 
44 /*******************************************************************************
45 **
46 ** Function         ce_t4t_send_to_lower
47 **
48 ** Description      Send packet to lower layer
49 **
50 ** Returns          TRUE if success
51 **
52 *******************************************************************************/
ce_t4t_send_to_lower(BT_HDR * p_r_apdu)53 static BOOLEAN ce_t4t_send_to_lower (BT_HDR *p_r_apdu)
54 {
55 #if (BT_TRACE_PROTOCOL == TRUE)
56     DispCET4Tags (p_r_apdu, FALSE);
57 #endif
58 
59     if (NFC_SendData (NFC_RF_CONN_ID, p_r_apdu) != NFC_STATUS_OK)
60     {
61         CE_TRACE_ERROR0 ("ce_t4t_send_to_lower (): NFC_SendData () failed");
62         return FALSE;
63     }
64     return TRUE;
65 }
66 
67 /*******************************************************************************
68 **
69 ** Function         ce_t4t_send_status
70 **
71 ** Description      Send status on R-APDU to peer
72 **
73 ** Returns          TRUE if success
74 **
75 *******************************************************************************/
ce_t4t_send_status(UINT16 status)76 static BOOLEAN ce_t4t_send_status (UINT16 status)
77 {
78     BT_HDR      *p_r_apdu;
79     UINT8       *p;
80 
81     CE_TRACE_DEBUG1 ("ce_t4t_send_status (): Status:0x%04X", status);
82 
83     p_r_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_CE_POOL_ID);
84 
85     if (!p_r_apdu)
86     {
87         CE_TRACE_ERROR0 ("ce_t4t_send_status (): Cannot allocate buffer");
88         return FALSE;
89     }
90 
91     p_r_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
92     p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
93 
94     UINT16_TO_BE_STREAM (p, status);
95 
96     p_r_apdu->len = T4T_RSP_STATUS_WORDS_SIZE;
97 
98     if (!ce_t4t_send_to_lower (p_r_apdu))
99     {
100         return FALSE;
101     }
102     return TRUE;
103 }
104 
105 /*******************************************************************************
106 **
107 ** Function         ce_t4t_select_file
108 **
109 ** Description      Select a file
110 **
111 ** Returns          TRUE if success
112 **
113 *******************************************************************************/
ce_t4t_select_file(UINT16 file_id)114 static BOOLEAN ce_t4t_select_file (UINT16 file_id)
115 {
116     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
117 
118     CE_TRACE_DEBUG1 ("ce_t4t_select_file (): FileID:0x%04X", file_id);
119 
120     if (file_id == T4T_CC_FILE_ID)
121     {
122         CE_TRACE_DEBUG0 ("ce_t4t_select_file (): Select CC file");
123 
124         p_t4t->status |= CE_T4T_STATUS_CC_FILE_SELECTED;
125         p_t4t->status &= ~ (CE_T4T_STATUS_NDEF_SELECTED);
126 
127         return TRUE;
128     }
129 
130     if (file_id == CE_T4T_MANDATORY_NDEF_FILE_ID)
131     {
132         CE_TRACE_DEBUG3 ("ce_t4t_select_file (): NLEN:0x%04X, MaxFileSize:0x%04X, WriteAccess:%s",
133                           p_t4t->nlen,
134                           p_t4t->max_file_size,
135                           (p_t4t->status & CE_T4T_STATUS_NDEF_FILE_READ_ONLY ? "RW" : "RO"));
136 
137         p_t4t->status |= CE_T4T_STATUS_NDEF_SELECTED;
138         p_t4t->status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED);
139 
140         return TRUE;
141     }
142     else
143     {
144         CE_TRACE_ERROR1 ("ce_t4t_select_file (): Cannot find file ID (0x%04X)", file_id);
145 
146         p_t4t->status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED);
147         p_t4t->status &= ~ (CE_T4T_STATUS_NDEF_SELECTED);
148 
149         return FALSE;
150     }
151 }
152 
153 /*******************************************************************************
154 **
155 ** Function         ce_t4t_read_binary
156 **
157 ** Description      Read data from selected file and send R-APDU to peer
158 **
159 ** Returns          TRUE if success
160 **
161 *******************************************************************************/
ce_t4t_read_binary(UINT16 offset,UINT8 length)162 static BOOLEAN ce_t4t_read_binary (UINT16 offset, UINT8 length)
163 {
164     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
165     UINT8       *p_src = NULL, *p_dst;
166     BT_HDR      *p_r_apdu;
167 
168     CE_TRACE_DEBUG3 ("ce_t4t_read_binary (): Offset:0x%04X, Length:0x%04X, selected status = 0x%02X",
169                       offset, length, p_t4t->status);
170 
171     if (p_t4t->status & CE_T4T_STATUS_CC_FILE_SELECTED)
172     {
173         p_src = p_t4t->cc_file;
174     }
175     else if (p_t4t->status & CE_T4T_STATUS_NDEF_SELECTED)
176     {
177         if (p_t4t->p_scratch_buf)
178             p_src = p_t4t->p_scratch_buf;
179         else
180             p_src = p_t4t->p_ndef_msg;
181     }
182 
183     if (p_src)
184     {
185         p_r_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_CE_POOL_ID);
186 
187         if (!p_r_apdu)
188         {
189             CE_TRACE_ERROR0 ("ce_t4t_read_binary (): Cannot allocate buffer");
190             return FALSE;
191         }
192 
193         p_r_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
194         p_dst = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
195 
196         p_r_apdu->len = length;
197 
198         /* add NLEN before NDEF message and adjust offset             */
199         /* if NDEF file is selected and offset < T4T_FILE_LENGTH_SIZE */
200         if ((p_t4t->status & CE_T4T_STATUS_NDEF_SELECTED) && (length > 0))
201         {
202             if (offset == 0)
203             {
204                 UINT16_TO_BE_STREAM (p_dst, p_t4t->nlen);
205 
206                 if (length == 1)
207                 {
208                     length = 0;
209                     p_dst--;
210                 }
211                 else /* length >= 2 */
212                     length -= T4T_FILE_LENGTH_SIZE;
213             }
214             else if (offset == 1)
215             {
216                 UINT8_TO_BE_STREAM (p_dst, (UINT8) (p_t4t->nlen));
217 
218                 offset = 0;
219                 length--;
220             }
221             else
222             {
223                 offset -= T4T_FILE_LENGTH_SIZE;
224             }
225         }
226 
227         if (length > 0)
228         {
229             memcpy (p_dst, p_src + offset, length);
230             p_dst += length;
231         }
232 
233         UINT16_TO_BE_STREAM (p_dst, T4T_RSP_CMD_CMPLTED);
234         p_r_apdu->len += T4T_RSP_STATUS_WORDS_SIZE;
235 
236         if (!ce_t4t_send_to_lower (p_r_apdu))
237         {
238             return FALSE;
239         }
240         return TRUE;
241     }
242     else
243     {
244         CE_TRACE_ERROR0 ("ce_t4t_read_binary (): No selected file");
245 
246         if (!ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED))
247         {
248             return FALSE;
249         }
250         return TRUE;
251     }
252 }
253 
254 /*******************************************************************************
255 **
256 ** Function         ce_t4t_update_binary
257 **
258 ** Description      Update file and send R-APDU to peer
259 **
260 ** Returns          TRUE if success
261 **
262 *******************************************************************************/
ce_t4t_update_binary(UINT16 offset,UINT8 length,UINT8 * p_data)263 static BOOLEAN ce_t4t_update_binary (UINT16 offset, UINT8 length, UINT8 *p_data)
264 {
265     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
266     UINT8       *p;
267     UINT8        file_length[2];
268     UINT16       starting_offset;
269     tCE_DATA     ce_data;
270 
271     CE_TRACE_DEBUG3 ("ce_t4t_update_binary (): Offset:0x%04X, Length:0x%04X, selected status = 0x%02X",
272                       offset, length, p_t4t->status);
273 
274     starting_offset = offset;
275 
276     /* update file size (NLEN) */
277     if ((offset < T4T_FILE_LENGTH_SIZE) && (length > 0))
278     {
279         p = file_length;
280         UINT16_TO_BE_STREAM (p, p_t4t->nlen);
281 
282         while ((offset < T4T_FILE_LENGTH_SIZE) && (length > 0))
283         {
284             *(file_length + offset++) = *(p_data++);
285             length--;
286         }
287 
288         p = file_length;
289         BE_STREAM_TO_UINT16 (p_t4t->nlen, p);
290     }
291 
292     if (length > 0)
293         memcpy (p_t4t->p_scratch_buf + offset - T4T_FILE_LENGTH_SIZE, p_data, length);
294 
295     /* if this is the last step: writing non-zero length in NLEN */
296     if ((starting_offset == 0) && (p_t4t->nlen > 0))
297     {
298         nfc_stop_quick_timer (&p_t4t->timer);
299 
300         if (ce_cb.p_cback)
301         {
302             ce_data.update_info.status = NFC_STATUS_OK;
303             ce_data.update_info.length = p_t4t->nlen;
304             ce_data.update_info.p_data = p_t4t->p_scratch_buf;
305 
306             (*ce_cb.p_cback) (CE_T4T_NDEF_UPDATE_CPLT_EVT, &ce_data);
307             CE_TRACE_DEBUG0 ("ce_t4t_update_binary (): Sent CE_T4T_NDEF_UPDATE_CPLT_EVT");
308         }
309 
310         p_t4t->status &= ~ (CE_T4T_STATUS_NDEF_FILE_UPDATING);
311     }
312     else if (!(p_t4t->status & CE_T4T_STATUS_NDEF_FILE_UPDATING))
313     {
314         /* starting of updating */
315         p_t4t->status |= CE_T4T_STATUS_NDEF_FILE_UPDATING;
316 
317         nfc_start_quick_timer (&p_t4t->timer, NFC_TTYPE_CE_T4T_UPDATE,
318                                (CE_T4T_TOUT_UPDATE * QUICK_TIMER_TICKS_PER_SEC) / 1000);
319 
320         if (ce_cb.p_cback)
321             (*ce_cb.p_cback) (CE_T4T_NDEF_UPDATE_START_EVT, NULL);
322     }
323 
324     if (!ce_t4t_send_status (T4T_RSP_CMD_CMPLTED))
325     {
326         return FALSE;
327     }
328     else
329     {
330         return TRUE;
331     }
332 }
333 
334 /*******************************************************************************
335 **
336 ** Function         ce_t4t_set_version_in_cc
337 **
338 ** Description      update version in CC file
339 **                  If reader selects NDEF Tag Application with V1.0 AID then
340 **                  set V1.0 into CC file.
341 **                  If reader selects NDEF Tag Application with V2.0 AID then
342 **                  set V2.0 into CC file.
343 **
344 ** Returns          None
345 **
346 *******************************************************************************/
ce_t4t_set_version_in_cc(UINT8 version)347 static void ce_t4t_set_version_in_cc (UINT8 version)
348 {
349     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
350     UINT8       *p;
351 
352     CE_TRACE_DEBUG1 ("ce_t4t_set_version_in_cc (): version = 0x%02X", version);
353 
354     p = p_t4t->cc_file + T4T_VERSION_OFFSET_IN_CC;
355 
356     UINT8_TO_BE_STREAM (p, version);
357 }
358 
359 /*******************************************************************************
360 **
361 ** Function         ce_t4t_process_select_file_cmd
362 **
363 ** Description      This function processes Select Command by file ID.
364 **
365 ** Returns          TRUE if success
366 **
367 *******************************************************************************/
ce_t4t_process_select_file_cmd(UINT8 * p_cmd)368 static BOOLEAN ce_t4t_process_select_file_cmd (UINT8 *p_cmd)
369 {
370     UINT8  data_len;
371     UINT16 file_id, status_words;
372 
373     CE_TRACE_DEBUG0 ("ce_t4t_process_select_file_cmd ()");
374 
375     p_cmd++; /* skip P2 */
376 
377     /* Lc Byte */
378     BE_STREAM_TO_UINT8 (data_len, p_cmd);
379 
380     if (data_len == T4T_FILE_ID_SIZE)
381     {
382         /* File ID */
383         BE_STREAM_TO_UINT16 (file_id, p_cmd);
384 
385         if (ce_t4t_select_file (file_id))
386         {
387             status_words = T4T_RSP_CMD_CMPLTED;
388         }
389         else
390         {
391             status_words = T4T_RSP_NOT_FOUND;
392         }
393     }
394     else
395     {
396         status_words = T4T_RSP_WRONG_LENGTH;
397     }
398 
399     if (!ce_t4t_send_status (status_words))
400     {
401         return FALSE;
402     }
403 
404     if (status_words == T4T_RSP_CMD_CMPLTED)
405     {
406         return TRUE;
407     }
408     return FALSE;
409 }
410 
411 /*******************************************************************************
412 **
413 ** Function         ce_t4t_process_select_app_cmd
414 **
415 ** Description      This function processes Select Command by AID.
416 **
417 ** Returns          none
418 **
419 *******************************************************************************/
ce_t4t_process_select_app_cmd(UINT8 * p_cmd,BT_HDR * p_c_apdu)420 static void ce_t4t_process_select_app_cmd (UINT8 *p_cmd, BT_HDR *p_c_apdu)
421 {
422     UINT8    data_len;
423     UINT16   status_words = 0x0000; /* invalid status words */
424     tCE_DATA ce_data;
425     UINT8    xx;
426 
427     CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd ()");
428 
429     p_cmd++; /* skip P2 */
430 
431     /* Lc Byte */
432     BE_STREAM_TO_UINT8 (data_len, p_cmd);
433 
434 #if (CE_TEST_INCLUDED == TRUE)
435     if (mapping_aid_test_enabled)
436     {
437         if (  (data_len == T4T_V20_NDEF_TAG_AID_LEN)
438             &&(!memcmp(p_cmd, ce_test_tag_app_id, data_len))
439             &&(ce_cb.mem.t4t.p_ndef_msg)  )
440         {
441             GKI_freebuf (p_c_apdu);
442             ce_t4t_send_status ((UINT16) T4T_RSP_CMD_CMPLTED);
443             return;
444         }
445     }
446 #endif
447 
448     /*
449     ** Compare AIDs registered by applications
450     ** if found, use callback of the application
451     ** otherwise, return error and maintain the same status
452     */
453     ce_cb.mem.t4t.selected_aid_idx = CE_T4T_MAX_REG_AID;
454     for (xx = 0; xx < CE_T4T_MAX_REG_AID; xx++)
455     {
456         if (  (ce_cb.mem.t4t.reg_aid[xx].aid_len > 0)
457             &&(ce_cb.mem.t4t.reg_aid[xx].aid_len == data_len)
458             &&(!(memcmp(ce_cb.mem.t4t.reg_aid[xx].aid, p_cmd, data_len)))  )
459         {
460             ce_cb.mem.t4t.selected_aid_idx = xx;
461             break;
462         }
463     }
464 
465     /* if found matched AID */
466     if (ce_cb.mem.t4t.selected_aid_idx < CE_T4T_MAX_REG_AID)
467     {
468         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED);
469         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_NDEF_SELECTED);
470         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_T4T_APP_SELECTED);
471         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_WILDCARD_AID_SELECTED);
472         ce_cb.mem.t4t.status |= CE_T4T_STATUS_REG_AID_SELECTED;
473 
474         CE_TRACE_DEBUG4 ("ce_t4t_process_select_app_cmd (): Registered AID[%02X%02X%02X%02X...] is selected",
475                          ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[0],
476                          ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[1],
477                          ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[2],
478                          ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].aid[3]);
479 
480         ce_data.raw_frame.status = NFC_STATUS_OK;
481         ce_data.raw_frame.p_data = p_c_apdu;
482         ce_data.raw_frame.aid_handle = ce_cb.mem.t4t.selected_aid_idx;
483 
484         p_c_apdu = NULL;
485 
486         (*(ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].p_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data);
487     }
488     else if (  (data_len == T4T_V20_NDEF_TAG_AID_LEN)
489              &&(!memcmp(p_cmd, t4t_v20_ndef_tag_aid, data_len - 1))
490              &&(ce_cb.mem.t4t.p_ndef_msg)  )
491     {
492         p_cmd += data_len - 1;
493 
494         /* adjust version if possible */
495         if ((*p_cmd) == 0x00)
496         {
497             ce_t4t_set_version_in_cc (T4T_VERSION_1_0);
498             status_words = T4T_RSP_CMD_CMPLTED;
499         }
500         else if ((*p_cmd) == 0x01)
501         {
502             ce_t4t_set_version_in_cc (T4T_VERSION_2_0);
503             status_words = T4T_RSP_CMD_CMPLTED;
504         }
505         else
506         {
507             CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd (): Not found matched AID");
508             status_words = T4T_RSP_NOT_FOUND;
509         }
510     }
511     else if (ce_cb.mem.t4t.p_wildcard_aid_cback)
512     {
513         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED);
514         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_NDEF_SELECTED);
515         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_T4T_APP_SELECTED);
516         ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_REG_AID_SELECTED);
517         ce_cb.mem.t4t.status |= CE_T4T_STATUS_WILDCARD_AID_SELECTED;
518 
519         ce_data.raw_frame.status = NFC_STATUS_OK;
520         ce_data.raw_frame.p_data = p_c_apdu;
521         ce_data.raw_frame.aid_handle = CE_T4T_WILDCARD_AID_HANDLE;
522         p_c_apdu = NULL;
523 
524         CE_TRACE_DEBUG0 ("CET4T: Forward raw frame (SELECT APP) to wildcard AID handler");
525         (*(ce_cb.mem.t4t.p_wildcard_aid_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data);
526     }
527     else
528     {
529         CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd (): Not found matched AID or not listening T4T NDEF");
530         status_words = T4T_RSP_NOT_FOUND;
531     }
532 
533     if (status_words)
534     {
535         /* if T4T CE can support */
536         if (status_words == T4T_RSP_CMD_CMPLTED)
537         {
538             ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_CC_FILE_SELECTED);
539             ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_NDEF_SELECTED);
540             ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_REG_AID_SELECTED);
541             ce_cb.mem.t4t.status &= ~ (CE_T4T_STATUS_WILDCARD_AID_SELECTED);
542             ce_cb.mem.t4t.status |= CE_T4T_STATUS_T4T_APP_SELECTED;
543 
544             CE_TRACE_DEBUG0 ("ce_t4t_process_select_app_cmd (): T4T CE App selected");
545         }
546 
547         ce_t4t_send_status (status_words);
548         GKI_freebuf (p_c_apdu);
549     }
550     /* if status_words is not set then upper layer will send R-APDU */
551 
552     return;
553 }
554 
555 /*******************************************************************************
556 **
557 ** Function         ce_t4t_process_timeout
558 **
559 ** Description      process timeout event
560 **
561 ** Returns          none
562 **
563 *******************************************************************************/
ce_t4t_process_timeout(TIMER_LIST_ENT * p_tle)564 void ce_t4t_process_timeout (TIMER_LIST_ENT *p_tle)
565 {
566     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
567     tCE_DATA     ce_data;
568 
569     CE_TRACE_DEBUG1 ("ce_t4t_process_timeout () event=%d", p_tle->event);
570 
571     if (p_tle->event == NFC_TTYPE_CE_T4T_UPDATE)
572     {
573         if (p_t4t->status & CE_T4T_STATUS_NDEF_FILE_UPDATING)
574         {
575             ce_data.status = NFC_STATUS_TIMEOUT;
576 
577             if (ce_cb.p_cback)
578                 (*ce_cb.p_cback) (CE_T4T_NDEF_UPDATE_ABORT_EVT, &ce_data);
579 
580             p_t4t->status &= ~ (CE_T4T_STATUS_NDEF_FILE_UPDATING);
581         }
582     }
583     else
584     {
585         CE_TRACE_ERROR1 ("ce_t4t_process_timeout () unknown event=%d", p_tle->event);
586     }
587 }
588 
589 /*******************************************************************************
590 **
591 ** Function         ce_t4t_data_cback
592 **
593 ** Description      This callback function receives the data from NFCC.
594 **
595 ** Returns          none
596 **
597 *******************************************************************************/
ce_t4t_data_cback(UINT8 conn_id,tNFC_CONN_EVT event,tNFC_CONN * p_data)598 static void ce_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data)
599 {
600     BT_HDR  *p_c_apdu;
601     UINT8   *p_cmd;
602     UINT8    cla, instruct, select_type = 0, length;
603     UINT16   offset, max_file_size;
604     tCE_DATA ce_data;
605 
606     if (event == NFC_DEACTIVATE_CEVT)
607     {
608         NFC_SetStaticRfCback (NULL);
609         return;
610     }
611     if (event != NFC_DATA_CEVT)
612     {
613         return;
614     }
615 
616     p_c_apdu = (BT_HDR *) p_data->data.p_data;
617 
618 #if (BT_TRACE_PROTOCOL == TRUE)
619     DispCET4Tags (p_c_apdu, TRUE);
620 #endif
621 
622     CE_TRACE_DEBUG1 ("ce_t4t_data_cback (): conn_id = 0x%02X", conn_id);
623 
624     p_cmd = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
625 
626     /* Class Byte */
627     BE_STREAM_TO_UINT8 (cla, p_cmd);
628 
629     /* Don't check class if registered AID has been selected */
630     if (  (cla != T4T_CMD_CLASS)
631         &&((ce_cb.mem.t4t.status & CE_T4T_STATUS_REG_AID_SELECTED) == 0)
632         &&((ce_cb.mem.t4t.status & CE_T4T_STATUS_WILDCARD_AID_SELECTED) == 0)  )
633     {
634         GKI_freebuf (p_c_apdu);
635         ce_t4t_send_status (T4T_RSP_CLASS_NOT_SUPPORTED);
636         return;
637     }
638 
639     /* Instruction Byte */
640     BE_STREAM_TO_UINT8 (instruct, p_cmd);
641 
642     if ((cla == T4T_CMD_CLASS) && (instruct == T4T_CMD_INS_SELECT))
643     {
644         /* P1 Byte */
645         BE_STREAM_TO_UINT8 (select_type, p_cmd);
646 
647         if (select_type == T4T_CMD_P1_SELECT_BY_NAME)
648         {
649             ce_t4t_process_select_app_cmd (p_cmd, p_c_apdu);
650             return;
651         }
652     }
653 
654     /* if registered AID is selected */
655     if (ce_cb.mem.t4t.status & CE_T4T_STATUS_REG_AID_SELECTED)
656     {
657         CE_TRACE_DEBUG0 ("CET4T: Forward raw frame to registered AID");
658 
659         /* forward raw frame to upper layer */
660         if (ce_cb.mem.t4t.selected_aid_idx < CE_T4T_MAX_REG_AID)
661         {
662             ce_data.raw_frame.status = p_data->data.status;
663             ce_data.raw_frame.p_data = p_c_apdu;
664             ce_data.raw_frame.aid_handle = ce_cb.mem.t4t.selected_aid_idx;
665             p_c_apdu = NULL;
666 
667             (*(ce_cb.mem.t4t.reg_aid[ce_cb.mem.t4t.selected_aid_idx].p_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data);
668         }
669         else
670         {
671             GKI_freebuf (p_c_apdu);
672             ce_t4t_send_status (T4T_RSP_NOT_FOUND);
673         }
674     }
675     else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_WILDCARD_AID_SELECTED)
676     {
677         CE_TRACE_DEBUG0 ("CET4T: Forward raw frame to wildcard AID handler");
678 
679         /* forward raw frame to upper layer */
680         ce_data.raw_frame.status = p_data->data.status;
681         ce_data.raw_frame.p_data = p_c_apdu;
682         ce_data.raw_frame.aid_handle = CE_T4T_WILDCARD_AID_HANDLE;
683         p_c_apdu = NULL;
684 
685         (*(ce_cb.mem.t4t.p_wildcard_aid_cback)) (CE_T4T_RAW_FRAME_EVT, &ce_data);
686     }
687     else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_T4T_APP_SELECTED)
688     {
689         if (instruct == T4T_CMD_INS_SELECT)
690         {
691             /* P1 Byte is already parsed */
692             if (select_type == T4T_CMD_P1_SELECT_BY_FILE_ID)
693             {
694                 ce_t4t_process_select_file_cmd (p_cmd);
695             }
696             else
697             {
698                 CE_TRACE_ERROR1 ("CET4T: Bad P1 byte (0x%02X)", select_type);
699                 ce_t4t_send_status (T4T_RSP_WRONG_PARAMS);
700             }
701         }
702         else if (instruct == T4T_CMD_INS_READ_BINARY)
703         {
704             if (  (ce_cb.mem.t4t.status & CE_T4T_STATUS_CC_FILE_SELECTED)
705                 ||(ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_SELECTED)  )
706             {
707                 if (ce_cb.mem.t4t.status & CE_T4T_STATUS_CC_FILE_SELECTED)
708                 {
709                     max_file_size = T4T_FC_TLV_OFFSET_IN_CC + T4T_FILE_CONTROL_TLV_SIZE;
710                 }
711                 else
712                 {
713                     max_file_size = ce_cb.mem.t4t.max_file_size;
714                 }
715 
716                 BE_STREAM_TO_UINT16 (offset, p_cmd); /* Offset */
717                 BE_STREAM_TO_UINT8 (length, p_cmd); /* Le     */
718 
719                 /* check if valid parameters */
720                 if (length <= CE_T4T_MAX_LE)
721                 {
722                     /* CE allows to read more than current file size but not max file size */
723                     if (length + offset > max_file_size)
724                     {
725                         if (offset < max_file_size)
726                         {
727                             length = (UINT8) (max_file_size - offset);
728 
729                             CE_TRACE_DEBUG2 ("CET4T: length is reduced to %d by max_file_size (%d)",
730                                               length, max_file_size);
731                         }
732                         else
733                         {
734                             CE_TRACE_ERROR2 ("CET4T: offset (%d) must be less than max_file_size (%d)",
735                                               offset, max_file_size);
736                             length = 0;
737                         }
738                     }
739                 }
740                 else
741                 {
742                     CE_TRACE_ERROR2 ("CET4T: length (%d) must be less than MLe (%d)",
743                                       length, CE_T4T_MAX_LE);
744                     length = 0;
745                 }
746 
747                 if (length > 0)
748                     ce_t4t_read_binary (offset, length);
749                 else
750                     ce_t4t_send_status (T4T_RSP_WRONG_PARAMS);
751             }
752             else
753             {
754                 CE_TRACE_ERROR0 ("CET4T: File has not been selected");
755                 ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
756             }
757         }
758         else if (instruct == T4T_CMD_INS_UPDATE_BINARY)
759         {
760             if (ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_FILE_READ_ONLY)
761             {
762                 CE_TRACE_ERROR0 ("CET4T: No access right");
763                 ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
764             }
765             else if (ce_cb.mem.t4t.status & CE_T4T_STATUS_NDEF_SELECTED)
766             {
767                 BE_STREAM_TO_UINT16 (offset, p_cmd); /* Offset */
768                 BE_STREAM_TO_UINT8 (length, p_cmd); /* Lc     */
769 
770                 /* check if valid parameters */
771                 if (length <= CE_T4T_MAX_LC)
772                 {
773                     if (length + offset > ce_cb.mem.t4t.max_file_size)
774                     {
775                         CE_TRACE_ERROR3 ("CET4T: length (%d) + offset (%d) must be less than max_file_size (%d)",
776                                           length, offset, ce_cb.mem.t4t.max_file_size);
777                         length = 0;
778                     }
779                 }
780                 else
781                 {
782                     CE_TRACE_ERROR2 ("CET4T: length (%d) must be less than MLc (%d)",
783                                       length, CE_T4T_MAX_LC);
784                     length = 0;
785                 }
786 
787                 if (length > 0)
788                     ce_t4t_update_binary (offset, length, p_cmd);
789                 else
790                     ce_t4t_send_status (T4T_RSP_WRONG_PARAMS);
791             }
792             else
793             {
794                 CE_TRACE_ERROR0 ("CET4T: NDEF File has not been selected");
795                 ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
796             }
797         }
798         else
799         {
800             CE_TRACE_ERROR1 ("CET4T: Unsupported Instruction byte (0x%02X)", instruct);
801             ce_t4t_send_status (T4T_RSP_INSTR_NOT_SUPPORTED);
802         }
803     }
804     else
805     {
806         CE_TRACE_ERROR0 ("CET4T: Application has not been selected");
807         ce_t4t_send_status (T4T_RSP_CMD_NOT_ALLOWED);
808     }
809 
810     if (p_c_apdu)
811         GKI_freebuf (p_c_apdu);
812 }
813 
814 /*******************************************************************************
815 **
816 ** Function         ce_select_t4t
817 **
818 ** Description      Select Type 4 Tag
819 **
820 ** Returns          NFC_STATUS_OK if success
821 **
822 *******************************************************************************/
ce_select_t4t(void)823 tNFC_STATUS ce_select_t4t (void)
824 {
825     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
826 
827     CE_TRACE_DEBUG0 ("ce_select_t4t ()");
828 
829     nfc_stop_quick_timer (&p_t4t->timer);
830 
831     /* clear other than read-only flag */
832     p_t4t->status &= CE_T4T_STATUS_NDEF_FILE_READ_ONLY;
833 
834     NFC_SetStaticRfCback (ce_t4t_data_cback);
835 
836     return NFC_STATUS_OK;
837 }
838 
839 /*******************************************************************************
840 **
841 ** Function         CE_T4tSetLocalNDEFMsg
842 **
843 ** Description      Initialise CE Type 4 Tag with mandatory NDEF message
844 **
845 **                  The following event may be returned
846 **                      CE_T4T_UPDATE_START_EVT for starting update
847 **                      CE_T4T_UPDATE_CPLT_EVT for complete update
848 **                      CE_T4T_UPDATE_ABORT_EVT for failure of update
849 **                      CE_T4T_RAW_FRAME_EVT for raw frame
850 **
851 **                  read_only:      TRUE if read only
852 **                  ndef_msg_max:   Max NDEF message size
853 **                  ndef_msg_len:   NDEF message size
854 **                  p_ndef_msg:     NDEF message (excluding NLEN)
855 **                  p_scratch_buf:  temp storage for update
856 **
857 ** Returns          NFC_STATUS_OK if success
858 **
859 *******************************************************************************/
CE_T4tSetLocalNDEFMsg(BOOLEAN read_only,UINT16 ndef_msg_max,UINT16 ndef_msg_len,UINT8 * p_ndef_msg,UINT8 * p_scratch_buf)860 tNFC_STATUS CE_T4tSetLocalNDEFMsg (BOOLEAN    read_only,
861                                    UINT16     ndef_msg_max,
862                                    UINT16     ndef_msg_len,
863                                    UINT8      *p_ndef_msg,
864                                    UINT8      *p_scratch_buf)
865 {
866     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
867     UINT8       *p;
868 
869     CE_TRACE_API3 ("CE_T4tSetLocalNDEFMsg () read_only=%d, ndef_msg_max=%d, ndef_msg_len=%d",
870                    read_only, ndef_msg_max, ndef_msg_len);
871 
872     if (!p_ndef_msg)
873     {
874         p_t4t->p_ndef_msg = NULL;
875 
876         CE_TRACE_DEBUG0 ("CE_T4tSetLocalNDEFMsg (): T4T is disabled");
877         return NFC_STATUS_OK;
878     }
879 
880     if ((!read_only) && (!p_scratch_buf))
881     {
882         CE_TRACE_ERROR0 ("CE_T4tSetLocalNDEFMsg (): p_scratch_buf cannot be NULL if not read-only");
883         return NFC_STATUS_FAILED;
884     }
885 
886 #if (CE_TEST_INCLUDED == TRUE)
887     mapping_aid_test_enabled = FALSE;
888 #endif
889 
890     /* Initialise CC file */
891     p = p_t4t->cc_file;
892 
893     UINT16_TO_BE_STREAM (p, T4T_CC_FILE_MIN_LEN);
894     UINT8_TO_BE_STREAM (p, T4T_MY_VERSION);
895     UINT16_TO_BE_STREAM (p, CE_T4T_MAX_LE);
896     UINT16_TO_BE_STREAM (p, CE_T4T_MAX_LC);
897 
898     /* Mandatory NDEF File Control TLV */
899     UINT8_TO_BE_STREAM (p, T4T_NDEF_FILE_CONTROL_TYPE);            /* type */
900     UINT8_TO_BE_STREAM (p, T4T_FILE_CONTROL_LENGTH);               /* length */
901     UINT16_TO_BE_STREAM (p, CE_T4T_MANDATORY_NDEF_FILE_ID);         /* file ID */
902     UINT16_TO_BE_STREAM (p, ndef_msg_max + T4T_FILE_LENGTH_SIZE);   /* max NDEF file size */
903     UINT8_TO_BE_STREAM (p, T4T_FC_READ_ACCESS);                    /* read access */
904 
905     if (read_only)
906     {
907         UINT8_TO_BE_STREAM (p, T4T_FC_NO_WRITE_ACCESS);    /* read only */
908         p_t4t->status |= CE_T4T_STATUS_NDEF_FILE_READ_ONLY;
909     }
910     else
911     {
912         UINT8_TO_BE_STREAM (p, T4T_FC_WRITE_ACCESS);       /* write access */
913         p_t4t->status &= ~ (CE_T4T_STATUS_NDEF_FILE_READ_ONLY);
914     }
915 
916     /* set mandatory NDEF file */
917     p_t4t->p_ndef_msg    = p_ndef_msg;
918     p_t4t->nlen          = ndef_msg_len;
919     p_t4t->max_file_size = ndef_msg_max + T4T_FILE_LENGTH_SIZE;
920 
921     /* Initialize scratch buffer */
922     p_t4t->p_scratch_buf = p_scratch_buf;
923 
924     if (p_scratch_buf)
925     {
926         memcpy (p_scratch_buf, p_ndef_msg, ndef_msg_len);
927     }
928 
929     return NFC_STATUS_OK;
930 }
931 
932 /*******************************************************************************
933 **
934 ** Function         CE_T4tRegisterAID
935 **
936 ** Description      Register AID in CE T4T
937 **
938 **                  aid_len: length of AID (up to NFC_MAX_AID_LEN)
939 **                  p_aid:   AID
940 **                  p_cback: Raw frame will be forwarded with CE_RAW_FRAME_EVT
941 **
942 ** Returns          tCE_T4T_AID_HANDLE if successful,
943 **                  CE_T4T_AID_HANDLE_INVALID otherwisse
944 **
945 *******************************************************************************/
CE_T4tRegisterAID(UINT8 aid_len,UINT8 * p_aid,tCE_CBACK * p_cback)946 tCE_T4T_AID_HANDLE CE_T4tRegisterAID (UINT8 aid_len, UINT8 *p_aid, tCE_CBACK *p_cback)
947 {
948     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
949     UINT8       xx;
950 
951     /* Handle registering callback for wildcard AID (all AIDs) */
952     if (aid_len == 0)
953     {
954         CE_TRACE_API0 ("CE_T4tRegisterAID (): registering callback for wildcard AID ");
955 
956         /* Check if a wildcard callback is already registered (only one is allowed) */
957         if (p_t4t->p_wildcard_aid_cback != NULL)
958         {
959             CE_TRACE_ERROR0 ("CE_T4tRegisterAID (): only one wildcard AID can be registered at time.");
960             return CE_T4T_AID_HANDLE_INVALID;
961         }
962 
963         CE_TRACE_DEBUG1 ("CE_T4tRegisterAID (): handle 0x%02x registered (for wildcard AID)", CE_T4T_WILDCARD_AID_HANDLE);
964         p_t4t->p_wildcard_aid_cback = p_cback;
965         return CE_T4T_WILDCARD_AID_HANDLE;
966     }
967 
968 
969     CE_TRACE_API5 ("CE_T4tRegisterAID () AID [%02X%02X%02X%02X...], %d bytes",
970                    *p_aid, *(p_aid+1), *(p_aid+2), *(p_aid+3), aid_len);
971 
972     if (aid_len > NFC_MAX_AID_LEN)
973     {
974         CE_TRACE_ERROR1 ("CE_T4tRegisterAID (): AID is up to %d bytes", NFC_MAX_AID_LEN);
975         return CE_T4T_AID_HANDLE_INVALID;
976     }
977 
978     if (p_cback == NULL)
979     {
980         CE_TRACE_ERROR0 ("CE_T4tRegisterAID (): callback must be provided");
981         return CE_T4T_AID_HANDLE_INVALID;
982     }
983 
984     for (xx = 0; xx < CE_T4T_MAX_REG_AID; xx++)
985     {
986         if (  (p_t4t->reg_aid[xx].aid_len == aid_len)
987             &&(!(memcmp(p_t4t->reg_aid[xx].aid, p_aid, aid_len)))  )
988         {
989             CE_TRACE_ERROR0 ("CE_T4tRegisterAID (): already registered");
990             return CE_T4T_AID_HANDLE_INVALID;
991         }
992     }
993 
994     for (xx = 0; xx < CE_T4T_MAX_REG_AID; xx++)
995     {
996         if (p_t4t->reg_aid[xx].aid_len == 0)
997         {
998             p_t4t->reg_aid[xx].aid_len = aid_len;
999             p_t4t->reg_aid[xx].p_cback = p_cback;
1000             memcpy (p_t4t->reg_aid[xx].aid, p_aid, aid_len);
1001             break;
1002         }
1003     }
1004 
1005     if (xx >= CE_T4T_MAX_REG_AID)
1006     {
1007         CE_TRACE_ERROR0 ("CE_T4tRegisterAID (): No resource");
1008         return CE_T4T_AID_HANDLE_INVALID;
1009     }
1010     else
1011     {
1012         CE_TRACE_DEBUG1 ("CE_T4tRegisterAID (): handle 0x%02x registered", xx);
1013     }
1014 
1015     return (xx);
1016 }
1017 
1018 /*******************************************************************************
1019 **
1020 ** Function         CE_T4tDeregisterAID
1021 **
1022 ** Description      Deregister AID in CE T4T
1023 **
1024 ** Returns          NFC_STATUS_OK if success
1025 **
1026 *******************************************************************************/
CE_T4tDeregisterAID(tCE_T4T_AID_HANDLE aid_handle)1027 NFC_API extern void CE_T4tDeregisterAID (tCE_T4T_AID_HANDLE aid_handle)
1028 {
1029     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
1030 
1031     CE_TRACE_API1 ("CE_T4tDeregisterAID () handle 0x%02x", aid_handle);
1032 
1033     /* Check if deregistering wildcard AID */
1034     if (aid_handle == CE_T4T_WILDCARD_AID_HANDLE)
1035     {
1036         if (p_t4t->p_wildcard_aid_cback != NULL)
1037         {
1038             p_t4t->p_wildcard_aid_cback = NULL;
1039         }
1040         else
1041         {
1042             CE_TRACE_ERROR0 ("CE_T4tDeregisterAID (): Invalid handle");
1043         }
1044         return;
1045     }
1046 
1047     /* Deregister AID */
1048     if ((aid_handle >= CE_T4T_MAX_REG_AID) || (p_t4t->reg_aid[aid_handle].aid_len==0))
1049     {
1050         CE_TRACE_ERROR0 ("CE_T4tDeregisterAID (): Invalid handle");
1051     }
1052     else
1053     {
1054         p_t4t->reg_aid[aid_handle].aid_len = 0;
1055         p_t4t->reg_aid[aid_handle].p_cback = NULL;
1056     }
1057 }
1058 
1059 /*******************************************************************************
1060 **
1061 ** Function         CE_T4TTestSetCC
1062 **
1063 ** Description      Set fields in Capability Container File for testing
1064 **
1065 ** Returns          NFC_STATUS_OK if success
1066 **
1067 *******************************************************************************/
CE_T4TTestSetCC(UINT16 cc_len,UINT8 version,UINT16 max_le,UINT16 max_lc)1068 tNFC_STATUS CE_T4TTestSetCC (UINT16 cc_len,
1069                              UINT8  version,
1070                              UINT16 max_le,
1071                              UINT16 max_lc)
1072 {
1073 #if (CE_TEST_INCLUDED == TRUE)
1074     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
1075     UINT8       *p;
1076 
1077     CE_TRACE_DEBUG4 ("CE_T4TTestSetCC (): CCLen:0x%04X, Ver:0x%02X, MaxLe:0x%04X, MaxLc:0x%04X",
1078                       cc_len, version, max_le, max_lc);
1079 
1080     /* CC file */
1081     p = p_t4t->cc_file;
1082 
1083     if (cc_len != 0xFFFF)
1084     {
1085         UINT16_TO_BE_STREAM (p, cc_len);
1086     }
1087     else
1088         p += 2;
1089 
1090     if (version != 0xFF)
1091     {
1092         mapping_aid_test_enabled = TRUE;
1093         if (version == T4T_VERSION_1_0)
1094             ce_test_tag_app_id[T4T_V20_NDEF_TAG_AID_LEN - 1] = 0x00;
1095         else if (version == T4T_VERSION_2_0)
1096             ce_test_tag_app_id[T4T_V20_NDEF_TAG_AID_LEN - 1] = 0x01;
1097         else /* Undefined version */
1098             ce_test_tag_app_id[T4T_V20_NDEF_TAG_AID_LEN - 1] = 0xFF;
1099 
1100         UINT8_TO_BE_STREAM (p, version);
1101     }
1102     else
1103     {
1104         mapping_aid_test_enabled = FALSE;
1105         p += 1;
1106     }
1107 
1108     if (max_le != 0xFFFF)
1109     {
1110         UINT16_TO_BE_STREAM (p, max_le);
1111     }
1112     else
1113         p += 2;
1114 
1115     if (max_lc != 0xFFFF)
1116     {
1117         UINT16_TO_BE_STREAM (p, max_lc);
1118     }
1119     else
1120         p += 2;
1121 
1122     return NFC_STATUS_OK;
1123 #else
1124     return NFC_STATUS_FAILED;
1125 #endif
1126 }
1127 
1128 /*******************************************************************************
1129 **
1130 ** Function         CE_T4TTestSetNDEFCtrlTLV
1131 **
1132 ** Description      Set fields in NDEF File Control TLV for testing
1133 **
1134 ** Returns          NFC_STATUS_OK if success
1135 **
1136 *******************************************************************************/
CE_T4TTestSetNDEFCtrlTLV(UINT8 type,UINT8 length,UINT16 file_id,UINT16 max_file_size,UINT8 read_access,UINT8 write_access)1137 tNFC_STATUS CE_T4TTestSetNDEFCtrlTLV (UINT8  type,
1138                                       UINT8  length,
1139                                       UINT16 file_id,
1140                                       UINT16 max_file_size,
1141                                       UINT8  read_access,
1142                                       UINT8  write_access)
1143 {
1144 #if (CE_TEST_INCLUDED == TRUE)
1145     tCE_T4T_MEM *p_t4t = &ce_cb.mem.t4t;
1146     UINT8       *p;
1147 
1148     CE_TRACE_DEBUG6 ("CE_T4TTestSetNDEFCtrlTLV (): type:0x%02X, len:0x%02X, FileID:0x%04X, MaxFile:0x%04X, RdAcc:0x%02X, WrAcc:0x%02X",
1149                       type, length, file_id, max_file_size, read_access, write_access);
1150 
1151     /* NDEF File control TLV */
1152     p = p_t4t->cc_file + T4T_FC_TLV_OFFSET_IN_CC;
1153 
1154     if (type != 0xFF)
1155     {
1156         UINT8_TO_BE_STREAM (p, type);
1157     }
1158     else
1159         p += 1;
1160 
1161     if (length != 0xFF)
1162     {
1163         UINT8_TO_BE_STREAM (p, length);
1164     }
1165     else
1166         p += 1;
1167 
1168     if (file_id != 0xFFFF)
1169     {
1170         UINT16_TO_BE_STREAM (p, file_id);
1171     }
1172     else
1173         p += 2;
1174 
1175     if (max_file_size != 0xFFFF)
1176     {
1177         UINT16_TO_BE_STREAM (p, max_file_size);
1178     }
1179     else
1180         p += 2;
1181 
1182     if (read_access != 0xFF)
1183     {
1184         UINT8_TO_BE_STREAM (p, read_access);
1185     }
1186     else
1187         p += 1;
1188 
1189     if (write_access != 0xFF)
1190     {
1191         UINT8_TO_BE_STREAM (p, write_access);
1192     }
1193     else
1194         p += 1;
1195 
1196     return NFC_STATUS_OK;
1197 #else
1198     return NFC_STATUS_FAILED;
1199 #endif
1200 }
1201 #endif /* NFC_INCLUDED == TRUE */
1202