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