1 /******************************************************************************
2 *
3 * Copyright (C) 2010-2013 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19
20 /******************************************************************************
21 *
22 * This file contains the implementation for Type 4 tag in Reader/Writer
23 * mode.
24 *
25 ******************************************************************************/
26 #include <string.h>
27 #include "nfc_target.h"
28 #include "bt_types.h"
29 #include "trace_api.h"
30
31 #if (NFC_INCLUDED == TRUE)
32
33 #include "nfc_api.h"
34 #include "nfc_int.h"
35 #include "rw_api.h"
36 #include "rw_int.h"
37 #include "tags_int.h"
38 #include "gki.h"
39
40 /* main state */
41 #define RW_T4T_STATE_NOT_ACTIVATED 0x00 /* T4T is not activated */
42 #define RW_T4T_STATE_IDLE 0x01 /* waiting for upper layer API */
43 #define RW_T4T_STATE_DETECT_NDEF 0x02 /* performing NDEF detection precedure */
44 #define RW_T4T_STATE_READ_NDEF 0x03 /* performing read NDEF procedure */
45 #define RW_T4T_STATE_UPDATE_NDEF 0x04 /* performing update NDEF procedure */
46 #define RW_T4T_STATE_PRESENCE_CHECK 0x05 /* checking presence of tag */
47 #define RW_T4T_STATE_SET_READ_ONLY 0x06 /* convert tag to read only */
48
49 /* sub state */
50 #define RW_T4T_SUBSTATE_WAIT_SELECT_APP 0x00 /* waiting for response of selecting AID */
51 #define RW_T4T_SUBSTATE_WAIT_SELECT_CC 0x01 /* waiting for response of selecting CC */
52 #define RW_T4T_SUBSTATE_WAIT_CC_FILE 0x02 /* waiting for response of reading CC */
53 #define RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE 0x03 /* waiting for response of selecting NDEF */
54 #define RW_T4T_SUBSTATE_WAIT_READ_NLEN 0x04 /* waiting for response of reading NLEN */
55 #define RW_T4T_SUBSTATE_WAIT_READ_RESP 0x05 /* waiting for response of reading file */
56 #define RW_T4T_SUBSTATE_WAIT_UPDATE_RESP 0x06 /* waiting for response of updating file */
57 #define RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN 0x07 /* waiting for response of updating NLEN */
58 #define RW_T4T_SUBSTATE_WAIT_UPDATE_CC 0x08 /* waiting for response of updating CC */
59
60 #if (BT_TRACE_VERBOSE == TRUE)
61 static char *rw_t4t_get_state_name (UINT8 state);
62 static char *rw_t4t_get_sub_state_name (UINT8 sub_state);
63 #endif
64
65 static BOOLEAN rw_t4t_send_to_lower (BT_HDR *p_c_apdu);
66 static BOOLEAN rw_t4t_select_file (UINT16 file_id);
67 static BOOLEAN rw_t4t_read_file (UINT16 offset, UINT16 length, BOOLEAN is_continue);
68 static BOOLEAN rw_t4t_update_nlen (UINT16 ndef_len);
69 static BOOLEAN rw_t4t_update_file (void);
70 static BOOLEAN rw_t4t_update_cc_to_readonly (void);
71 static BOOLEAN rw_t4t_select_application (UINT8 version);
72 static BOOLEAN rw_t4t_validate_cc_file (void);
73 static void rw_t4t_handle_error (tNFC_STATUS status, UINT8 sw1, UINT8 sw2);
74 static void rw_t4t_sm_detect_ndef (BT_HDR *p_r_apdu);
75 static void rw_t4t_sm_read_ndef (BT_HDR *p_r_apdu);
76 static void rw_t4t_sm_update_ndef (BT_HDR *p_r_apdu);
77 static void rw_t4t_sm_set_readonly (BT_HDR *p_r_apdu);
78 static void rw_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data);
79
80 /*******************************************************************************
81 **
82 ** Function rw_t4t_send_to_lower
83 **
84 ** Description Send C-APDU to lower layer
85 **
86 ** Returns TRUE if success
87 **
88 *******************************************************************************/
rw_t4t_send_to_lower(BT_HDR * p_c_apdu)89 static BOOLEAN rw_t4t_send_to_lower (BT_HDR *p_c_apdu)
90 {
91 #if (BT_TRACE_PROTOCOL == TRUE)
92 DispRWT4Tags (p_c_apdu, FALSE);
93 #endif
94
95 if (NFC_SendData (NFC_RF_CONN_ID, p_c_apdu) != NFC_STATUS_OK)
96 {
97 RW_TRACE_ERROR0 ("rw_t4t_send_to_lower (): NFC_SendData () failed");
98 return FALSE;
99 }
100
101 nfc_start_quick_timer (&rw_cb.tcb.t4t.timer, NFC_TTYPE_RW_T4T_RESPONSE,
102 (RW_T4T_TOUT_RESP * QUICK_TIMER_TICKS_PER_SEC) / 1000);
103
104 return TRUE;
105 }
106
107 /*******************************************************************************
108 **
109 ** Function rw_t4t_select_file
110 **
111 ** Description Send Select Command (by File ID) to peer
112 **
113 ** Returns TRUE if success
114 **
115 *******************************************************************************/
rw_t4t_select_file(UINT16 file_id)116 static BOOLEAN rw_t4t_select_file (UINT16 file_id)
117 {
118 BT_HDR *p_c_apdu;
119 UINT8 *p;
120
121 RW_TRACE_DEBUG1 ("rw_t4t_select_file (): File ID:0x%04X", file_id);
122
123 p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
124
125 if (!p_c_apdu)
126 {
127 RW_TRACE_ERROR0 ("rw_t4t_select_file (): Cannot allocate buffer");
128 return FALSE;
129 }
130
131 p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
132 p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
133
134 UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
135 UINT8_TO_BE_STREAM (p, T4T_CMD_INS_SELECT);
136 UINT8_TO_BE_STREAM (p, T4T_CMD_P1_SELECT_BY_FILE_ID);
137
138 /* if current version mapping is V2.0 */
139 if (rw_cb.tcb.t4t.version == T4T_VERSION_2_0)
140 {
141 UINT8_TO_BE_STREAM (p, T4T_CMD_P2_FIRST_OR_ONLY_0CH);
142 }
143 else /* version 1.0 */
144 {
145 UINT8_TO_BE_STREAM (p, T4T_CMD_P2_FIRST_OR_ONLY_00H);
146 }
147
148 UINT8_TO_BE_STREAM (p, T4T_FILE_ID_SIZE);
149 UINT16_TO_BE_STREAM (p, file_id);
150
151 p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_FILE_ID_SIZE;
152
153 if (!rw_t4t_send_to_lower (p_c_apdu))
154 {
155 return FALSE;
156 }
157
158 return TRUE;
159 }
160
161 /*******************************************************************************
162 **
163 ** Function rw_t4t_read_file
164 **
165 ** Description Send ReadBinary Command to peer
166 **
167 ** Returns TRUE if success
168 **
169 *******************************************************************************/
rw_t4t_read_file(UINT16 offset,UINT16 length,BOOLEAN is_continue)170 static BOOLEAN rw_t4t_read_file (UINT16 offset, UINT16 length, BOOLEAN is_continue)
171 {
172 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
173 BT_HDR *p_c_apdu;
174 UINT8 *p;
175
176 RW_TRACE_DEBUG3 ("rw_t4t_read_file () offset:%d, length:%d, is_continue:%d, ",
177 offset, length, is_continue);
178
179 p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
180
181 if (!p_c_apdu)
182 {
183 RW_TRACE_ERROR0 ("rw_t4t_read_file (): Cannot allocate buffer");
184 return FALSE;
185 }
186
187 /* if this is the first reading */
188 if (is_continue == FALSE)
189 {
190 /* initialise starting offset and total length */
191 /* these will be updated when receiving response */
192 p_t4t->rw_offset = offset;
193 p_t4t->rw_length = length;
194 }
195
196 /* adjust reading length if payload is bigger than max size per single command */
197 if (length > p_t4t->max_read_size)
198 {
199 length = (UINT8) (p_t4t->max_read_size);
200 }
201
202 p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
203 p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
204
205 UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
206 UINT8_TO_BE_STREAM (p, T4T_CMD_INS_READ_BINARY);
207 UINT16_TO_BE_STREAM (p, offset);
208 UINT8_TO_BE_STREAM (p, length); /* Le */
209
210 p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 1; /* adding Le */
211
212 if (!rw_t4t_send_to_lower (p_c_apdu))
213 {
214 return FALSE;
215 }
216
217 return TRUE;
218 }
219
220 /*******************************************************************************
221 **
222 ** Function rw_t4t_update_nlen
223 **
224 ** Description Send UpdateBinary Command to update NLEN to peer
225 **
226 ** Returns TRUE if success
227 **
228 *******************************************************************************/
rw_t4t_update_nlen(UINT16 ndef_len)229 static BOOLEAN rw_t4t_update_nlen (UINT16 ndef_len)
230 {
231 BT_HDR *p_c_apdu;
232 UINT8 *p;
233
234 RW_TRACE_DEBUG1 ("rw_t4t_update_nlen () NLEN:%d", ndef_len);
235
236 p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
237
238 if (!p_c_apdu)
239 {
240 RW_TRACE_ERROR0 ("rw_t4t_update_nlen (): Cannot allocate buffer");
241 return FALSE;
242 }
243
244 p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
245 p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
246
247 UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
248 UINT8_TO_BE_STREAM (p, T4T_CMD_INS_UPDATE_BINARY);
249 UINT16_TO_BE_STREAM (p, 0x0000); /* offset for NLEN */
250 UINT8_TO_BE_STREAM (p, T4T_FILE_LENGTH_SIZE);
251 UINT16_TO_BE_STREAM (p, ndef_len);
252
253 p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_FILE_LENGTH_SIZE;
254
255 if (!rw_t4t_send_to_lower (p_c_apdu))
256 {
257 return FALSE;
258 }
259
260 return TRUE;
261 }
262
263 /*******************************************************************************
264 **
265 ** Function rw_t4t_update_file
266 **
267 ** Description Send UpdateBinary Command to peer
268 **
269 ** Returns TRUE if success
270 **
271 *******************************************************************************/
rw_t4t_update_file(void)272 static BOOLEAN rw_t4t_update_file (void)
273 {
274 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
275 BT_HDR *p_c_apdu;
276 UINT8 *p;
277 UINT16 length;
278
279 RW_TRACE_DEBUG2 ("rw_t4t_update_file () rw_offset:%d, rw_length:%d",
280 p_t4t->rw_offset, p_t4t->rw_length);
281
282 p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
283
284 if (!p_c_apdu)
285 {
286 RW_TRACE_ERROR0 ("rw_t4t_write_file (): Cannot allocate buffer");
287 return FALSE;
288 }
289
290 /* try to send all of remaining data */
291 length = p_t4t->rw_length;
292
293 /* adjust updating length if payload is bigger than max size per single command */
294 if (length > p_t4t->max_update_size)
295 {
296 length = (UINT8) (p_t4t->max_update_size);
297 }
298
299 p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
300 p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
301
302 UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
303 UINT8_TO_BE_STREAM (p, T4T_CMD_INS_UPDATE_BINARY);
304 UINT16_TO_BE_STREAM (p, p_t4t->rw_offset);
305 UINT8_TO_BE_STREAM (p, length);
306
307 memcpy (p, p_t4t->p_update_data, length);
308
309 p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + length;
310
311 if (!rw_t4t_send_to_lower (p_c_apdu))
312 {
313 return FALSE;
314 }
315
316 /* adjust offset, length and pointer for remaining data */
317 p_t4t->rw_offset += length;
318 p_t4t->rw_length -= length;
319 p_t4t->p_update_data += length;
320
321 return TRUE;
322 }
323
324 /*******************************************************************************
325 **
326 ** Function rw_t4t_update_cc_to_readonly
327 **
328 ** Description Send UpdateBinary Command for changing Write access
329 **
330 ** Returns TRUE if success
331 **
332 *******************************************************************************/
rw_t4t_update_cc_to_readonly(void)333 static BOOLEAN rw_t4t_update_cc_to_readonly (void)
334 {
335 BT_HDR *p_c_apdu;
336 UINT8 *p;
337
338 RW_TRACE_DEBUG0 ("rw_t4t_update_cc_to_readonly (): Remove Write access from CC");
339
340 p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
341
342 if (!p_c_apdu)
343 {
344 RW_TRACE_ERROR0 ("rw_t4t_update_cc_to_readonly (): Cannot allocate buffer");
345 return FALSE;
346 }
347
348 p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
349 p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
350
351 /* Add Command Header */
352 UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
353 UINT8_TO_BE_STREAM (p, T4T_CMD_INS_UPDATE_BINARY);
354 UINT16_TO_BE_STREAM (p, (T4T_FC_TLV_OFFSET_IN_CC + T4T_FC_WRITE_ACCESS_OFFSET_IN_TLV)); /* Offset for Read Write access byte of CC */
355 UINT8_TO_BE_STREAM (p, 1); /* Length of write access field in cc interms of bytes */
356
357 /* Remove Write access */
358 UINT8_TO_BE_STREAM (p, T4T_FC_NO_WRITE_ACCESS);
359
360
361 p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + 1;
362
363 if (!rw_t4t_send_to_lower (p_c_apdu))
364 {
365 return FALSE;
366 }
367
368 return TRUE;
369 }
370
371 /*******************************************************************************
372 **
373 ** Function rw_t4t_select_application
374 **
375 ** Description Select Application
376 **
377 ** NDEF Tag Application Select - C-APDU
378 **
379 ** CLA INS P1 P2 Lc Data(AID) Le
380 ** V1.0: 00 A4 04 00 07 D2760000850100 -
381 ** V2.0: 00 A4 04 00 07 D2760000850101 00
382 **
383 ** Returns TRUE if success
384 **
385 *******************************************************************************/
rw_t4t_select_application(UINT8 version)386 static BOOLEAN rw_t4t_select_application (UINT8 version)
387 {
388 BT_HDR *p_c_apdu;
389 UINT8 *p;
390
391 RW_TRACE_DEBUG1 ("rw_t4t_select_application () version:0x%X", version);
392
393 p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
394
395 if (!p_c_apdu)
396 {
397 RW_TRACE_ERROR0 ("rw_t4t_select_application (): Cannot allocate buffer");
398 return FALSE;
399 }
400
401 p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
402 p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
403
404 UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
405 UINT8_TO_BE_STREAM (p, T4T_CMD_INS_SELECT);
406 UINT8_TO_BE_STREAM (p, T4T_CMD_P1_SELECT_BY_NAME);
407 UINT8_TO_BE_STREAM (p, T4T_CMD_P2_FIRST_OR_ONLY_00H);
408
409 if (version == T4T_VERSION_1_0) /* this is for V1.0 */
410 {
411 UINT8_TO_BE_STREAM (p, T4T_V10_NDEF_TAG_AID_LEN);
412
413 memcpy (p, t4t_v10_ndef_tag_aid, T4T_V10_NDEF_TAG_AID_LEN);
414
415 p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_V10_NDEF_TAG_AID_LEN;
416 }
417 else if (version == T4T_VERSION_2_0) /* this is for V2.0 */
418 {
419 UINT8_TO_BE_STREAM (p, T4T_V20_NDEF_TAG_AID_LEN);
420
421 memcpy (p, t4t_v20_ndef_tag_aid, T4T_V20_NDEF_TAG_AID_LEN);
422 p += T4T_V20_NDEF_TAG_AID_LEN;
423
424 UINT8_TO_BE_STREAM (p, 0x00); /* Le set to 0x00 */
425
426 p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_V20_NDEF_TAG_AID_LEN + 1;
427 }
428 else
429 {
430 return FALSE;
431 }
432
433 if (!rw_t4t_send_to_lower (p_c_apdu))
434 {
435 return FALSE;
436 }
437
438 return TRUE;
439 }
440
441 /*******************************************************************************
442 **
443 ** Function rw_t4t_validate_cc_file
444 **
445 ** Description Validate CC file and mandatory NDEF TLV
446 **
447 ** Returns TRUE if success
448 **
449 *******************************************************************************/
rw_t4t_validate_cc_file(void)450 static BOOLEAN rw_t4t_validate_cc_file (void)
451 {
452 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
453
454 RW_TRACE_DEBUG0 ("rw_t4t_validate_cc_file ()");
455
456 if (p_t4t->cc_file.cclen < T4T_CC_FILE_MIN_LEN)
457 {
458 RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): CCLEN (%d) is too short",
459 p_t4t->cc_file.cclen);
460 return FALSE;
461 }
462
463 if (T4T_GET_MAJOR_VERSION (p_t4t->cc_file.version) != T4T_GET_MAJOR_VERSION (p_t4t->version))
464 {
465 RW_TRACE_ERROR2 ("rw_t4t_validate_cc_file (): Peer version (0x%02X) is matched to ours (0x%02X)",
466 p_t4t->cc_file.version, p_t4t->version);
467 return FALSE;
468 }
469
470 if (p_t4t->cc_file.max_le < 0x000F)
471 {
472 RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): MaxLe (%d) is too small",
473 p_t4t->cc_file.max_le);
474 return FALSE;
475 }
476
477 if (p_t4t->cc_file.max_lc < 0x0001)
478 {
479 RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): MaxLc (%d) is too small",
480 p_t4t->cc_file.max_lc);
481 return FALSE;
482 }
483
484 if ( (p_t4t->cc_file.ndef_fc.file_id == T4T_CC_FILE_ID)
485 ||(p_t4t->cc_file.ndef_fc.file_id == 0xE102)
486 ||(p_t4t->cc_file.ndef_fc.file_id == 0xE103)
487 ||((p_t4t->cc_file.ndef_fc.file_id == 0x0000) && (p_t4t->cc_file.version == 0x20))
488 ||(p_t4t->cc_file.ndef_fc.file_id == 0x3F00)
489 ||(p_t4t->cc_file.ndef_fc.file_id == 0x3FFF)
490 ||(p_t4t->cc_file.ndef_fc.file_id == 0xFFFF) )
491 {
492 RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): File ID (0x%04X) is invalid",
493 p_t4t->cc_file.ndef_fc.file_id);
494 return FALSE;
495 }
496
497 if ( (p_t4t->cc_file.ndef_fc.max_file_size < 0x0005)
498 ||(p_t4t->cc_file.ndef_fc.max_file_size == 0xFFFF) )
499 {
500 RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): max_file_size (%d) is reserved",
501 p_t4t->cc_file.ndef_fc.max_file_size);
502 return FALSE;
503 }
504
505 if (p_t4t->cc_file.ndef_fc.read_access != T4T_FC_READ_ACCESS)
506 {
507 RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): Read Access (0x%02X) is invalid",
508 p_t4t->cc_file.ndef_fc.read_access);
509 return FALSE;
510 }
511
512 if ( (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
513 &&(p_t4t->cc_file.ndef_fc.write_access != T4T_FC_NO_WRITE_ACCESS) )
514 {
515 RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): Write Access (0x%02X) is invalid",
516 p_t4t->cc_file.ndef_fc.write_access);
517 return FALSE;
518 }
519
520 return TRUE;
521 }
522
523 /*******************************************************************************
524 **
525 ** Function rw_t4t_handle_error
526 **
527 ** Description notify error to application and clean up
528 **
529 ** Returns none
530 **
531 *******************************************************************************/
rw_t4t_handle_error(tNFC_STATUS status,UINT8 sw1,UINT8 sw2)532 static void rw_t4t_handle_error (tNFC_STATUS status, UINT8 sw1, UINT8 sw2)
533 {
534 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
535 tRW_DATA rw_data;
536 tRW_EVENT event;
537
538 RW_TRACE_DEBUG4 ("rw_t4t_handle_error (): status:0x%02X, sw1:0x%02X, sw2:0x%02X, state:0x%X",
539 status, sw1, sw2, p_t4t->state);
540
541 nfc_stop_quick_timer (&p_t4t->timer);
542
543 if (rw_cb.p_cback)
544 {
545 rw_data.status = status;
546
547 rw_data.t4t_sw.sw1 = sw1;
548 rw_data.t4t_sw.sw2 = sw2;
549
550 switch (p_t4t->state)
551 {
552 case RW_T4T_STATE_DETECT_NDEF:
553 rw_data.ndef.flags = RW_NDEF_FL_UNKNOWN;
554 event = RW_T4T_NDEF_DETECT_EVT;
555 break;
556
557 case RW_T4T_STATE_READ_NDEF:
558 event = RW_T4T_NDEF_READ_FAIL_EVT;
559 break;
560
561 case RW_T4T_STATE_UPDATE_NDEF:
562 event = RW_T4T_NDEF_UPDATE_FAIL_EVT;
563 break;
564
565 case RW_T4T_STATE_PRESENCE_CHECK:
566 event = RW_T4T_PRESENCE_CHECK_EVT;
567 rw_data.status = NFC_STATUS_FAILED;
568 break;
569
570 case RW_T4T_STATE_SET_READ_ONLY:
571 event = RW_T4T_SET_TO_RO_EVT;
572 break;
573
574 default:
575 event = RW_T4T_MAX_EVT;
576 break;
577 }
578
579 p_t4t->state = RW_T4T_STATE_IDLE;
580
581 if (event != RW_T4T_MAX_EVT)
582 {
583 (*(rw_cb.p_cback)) (event, &rw_data);
584 }
585 }
586 else
587 {
588 p_t4t->state = RW_T4T_STATE_IDLE;
589 }
590 }
591
592 /*******************************************************************************
593 **
594 ** Function rw_t4t_sm_detect_ndef
595 **
596 ** Description State machine for NDEF detection procedure
597 **
598 ** Returns none
599 **
600 *******************************************************************************/
rw_t4t_sm_detect_ndef(BT_HDR * p_r_apdu)601 static void rw_t4t_sm_detect_ndef (BT_HDR *p_r_apdu)
602 {
603 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
604 UINT8 *p, type, length;
605 UINT16 status_words, nlen;
606 tRW_DATA rw_data;
607
608 #if (BT_TRACE_VERBOSE == TRUE)
609 RW_TRACE_DEBUG2 ("rw_t4t_sm_detect_ndef (): sub_state:%s (%d)",
610 rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
611 #else
612 RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): sub_state=%d", p_t4t->sub_state);
613 #endif
614
615 /* get status words */
616 p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
617 p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
618 BE_STREAM_TO_UINT16 (status_words, p);
619
620 if (status_words != T4T_RSP_CMD_CMPLTED)
621 {
622 /* try V1.0 after failing of V2.0 */
623 if ( (p_t4t->sub_state == RW_T4T_SUBSTATE_WAIT_SELECT_APP)
624 &&(p_t4t->version == T4T_VERSION_2_0) )
625 {
626 p_t4t->version = T4T_VERSION_1_0;
627
628 RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): retry with version=0x%02X",
629 p_t4t->version);
630
631 if (!rw_t4t_select_application (T4T_VERSION_1_0))
632 {
633 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
634 }
635 return;
636 }
637
638 p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
639 rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
640 return;
641 }
642
643 switch (p_t4t->sub_state)
644 {
645 case RW_T4T_SUBSTATE_WAIT_SELECT_APP:
646
647 /* NDEF Tag application has been selected then select CC file */
648 if (!rw_t4t_select_file (T4T_CC_FILE_ID))
649 {
650 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
651 }
652 else
653 {
654 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
655 }
656 break;
657
658 case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
659
660 /* CC file has been selected then read mandatory part of CC file */
661 if (!rw_t4t_read_file (0x00, T4T_CC_FILE_MIN_LEN, FALSE))
662 {
663 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
664 }
665 else
666 {
667 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_CC_FILE;
668 }
669 break;
670
671 case RW_T4T_SUBSTATE_WAIT_CC_FILE:
672
673 /* CC file has been read then validate and select mandatory NDEF file */
674 if (p_r_apdu->len >= T4T_CC_FILE_MIN_LEN + T4T_RSP_STATUS_WORDS_SIZE)
675 {
676 p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
677
678 BE_STREAM_TO_UINT16 (p_t4t->cc_file.cclen, p);
679 BE_STREAM_TO_UINT8 (p_t4t->cc_file.version, p);
680 BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_le, p);
681 BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_lc, p);
682
683 BE_STREAM_TO_UINT8 (type, p);
684 BE_STREAM_TO_UINT8 (length, p);
685
686 if ( (type == T4T_NDEF_FILE_CONTROL_TYPE)
687 &&(length == T4T_FILE_CONTROL_LENGTH) )
688 {
689 BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.file_id, p);
690 BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.max_file_size, p);
691 BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.read_access, p);
692 BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.write_access, p);
693
694 #if (BT_TRACE_VERBOSE == TRUE)
695 RW_TRACE_DEBUG0 ("Capability Container (CC) file");
696 RW_TRACE_DEBUG1 (" CCLEN: 0x%04X", p_t4t->cc_file.cclen);
697 RW_TRACE_DEBUG1 (" Version:0x%02X", p_t4t->cc_file.version);
698 RW_TRACE_DEBUG1 (" MaxLe: 0x%04X", p_t4t->cc_file.max_le);
699 RW_TRACE_DEBUG1 (" MaxLc: 0x%04X", p_t4t->cc_file.max_lc);
700 RW_TRACE_DEBUG0 (" NDEF File Control TLV");
701 RW_TRACE_DEBUG1 (" FileID: 0x%04X", p_t4t->cc_file.ndef_fc.file_id);
702 RW_TRACE_DEBUG1 (" MaxFileSize: 0x%04X", p_t4t->cc_file.ndef_fc.max_file_size);
703 RW_TRACE_DEBUG1 (" ReadAccess: 0x%02X", p_t4t->cc_file.ndef_fc.read_access);
704 RW_TRACE_DEBUG1 (" WriteAccess: 0x%02X", p_t4t->cc_file.ndef_fc.write_access);
705 #endif
706
707 if (rw_t4t_validate_cc_file ())
708 {
709 if (!rw_t4t_select_file (p_t4t->cc_file.ndef_fc.file_id))
710 {
711 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
712 }
713 else
714 {
715 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
716 }
717 break;
718 }
719 }
720 }
721
722 /* invalid response or CC file */
723 p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
724 rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
725 break;
726
727 case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
728
729 /* NDEF file has been selected then read the first 2 bytes (NLEN) */
730 if (!rw_t4t_read_file (0, T4T_FILE_LENGTH_SIZE, FALSE))
731 {
732 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
733 }
734 else
735 {
736 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_NLEN;
737 }
738 break;
739
740 case RW_T4T_SUBSTATE_WAIT_READ_NLEN:
741
742 /* NLEN has been read then report upper layer */
743 if (p_r_apdu->len == T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE)
744 {
745 /* get length of NDEF */
746 p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
747 BE_STREAM_TO_UINT16 (nlen, p);
748
749 if (nlen <= p_t4t->cc_file.ndef_fc.max_file_size - T4T_FILE_LENGTH_SIZE)
750 {
751 p_t4t->ndef_status = RW_T4T_NDEF_STATUS_NDEF_DETECTED;
752
753 if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
754 {
755 p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
756 }
757
758 /* Get max bytes to read per command */
759 if (p_t4t->cc_file.max_le >= RW_T4T_MAX_DATA_PER_READ)
760 {
761 p_t4t->max_read_size = RW_T4T_MAX_DATA_PER_READ;
762 }
763 else
764 {
765 p_t4t->max_read_size = p_t4t->cc_file.max_le;
766 }
767
768 /* Le: valid range is 0x01 to 0xFF */
769 if (p_t4t->max_read_size >= T4T_MAX_LENGTH_LE)
770 {
771 p_t4t->max_read_size = T4T_MAX_LENGTH_LE;
772 }
773
774 /* Get max bytes to update per command */
775 if (p_t4t->cc_file.max_lc >= RW_T4T_MAX_DATA_PER_WRITE)
776 {
777 p_t4t->max_update_size = RW_T4T_MAX_DATA_PER_WRITE;
778 }
779 else
780 {
781 p_t4t->max_update_size = p_t4t->cc_file.max_lc;
782 }
783
784 /* Lc: valid range is 0x01 to 0xFF */
785 if (p_t4t->max_update_size >= T4T_MAX_LENGTH_LC)
786 {
787 p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
788 }
789
790 p_t4t->ndef_length = nlen;
791 p_t4t->state = RW_T4T_STATE_IDLE;
792
793 if (rw_cb.p_cback)
794 {
795 rw_data.ndef.status = NFC_STATUS_OK;
796 rw_data.ndef.protocol = NFC_PROTOCOL_ISO_DEP;
797 rw_data.ndef.max_size = (UINT32) (p_t4t->cc_file.ndef_fc.max_file_size - (UINT16) T4T_FILE_LENGTH_SIZE);
798 rw_data.ndef.cur_size = nlen;
799 rw_data.ndef.flags = RW_NDEF_FL_SUPPORTED | RW_NDEF_FL_FORMATED;
800 if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
801 {
802 rw_data.ndef.flags |= RW_NDEF_FL_READ_ONLY;
803 }
804
805 (*(rw_cb.p_cback)) (RW_T4T_NDEF_DETECT_EVT, &rw_data);
806
807 RW_TRACE_DEBUG0 ("rw_t4t_sm_detect_ndef (): Sent RW_T4T_NDEF_DETECT_EVT");
808 }
809 }
810 else
811 {
812 /* NLEN should be less than max file size */
813 RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): NLEN (%d) + 2 must be <= max file size (%d)",
814 nlen, p_t4t->cc_file.ndef_fc.max_file_size);
815
816 p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
817 rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
818 }
819 }
820 else
821 {
822 /* response payload size should be T4T_FILE_LENGTH_SIZE */
823 RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): Length (%d) of R-APDU must be %d",
824 p_r_apdu->len, T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE);
825
826 p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
827 rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
828 }
829 break;
830
831 default:
832 RW_TRACE_ERROR1 ("rw_t4t_sm_detect_ndef (): unknown sub_state=%d", p_t4t->sub_state);
833 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
834 break;
835 }
836 }
837
838 /*******************************************************************************
839 **
840 ** Function rw_t4t_sm_read_ndef
841 **
842 ** Description State machine for NDEF read procedure
843 **
844 ** Returns none
845 **
846 *******************************************************************************/
rw_t4t_sm_read_ndef(BT_HDR * p_r_apdu)847 static void rw_t4t_sm_read_ndef (BT_HDR *p_r_apdu)
848 {
849 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
850 UINT8 *p;
851 UINT16 status_words;
852 tRW_DATA rw_data;
853
854 #if (BT_TRACE_VERBOSE == TRUE)
855 RW_TRACE_DEBUG2 ("rw_t4t_sm_read_ndef (): sub_state:%s (%d)",
856 rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
857 #else
858 RW_TRACE_DEBUG1 ("rw_t4t_sm_read_ndef (): sub_state=%d", p_t4t->sub_state);
859 #endif
860
861 /* get status words */
862 p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
863 p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
864 BE_STREAM_TO_UINT16 (status_words, p);
865
866 if (status_words != T4T_RSP_CMD_CMPLTED)
867 {
868 rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
869 GKI_freebuf (p_r_apdu);
870 return;
871 }
872
873 switch (p_t4t->sub_state)
874 {
875 case RW_T4T_SUBSTATE_WAIT_READ_RESP:
876
877 /* Read partial or complete data */
878 p_r_apdu->len -= T4T_RSP_STATUS_WORDS_SIZE;
879
880 if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length))
881 {
882 p_t4t->rw_length -= p_r_apdu->len;
883 p_t4t->rw_offset += p_r_apdu->len;
884
885 if (rw_cb.p_cback)
886 {
887 rw_data.data.status = NFC_STATUS_OK;
888 rw_data.data.p_data = p_r_apdu;
889
890 /* if need to read more data */
891 if (p_t4t->rw_length > 0)
892 {
893 (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_EVT, &rw_data);
894
895 if (!rw_t4t_read_file (p_t4t->rw_offset, p_t4t->rw_length, TRUE))
896 {
897 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
898 }
899 }
900 else
901 {
902 p_t4t->state = RW_T4T_STATE_IDLE;
903
904 (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);
905
906 RW_TRACE_DEBUG0 ("rw_t4t_sm_read_ndef (): Sent RW_T4T_NDEF_READ_CPLT_EVT");
907
908 }
909
910 p_r_apdu = NULL;
911 }
912 else
913 {
914 p_t4t->rw_length = 0;
915 p_t4t->state = RW_T4T_STATE_IDLE;
916 }
917 }
918 else
919 {
920 RW_TRACE_ERROR2 ("rw_t4t_sm_read_ndef (): invalid payload length (%d), rw_length (%d)",
921 p_r_apdu->len, p_t4t->rw_length);
922 rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
923 }
924 break;
925
926 default:
927 RW_TRACE_ERROR1 ("rw_t4t_sm_read_ndef (): unknown sub_state = %d", p_t4t->sub_state);
928 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
929 break;
930 }
931
932 if (p_r_apdu)
933 GKI_freebuf (p_r_apdu);
934 }
935
936 /*******************************************************************************
937 **
938 ** Function rw_t4t_sm_update_ndef
939 **
940 ** Description State machine for NDEF update procedure
941 **
942 ** Returns none
943 **
944 *******************************************************************************/
rw_t4t_sm_update_ndef(BT_HDR * p_r_apdu)945 static void rw_t4t_sm_update_ndef (BT_HDR *p_r_apdu)
946 {
947 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
948 UINT8 *p;
949 UINT16 status_words;
950 tRW_DATA rw_data;
951
952 #if (BT_TRACE_VERBOSE == TRUE)
953 RW_TRACE_DEBUG2 ("rw_t4t_sm_update_ndef (): sub_state:%s (%d)",
954 rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
955 #else
956 RW_TRACE_DEBUG1 ("rw_t4t_sm_update_ndef (): sub_state=%d", p_t4t->sub_state);
957 #endif
958
959 /* Get status words */
960 p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
961 p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
962 BE_STREAM_TO_UINT16 (status_words, p);
963
964 if (status_words != T4T_RSP_CMD_CMPLTED)
965 {
966 rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
967 return;
968 }
969
970 switch (p_t4t->sub_state)
971 {
972 case RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN:
973
974 /* NLEN has been updated */
975 /* if need to update data */
976 if (p_t4t->p_update_data)
977 {
978 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_RESP;
979
980 if (!rw_t4t_update_file ())
981 {
982 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
983 p_t4t->p_update_data = NULL;
984 }
985 }
986 else
987 {
988 p_t4t->state = RW_T4T_STATE_IDLE;
989
990 /* just finished last step of updating (updating NLEN) */
991 if (rw_cb.p_cback)
992 {
993 rw_data.status = NFC_STATUS_OK;
994
995 (*(rw_cb.p_cback)) (RW_T4T_NDEF_UPDATE_CPLT_EVT, &rw_data);
996 RW_TRACE_DEBUG0 ("rw_t4t_sm_update_ndef (): Sent RW_T4T_NDEF_UPDATE_CPLT_EVT");
997 }
998 }
999 break;
1000
1001 case RW_T4T_SUBSTATE_WAIT_UPDATE_RESP:
1002
1003 /* if updating is not completed */
1004 if (p_t4t->rw_length > 0)
1005 {
1006 if (!rw_t4t_update_file ())
1007 {
1008 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1009 p_t4t->p_update_data = NULL;
1010 }
1011 }
1012 else
1013 {
1014 p_t4t->p_update_data = NULL;
1015
1016 /* update NLEN as last step of updating file */
1017 if (!rw_t4t_update_nlen (p_t4t->ndef_length))
1018 {
1019 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1020 }
1021 else
1022 {
1023 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN;
1024 }
1025 }
1026 break;
1027
1028 default:
1029 RW_TRACE_ERROR1 ("rw_t4t_sm_update_ndef (): unknown sub_state = %d", p_t4t->sub_state);
1030 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1031 break;
1032 }
1033 }
1034
1035 /*******************************************************************************
1036 **
1037 ** Function rw_t4t_sm_set_readonly
1038 **
1039 ** Description State machine for CC update procedure
1040 **
1041 ** Returns none
1042 **
1043 *******************************************************************************/
rw_t4t_sm_set_readonly(BT_HDR * p_r_apdu)1044 static void rw_t4t_sm_set_readonly (BT_HDR *p_r_apdu)
1045 {
1046 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
1047 UINT8 *p;
1048 UINT16 status_words;
1049 tRW_DATA rw_data;
1050
1051 #if (BT_TRACE_VERBOSE == TRUE)
1052 RW_TRACE_DEBUG2 ("rw_t4t_sm_set_readonly (): sub_state:%s (%d)",
1053 rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
1054 #else
1055 RW_TRACE_DEBUG1 ("rw_t4t_sm_set_readonly (): sub_state=%d", p_t4t->sub_state);
1056 #endif
1057
1058 /* Get status words */
1059 p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
1060 p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
1061 BE_STREAM_TO_UINT16 (status_words, p);
1062
1063 if (status_words != T4T_RSP_CMD_CMPLTED)
1064 {
1065 rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
1066 return;
1067 }
1068
1069 switch (p_t4t->sub_state)
1070 {
1071 case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
1072
1073 /* CC file has been selected then update write access to read-only in CC file */
1074 if (!rw_t4t_update_cc_to_readonly ())
1075 {
1076 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1077 }
1078 else
1079 {
1080 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_CC;
1081 }
1082 break;
1083
1084 case RW_T4T_SUBSTATE_WAIT_UPDATE_CC:
1085 /* CC Updated, Select NDEF File to allow NDEF operation */
1086 p_t4t->cc_file.ndef_fc.write_access = T4T_FC_NO_WRITE_ACCESS;
1087 p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
1088
1089 if (!rw_t4t_select_file (p_t4t->cc_file.ndef_fc.file_id))
1090 {
1091 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1092 }
1093 else
1094 {
1095 p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
1096 }
1097 break;
1098
1099 case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
1100 p_t4t->state = RW_T4T_STATE_IDLE;
1101 /* just finished last step of configuring tag read only (Selecting NDEF file CC) */
1102 if (rw_cb.p_cback)
1103 {
1104 rw_data.status = NFC_STATUS_OK;
1105
1106 RW_TRACE_DEBUG0 ("rw_t4t_sm_set_readonly (): Sent RW_T4T_SET_TO_RO_EVT");
1107 (*(rw_cb.p_cback)) (RW_T4T_SET_TO_RO_EVT, &rw_data);
1108 }
1109 break;
1110
1111 default:
1112 RW_TRACE_ERROR1 ("rw_t4t_sm_set_readonly (): unknown sub_state = %d", p_t4t->sub_state);
1113 rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1114 break;
1115 }
1116 }
1117
1118 /*******************************************************************************
1119 **
1120 ** Function rw_t4t_process_timeout
1121 **
1122 ** Description process timeout event
1123 **
1124 ** Returns none
1125 **
1126 *******************************************************************************/
rw_t4t_process_timeout(TIMER_LIST_ENT * p_tle)1127 void rw_t4t_process_timeout (TIMER_LIST_ENT *p_tle)
1128 {
1129 RW_TRACE_DEBUG1 ("rw_t4t_process_timeout () event=%d", p_tle->event);
1130
1131 if (p_tle->event == NFC_TTYPE_RW_T4T_RESPONSE)
1132 {
1133 rw_t4t_handle_error (NFC_STATUS_TIMEOUT, 0, 0);
1134 }
1135 else
1136 {
1137 RW_TRACE_ERROR1 ("rw_t4t_process_timeout () unknown event=%d", p_tle->event);
1138 }
1139 }
1140
1141 /*******************************************************************************
1142 **
1143 ** Function rw_t4t_data_cback
1144 **
1145 ** Description This callback function receives the data from NFCC.
1146 **
1147 ** Returns none
1148 **
1149 *******************************************************************************/
rw_t4t_data_cback(UINT8 conn_id,tNFC_CONN_EVT event,tNFC_CONN * p_data)1150 static void rw_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data)
1151 {
1152 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
1153 BT_HDR *p_r_apdu;
1154 tRW_DATA rw_data;
1155
1156 #if (BT_TRACE_VERBOSE == TRUE)
1157 UINT8 begin_state = p_t4t->state;
1158 #endif
1159
1160 RW_TRACE_DEBUG1 ("rw_t4t_data_cback () event = 0x%X", event);
1161 nfc_stop_quick_timer (&p_t4t->timer);
1162
1163 switch (event)
1164 {
1165 case NFC_DEACTIVATE_CEVT:
1166 NFC_SetStaticRfCback (NULL);
1167 p_t4t->state = RW_T4T_STATE_NOT_ACTIVATED;
1168 return;
1169
1170 case NFC_ERROR_CEVT:
1171 rw_data.status = (tNFC_STATUS) (*(UINT8*) p_data);
1172
1173 if (p_t4t->state != RW_T4T_STATE_IDLE)
1174 {
1175 rw_t4t_handle_error (rw_data.status, 0, 0);
1176 }
1177 else
1178 {
1179 (*(rw_cb.p_cback)) (RW_T4T_INTF_ERROR_EVT, &rw_data);
1180 }
1181 return;
1182
1183 case NFC_DATA_CEVT:
1184 p_r_apdu = (BT_HDR *) p_data->data.p_data;
1185 break;
1186
1187 default:
1188 return;
1189 }
1190
1191 #if (BT_TRACE_PROTOCOL == TRUE)
1192 DispRWT4Tags (p_r_apdu, TRUE);
1193 #endif
1194
1195 #if (BT_TRACE_VERBOSE == TRUE)
1196 RW_TRACE_DEBUG2 ("RW T4T state: <%s (%d)>",
1197 rw_t4t_get_state_name (p_t4t->state), p_t4t->state);
1198 #else
1199 RW_TRACE_DEBUG1 ("RW T4T state: %d", p_t4t->state);
1200 #endif
1201
1202 switch (p_t4t->state)
1203 {
1204 case RW_T4T_STATE_IDLE:
1205 /* Unexpected R-APDU, it should be raw frame response */
1206 /* forward to upper layer without parsing */
1207 if (rw_cb.p_cback)
1208 {
1209 rw_data.raw_frame.status = NFC_STATUS_OK;
1210 rw_data.raw_frame.p_data = p_r_apdu;
1211 (*(rw_cb.p_cback)) (RW_T4T_RAW_FRAME_EVT, &rw_data);
1212 p_r_apdu = NULL;
1213 }
1214 else
1215 {
1216 GKI_freebuf (p_r_apdu);
1217 }
1218 break;
1219 case RW_T4T_STATE_DETECT_NDEF:
1220 rw_t4t_sm_detect_ndef (p_r_apdu);
1221 GKI_freebuf (p_r_apdu);
1222 break;
1223 case RW_T4T_STATE_READ_NDEF:
1224 rw_t4t_sm_read_ndef (p_r_apdu);
1225 /* p_r_apdu may send upper lyaer */
1226 break;
1227 case RW_T4T_STATE_UPDATE_NDEF:
1228 rw_t4t_sm_update_ndef (p_r_apdu);
1229 GKI_freebuf (p_r_apdu);
1230 break;
1231 case RW_T4T_STATE_PRESENCE_CHECK:
1232 /* if any response, send presence check with ok */
1233 rw_data.status = NFC_STATUS_OK;
1234 p_t4t->state = RW_T4T_STATE_IDLE;
1235 (*(rw_cb.p_cback)) (RW_T4T_PRESENCE_CHECK_EVT, &rw_data);
1236 GKI_freebuf (p_r_apdu);
1237 break;
1238 case RW_T4T_STATE_SET_READ_ONLY:
1239 rw_t4t_sm_set_readonly (p_r_apdu);
1240 GKI_freebuf (p_r_apdu);
1241 break;
1242 default:
1243 RW_TRACE_ERROR1 ("rw_t4t_data_cback (): invalid state=%d", p_t4t->state);
1244 GKI_freebuf (p_r_apdu);
1245 break;
1246 }
1247
1248 #if (BT_TRACE_VERBOSE == TRUE)
1249 if (begin_state != p_t4t->state)
1250 {
1251 RW_TRACE_DEBUG2 ("RW T4T state changed:<%s> -> <%s>",
1252 rw_t4t_get_state_name (begin_state),
1253 rw_t4t_get_state_name (p_t4t->state));
1254 }
1255 #endif
1256 }
1257
1258
1259 /*******************************************************************************
1260 **
1261 ** Function rw_t4t_select
1262 **
1263 ** Description Initialise T4T
1264 **
1265 ** Returns NFC_STATUS_OK if success
1266 **
1267 *******************************************************************************/
rw_t4t_select(void)1268 tNFC_STATUS rw_t4t_select (void)
1269 {
1270 tRW_T4T_CB *p_t4t = &rw_cb.tcb.t4t;
1271
1272 RW_TRACE_DEBUG0 ("rw_t4t_select ()");
1273
1274 NFC_SetStaticRfCback (rw_t4t_data_cback);
1275
1276 p_t4t->state = RW_T4T_STATE_IDLE;
1277 p_t4t->version = T4T_MY_VERSION;
1278
1279 /* set it min of max R-APDU data size before reading CC file */
1280 p_t4t->cc_file.max_le = T4T_MIN_MLE;
1281
1282 /* These will be udated during NDEF detection */
1283 p_t4t->max_read_size = T4T_MAX_LENGTH_LE;
1284 p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
1285
1286 return NFC_STATUS_OK;
1287 }
1288
1289 /*******************************************************************************
1290 **
1291 ** Function RW_T4tDetectNDef
1292 **
1293 ** Description This function performs NDEF detection procedure
1294 **
1295 ** RW_T4T_NDEF_DETECT_EVT will be returned
1296 **
1297 ** Returns NFC_STATUS_OK if success
1298 ** NFC_STATUS_FAILED if T4T is busy or other error
1299 **
1300 *******************************************************************************/
RW_T4tDetectNDef(void)1301 tNFC_STATUS RW_T4tDetectNDef (void)
1302 {
1303 RW_TRACE_API0 ("RW_T4tDetectNDef ()");
1304
1305 if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1306 {
1307 RW_TRACE_ERROR1 ("RW_T4tDetectNDef ():Unable to start command at state (0x%X)",
1308 rw_cb.tcb.t4t.state);
1309 return NFC_STATUS_FAILED;
1310 }
1311
1312 if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1313 {
1314 /* NDEF Tag application has been selected then select CC file */
1315 if (!rw_t4t_select_file (T4T_CC_FILE_ID))
1316 {
1317 return NFC_STATUS_FAILED;
1318 }
1319 rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
1320 }
1321 else
1322 {
1323 /* Select NDEF Tag Application */
1324 if (!rw_t4t_select_application (rw_cb.tcb.t4t.version))
1325 {
1326 return NFC_STATUS_FAILED;
1327 }
1328 rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_APP;
1329 }
1330
1331 rw_cb.tcb.t4t.state = RW_T4T_STATE_DETECT_NDEF;
1332
1333 return NFC_STATUS_OK;
1334 }
1335
1336 /*******************************************************************************
1337 **
1338 ** Function RW_T4tReadNDef
1339 **
1340 ** Description This function performs NDEF read procedure
1341 ** Note: RW_T4tDetectNDef () must be called before using this
1342 **
1343 ** The following event will be returned
1344 ** RW_T4T_NDEF_READ_EVT for each segmented NDEF message
1345 ** RW_T4T_NDEF_READ_CPLT_EVT for the last segment or complete NDEF
1346 ** RW_T4T_NDEF_READ_FAIL_EVT for failure
1347 **
1348 ** Returns NFC_STATUS_OK if success
1349 ** NFC_STATUS_FAILED if T4T is busy or other error
1350 **
1351 *******************************************************************************/
RW_T4tReadNDef(void)1352 tNFC_STATUS RW_T4tReadNDef (void)
1353 {
1354 RW_TRACE_API0 ("RW_T4tReadNDef ()");
1355
1356 if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1357 {
1358 RW_TRACE_ERROR1 ("RW_T4tReadNDef ():Unable to start command at state (0x%X)",
1359 rw_cb.tcb.t4t.state);
1360 return NFC_STATUS_FAILED;
1361 }
1362
1363 /* if NDEF has been detected */
1364 if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1365 {
1366 /* start reading NDEF */
1367 if (!rw_t4t_read_file (T4T_FILE_LENGTH_SIZE, rw_cb.tcb.t4t.ndef_length, FALSE))
1368 {
1369 return NFC_STATUS_FAILED;
1370 }
1371
1372 rw_cb.tcb.t4t.state = RW_T4T_STATE_READ_NDEF;
1373 rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_READ_RESP;
1374
1375 return NFC_STATUS_OK;
1376 }
1377 else
1378 {
1379 RW_TRACE_ERROR0 ("RW_T4tReadNDef ():No NDEF detected");
1380 return NFC_STATUS_FAILED;
1381 }
1382 }
1383
1384 /*******************************************************************************
1385 **
1386 ** Function RW_T4tUpdateNDef
1387 **
1388 ** Description This function performs NDEF update procedure
1389 ** Note: RW_T4tDetectNDef () must be called before using this
1390 ** Updating data must not be removed until returning event
1391 **
1392 ** The following event will be returned
1393 ** RW_T4T_NDEF_UPDATE_CPLT_EVT for complete
1394 ** RW_T4T_NDEF_UPDATE_FAIL_EVT for failure
1395 **
1396 ** Returns NFC_STATUS_OK if success
1397 ** NFC_STATUS_FAILED if T4T is busy or other error
1398 **
1399 *******************************************************************************/
RW_T4tUpdateNDef(UINT16 length,UINT8 * p_data)1400 tNFC_STATUS RW_T4tUpdateNDef (UINT16 length, UINT8 *p_data)
1401 {
1402 RW_TRACE_API1 ("RW_T4tUpdateNDef () length:%d", length);
1403
1404 if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1405 {
1406 RW_TRACE_ERROR1 ("RW_T4tUpdateNDef ():Unable to start command at state (0x%X)",
1407 rw_cb.tcb.t4t.state);
1408 return NFC_STATUS_FAILED;
1409 }
1410
1411 /* if NDEF has been detected */
1412 if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1413 {
1414 /* if read-only */
1415 if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY)
1416 {
1417 RW_TRACE_ERROR0 ("RW_T4tUpdateNDef ():NDEF is read-only");
1418 return NFC_STATUS_FAILED;
1419 }
1420
1421 if (rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size < length + T4T_FILE_LENGTH_SIZE)
1422 {
1423 RW_TRACE_ERROR2 ("RW_T4tUpdateNDef ():data (%d bytes) plus NLEN is more than max file size (%d)",
1424 length, rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size);
1425 return NFC_STATUS_FAILED;
1426 }
1427
1428 /* store NDEF length and data */
1429 rw_cb.tcb.t4t.ndef_length = length;
1430 rw_cb.tcb.t4t.p_update_data = p_data;
1431
1432 rw_cb.tcb.t4t.rw_offset = T4T_FILE_LENGTH_SIZE;
1433 rw_cb.tcb.t4t.rw_length = length;
1434
1435 /* set NLEN to 0x0000 for the first step */
1436 if (!rw_t4t_update_nlen (0x0000))
1437 {
1438 return NFC_STATUS_FAILED;
1439 }
1440
1441 rw_cb.tcb.t4t.state = RW_T4T_STATE_UPDATE_NDEF;
1442 rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN;
1443
1444 return NFC_STATUS_OK;
1445 }
1446 else
1447 {
1448 RW_TRACE_ERROR0 ("RW_T4tUpdateNDef ():No NDEF detected");
1449 return NFC_STATUS_FAILED;
1450 }
1451 }
1452
1453 /*****************************************************************************
1454 **
1455 ** Function RW_T4tPresenceCheck
1456 **
1457 ** Description
1458 ** Check if the tag is still in the field.
1459 **
1460 ** The RW_T4T_PRESENCE_CHECK_EVT w/ status is used to indicate presence
1461 ** or non-presence.
1462 **
1463 ** Returns
1464 ** NFC_STATUS_OK, if raw data frame sent
1465 ** NFC_STATUS_NO_BUFFERS: unable to allocate a buffer for this operation
1466 ** NFC_STATUS_FAILED: other error
1467 **
1468 *****************************************************************************/
RW_T4tPresenceCheck(void)1469 tNFC_STATUS RW_T4tPresenceCheck (void)
1470 {
1471 tNFC_STATUS retval = NFC_STATUS_OK;
1472 tRW_DATA evt_data;
1473
1474 RW_TRACE_API0 ("RW_T4tPresenceCheck ()");
1475
1476 /* If RW_SelectTagType was not called (no conn_callback) return failure */
1477 if (!rw_cb.p_cback)
1478 {
1479 retval = NFC_STATUS_FAILED;
1480 }
1481 /* If we are not activated, then RW_T4T_PRESENCE_CHECK_EVT with NFC_STATUS_FAILED */
1482 else if (rw_cb.tcb.t4t.state == RW_T4T_STATE_NOT_ACTIVATED)
1483 {
1484 evt_data.status = NFC_STATUS_FAILED;
1485 (*rw_cb.p_cback) (RW_T4T_PRESENCE_CHECK_EVT, &evt_data);
1486 }
1487 /* If command is pending, assume tag is still present */
1488 else if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1489 {
1490 evt_data.status = NFC_STATUS_OK;
1491 (*rw_cb.p_cback) (RW_T4T_PRESENCE_CHECK_EVT, &evt_data);
1492 }
1493 else
1494 {
1495 if (rw_t4t_read_file (0, 1, FALSE))
1496 {
1497 rw_cb.tcb.t4t.state = RW_T4T_STATE_PRESENCE_CHECK;
1498 }
1499 else
1500 {
1501 retval = NFC_STATUS_NO_BUFFERS;
1502 }
1503 }
1504
1505 return (retval);
1506 }
1507
1508 /*****************************************************************************
1509 **
1510 ** Function RW_T4tSetNDefReadOnly
1511 **
1512 ** Description This function performs NDEF read-only procedure
1513 ** Note: RW_T4tDetectNDef() must be called before using this
1514 **
1515 ** The RW_T4T_SET_TO_RO_EVT event will be returned.
1516 **
1517 ** Returns NFC_STATUS_OK if success
1518 ** NFC_STATUS_FAILED if T4T is busy or other error
1519 **
1520 *****************************************************************************/
RW_T4tSetNDefReadOnly(void)1521 tNFC_STATUS RW_T4tSetNDefReadOnly (void)
1522 {
1523 tNFC_STATUS retval = NFC_STATUS_OK;
1524 tRW_DATA evt_data;
1525
1526 RW_TRACE_API0 ("RW_T4tSetNDefReadOnly ()");
1527
1528 if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1529 {
1530 RW_TRACE_ERROR1 ("RW_T4tSetNDefReadOnly ():Unable to start command at state (0x%X)",
1531 rw_cb.tcb.t4t.state);
1532 return NFC_STATUS_FAILED;
1533 }
1534
1535 /* if NDEF has been detected */
1536 if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1537 {
1538 /* if read-only */
1539 if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY)
1540 {
1541 RW_TRACE_API0 ("RW_T4tSetNDefReadOnly (): NDEF is already read-only");
1542
1543 evt_data.status = NFC_STATUS_OK;
1544 (*rw_cb.p_cback) (RW_T4T_SET_TO_RO_EVT, &evt_data);
1545 return (retval);
1546 }
1547
1548 /* NDEF Tag application has been selected then select CC file */
1549 if (!rw_t4t_select_file (T4T_CC_FILE_ID))
1550 {
1551 return NFC_STATUS_FAILED;
1552 }
1553
1554 rw_cb.tcb.t4t.state = RW_T4T_STATE_SET_READ_ONLY;
1555 rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
1556
1557 return NFC_STATUS_OK;
1558 }
1559 else
1560 {
1561 RW_TRACE_ERROR0 ("RW_T4tSetNDefReadOnly ():No NDEF detected");
1562 return NFC_STATUS_FAILED;
1563 }
1564 return (retval);
1565 }
1566
1567 #if (BT_TRACE_VERBOSE == TRUE)
1568 /*******************************************************************************
1569 **
1570 ** Function rw_t4t_get_state_name
1571 **
1572 ** Description This function returns the state name.
1573 **
1574 ** NOTE conditionally compiled to save memory.
1575 **
1576 ** Returns pointer to the name
1577 **
1578 *******************************************************************************/
rw_t4t_get_state_name(UINT8 state)1579 static char *rw_t4t_get_state_name (UINT8 state)
1580 {
1581 switch (state)
1582 {
1583 case RW_T4T_STATE_NOT_ACTIVATED:
1584 return ("NOT_ACTIVATED");
1585 case RW_T4T_STATE_IDLE:
1586 return ("IDLE");
1587 case RW_T4T_STATE_DETECT_NDEF:
1588 return ("NDEF_DETECTION");
1589 case RW_T4T_STATE_READ_NDEF:
1590 return ("READ_NDEF");
1591 case RW_T4T_STATE_UPDATE_NDEF:
1592 return ("UPDATE_NDEF");
1593 case RW_T4T_STATE_PRESENCE_CHECK:
1594 return ("PRESENCE_CHECK");
1595 case RW_T4T_STATE_SET_READ_ONLY:
1596 return ("SET_READ_ONLY");
1597
1598 default:
1599 return ("???? UNKNOWN STATE");
1600 }
1601 }
1602
1603 /*******************************************************************************
1604 **
1605 ** Function rw_t4t_get_sub_state_name
1606 **
1607 ** Description This function returns the sub_state name.
1608 **
1609 ** NOTE conditionally compiled to save memory.
1610 **
1611 ** Returns pointer to the name
1612 **
1613 *******************************************************************************/
rw_t4t_get_sub_state_name(UINT8 sub_state)1614 static char *rw_t4t_get_sub_state_name (UINT8 sub_state)
1615 {
1616 switch (sub_state)
1617 {
1618 case RW_T4T_SUBSTATE_WAIT_SELECT_APP:
1619 return ("WAIT_SELECT_APP");
1620 case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
1621 return ("WAIT_SELECT_CC");
1622 case RW_T4T_SUBSTATE_WAIT_CC_FILE:
1623 return ("WAIT_CC_FILE");
1624 case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
1625 return ("WAIT_SELECT_NDEF_FILE");
1626 case RW_T4T_SUBSTATE_WAIT_READ_NLEN:
1627 return ("WAIT_READ_NLEN");
1628
1629 case RW_T4T_SUBSTATE_WAIT_READ_RESP:
1630 return ("WAIT_READ_RESP");
1631 case RW_T4T_SUBSTATE_WAIT_UPDATE_RESP:
1632 return ("WAIT_UPDATE_RESP");
1633 case RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN:
1634 return ("WAIT_UPDATE_NLEN");
1635 default:
1636 return ("???? UNKNOWN SUBSTATE");
1637 }
1638 }
1639 #endif
1640
1641 #endif /* (NFC_INCLUDED == TRUE) */
1642