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