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