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