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