Home | History | Annotate | Download | only in dm
      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  *  Handle ndef messages
     22  *
     23  ******************************************************************************/
     24 #include <string.h>
     25 #include "nfa_sys.h"
     26 #include "nfa_api.h"
     27 #include "nfa_dm_int.h"
     28 #include "nfa_sys_int.h"
     29 #include "nfc_api.h"
     30 #include "ndef_utils.h"
     31 
     32 /*******************************************************************************
     33 * URI Well-known-type prefixes
     34 *******************************************************************************/
     35 const UINT8 *nfa_dm_ndef_wkt_uri_str_tbl[] = {
     36     NULL,           /* 0x00 */
     37     (const UINT8*) "http://www.",  /* 0x01 */
     38     (const UINT8*) "https://www.", /* 0x02 */
     39     (const UINT8*) "http://",      /* 0x03 */
     40     (const UINT8*) "https://",     /* 0x04 */
     41     (const UINT8*) "tel:",         /* 0x05 */
     42     (const UINT8*) "mailto:",      /* 0x06 */
     43     (const UINT8*) "ftp://anonymous:anonymous@",   /* 0x07 */
     44     (const UINT8*) "ftp://ftp.",   /* 0x08 */
     45     (const UINT8*) "ftps://",      /* 0x09 */
     46     (const UINT8*) "sftp://",      /* 0x0A */
     47     (const UINT8*) "smb://",       /* 0x0B */
     48     (const UINT8*) "nfs://",       /* 0x0C */
     49     (const UINT8*) "ftp://",       /* 0x0D */
     50     (const UINT8*) "dav://",       /* 0x0E */
     51     (const UINT8*) "news:",        /* 0x0F */
     52     (const UINT8*) "telnet://",    /* 0x10 */
     53     (const UINT8*) "imap:",        /* 0x11 */
     54     (const UINT8*) "rtsp://",      /* 0x12 */
     55     (const UINT8*) "urn:",         /* 0x13 */
     56     (const UINT8*) "pop:",         /* 0x14 */
     57     (const UINT8*) "sip:",         /* 0x15 */
     58     (const UINT8*) "sips:",        /* 0x16 */
     59     (const UINT8*) "tftp:",        /* 0x17 */
     60     (const UINT8*) "btspp://",     /* 0x18 */
     61     (const UINT8*) "btl2cap://",   /* 0x19 */
     62     (const UINT8*) "btgoep://",    /* 0x1A */
     63     (const UINT8*) "tcpobex://",   /* 0x1B */
     64     (const UINT8*) "irdaobex://",  /* 0x1C */
     65     (const UINT8*) "file://",      /* 0x1D */
     66     (const UINT8*) "urn:epc:id:",  /* 0x1E */
     67     (const UINT8*) "urn:epc:tag:", /* 0x1F */
     68     (const UINT8*) "urn:epc:pat:", /* 0x20 */
     69     (const UINT8*) "urn:epc:raw:", /* 0x21 */
     70     (const UINT8*) "urn:epc:",     /* 0x22 */
     71     (const UINT8*) "urn:nfc:"      /* 0x23 */
     72 };
     73 #define NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE (sizeof (nfa_dm_ndef_wkt_uri_str_tbl) / sizeof (UINT8 *))
     74 
     75 /*******************************************************************************
     76 **
     77 ** Function         nfa_dm_ndef_dereg_hdlr_by_handle
     78 **
     79 ** Description      Deregister NDEF record type handler
     80 **
     81 ** Returns          TRUE (message buffer to be freed by caller)
     82 **
     83 *******************************************************************************/
     84 void nfa_dm_ndef_dereg_hdlr_by_handle (tNFA_HANDLE ndef_type_handle)
     85 {
     86     tNFA_DM_CB *p_cb = &nfa_dm_cb;
     87     UINT16 hdlr_idx;
     88     hdlr_idx = (UINT16) (ndef_type_handle & NFA_HANDLE_MASK);
     89 
     90     if (p_cb->p_ndef_handler[hdlr_idx])
     91     {
     92         GKI_freebuf (p_cb->p_ndef_handler[hdlr_idx]);
     93         p_cb->p_ndef_handler[hdlr_idx] = NULL;
     94     }
     95 }
     96 
     97 /*******************************************************************************
     98 **
     99 ** Function         nfa_dm_ndef_dereg_all
    100 **
    101 ** Description      Deregister all NDEF record type handlers (called during
    102 **                  shutdown(.
    103 **
    104 ** Returns          Nothing
    105 **
    106 *******************************************************************************/
    107 void nfa_dm_ndef_dereg_all (void)
    108 {
    109     tNFA_DM_CB *p_cb = &nfa_dm_cb;
    110     UINT32 i;
    111 
    112     for (i = 0; i < NFA_NDEF_MAX_HANDLERS; i++)
    113     {
    114         /* If this is a free slot, then remember it */
    115         if (p_cb->p_ndef_handler[i] != NULL)
    116         {
    117             GKI_freebuf (p_cb->p_ndef_handler[i]);
    118             p_cb->p_ndef_handler[i] = NULL;
    119         }
    120     }
    121 }
    122 
    123 
    124 /*******************************************************************************
    125 **
    126 ** Function         nfa_dm_ndef_reg_hdlr
    127 **
    128 ** Description      Register NDEF record type handler
    129 **
    130 ** Returns          TRUE if message buffer is to be freed by caller
    131 **
    132 *******************************************************************************/
    133 BOOLEAN nfa_dm_ndef_reg_hdlr (tNFA_DM_MSG *p_data)
    134 {
    135     tNFA_DM_CB *p_cb = &nfa_dm_cb;
    136     UINT32 hdlr_idx, i;
    137     tNFA_DM_API_REG_NDEF_HDLR *p_reg_info = (tNFA_DM_API_REG_NDEF_HDLR *) p_data;
    138     tNFA_NDEF_REGISTER ndef_register;
    139 
    140     /* If registering default handler, check to see if one is already registered */
    141     if (p_reg_info->tnf == NFA_TNF_DEFAULT)
    142     {
    143         /* check if default handler is already registered */
    144         if (p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX])
    145         {
    146             NFA_TRACE_WARNING0 ("Default NDEF handler being changed.");
    147 
    148             /* Free old registration info */
    149             nfa_dm_ndef_dereg_hdlr_by_handle ((tNFA_HANDLE) NFA_NDEF_DEFAULT_HANDLER_IDX);
    150         }
    151         NFA_TRACE_DEBUG0 ("Default NDEF handler successfully registered.");
    152         hdlr_idx = NFA_NDEF_DEFAULT_HANDLER_IDX;
    153     }
    154     /* Get available entry in ndef_handler table, and check if requested type is already registered */
    155     else
    156     {
    157         hdlr_idx = NFA_HANDLE_INVALID;
    158 
    159         /* Check if this type is already registered */
    160         for (i = (NFA_NDEF_DEFAULT_HANDLER_IDX+1); i < NFA_NDEF_MAX_HANDLERS; i++)
    161         {
    162             /* If this is a free slot, then remember it */
    163             if (p_cb->p_ndef_handler[i] == NULL)
    164             {
    165                 hdlr_idx = i;
    166                 break;
    167             }
    168         }
    169     }
    170 
    171     if (hdlr_idx != NFA_HANDLE_INVALID)
    172     {
    173         /* Update the table */
    174         p_cb->p_ndef_handler[hdlr_idx] = p_reg_info;
    175 
    176         p_reg_info->ndef_type_handle = (tNFA_HANDLE) (NFA_HANDLE_GROUP_NDEF_HANDLER | hdlr_idx);
    177 
    178         ndef_register.ndef_type_handle = p_reg_info->ndef_type_handle;
    179         ndef_register.status = NFA_STATUS_OK;
    180 
    181         NFA_TRACE_DEBUG1 ("NDEF handler successfully registered. Handle=0x%08x", p_reg_info->ndef_type_handle);
    182         (*(p_reg_info->p_ndef_cback)) (NFA_NDEF_REGISTER_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_register);
    183 
    184         return FALSE;       /* indicate that we will free message buffer when type_handler is deregistered */
    185     }
    186     else
    187     {
    188         /* Error */
    189         NFA_TRACE_ERROR0 ("NDEF handler failed to register.");
    190         ndef_register.ndef_type_handle = NFA_HANDLE_INVALID;
    191         ndef_register.status = NFA_STATUS_FAILED;
    192         (*(p_reg_info->p_ndef_cback)) (NFA_NDEF_REGISTER_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_register);
    193 
    194         return TRUE;
    195     }
    196 }
    197 
    198 /*******************************************************************************
    199 **
    200 ** Function         nfa_dm_ndef_dereg_hdlr
    201 **
    202 ** Description      Deregister NDEF record type handler
    203 **
    204 ** Returns          TRUE (message buffer to be freed by caller)
    205 **
    206 *******************************************************************************/
    207 BOOLEAN nfa_dm_ndef_dereg_hdlr (tNFA_DM_MSG *p_data)
    208 {
    209     tNFA_DM_API_DEREG_NDEF_HDLR *p_dereginfo = (tNFA_DM_API_DEREG_NDEF_HDLR *) p_data;
    210 
    211     /* Make sure this is a NDEF_HDLR handle */
    212     if (  ((p_dereginfo->ndef_type_handle & NFA_HANDLE_GROUP_MASK) != NFA_HANDLE_GROUP_NDEF_HANDLER)
    213         ||((p_dereginfo->ndef_type_handle & NFA_HANDLE_MASK) >= NFA_NDEF_MAX_HANDLERS)  )
    214     {
    215         NFA_TRACE_ERROR1 ("Invalid handle for NDEF type handler: 0x%08x", p_dereginfo->ndef_type_handle);
    216     }
    217     else
    218     {
    219         nfa_dm_ndef_dereg_hdlr_by_handle (p_dereginfo->ndef_type_handle);
    220     }
    221 
    222 
    223     return TRUE;
    224 }
    225 
    226 /*******************************************************************************
    227 **
    228 ** Function         nfa_dm_ndef_find_next_handler
    229 **
    230 ** Description      Find next ndef handler for a given record type
    231 **
    232 ** Returns          void
    233 **
    234 *******************************************************************************/
    235 tNFA_DM_API_REG_NDEF_HDLR *nfa_dm_ndef_find_next_handler (tNFA_DM_API_REG_NDEF_HDLR *p_init_handler,
    236                                                           UINT8                     tnf,
    237                                                           UINT8                     *p_type_name,
    238                                                           UINT8                     type_name_len,
    239                                                           UINT8                     *p_payload,
    240                                                           UINT32                    payload_len)
    241 {
    242     tNFA_DM_CB *p_cb = &nfa_dm_cb;
    243     UINT8 i;
    244 
    245     /* if init_handler is NULL, then start with the first non-default handler */
    246     if (!p_init_handler)
    247         i=NFA_NDEF_DEFAULT_HANDLER_IDX+1;
    248     else
    249     {
    250         /* Point to handler index after p_init_handler */
    251         i = (p_init_handler->ndef_type_handle & NFA_HANDLE_MASK) + 1;
    252     }
    253 
    254 
    255     /* Look for next handler */
    256     for (; i < NFA_NDEF_MAX_HANDLERS; i++)
    257     {
    258         /* Check if TNF matches */
    259         if (  (p_cb->p_ndef_handler[i])
    260             &&(p_cb->p_ndef_handler[i]->tnf == tnf)  )
    261         {
    262             /* TNF matches. */
    263             /* If handler is for a specific URI type, check if type is WKT URI, */
    264             /* and that the URI prefix abrieviation for this handler matches */
    265             if (p_cb->p_ndef_handler[i]->flags & NFA_NDEF_FLAGS_WKT_URI)
    266             {
    267                 /* This is a handler for a specific URI type */
    268                 /* Check if this recurd is WKT URI */
    269                 if ((type_name_len == 1) && (*p_type_name == 'U'))
    270                 {
    271                     /* Check if URI prefix abrieviation matches */
    272                     if ((payload_len>1) && (p_payload[0] == p_cb->p_ndef_handler[i]->uri_id))
    273                     {
    274                         /* URI prefix abrieviation matches */
    275                         /* If handler does not specify an absolute URI, then match found. */
    276                         /* If absolute URI, then compare URI for match (skip over uri_id in ndef payload) */
    277                         if (  (p_cb->p_ndef_handler[i]->uri_id != NFA_NDEF_URI_ID_ABSOLUTE)
    278                             ||(memcmp (&p_payload[1], p_cb->p_ndef_handler[i]->name, p_cb->p_ndef_handler[i]->name_len) == 0)  )
    279                         {
    280                             /* Handler found. */
    281                             break;
    282                         }
    283                     }
    284                     /* Check if handler is absolute URI but NDEF is using prefix abrieviation */
    285                     else if ((p_cb->p_ndef_handler[i]->uri_id == NFA_NDEF_URI_ID_ABSOLUTE) && (p_payload[0] != NFA_NDEF_URI_ID_ABSOLUTE))
    286                     {
    287                         /* Handler is absolute URI but NDEF is using prefix abrieviation. Compare URI prefix */
    288                         if (  (p_payload[0]<NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE)
    289                             &&(memcmp (p_cb->p_ndef_handler[i]->name, (char *) nfa_dm_ndef_wkt_uri_str_tbl[p_payload[0]], p_cb->p_ndef_handler[i]->name_len) == 0)  )
    290                         {
    291                             /* Handler found. */
    292                             break;
    293                         }
    294                     }
    295                     /* Check if handler is using prefix abrieviation, but NDEF is using absolute URI */
    296                     else if ((p_cb->p_ndef_handler[i]->uri_id != NFA_NDEF_URI_ID_ABSOLUTE) && (p_payload[0] == NFA_NDEF_URI_ID_ABSOLUTE))
    297                     {
    298                         /* Handler is using prefix abrieviation, but NDEF is using absolute URI. Compare URI prefix */
    299                         if (  (p_cb->p_ndef_handler[i]->uri_id<NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE)
    300                             &&(memcmp (&p_payload[1], nfa_dm_ndef_wkt_uri_str_tbl[p_cb->p_ndef_handler[i]->uri_id], strlen ((const char*) nfa_dm_ndef_wkt_uri_str_tbl[p_cb->p_ndef_handler[i]->uri_id])) == 0)  )
    301                         {
    302                             /* Handler found. */
    303                             break;
    304                         }
    305                     }
    306                 }
    307             }
    308             /* Not looking for specific URI. Check if type_name for this handler matches the NDEF record's type_name */
    309             else if (p_cb->p_ndef_handler[i]->name_len == type_name_len)
    310             {
    311                 if (  (type_name_len == 0)
    312                     ||(memcmp(p_cb->p_ndef_handler[i]->name, p_type_name, type_name_len) == 0)  )
    313                 {
    314                     /* Handler found */
    315                     break;
    316                 }
    317             }
    318         }
    319 
    320     }
    321 
    322     if (i < NFA_NDEF_MAX_HANDLERS)
    323         return (p_cb->p_ndef_handler[i]);
    324     else
    325         return (NULL);
    326 }
    327 
    328 /*******************************************************************************
    329 **
    330 ** Function         nfa_dm_ndef_clear_notified_flag
    331 **
    332 ** Description      Clear 'whole_message_notified' flag for all the handlers
    333 **                  (flag used to indicate that this handler has already
    334 **                  handled the entire incoming NDEF message)
    335 **
    336 ** Returns          void
    337 **
    338 *******************************************************************************/
    339 void nfa_dm_ndef_clear_notified_flag (void)
    340 {
    341     tNFA_DM_CB *p_cb = &nfa_dm_cb;
    342     UINT8 i;
    343 
    344     for (i = 0; i < NFA_NDEF_MAX_HANDLERS; i++)
    345     {
    346         if (p_cb->p_ndef_handler[i])
    347         {
    348             p_cb->p_ndef_handler[i]->flags &= ~NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED;
    349         }
    350     }
    351 
    352 
    353 }
    354 
    355 /*******************************************************************************
    356 **
    357 ** Function         nfa_dm_ndef_handle_message
    358 **
    359 ** Description      Handle incoming ndef message
    360 **
    361 ** Returns          void
    362 **
    363 *******************************************************************************/
    364 void nfa_dm_ndef_handle_message (tNFA_STATUS status, UINT8 *p_msg_buf, UINT32 len)
    365 {
    366     tNFA_DM_CB *p_cb = &nfa_dm_cb;
    367     tNDEF_STATUS ndef_status;
    368     UINT8 *p_rec, *p_ndef_start, *p_type, *p_payload, *p_rec_end;
    369     UINT32 payload_len;
    370     UINT8 tnf, type_len, rec_hdr_flags, id_len;
    371     tNFA_DM_API_REG_NDEF_HDLR *p_handler;
    372     tNFA_NDEF_DATA ndef_data;
    373     UINT8 rec_count = 0;
    374     BOOLEAN record_handled, entire_message_handled;
    375 
    376     NFA_TRACE_DEBUG3 ("nfa_dm_ndef_handle_message status=%i, msgbuf=%08x, len=%i", status, p_msg_buf, len);
    377 
    378     if (status != NFA_STATUS_OK)
    379     {
    380         /* If problem reading NDEF message, then exit (no action required) */
    381         return;
    382     }
    383 
    384     /* If in exclusive RF mode is activer, then route NDEF message callback registered with NFA_StartExclusiveRfControl */
    385     if ((p_cb->flags & NFA_DM_FLAGS_EXCL_RF_ACTIVE) && (p_cb->p_excl_ndef_cback))
    386     {
    387         ndef_data.ndef_type_handle = 0;     /* No ndef-handler handle, since this callback is not from RegisterNDefHandler */
    388         ndef_data.p_data = p_msg_buf;
    389         ndef_data.len = len;
    390         (*p_cb->p_excl_ndef_cback) (NFA_NDEF_DATA_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_data);
    391         return;
    392     }
    393 
    394     /* Handle zero length - notify default handler */
    395     if (len == 0)
    396     {
    397         if ((p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX]) != NULL)
    398         {
    399             NFA_TRACE_DEBUG0 ("Notifying default handler of zero-length NDEF message...");
    400             ndef_data.ndef_type_handle = p_handler->ndef_type_handle;
    401             ndef_data.p_data = NULL;   /* Start of record */
    402             ndef_data.len = 0;
    403             (*p_handler->p_ndef_cback) (NFA_NDEF_DATA_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_data);
    404         }
    405         return;
    406     }
    407 
    408     /* Validate the NDEF message */
    409     if ((ndef_status = NDEF_MsgValidate (p_msg_buf, len, TRUE)) != NDEF_OK)
    410     {
    411         NFA_TRACE_ERROR1 ("Received invalid NDEF message. NDEF status=0x%x", ndef_status);
    412         return;
    413     }
    414 
    415     /* NDEF message received from backgound polling. Pass the NDEF message to the NDEF handlers */
    416 
    417     /* New NDEF message. Clear 'notified' flag for all the handlers */
    418     nfa_dm_ndef_clear_notified_flag ();
    419 
    420     /* Indicate that no handler has handled this entire NDEF message (e.g. connection-handover handler *) */
    421     entire_message_handled = FALSE;
    422 
    423     /* Get first record in message */
    424     p_rec = p_ndef_start = p_msg_buf;
    425 
    426     /* Check each record in the NDEF message */
    427     while (p_rec != NULL)
    428     {
    429         /* Get record type */
    430         p_type = NDEF_RecGetType (p_rec, &tnf, &type_len);
    431 
    432         /* Indicate record not handled yet */
    433         record_handled = FALSE;
    434 
    435         /* Get pointer to record payload */
    436         p_payload = NDEF_RecGetPayload (p_rec, &payload_len);
    437 
    438         /* Find first handler for this type */
    439         if ((p_handler = nfa_dm_ndef_find_next_handler (NULL, tnf, p_type, type_len, p_payload, payload_len)) == NULL)
    440         {
    441             /* Not a registered NDEF type. Use default handler */
    442             if ((p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX]) != NULL)
    443             {
    444                 NFA_TRACE_DEBUG0 ("No handler found. Using default handler...");
    445             }
    446         }
    447 
    448         while (p_handler)
    449         {
    450             /* If handler is for whole NDEF message, and it has already been notified, then skip notification */
    451             if (p_handler->flags & NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED)
    452             {
    453                 /* Look for next handler */
    454                 p_handler = nfa_dm_ndef_find_next_handler (p_handler, tnf, p_type, type_len, p_payload, payload_len);
    455                 continue;
    456             }
    457 
    458             /* Get pointer to record payload */
    459             NFA_TRACE_DEBUG1 ("Calling ndef type handler (%x)", p_handler->ndef_type_handle);
    460 
    461             ndef_data.ndef_type_handle = p_handler->ndef_type_handle;
    462             ndef_data.p_data = p_rec;   /* Start of record */
    463 
    464             /* Calculate length of NDEF record */
    465             if (p_payload != NULL)
    466                 ndef_data.len = payload_len + (UINT32) (p_payload - p_rec);
    467             else
    468             {
    469                 /* If no payload, calculate length of ndef record header */
    470                 p_rec_end = p_rec;
    471 
    472                 /* First byte is the header flags */
    473                 rec_hdr_flags = *p_rec_end++;
    474 
    475                 /* Next byte is the type field length */
    476                 type_len = *p_rec_end++;
    477 
    478                 /* Next is the payload length (1 or 4 bytes) */
    479                 if (rec_hdr_flags & NDEF_SR_MASK)
    480                 {
    481                     p_rec_end++;
    482                 }
    483                 else
    484                 {
    485                     p_rec_end+=4;
    486                 }
    487 
    488                 /* ID field Length */
    489                 if (rec_hdr_flags & NDEF_IL_MASK)
    490                     id_len = *p_rec_end++;
    491                 else
    492                     id_len = 0;
    493                 p_rec_end+=id_len;
    494 
    495                 ndef_data.len = (UINT32) (p_rec_end - p_rec);
    496             }
    497 
    498             /* If handler wants entire ndef message, then pass pointer to start of message and  */
    499             /* set 'notified' flag so handler won't get notified on subsequent records for this */
    500             /* NDEF message.                                                                    */
    501             if (p_handler->flags & NFA_NDEF_FLAGS_HANDLE_WHOLE_MESSAGE)
    502             {
    503                 ndef_data.p_data = p_ndef_start;   /* Start of NDEF message */
    504                 ndef_data.len = len;
    505                 p_handler->flags |= NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED;
    506 
    507                 /* Indicate that at least one handler has received entire NDEF message */
    508                 entire_message_handled = TRUE;
    509             }
    510 
    511             /* Notify NDEF type handler */
    512             (*p_handler->p_ndef_cback) (NFA_NDEF_DATA_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_data);
    513 
    514             /* Indicate that at lease one handler has received this record */
    515             record_handled = TRUE;
    516 
    517             /* Look for next handler */
    518             p_handler = nfa_dm_ndef_find_next_handler (p_handler, tnf, p_type, type_len, p_payload, payload_len);
    519         }
    520 
    521 
    522         /* Check if at least one handler was notified of this record (only happens if no default handler was register) */
    523         if ((!record_handled) && (!entire_message_handled))
    524         {
    525             /* Unregistered NDEF record type; no default handler */
    526             NFA_TRACE_WARNING1 ("Unhandled NDEF record (#%i)", rec_count);
    527         }
    528 
    529         rec_count++;
    530         p_rec = NDEF_MsgGetNextRec (p_rec);
    531     }
    532 }
    533