ce_t3t.c revision e9629bad30a9f478b336ab46b8e6e02f7f87af46
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
39enum {
40    CE_T3T_COMMAND_INVALID,
41    CE_T3T_COMMAND_NFC_FORUM,
42    CE_T3T_COMMAND_FELICA
43};
44
45/* T3T CE states */
46enum {
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*******************************************************************************/
60static 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*******************************************************************************/
71void 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*******************************************************************************/
87void 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*******************************************************************************/
116UINT8 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*****************************************************************************/
145BT_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*******************************************************************************/
168void 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*******************************************************************************/
212void 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*******************************************************************************/
397void 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*******************************************************************************/
554void 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*******************************************************************************/
663void 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*******************************************************************************/
844void 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*******************************************************************************/
886tNFC_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*******************************************************************************/
910tNFC_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*******************************************************************************/
966tNFC_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*******************************************************************************/
994tNFC_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*******************************************************************************/
1050tNFC_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