• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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,BT_HDR * p_msg)663 void ce_t3t_data_cback (UINT8 conn_id, BT_HDR *p_msg)
664 {
665     tCE_CB *p_ce_cb = &ce_cb;
666     tCE_T3T_MEM *p_cb = &p_ce_cb->mem.t3t;
667     tCE_DATA     ce_data;
668     UINT8 cmd_id, bl0, entry_len, i;
669     UINT8 *p_nfcid2 = NULL;
670     UINT8 *p = (UINT8 *) (p_msg +1) + p_msg->offset;
671     UINT8 cmd_nfcid2[NCI_RF_F_UID_LEN];
672     UINT16 block_list_start_offset, remaining;
673     BOOLEAN msg_processed = FALSE;
674     BOOLEAN block_list_ok;
675     UINT8 sod;
676     UINT8 cmd_type;
677 
678 #if (BT_TRACE_PROTOCOL == TRUE)
679     DispT3TagMessage (p_msg, TRUE);
680 #endif
681 
682     /* If activate system code is not NDEF, or if no local NDEF contents was set, then pass data up to the app */
683     if ((p_cb->system_code != T3T_SYSTEM_CODE_NDEF) || (!p_cb->ndef_info.initialized))
684     {
685         ce_data.raw_frame.status = NFC_STATUS_OK;
686         ce_data.raw_frame.p_data = p_msg;
687         p_ce_cb->p_cback (CE_T3T_RAW_FRAME_EVT, &ce_data);
688         return;
689     }
690 
691     /* Verify that message contains at least Sod and cmd_id */
692     if (p_msg->len < 2)
693     {
694         CE_TRACE_ERROR1 ("CE: received invalid T3t message (invalid length: %i)", p_msg->len);
695     }
696     else
697     {
698 
699         /* Get and validate command opcode */
700         STREAM_TO_UINT8 (sod, p);
701         STREAM_TO_UINT8 (cmd_id, p);
702 
703         /* Valid command and message length */
704         cmd_type = ce_t3t_is_valid_opcode (cmd_id);
705         if (cmd_type == CE_T3T_COMMAND_INVALID)
706         {
707             CE_TRACE_ERROR1 ("CE: received invalid T3t message (invalid command: 0x%02X)", cmd_id);
708         }
709         else if (cmd_type == CE_T3T_COMMAND_FELICA)
710         {
711             ce_t3t_handle_non_nfc_forum_cmd (p_ce_cb, cmd_id, p_msg);
712             msg_processed = TRUE;
713         }
714         else
715         {
716             /* Verify that message contains at least NFCID2 and NUM services */
717             if (p_msg->len < T3T_MSG_CMD_COMMON_HDR_LEN)
718             {
719                 CE_TRACE_ERROR1 ("CE: received invalid T3t message (invalid length: %i)", p_msg->len);
720             }
721             else
722             {
723                 /* Handle NFC_FORUM command (UPDATE or CHECK) */
724                 STREAM_TO_ARRAY (cmd_nfcid2, p, NCI_RF_F_UID_LEN);
725                 STREAM_TO_UINT8 (p_cb->cur_cmd.num_services, p);
726 
727                 /* Calculate offset of block-list-start */
728                 block_list_start_offset = T3T_MSG_CMD_COMMON_HDR_LEN + 2*p_cb->cur_cmd.num_services + 1;
729 
730                 if (p_cb->state == CE_T3T_STATE_NOT_ACTIVATED)
731                 {
732                     CE_TRACE_ERROR2 ("CE: received command 0x%02X while in bad state (%i))", cmd_id, p_cb->state);
733                 }
734                 else if (memcmp (cmd_nfcid2, p_cb->local_nfcid2, NCI_RF_F_UID_LEN) != 0)
735                 {
736                     CE_TRACE_ERROR0 ("CE: received invalid T3t message (invalid NFCID2)");
737                     p_nfcid2 = cmd_nfcid2;      /* respond with ERROR using the NFCID2 from the command message */
738                 }
739                 else if (p_msg->len < block_list_start_offset)
740                 {
741                     /* Does not have minimum (including number_of_blocks field) */
742                     CE_TRACE_ERROR0 ("CE: incomplete message");
743                 }
744                 else
745                 {
746                     /* Parse service code list */
747                     for (i = 0; i < p_cb->cur_cmd.num_services; i++)
748                     {
749                         STREAM_TO_UINT16 (p_cb->cur_cmd.service_code_list[i], p);
750                     }
751 
752                     /* Verify that block list */
753                     block_list_ok = TRUE;
754                     STREAM_TO_UINT8 (p_cb->cur_cmd.num_blocks, p);
755                     remaining = p_msg->len - block_list_start_offset;
756                     p_cb->cur_cmd.p_block_list_start = p;
757                     for (i = 0; i < p_cb->cur_cmd.num_blocks; i++)
758                     {
759                         /* Each entry is at lease 2 bytes long */
760                         if (remaining < 2)
761                         {
762                             /* Unexpected end of message (while reading block-list) */
763                             CE_TRACE_ERROR0 ("CE: received invalid T3t message (unexpected end of block-list)");
764                             block_list_ok = FALSE;
765                             break;
766                         }
767 
768                         /* Get byte0 of block-list entry */
769                         bl0 = *p;
770 
771                         /* Validate service code index and size of block-list */
772                         if ((bl0 & T3T_MSG_SERVICE_LIST_MASK) >= p_cb->cur_cmd.num_services)
773                         {
774                             /* Invalid service code */
775                             CE_TRACE_ERROR1 ("CE: received invalid T3t message (invalid service index: %i)", (bl0 & T3T_MSG_SERVICE_LIST_MASK));
776                             block_list_ok = FALSE;
777                             break;
778                         }
779                         else if ((!(bl0 & T3T_MSG_MASK_TWO_BYTE_BLOCK_DESC_FORMAT)) && (remaining < 3))
780                         {
781                             /* Unexpected end of message (while reading 3-byte entry) */
782                             CE_TRACE_ERROR0 ("CE: received invalid T3t message (unexpected end of block-list)");
783                             block_list_ok = FALSE;
784                             break;
785                         }
786 
787                         /* Advance pointers to next block-list entry */
788                         entry_len = (bl0 & T3T_MSG_MASK_TWO_BYTE_BLOCK_DESC_FORMAT) ? 2 : 3;
789                         p+=entry_len;
790                         remaining-=entry_len;
791                     }
792 
793                     /* Block list is verified. Call CHECK or UPDATE handler */
794                     if (block_list_ok)
795                     {
796                         p_cb->cur_cmd.p_block_data_start = p;
797                         if (cmd_id == T3T_MSG_OPC_CHECK_CMD)
798                         {
799                             /* This is a CHECK command. Sanity check: there shouldn't be any more data remaining after reading block list */
800                             if (remaining)
801                             {
802                                 CE_TRACE_ERROR1 ("CE: unexpected data after after CHECK command (#i bytes)", remaining);
803                             }
804                             ce_t3t_handle_check_cmd (p_ce_cb, p_msg);
805                             msg_processed = TRUE;
806                         }
807                         else
808                         {
809                             /* This is an UPDATE command. See if message contains all the expected block data */
810                             if (remaining < p_cb->cur_cmd.num_blocks*T3T_MSG_BLOCKSIZE)
811                             {
812                                 CE_TRACE_ERROR0 ("CE: unexpected end of block-data");
813                             }
814                             else
815                             {
816                                 ce_t3t_handle_update_cmd (p_ce_cb, p_msg);
817                                 msg_processed = TRUE;
818                             }
819                         }
820                     }
821                 }
822             }
823         }
824     }
825 
826     if (!msg_processed)
827     {
828         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);
829         GKI_freebuf (p_msg);
830     }
831 
832 
833 }
834 
835 /*******************************************************************************
836 **
837 ** Function         ce_t3t_conn_cback
838 **
839 ** Description      This callback function receives the events/data from NFCC.
840 **
841 ** Returns          none
842 **
843 *******************************************************************************/
ce_t3t_conn_cback(UINT8 conn_id,tNFC_CONN_EVT event,tNFC_CONN * p_data)844 void ce_t3t_conn_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data)
845 {
846     tCE_T3T_MEM *p_cb = &ce_cb.mem.t3t;
847 
848     CE_TRACE_DEBUG2 ("ce_t3t_conn_cback: conn_id=%i, evt=%i", conn_id, event);
849 
850     switch (event)
851     {
852     case NFC_CONN_CREATE_CEVT:
853         break;
854 
855     case NFC_CONN_CLOSE_CEVT:
856         p_cb->state = CE_T3T_STATE_NOT_ACTIVATED;
857         break;
858 
859     case NFC_DATA_CEVT:
860         if (p_data->data.status == NFC_STATUS_OK)
861         {
862             ce_t3t_data_cback (conn_id, p_data->data.p_data);
863         }
864         break;
865 
866     case NFC_DEACTIVATE_CEVT:
867         p_cb->state = CE_T3T_STATE_NOT_ACTIVATED;
868         NFC_SetStaticRfCback (NULL);
869         break;
870 
871     default:
872         break;
873 
874     }
875 }
876 
877 /*******************************************************************************
878 **
879 ** Function         ce_select_t3t
880 **
881 ** Description      Select Type 3 Tag
882 **
883 ** Returns          NFC_STATUS_OK if success
884 **
885 *******************************************************************************/
ce_select_t3t(UINT16 system_code,UINT8 nfcid2[NCI_RF_F_UID_LEN])886 tNFC_STATUS ce_select_t3t (UINT16 system_code, UINT8 nfcid2[NCI_RF_F_UID_LEN])
887 {
888     tCE_T3T_MEM *p_cb = &ce_cb.mem.t3t;
889 
890     CE_TRACE_DEBUG0 ("ce_select_t3t ()");
891 
892     p_cb->state = CE_T3T_STATE_IDLE;
893     p_cb->system_code = system_code;
894     memcpy (p_cb->local_nfcid2, nfcid2, NCI_RF_F_UID_LEN);
895 
896     NFC_SetStaticRfCback (ce_t3t_conn_cback);
897     return NFC_STATUS_OK;
898 }
899 
900 
901 /*******************************************************************************
902 **
903 ** Function         CE_T3tSetLocalNDEFMsg
904 **
905 ** Description      Initialise CE Type 3 Tag with mandatory NDEF message
906 **
907 ** Returns          NFC_STATUS_OK if success
908 **
909 *******************************************************************************/
CE_T3tSetLocalNDEFMsg(BOOLEAN read_only,UINT32 size_max,UINT32 size_current,UINT8 * p_buf,UINT8 * p_scratch_buf)910 tNFC_STATUS CE_T3tSetLocalNDEFMsg (BOOLEAN read_only,
911                                    UINT32  size_max,
912                                    UINT32  size_current,
913                                    UINT8   *p_buf,
914                                    UINT8   *p_scratch_buf)
915 {
916     tCE_T3T_MEM *p_cb = &ce_cb.mem.t3t;
917 
918     CE_TRACE_API3 ("CE_T3tSetContent: ro=%i, size_max=%i, size_current=%i", read_only, size_max, size_current);
919 
920     /* Verify scratch buffer was provided if NDEF message is read/write */
921     if ((!read_only) && (!p_scratch_buf))
922     {
923         CE_TRACE_ERROR0 ("CE_T3tSetLocalNDEFMsg (): p_scratch_buf cannot be NULL if not read-only");
924         return NFC_STATUS_FAILED;
925     }
926 
927     /* Check if disabling the local NDEF */
928     if (!p_buf)
929     {
930         p_cb->ndef_info.initialized = FALSE;
931     }
932     /* Save ndef attributes */
933     else
934     {
935         p_cb->ndef_info.initialized = TRUE;
936         p_cb->ndef_info.ln = size_current;                          /* Current length */
937         p_cb->ndef_info.nmaxb = (UINT16) ((size_max + 15) / T3T_MSG_BLOCKSIZE);  /* Max length (in blocks) */
938         p_cb->ndef_info.rwflag = (read_only) ? T3T_MSG_NDEF_RWFLAG_RO : T3T_MSG_NDEF_RWFLAG_RW;
939         p_cb->ndef_info.writef = T3T_MSG_NDEF_WRITEF_OFF;
940         p_cb->ndef_info.version = 0x10;
941         p_cb->ndef_info.p_buf = p_buf;
942         p_cb->ndef_info.p_scratch_buf = p_scratch_buf;
943 
944         /* Initiate scratch buffer with same contents as read-buffer */
945         if (p_scratch_buf)
946         {
947             p_cb->ndef_info.scratch_ln      = p_cb->ndef_info.ln;
948             p_cb->ndef_info.scratch_writef  = T3T_MSG_NDEF_WRITEF_OFF;
949             memcpy (p_scratch_buf, p_buf, p_cb->ndef_info.ln);
950         }
951     }
952 
953     return (NFC_STATUS_OK);
954 }
955 
956 /*******************************************************************************
957 **
958 ** Function         CE_T3tSetLocalNDefParams
959 **
960 ** Description      Sets T3T-specific NDEF parameters. (Optional - if not
961 **                  called, then CE will use default parameters)
962 **
963 ** Returns          NFC_STATUS_OK if success
964 **
965 *******************************************************************************/
CE_T3tSetLocalNDefParams(UINT8 nbr,UINT8 nbw)966 tNFC_STATUS CE_T3tSetLocalNDefParams (UINT8 nbr, UINT8 nbw)
967 {
968     tCE_T3T_MEM *p_cb = &ce_cb.mem.t3t;
969 
970     CE_TRACE_API2 ("CE_T3tSetLocalNDefParams: nbr=%i, nbw=%i", nbr, nbw);
971 
972     /* Validate */
973     if ((nbr > T3T_MSG_NUM_BLOCKS_CHECK_MAX) || (nbw>T3T_MSG_NUM_BLOCKS_UPDATE_MAX) || (nbr < 1) || (nbw < 1))
974     {
975         CE_TRACE_ERROR0 ("CE_T3tSetLocalNDefParams: invalid params");
976         return NFC_STATUS_FAILED;
977     }
978 
979     p_cb->ndef_info.nbr = nbr;
980     p_cb->ndef_info.nbw = nbw;
981 
982     return NFC_STATUS_OK;
983 }
984 
985 /*******************************************************************************
986 **
987 ** Function         CE_T3tSendCheckRsp
988 **
989 ** Description      Send CHECK response message
990 **
991 ** Returns          NFC_STATUS_OK if success
992 **
993 *******************************************************************************/
CE_T3tSendCheckRsp(UINT8 status1,UINT8 status2,UINT8 num_blocks,UINT8 * p_block_data)994 tNFC_STATUS CE_T3tSendCheckRsp (UINT8 status1, UINT8 status2, UINT8 num_blocks, UINT8 *p_block_data)
995 {
996     tCE_T3T_MEM *p_cb = &ce_cb.mem.t3t;
997     tNFC_STATUS retval = NFC_STATUS_OK;
998     BT_HDR *p_rsp_msg;
999     UINT8 *p_dst, *p_rsp_start;
1000 
1001     CE_TRACE_API3 ("CE_T3tCheckRsp: status1=0x%02X, status2=0x%02X, num_blocks=%i", status1, status2, num_blocks);
1002 
1003     /* Validate num_blocks */
1004     if (num_blocks > T3T_MSG_NUM_BLOCKS_CHECK_MAX)
1005     {
1006         CE_TRACE_ERROR2 ("CE_T3tCheckRsp num_blocks (%i) exceeds maximum (%i)", num_blocks, T3T_MSG_NUM_BLOCKS_CHECK_MAX);
1007         return (NFC_STATUS_FAILED);
1008     }
1009 
1010     if ((p_rsp_msg = ce_t3t_get_rsp_buf ()) != NULL)
1011     {
1012         p_dst = p_rsp_start = (UINT8 *) (p_rsp_msg+1) + p_rsp_msg->offset;
1013 
1014         /* Response Code */
1015         UINT8_TO_STREAM (p_dst, T3T_MSG_OPC_CHECK_RSP);
1016 
1017         /* Manufacturer ID */
1018         ARRAY_TO_STREAM (p_dst, p_cb->local_nfcid2, NCI_RF_F_UID_LEN);
1019 
1020         /* Status1 and Status2 */
1021         UINT8_TO_STREAM (p_dst, status1);
1022         UINT8_TO_STREAM (p_dst, status2);
1023 
1024         if (status1 == T3T_MSG_RSP_STATUS_OK)
1025         {
1026             UINT8_TO_STREAM (p_dst, num_blocks);
1027             ARRAY_TO_STREAM (p_dst, p_block_data, (num_blocks * T3T_MSG_BLOCKSIZE));
1028         }
1029 
1030         p_rsp_msg->len = (UINT16) (p_dst - p_rsp_start);
1031         ce_t3t_send_to_lower (p_rsp_msg);
1032     }
1033     else
1034     {
1035         CE_TRACE_ERROR0 ("CE: Unable to allocate buffer for response message");
1036     }
1037 
1038     return (retval);
1039 }
1040 
1041 /*******************************************************************************
1042 **
1043 ** Function         CE_T3tSendUpdateRsp
1044 **
1045 ** Description      Send UPDATE response message
1046 **
1047 ** Returns          NFC_STATUS_OK if success
1048 **
1049 *******************************************************************************/
CE_T3tSendUpdateRsp(UINT8 status1,UINT8 status2)1050 tNFC_STATUS CE_T3tSendUpdateRsp (UINT8 status1, UINT8 status2)
1051 {
1052     tNFC_STATUS retval = NFC_STATUS_OK;
1053     tCE_CB *p_ce_cb = &ce_cb;
1054 
1055     CE_TRACE_API2 ("CE_T3tUpdateRsp: status1=0x%02X, status2=0x%02X", status1, status2);
1056     ce_t3t_send_rsp (p_ce_cb, NULL, T3T_MSG_OPC_UPDATE_RSP, status1, status2);
1057 
1058     return (retval);
1059 }
1060 
1061 #endif /* NFC_INCLUDED == TRUE */
1062