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