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