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