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 3 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 enum {
38 CE_T3T_COMMAND_INVALID,
39 CE_T3T_COMMAND_NFC_FORUM,
40 CE_T3T_COMMAND_FELICA
41 };
42
43 /* T3T CE states */
44 enum { CE_T3T_STATE_NOT_ACTIVATED, CE_T3T_STATE_IDLE, CE_T3T_STATE_UPDATING };
45
46 /* Bitmasks to indicate type of UPDATE */
47 #define CE_T3T_UPDATE_FL_NDEF_UPDATE_START 0x01
48 #define CE_T3T_UPDATE_FL_NDEF_UPDATE_CPLT 0x02
49 #define CE_T3T_UPDATE_FL_UPDATE 0x04
50
51 /*******************************************************************************
52 * Static constant definitions
53 *******************************************************************************/
54 /* Default PMm param */
55 static const uint8_t CE_DEFAULT_LF_PMM[NCI_T3T_PMM_LEN] = {
56 0x01, /* This PAD0 is used to identify HCE-F on Android */
57 0xFE, /* This PAD0 is used to identify HCE-F on Android */
58 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
59
60 /*******************************************************************************
61 **
62 ** Function ce_t3t_init
63 **
64 ** Description Initialize tag-specific fields of ce control block
65 **
66 ** Returns none
67 **
68 *******************************************************************************/
ce_t3t_init(void)69 void ce_t3t_init(void) {
70 memcpy(ce_cb.mem.t3t.local_pmm, CE_DEFAULT_LF_PMM, NCI_T3T_PMM_LEN);
71 ce_cb.mem.t3t.ndef_info.nbr = CE_T3T_DEFAULT_CHECK_MAXBLOCKS;
72 ce_cb.mem.t3t.ndef_info.nbw = CE_T3T_DEFAULT_UPDATE_MAXBLOCKS;
73 }
74
75 /*******************************************************************************
76 **
77 ** Function ce_t3t_send_to_lower
78 **
79 ** Description Send C-APDU to lower layer
80 **
81 ** Returns none
82 **
83 *******************************************************************************/
ce_t3t_send_to_lower(NFC_HDR * p_msg)84 void ce_t3t_send_to_lower(NFC_HDR* p_msg) {
85 uint8_t* p;
86
87 /* Set NFC-F SoD field (payload len + 1) */
88 p_msg->offset -= 1; /* Point to SoD field */
89 p = (uint8_t*)(p_msg + 1) + p_msg->offset;
90 UINT8_TO_STREAM(p, (p_msg->len + 1));
91 p_msg->len += 1; /* Increment len to include SoD */
92
93 #if (BT_TRACE_PROTOCOL == TRUE)
94 DispT3TagMessage(p_msg, false);
95 #endif
96
97 if (NFC_SendData(NFC_RF_CONN_ID, p_msg) != NFC_STATUS_OK) {
98 CE_TRACE_ERROR0("ce_t3t_send_to_lower (): NFC_SendData () failed");
99 }
100 }
101
102 /*******************************************************************************
103 **
104 ** Function ce_t3t_is_valid_opcode
105 **
106 ** Description Valid opcode
107 **
108 ** Returns Type of command
109 **
110 *******************************************************************************/
ce_t3t_is_valid_opcode(uint8_t cmd_id)111 uint8_t ce_t3t_is_valid_opcode(uint8_t cmd_id) {
112 uint8_t retval = CE_T3T_COMMAND_INVALID;
113
114 if ((cmd_id == T3T_MSG_OPC_CHECK_CMD) || (cmd_id == T3T_MSG_OPC_UPDATE_CMD)) {
115 retval = CE_T3T_COMMAND_NFC_FORUM;
116 } else if ((cmd_id == T3T_MSG_OPC_POLL_CMD) ||
117 (cmd_id == T3T_MSG_OPC_REQ_SERVICE_CMD) ||
118 (cmd_id == T3T_MSG_OPC_REQ_RESPONSE_CMD) ||
119 (cmd_id == T3T_MSG_OPC_REQ_SYSTEMCODE_CMD)) {
120 retval = CE_T3T_COMMAND_FELICA;
121 }
122
123 return (retval);
124 }
125
126 /*****************************************************************************
127 **
128 ** Function ce_t3t_get_rsp_buf
129 **
130 ** Description Get a buffer for sending T3T messages
131 **
132 ** Returns NFC_HDR *
133 **
134 *****************************************************************************/
ce_t3t_get_rsp_buf(void)135 NFC_HDR* ce_t3t_get_rsp_buf(void) {
136 NFC_HDR* p_cmd_buf;
137
138 p_cmd_buf = (NFC_HDR*)GKI_getpoolbuf(NFC_CE_POOL_ID);
139 if (p_cmd_buf != NULL) {
140 /* Reserve offset for NCI_DATA_HDR and NFC-F Sod (LEN) field */
141 p_cmd_buf->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + 1;
142 p_cmd_buf->len = 0;
143 }
144
145 return (p_cmd_buf);
146 }
147
148 /*******************************************************************************
149 **
150 ** Function ce_t3t_send_rsp
151 **
152 ** Description Send response to reader/writer
153 **
154 ** Returns none
155 **
156 *******************************************************************************/
ce_t3t_send_rsp(tCE_CB * p_ce_cb,uint8_t * p_nfcid2,uint8_t opcode,uint8_t status1,uint8_t status2)157 void ce_t3t_send_rsp(tCE_CB* p_ce_cb, uint8_t* p_nfcid2, uint8_t opcode,
158 uint8_t status1, uint8_t status2) {
159 tCE_T3T_MEM* p_cb = &p_ce_cb->mem.t3t;
160 NFC_HDR* p_rsp_msg;
161 uint8_t *p_dst, *p_rsp_start;
162
163 /* If p_nfcid2 is NULL, then used activated NFCID2 */
164 if (p_nfcid2 == NULL) {
165 p_nfcid2 = p_cb->local_nfcid2;
166 }
167
168 p_rsp_msg = ce_t3t_get_rsp_buf();
169 if (p_rsp_msg != NULL) {
170 p_dst = p_rsp_start = (uint8_t*)(p_rsp_msg + 1) + p_rsp_msg->offset;
171
172 /* Response Code */
173 UINT8_TO_STREAM(p_dst, opcode);
174
175 /* Manufacturer ID */
176 ARRAY_TO_STREAM(p_dst, p_nfcid2, NCI_RF_F_UID_LEN);
177
178 /* Status1 and Status2 */
179 UINT8_TO_STREAM(p_dst, status1);
180 UINT8_TO_STREAM(p_dst, status2);
181
182 p_rsp_msg->len = (uint16_t)(p_dst - p_rsp_start);
183 ce_t3t_send_to_lower(p_rsp_msg);
184 } else {
185 CE_TRACE_ERROR0("CE: Unable to allocat buffer for response message");
186 }
187 }
188
189 /*******************************************************************************
190 **
191 ** Function ce_t3t_handle_update_cmd
192 **
193 ** Description Handle UPDATE command from reader/writer
194 **
195 ** Returns none
196 **
197 *******************************************************************************/
ce_t3t_handle_update_cmd(tCE_CB * p_ce_cb,NFC_HDR * p_cmd_msg)198 void ce_t3t_handle_update_cmd(tCE_CB* p_ce_cb, NFC_HDR* p_cmd_msg) {
199 tCE_T3T_MEM* p_cb = &p_ce_cb->mem.t3t;
200 uint8_t* p_temp;
201 uint8_t* p_block_list = p_cb->cur_cmd.p_block_list_start;
202 uint8_t* p_block_data = p_cb->cur_cmd.p_block_data_start;
203 uint8_t i, j, bl0;
204 uint16_t block_number, service_code, checksum, checksum_rx;
205 uint32_t newlen_hiword;
206 tCE_T3T_NDEF_INFO ndef_info;
207 tNFC_STATUS nfc_status = NFC_STATUS_OK;
208 uint8_t update_flags = 0;
209 tCE_UPDATE_INFO update_info;
210
211 /* If in idle state, notify app that update is starting */
212 if (p_cb->state == CE_T3T_STATE_IDLE) {
213 p_cb->state = CE_T3T_STATE_UPDATING;
214 }
215
216 for (i = 0; i < p_cb->cur_cmd.num_blocks; i++) {
217 /* Read byte0 of block list */
218 STREAM_TO_UINT8(bl0, p_block_list);
219
220 if (bl0 & T3T_MSG_MASK_TWO_BYTE_BLOCK_DESC_FORMAT) {
221 STREAM_TO_UINT8(block_number, p_block_list);
222 } else {
223 STREAM_TO_UINT16(block_number, p_block_list);
224 }
225
226 /* Read the block from memory */
227 service_code =
228 p_cb->cur_cmd.service_code_list[bl0 & T3T_MSG_SERVICE_LIST_MASK];
229
230 /* Reject UPDATE command if service code=T3T_MSG_NDEF_SC_RO */
231 if (service_code == T3T_MSG_NDEF_SC_RO) {
232 /* Error: invalid block number to update */
233 CE_TRACE_ERROR0("CE: UPDATE request using read-only service");
234 nfc_status = NFC_STATUS_FAILED;
235 break;
236 }
237
238 /* Check for NDEF */
239 if (service_code == T3T_MSG_NDEF_SC_RW) {
240 if (p_cb->cur_cmd.num_blocks > p_cb->ndef_info.nbw) {
241 CE_TRACE_ERROR2(
242 "CE: Requested too many blocks to update (requested: %i, max: %i)",
243 p_cb->cur_cmd.num_blocks, p_cb->ndef_info.nbw);
244 nfc_status = NFC_STATUS_FAILED;
245 break;
246 } else if (p_cb->ndef_info.rwflag == T3T_MSG_NDEF_RWFLAG_RO) {
247 CE_TRACE_ERROR0("CE: error: write-request to read-only NDEF message.");
248 nfc_status = NFC_STATUS_FAILED;
249 break;
250 } else if (block_number == 0) {
251 CE_TRACE_DEBUG2("CE: Update sc 0x%04x block %i.", service_code,
252 block_number);
253
254 /* Special caes: NDEF block0 is the ndef attribute block */
255 p_temp = p_block_data;
256 STREAM_TO_UINT8(ndef_info.version, p_block_data);
257 p_block_data += 8; /* Ignore nbr,nbw,maxb,and reserved (reader/writer
258 not allowed to update this) */
259 STREAM_TO_UINT8(ndef_info.writef, p_block_data);
260 p_block_data++; /* Ignore rwflag (reader/writer not allowed to update
261 this) */
262 STREAM_TO_UINT8(newlen_hiword, p_block_data);
263 BE_STREAM_TO_UINT16(ndef_info.ln, p_block_data);
264 ndef_info.ln += (newlen_hiword << 16);
265 BE_STREAM_TO_UINT16(checksum_rx, p_block_data);
266
267 checksum = 0;
268 for (j = 0; j < T3T_MSG_NDEF_ATTR_INFO_SIZE; j++) {
269 checksum += p_temp[j];
270 }
271
272 /* Compare calcuated checksum with received checksum */
273 if (checksum != checksum_rx) {
274 CE_TRACE_ERROR0("CE: Checksum failed for NDEF attribute block.");
275 nfc_status = NFC_STATUS_FAILED;
276 } else {
277 /* Update NDEF attribute block (only allowed to update current length
278 * and writef fields) */
279 p_cb->ndef_info.scratch_ln = ndef_info.ln;
280 p_cb->ndef_info.scratch_writef = ndef_info.writef;
281
282 /* If writef=0 indicates completion of NDEF update */
283 if (ndef_info.writef == 0) {
284 update_flags |= CE_T3T_UPDATE_FL_NDEF_UPDATE_CPLT;
285 }
286 /* writef=1 indicates start of NDEF update */
287 else {
288 update_flags |= CE_T3T_UPDATE_FL_NDEF_UPDATE_START;
289 }
290 }
291 } else {
292 CE_TRACE_DEBUG2("CE: Udpate sc 0x%04x block %i.", service_code,
293 block_number);
294
295 /* Verify that block_number is within NDEF memory */
296 if (block_number > p_cb->ndef_info.nmaxb) {
297 /* Error: invalid block number to update */
298 CE_TRACE_ERROR2(
299 "CE: Requested invalid NDEF block number to update %i (max is "
300 "%i).",
301 block_number, p_cb->ndef_info.nmaxb);
302 nfc_status = NFC_STATUS_FAILED;
303 break;
304 } else {
305 /* Update NDEF memory block */
306 STREAM_TO_ARRAY(
307 (&p_cb->ndef_info
308 .p_scratch_buf[(block_number - 1) * T3T_MSG_BLOCKSIZE]),
309 p_block_data, T3T_MSG_BLOCKSIZE);
310 }
311
312 /* Set flag to indicate that this UPDATE contained at least one block */
313 update_flags |= CE_T3T_UPDATE_FL_UPDATE;
314 }
315 } else {
316 /* Error: invalid service code */
317 CE_TRACE_ERROR1("CE: Requested invalid service code: 0x%04x.",
318 service_code);
319 nfc_status = NFC_STATUS_FAILED;
320 break;
321 }
322 }
323
324 /* Send appropriate response to reader/writer */
325 if (nfc_status == NFC_STATUS_OK) {
326 ce_t3t_send_rsp(p_ce_cb, NULL, T3T_MSG_OPC_UPDATE_RSP,
327 T3T_MSG_RSP_STATUS_OK, T3T_MSG_RSP_STATUS_OK);
328 } else {
329 ce_t3t_send_rsp(p_ce_cb, NULL, T3T_MSG_OPC_UPDATE_RSP,
330 T3T_MSG_RSP_STATUS_ERROR, T3T_MSG_RSP_STATUS2_ERROR_MEMORY);
331 p_cb->state = CE_T3T_STATE_IDLE;
332 }
333
334 /* Notify the app of what got updated */
335 if (update_flags & CE_T3T_UPDATE_FL_NDEF_UPDATE_START) {
336 /* NDEF attribute got updated with WriteF=TRUE */
337 p_ce_cb->p_cback(CE_T3T_NDEF_UPDATE_START_EVT, NULL);
338 }
339
340 if (update_flags & CE_T3T_UPDATE_FL_UPDATE) {
341 /* UPDATE message contained at least one non-NDEF block */
342 p_ce_cb->p_cback(CE_T3T_UPDATE_EVT, NULL);
343 }
344
345 if (update_flags & CE_T3T_UPDATE_FL_NDEF_UPDATE_CPLT) {
346 /* NDEF attribute got updated with WriteF=FALSE */
347 update_info.status = nfc_status;
348 update_info.p_data = p_cb->ndef_info.p_scratch_buf;
349 update_info.length = p_cb->ndef_info.scratch_ln;
350 p_cb->state = CE_T3T_STATE_IDLE;
351 p_ce_cb->p_cback(CE_T3T_NDEF_UPDATE_CPLT_EVT, (tCE_DATA*)&update_info);
352 }
353
354 GKI_freebuf(p_cmd_msg);
355 }
356
357 /*******************************************************************************
358 **
359 ** Function ce_t3t_handle_check_cmd
360 **
361 ** Description Handle CHECK command from reader/writer
362 **
363 ** Returns Nothing
364 **
365 *******************************************************************************/
ce_t3t_handle_check_cmd(tCE_CB * p_ce_cb,NFC_HDR * p_cmd_msg)366 void ce_t3t_handle_check_cmd(tCE_CB* p_ce_cb, NFC_HDR* p_cmd_msg) {
367 tCE_T3T_MEM* p_cb = &p_ce_cb->mem.t3t;
368 NFC_HDR* p_rsp_msg;
369 uint8_t* p_rsp_start;
370 uint8_t *p_dst, *p_temp, *p_status;
371 uint8_t* p_src = p_cb->cur_cmd.p_block_list_start;
372 uint8_t i, bl0;
373 uint8_t ndef_writef;
374 uint32_t ndef_len;
375 uint16_t block_number, service_code, checksum;
376
377 p_rsp_msg = ce_t3t_get_rsp_buf();
378 if (p_rsp_msg != NULL) {
379 p_dst = p_rsp_start = (uint8_t*)(p_rsp_msg + 1) + p_rsp_msg->offset;
380
381 /* Response Code */
382 UINT8_TO_STREAM(p_dst, T3T_MSG_OPC_CHECK_RSP);
383
384 /* Manufacturer ID */
385 ARRAY_TO_STREAM(p_dst, p_cb->local_nfcid2, NCI_RF_F_UID_LEN);
386
387 /* Save pointer to start of status field */
388 p_status = p_dst;
389
390 /* Status1 and Status2 (assume success initially */
391 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS_OK);
392 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS_OK);
393 UINT8_TO_STREAM(p_dst, p_cb->cur_cmd.num_blocks);
394
395 for (i = 0; i < p_cb->cur_cmd.num_blocks; i++) {
396 /* Read byte0 of block list */
397 STREAM_TO_UINT8(bl0, p_src);
398
399 if (bl0 & T3T_MSG_MASK_TWO_BYTE_BLOCK_DESC_FORMAT) {
400 STREAM_TO_UINT8(block_number, p_src);
401 } else {
402 STREAM_TO_UINT16(block_number, p_src);
403 }
404
405 /* Read the block from memory */
406 service_code =
407 p_cb->cur_cmd.service_code_list[bl0 & T3T_MSG_SERVICE_LIST_MASK];
408
409 /* Check for NDEF */
410 if ((service_code == T3T_MSG_NDEF_SC_RO) ||
411 (service_code == T3T_MSG_NDEF_SC_RW)) {
412 /* Verify Nbr (NDEF only) */
413 if (p_cb->cur_cmd.num_blocks > p_cb->ndef_info.nbr) {
414 /* Error: invalid number of blocks to check */
415 CE_TRACE_ERROR2(
416 "CE: Requested too many blocks to check (requested: %i, max: %i)",
417 p_cb->cur_cmd.num_blocks, p_cb->ndef_info.nbr);
418
419 p_dst = p_status;
420 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS_ERROR);
421 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS2_ERROR_MEMORY);
422 break;
423 } else if (block_number == 0) {
424 /* Special caes: NDEF block0 is the ndef attribute block */
425 p_temp = p_dst;
426
427 /* For rw ndef, use scratch buffer's attributes (in case reader/writer
428 * had previously updated NDEF) */
429 if ((p_cb->ndef_info.rwflag == T3T_MSG_NDEF_RWFLAG_RW) &&
430 (p_cb->ndef_info.p_scratch_buf)) {
431 ndef_writef = p_cb->ndef_info.scratch_writef;
432 ndef_len = p_cb->ndef_info.scratch_ln;
433 } else {
434 ndef_writef = p_cb->ndef_info.writef;
435 ndef_len = p_cb->ndef_info.ln;
436 }
437
438 UINT8_TO_STREAM(p_dst, p_cb->ndef_info.version);
439 UINT8_TO_STREAM(p_dst, p_cb->ndef_info.nbr);
440 UINT8_TO_STREAM(p_dst, p_cb->ndef_info.nbw);
441 UINT16_TO_BE_STREAM(p_dst, p_cb->ndef_info.nmaxb);
442 UINT32_TO_STREAM(p_dst, 0);
443 UINT8_TO_STREAM(p_dst, ndef_writef);
444 UINT8_TO_STREAM(p_dst, p_cb->ndef_info.rwflag);
445 UINT8_TO_STREAM(p_dst, (ndef_len >> 16 & 0xFF));
446 UINT16_TO_BE_STREAM(p_dst, (ndef_len & 0xFFFF));
447
448 checksum = 0;
449 for (i = 0; i < T3T_MSG_NDEF_ATTR_INFO_SIZE; i++) {
450 checksum += p_temp[i];
451 }
452 UINT16_TO_BE_STREAM(p_dst, checksum);
453 } else {
454 /* Verify that block_number is within NDEF memory */
455 if (block_number > p_cb->ndef_info.nmaxb) {
456 /* Invalid block number */
457 p_dst = p_status;
458
459 CE_TRACE_ERROR1("CE: Requested block number to check %i.",
460 block_number);
461
462 /* Error: invalid number of blocks to check */
463 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS_ERROR);
464 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS2_ERROR_MEMORY);
465 break;
466 } else {
467 /* If card is RW, then read from the scratch buffer (so reader/write
468 * can read back what it had just written */
469 if ((p_cb->ndef_info.rwflag == T3T_MSG_NDEF_RWFLAG_RW) &&
470 (p_cb->ndef_info.p_scratch_buf)) {
471 ARRAY_TO_STREAM(
472 p_dst,
473 (&p_cb->ndef_info
474 .p_scratch_buf[(block_number - 1) * T3T_MSG_BLOCKSIZE]),
475 T3T_MSG_BLOCKSIZE);
476 } else {
477 ARRAY_TO_STREAM(
478 p_dst, (&p_cb->ndef_info
479 .p_buf[(block_number - 1) * T3T_MSG_BLOCKSIZE]),
480 T3T_MSG_BLOCKSIZE);
481 }
482 }
483 }
484 } else {
485 /* Error: invalid service code */
486 CE_TRACE_ERROR1("CE: Requested invalid service code: 0x%04x.",
487 service_code);
488
489 p_dst = p_status;
490 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS_ERROR);
491 UINT8_TO_STREAM(p_dst, T3T_MSG_RSP_STATUS2_ERROR_MEMORY);
492 break;
493 }
494 }
495
496 p_rsp_msg->len = (uint16_t)(p_dst - p_rsp_start);
497 ce_t3t_send_to_lower(p_rsp_msg);
498 } else {
499 CE_TRACE_ERROR0("CE: Unable to allocat buffer for response message");
500 }
501
502 GKI_freebuf(p_cmd_msg);
503 }
504
505 /*******************************************************************************
506 **
507 ** Function ce_t3t_handle_non_nfc_forum_cmd
508 **
509 ** Description Handle POLL command from reader/writer
510 **
511 ** Returns Nothing
512 **
513 *******************************************************************************/
ce_t3t_handle_non_nfc_forum_cmd(tCE_CB * p_mem_cb,uint8_t cmd_id,NFC_HDR * p_cmd_msg)514 void ce_t3t_handle_non_nfc_forum_cmd(tCE_CB* p_mem_cb, uint8_t cmd_id,
515 NFC_HDR* p_cmd_msg) {
516 tCE_T3T_MEM* p_cb = &p_mem_cb->mem.t3t;
517 NFC_HDR* p_rsp_msg;
518 uint8_t* p_rsp_start;
519 uint8_t* p_dst;
520 uint8_t* p = (uint8_t*)(p_cmd_msg + 1) + p_cmd_msg->offset;
521 uint16_t sc;
522 uint8_t rc;
523 bool send_response = true;
524
525 p_rsp_msg = ce_t3t_get_rsp_buf();
526 if (p_rsp_msg != NULL) {
527 p_dst = p_rsp_start = (uint8_t*)(p_rsp_msg + 1) + p_rsp_msg->offset;
528
529 switch (cmd_id) {
530 case T3T_MSG_OPC_POLL_CMD:
531 /* Get system code and RC */
532 /* Skip over sod and cmd_id */
533 p += 2;
534 BE_STREAM_TO_UINT16(sc, p);
535 STREAM_TO_UINT8(rc, p);
536
537 /* If requesting wildcard system code, or specifically our system code,
538 * then send POLL response */
539 if ((sc == 0xFFFF) || (sc == p_cb->system_code)) {
540 /* Response Code */
541 UINT8_TO_STREAM(p_dst, T3T_MSG_OPC_POLL_RSP);
542
543 /* Manufacturer ID */
544 ARRAY_TO_STREAM(p_dst, p_cb->local_nfcid2, NCI_RF_F_UID_LEN);
545
546 /* Manufacturer Parameter PMm */
547 ARRAY_TO_STREAM(p_dst, p_cb->local_pmm, NCI_T3T_PMM_LEN);
548
549 /* If requesting system code */
550 if (rc == T3T_POLL_RC_SC) {
551 UINT16_TO_BE_STREAM(p_dst, p_cb->system_code);
552 }
553 } else {
554 send_response = false;
555 }
556 break;
557
558 case T3T_MSG_OPC_REQ_RESPONSE_CMD:
559 /* Response Code */
560 UINT8_TO_STREAM(p_dst, T3T_MSG_OPC_REQ_RESPONSE_RSP);
561
562 /* Manufacturer ID */
563 ARRAY_TO_STREAM(p_dst, p_cb->local_nfcid2, NCI_RF_F_UID_LEN);
564
565 /* Mode */
566 UINT8_TO_STREAM(p_dst, 0);
567 break;
568
569 case T3T_MSG_OPC_REQ_SYSTEMCODE_CMD:
570 /* Response Code */
571 UINT8_TO_STREAM(p_dst, T3T_MSG_OPC_REQ_SYSTEMCODE_RSP);
572
573 /* Manufacturer ID */
574 ARRAY_TO_STREAM(p_dst, p_cb->local_nfcid2, NCI_RF_F_UID_LEN);
575
576 /* Number of system codes */
577 UINT8_TO_STREAM(p_dst, 1);
578
579 /* system codes */
580 UINT16_TO_BE_STREAM(p_dst, T3T_SYSTEM_CODE_NDEF);
581 break;
582
583 case T3T_MSG_OPC_REQ_SERVICE_CMD:
584 default:
585 /* Unhandled command */
586 CE_TRACE_ERROR1("Unhandled CE opcode: %02x", cmd_id);
587 send_response = false;
588 break;
589 }
590
591 if (send_response) {
592 p_rsp_msg->len = (uint16_t)(p_dst - p_rsp_start);
593 ce_t3t_send_to_lower(p_rsp_msg);
594 } else {
595 GKI_freebuf(p_rsp_msg);
596 }
597 } else {
598 CE_TRACE_ERROR0("CE: Unable to allocat buffer for response message");
599 }
600 GKI_freebuf(p_cmd_msg);
601 }
602
603 /*******************************************************************************
604 **
605 ** Function ce_t3t_data_cback
606 **
607 ** Description This callback function receives the data from NFCC.
608 **
609 ** Returns none
610 **
611 *******************************************************************************/
ce_t3t_data_cback(uint8_t conn_id,tNFC_DATA_CEVT * p_data)612 void ce_t3t_data_cback(uint8_t conn_id, tNFC_DATA_CEVT* p_data) {
613 tCE_CB* p_ce_cb = &ce_cb;
614 tCE_T3T_MEM* p_cb = &p_ce_cb->mem.t3t;
615 NFC_HDR* p_msg = p_data->p_data;
616 tCE_DATA ce_data;
617 uint8_t cmd_id, bl0, entry_len, i;
618 uint8_t* p_nfcid2 = NULL;
619 uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
620 uint8_t cmd_nfcid2[NCI_RF_F_UID_LEN];
621 uint16_t block_list_start_offset, remaining;
622 bool msg_processed = false;
623 bool block_list_ok;
624 uint8_t sod;
625 uint8_t cmd_type;
626
627 #if (BT_TRACE_PROTOCOL == TRUE)
628 DispT3TagMessage(p_msg, true);
629 #endif
630
631 /* If activate system code is not NDEF, or if no local NDEF contents was set,
632 * then pass data up to the app */
633 if ((p_cb->system_code != T3T_SYSTEM_CODE_NDEF) ||
634 (!p_cb->ndef_info.initialized)) {
635 ce_data.raw_frame.status = p_data->status;
636 ce_data.raw_frame.p_data = p_msg;
637 p_ce_cb->p_cback(CE_T3T_RAW_FRAME_EVT, &ce_data);
638 return;
639 }
640
641 /* Verify that message contains at least Sod and cmd_id */
642 if (p_msg->len < 2) {
643 CE_TRACE_ERROR1("CE: received invalid T3t message (invalid length: %i)",
644 p_msg->len);
645 } else {
646 /* Get and validate command opcode */
647 STREAM_TO_UINT8(sod, p);
648 STREAM_TO_UINT8(cmd_id, p);
649
650 /* Valid command and message length */
651 cmd_type = ce_t3t_is_valid_opcode(cmd_id);
652 if (cmd_type == CE_T3T_COMMAND_INVALID) {
653 CE_TRACE_ERROR1(
654 "CE: received invalid T3t message (invalid command: 0x%02X)", cmd_id);
655 } else if (cmd_type == CE_T3T_COMMAND_FELICA) {
656 ce_t3t_handle_non_nfc_forum_cmd(p_ce_cb, cmd_id, p_msg);
657 msg_processed = true;
658 } else {
659 /* Verify that message contains at least NFCID2 and NUM services */
660 if (p_msg->len < T3T_MSG_CMD_COMMON_HDR_LEN) {
661 CE_TRACE_ERROR1("CE: received invalid T3t message (invalid length: %i)",
662 p_msg->len);
663 } else {
664 /* Handle NFC_FORUM command (UPDATE or CHECK) */
665 STREAM_TO_ARRAY(cmd_nfcid2, p, NCI_RF_F_UID_LEN);
666 STREAM_TO_UINT8(p_cb->cur_cmd.num_services, p);
667
668 /* Calculate offset of block-list-start */
669 block_list_start_offset =
670 T3T_MSG_CMD_COMMON_HDR_LEN + 2 * p_cb->cur_cmd.num_services + 1;
671
672 if (p_cb->state == CE_T3T_STATE_NOT_ACTIVATED) {
673 CE_TRACE_ERROR2(
674 "CE: received command 0x%02X while in bad state (%i))", cmd_id,
675 p_cb->state);
676 } else if (memcmp(cmd_nfcid2, p_cb->local_nfcid2, NCI_RF_F_UID_LEN) !=
677 0) {
678 CE_TRACE_ERROR0("CE: received invalid T3t message (invalid NFCID2)");
679 p_nfcid2 = cmd_nfcid2; /* respond with ERROR using the NFCID2 from the
680 command message */
681 } else if (p_msg->len < block_list_start_offset) {
682 /* Does not have minimum (including number_of_blocks field) */
683 CE_TRACE_ERROR0("CE: incomplete message");
684 } else {
685 /* Parse service code list */
686 for (i = 0; i < p_cb->cur_cmd.num_services; i++) {
687 STREAM_TO_UINT16(p_cb->cur_cmd.service_code_list[i], p);
688 }
689
690 /* Verify that block list */
691 block_list_ok = true;
692 STREAM_TO_UINT8(p_cb->cur_cmd.num_blocks, p);
693 remaining = p_msg->len - block_list_start_offset;
694 p_cb->cur_cmd.p_block_list_start = p;
695 for (i = 0; i < p_cb->cur_cmd.num_blocks; i++) {
696 /* Each entry is at lease 2 bytes long */
697 if (remaining < 2) {
698 /* Unexpected end of message (while reading block-list) */
699 CE_TRACE_ERROR0(
700 "CE: received invalid T3t message (unexpected end of "
701 "block-list)");
702 block_list_ok = false;
703 break;
704 }
705
706 /* Get byte0 of block-list entry */
707 bl0 = *p;
708
709 /* Validate service code index and size of block-list */
710 if ((bl0 & T3T_MSG_SERVICE_LIST_MASK) >=
711 p_cb->cur_cmd.num_services) {
712 /* Invalid service code */
713 CE_TRACE_ERROR1(
714 "CE: received invalid T3t message (invalid service index: "
715 "%i)",
716 (bl0 & T3T_MSG_SERVICE_LIST_MASK));
717 block_list_ok = false;
718 break;
719 } else if ((!(bl0 & T3T_MSG_MASK_TWO_BYTE_BLOCK_DESC_FORMAT)) &&
720 (remaining < 3)) {
721 /* Unexpected end of message (while reading 3-byte entry) */
722 CE_TRACE_ERROR0(
723 "CE: received invalid T3t message (unexpected end of "
724 "block-list)");
725 block_list_ok = false;
726 break;
727 }
728
729 /* Advance pointers to next block-list entry */
730 entry_len = (bl0 & T3T_MSG_MASK_TWO_BYTE_BLOCK_DESC_FORMAT) ? 2 : 3;
731 p += entry_len;
732 remaining -= entry_len;
733 }
734
735 /* Block list is verified. Call CHECK or UPDATE handler */
736 if (block_list_ok) {
737 p_cb->cur_cmd.p_block_data_start = p;
738 if (cmd_id == T3T_MSG_OPC_CHECK_CMD) {
739 /* This is a CHECK command. Sanity check: there shouldn't be any
740 * more data remaining after reading block list */
741 if (remaining) {
742 CE_TRACE_ERROR1(
743 "CE: unexpected data after after CHECK command (#i bytes)",
744 remaining);
745 }
746 ce_t3t_handle_check_cmd(p_ce_cb, p_msg);
747 msg_processed = true;
748 } else {
749 /* This is an UPDATE command. See if message contains all the
750 * expected block data */
751 if (remaining < p_cb->cur_cmd.num_blocks * T3T_MSG_BLOCKSIZE) {
752 CE_TRACE_ERROR0("CE: unexpected end of block-data");
753 } else {
754 ce_t3t_handle_update_cmd(p_ce_cb, p_msg);
755 msg_processed = true;
756 }
757 }
758 }
759 }
760 }
761 }
762 }
763
764 if (!msg_processed) {
765 ce_t3t_send_rsp(p_ce_cb, p_nfcid2, T3T_MSG_OPC_CHECK_RSP,
766 T3T_MSG_RSP_STATUS_ERROR,
767 T3T_MSG_RSP_STATUS2_ERROR_PROCESSING);
768 GKI_freebuf(p_msg);
769 }
770 }
771
772 /*******************************************************************************
773 **
774 ** Function ce_t3t_conn_cback
775 **
776 ** Description This callback function receives the events/data from NFCC.
777 **
778 ** Returns none
779 **
780 *******************************************************************************/
ce_t3t_conn_cback(uint8_t conn_id,tNFC_CONN_EVT event,tNFC_CONN * p_data)781 void ce_t3t_conn_cback(uint8_t conn_id, tNFC_CONN_EVT event,
782 tNFC_CONN* p_data) {
783 tCE_T3T_MEM* p_cb = &ce_cb.mem.t3t;
784
785 CE_TRACE_DEBUG2("ce_t3t_conn_cback: conn_id=%i, evt=%i", conn_id, event);
786
787 switch (event) {
788 case NFC_CONN_CREATE_CEVT:
789 break;
790
791 case NFC_CONN_CLOSE_CEVT:
792 p_cb->state = CE_T3T_STATE_NOT_ACTIVATED;
793 break;
794
795 case NFC_DATA_CEVT:
796 if (p_data->data.status == NFC_STATUS_OK) {
797 ce_t3t_data_cback(conn_id, &p_data->data);
798 }
799 break;
800
801 case NFC_DEACTIVATE_CEVT:
802 p_cb->state = CE_T3T_STATE_NOT_ACTIVATED;
803 NFC_SetStaticRfCback(NULL);
804 break;
805
806 default:
807 break;
808 }
809 }
810
811 /*******************************************************************************
812 **
813 ** Function ce_select_t3t
814 **
815 ** Description Select Type 3 Tag
816 **
817 ** Returns NFC_STATUS_OK if success
818 **
819 *******************************************************************************/
ce_select_t3t(uint16_t system_code,uint8_t nfcid2[NCI_RF_F_UID_LEN])820 tNFC_STATUS ce_select_t3t(uint16_t system_code,
821 uint8_t nfcid2[NCI_RF_F_UID_LEN]) {
822 tCE_T3T_MEM* p_cb = &ce_cb.mem.t3t;
823
824 CE_TRACE_DEBUG0("ce_select_t3t ()");
825
826 p_cb->state = CE_T3T_STATE_IDLE;
827 p_cb->system_code = system_code;
828 memcpy(p_cb->local_nfcid2, nfcid2, NCI_RF_F_UID_LEN);
829
830 NFC_SetStaticRfCback(ce_t3t_conn_cback);
831 return NFC_STATUS_OK;
832 }
833
834 /*******************************************************************************
835 **
836 ** Function CE_T3tSetLocalNDEFMsg
837 **
838 ** Description Initialise CE Type 3 Tag with mandatory NDEF message
839 **
840 ** Returns NFC_STATUS_OK if success
841 **
842 *******************************************************************************/
CE_T3tSetLocalNDEFMsg(bool read_only,uint32_t size_max,uint32_t size_current,uint8_t * p_buf,uint8_t * p_scratch_buf)843 tNFC_STATUS CE_T3tSetLocalNDEFMsg(bool read_only, uint32_t size_max,
844 uint32_t size_current, uint8_t* p_buf,
845 uint8_t* p_scratch_buf) {
846 tCE_T3T_MEM* p_cb = &ce_cb.mem.t3t;
847
848 CE_TRACE_API3("CE_T3tSetContent: ro=%i, size_max=%i, size_current=%i",
849 read_only, size_max, size_current);
850
851 /* Verify scratch buffer was provided if NDEF message is read/write */
852 if ((!read_only) && (!p_scratch_buf)) {
853 CE_TRACE_ERROR0(
854 "CE_T3tSetLocalNDEFMsg (): p_scratch_buf cannot be NULL if not "
855 "read-only");
856 return NFC_STATUS_FAILED;
857 }
858
859 /* Check if disabling the local NDEF */
860 if (!p_buf) {
861 p_cb->ndef_info.initialized = false;
862 }
863 /* Save ndef attributes */
864 else {
865 p_cb->ndef_info.initialized = true;
866 p_cb->ndef_info.ln = size_current; /* Current length */
867 p_cb->ndef_info.nmaxb = (uint16_t)(
868 (size_max + 15) / T3T_MSG_BLOCKSIZE); /* Max length (in blocks) */
869 p_cb->ndef_info.rwflag =
870 (read_only) ? T3T_MSG_NDEF_RWFLAG_RO : T3T_MSG_NDEF_RWFLAG_RW;
871 p_cb->ndef_info.writef = T3T_MSG_NDEF_WRITEF_OFF;
872 p_cb->ndef_info.version = 0x10;
873 p_cb->ndef_info.p_buf = p_buf;
874 p_cb->ndef_info.p_scratch_buf = p_scratch_buf;
875
876 /* Initiate scratch buffer with same contents as read-buffer */
877 if (p_scratch_buf) {
878 p_cb->ndef_info.scratch_ln = p_cb->ndef_info.ln;
879 p_cb->ndef_info.scratch_writef = T3T_MSG_NDEF_WRITEF_OFF;
880 memcpy(p_scratch_buf, p_buf, p_cb->ndef_info.ln);
881 }
882 }
883
884 return (NFC_STATUS_OK);
885 }
886
887 /*******************************************************************************
888 **
889 ** Function CE_T3tSetLocalNDefParams
890 **
891 ** Description Sets T3T-specific NDEF parameters. (Optional - if not
892 ** called, then CE will use default parameters)
893 **
894 ** Returns NFC_STATUS_OK if success
895 **
896 *******************************************************************************/
CE_T3tSetLocalNDefParams(uint8_t nbr,uint8_t nbw)897 tNFC_STATUS CE_T3tSetLocalNDefParams(uint8_t nbr, uint8_t nbw) {
898 tCE_T3T_MEM* p_cb = &ce_cb.mem.t3t;
899
900 CE_TRACE_API2("CE_T3tSetLocalNDefParams: nbr=%i, nbw=%i", nbr, nbw);
901
902 /* Validate */
903 if ((nbr > T3T_MSG_NUM_BLOCKS_CHECK_MAX) ||
904 (nbw > T3T_MSG_NUM_BLOCKS_UPDATE_MAX) || (nbr < 1) || (nbw < 1)) {
905 CE_TRACE_ERROR0("CE_T3tSetLocalNDefParams: invalid params");
906 return NFC_STATUS_FAILED;
907 }
908
909 p_cb->ndef_info.nbr = nbr;
910 p_cb->ndef_info.nbw = nbw;
911
912 return NFC_STATUS_OK;
913 }
914
915 /*******************************************************************************
916 **
917 ** Function CE_T3tSendCheckRsp
918 **
919 ** Description Send CHECK response message
920 **
921 ** Returns NFC_STATUS_OK if success
922 **
923 *******************************************************************************/
CE_T3tSendCheckRsp(uint8_t status1,uint8_t status2,uint8_t num_blocks,uint8_t * p_block_data)924 tNFC_STATUS CE_T3tSendCheckRsp(uint8_t status1, uint8_t status2,
925 uint8_t num_blocks, uint8_t* p_block_data) {
926 tCE_T3T_MEM* p_cb = &ce_cb.mem.t3t;
927 tNFC_STATUS retval = NFC_STATUS_OK;
928 NFC_HDR* p_rsp_msg;
929 uint8_t *p_dst, *p_rsp_start;
930
931 CE_TRACE_API3("CE_T3tCheckRsp: status1=0x%02X, status2=0x%02X, num_blocks=%i",
932 status1, status2, num_blocks);
933
934 /* Validate num_blocks */
935 if (num_blocks > T3T_MSG_NUM_BLOCKS_CHECK_MAX) {
936 CE_TRACE_ERROR2("CE_T3tCheckRsp num_blocks (%i) exceeds maximum (%i)",
937 num_blocks, T3T_MSG_NUM_BLOCKS_CHECK_MAX);
938 return (NFC_STATUS_FAILED);
939 }
940
941 p_rsp_msg = ce_t3t_get_rsp_buf();
942 if (p_rsp_msg != NULL) {
943 p_dst = p_rsp_start = (uint8_t*)(p_rsp_msg + 1) + p_rsp_msg->offset;
944
945 /* Response Code */
946 UINT8_TO_STREAM(p_dst, T3T_MSG_OPC_CHECK_RSP);
947
948 /* Manufacturer ID */
949 ARRAY_TO_STREAM(p_dst, p_cb->local_nfcid2, NCI_RF_F_UID_LEN);
950
951 /* Status1 and Status2 */
952 UINT8_TO_STREAM(p_dst, status1);
953 UINT8_TO_STREAM(p_dst, status2);
954
955 if (status1 == T3T_MSG_RSP_STATUS_OK) {
956 UINT8_TO_STREAM(p_dst, num_blocks);
957 ARRAY_TO_STREAM(p_dst, p_block_data, (num_blocks * T3T_MSG_BLOCKSIZE));
958 }
959
960 p_rsp_msg->len = (uint16_t)(p_dst - p_rsp_start);
961 ce_t3t_send_to_lower(p_rsp_msg);
962 } else {
963 CE_TRACE_ERROR0("CE: Unable to allocate buffer for response message");
964 }
965
966 return (retval);
967 }
968
969 /*******************************************************************************
970 **
971 ** Function CE_T3tSendUpdateRsp
972 **
973 ** Description Send UPDATE response message
974 **
975 ** Returns NFC_STATUS_OK if success
976 **
977 *******************************************************************************/
CE_T3tSendUpdateRsp(uint8_t status1,uint8_t status2)978 tNFC_STATUS CE_T3tSendUpdateRsp(uint8_t status1, uint8_t status2) {
979 tNFC_STATUS retval = NFC_STATUS_OK;
980 tCE_CB* p_ce_cb = &ce_cb;
981
982 CE_TRACE_API2("CE_T3tUpdateRsp: status1=0x%02X, status2=0x%02X", status1,
983 status2);
984 ce_t3t_send_rsp(p_ce_cb, NULL, T3T_MSG_OPC_UPDATE_RSP, status1, status2);
985
986 return (retval);
987 }
988