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