• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     nullptr,                                         /* 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 *******************************************************************************/
nfa_dm_ndef_dereg_hdlr_by_handle(tNFA_HANDLE ndef_type_handle)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] = nullptr;
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 *******************************************************************************/
nfa_dm_ndef_dereg_all(void)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] != nullptr) {
118       GKI_freebuf(p_cb->p_ndef_handler[i]);
119       p_cb->p_ndef_handler[i] = nullptr;
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 *******************************************************************************/
nfa_dm_ndef_reg_hdlr(tNFA_DM_MSG * p_data)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] == nullptr) {
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 *******************************************************************************/
nfa_dm_ndef_dereg_hdlr(tNFA_DM_MSG * p_data)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 *******************************************************************************/
nfa_dm_ndef_find_next_handler(tNFA_DM_API_REG_NDEF_HDLR * p_init_handler,uint8_t tnf,uint8_t * p_type_name,uint8_t type_name_len,uint8_t * p_payload,uint32_t payload_len)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                 ((payload_len > p_cb->p_ndef_handler[i]->name_len) &&
274                  (memcmp(&p_payload[1], p_cb->p_ndef_handler[i]->name,
275                          p_cb->p_ndef_handler[i]->name_len) == 0))) {
276               /* Handler found. */
277               break;
278             }
279           }
280           /* Check if handler is absolute URI but NDEF is using prefix
281              abrieviation */
282           else if ((p_cb->p_ndef_handler[i]->uri_id ==
283                     NFA_NDEF_URI_ID_ABSOLUTE) &&
284                    (p_payload[0] != NFA_NDEF_URI_ID_ABSOLUTE)) {
285             /* Handler is absolute URI but NDEF is using prefix abrieviation.
286              * Compare URI prefix */
287             if ((p_payload[0] < NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE) &&
288                 strlen(
289                     (const char*)nfa_dm_ndef_wkt_uri_str_tbl[p_payload[0]]) >=
290                     p_cb->p_ndef_handler[i]->name_len &&
291                 (memcmp(p_cb->p_ndef_handler[i]->name,
292                         (char*)nfa_dm_ndef_wkt_uri_str_tbl[p_payload[0]],
293                         p_cb->p_ndef_handler[i]->name_len) == 0)) {
294               /* Handler found. */
295               break;
296             }
297           }
298           /* Check if handler is using prefix abrieviation, but NDEF is using
299              absolute URI */
300           else if ((p_cb->p_ndef_handler[i]->uri_id !=
301                     NFA_NDEF_URI_ID_ABSOLUTE) &&
302                    (p_payload[0] == NFA_NDEF_URI_ID_ABSOLUTE)) {
303             /* Handler is using prefix abrieviation, but NDEF is using absolute
304              * URI. Compare URI prefix */
305             if ((p_cb->p_ndef_handler[i]->uri_id <
306                  NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE) &&
307                 payload_len > strlen((const char*)nfa_dm_ndef_wkt_uri_str_tbl
308                                          [p_cb->p_ndef_handler[i]->uri_id]) &&
309                 (memcmp(&p_payload[1],
310                         nfa_dm_ndef_wkt_uri_str_tbl[p_cb->p_ndef_handler[i]
311                                                         ->uri_id],
312                         strlen((const char*)nfa_dm_ndef_wkt_uri_str_tbl
313                                    [p_cb->p_ndef_handler[i]->uri_id])) == 0)) {
314               /* Handler found. */
315               break;
316             }
317           }
318         }
319       }
320       /* Not looking for specific URI. Check if type_name for this handler
321          matches the NDEF record's type_name */
322       else if (p_cb->p_ndef_handler[i]->name_len == type_name_len) {
323         if ((type_name_len == 0) || (memcmp(p_cb->p_ndef_handler[i]->name,
324                                             p_type_name, type_name_len) == 0)) {
325           /* Handler found */
326           break;
327         }
328       }
329     }
330   }
331 
332   if (i < NFA_NDEF_MAX_HANDLERS)
333     return (p_cb->p_ndef_handler[i]);
334   else
335     return (nullptr);
336 }
337 
338 /*******************************************************************************
339 **
340 ** Function         nfa_dm_ndef_clear_notified_flag
341 **
342 ** Description      Clear 'whole_message_notified' flag for all the handlers
343 **                  (flag used to indicate that this handler has already
344 **                  handled the entire incoming NDEF message)
345 **
346 ** Returns          void
347 **
348 *******************************************************************************/
nfa_dm_ndef_clear_notified_flag(void)349 void nfa_dm_ndef_clear_notified_flag(void) {
350   tNFA_DM_CB* p_cb = &nfa_dm_cb;
351   uint8_t i;
352 
353   for (i = 0; i < NFA_NDEF_MAX_HANDLERS; i++) {
354     if (p_cb->p_ndef_handler[i]) {
355       p_cb->p_ndef_handler[i]->flags &= ~NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED;
356     }
357   }
358 }
359 
360 /*******************************************************************************
361 **
362 ** Function         nfa_dm_ndef_handle_message
363 **
364 ** Description      Handle incoming ndef message
365 **
366 ** Returns          void
367 **
368 *******************************************************************************/
nfa_dm_ndef_handle_message(tNFA_STATUS status,uint8_t * p_msg_buf,uint32_t len)369 void nfa_dm_ndef_handle_message(tNFA_STATUS status, uint8_t* p_msg_buf,
370                                 uint32_t len) {
371   tNFA_DM_CB* p_cb = &nfa_dm_cb;
372   tNDEF_STATUS ndef_status;
373   uint8_t *p_rec, *p_ndef_start, *p_type, *p_payload, *p_rec_end;
374   uint32_t payload_len;
375   uint8_t tnf, type_len, rec_hdr_flags, id_len;
376   tNFA_DM_API_REG_NDEF_HDLR* p_handler;
377   tNFA_NDEF_DATA ndef_data;
378   uint8_t rec_count = 0;
379   bool record_handled, entire_message_handled;
380 
381   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
382       "nfa_dm_ndef_handle_message status=%i, len=%i", status, len);
383 
384   if (status != NFA_STATUS_OK) {
385     /* If problem reading NDEF message, then exit (no action required) */
386     return;
387   }
388 
389   /* If in exclusive RF mode is activer, then route NDEF message callback
390    * registered with NFA_StartExclusiveRfControl */
391   if ((p_cb->flags & NFA_DM_FLAGS_EXCL_RF_ACTIVE) &&
392       (p_cb->p_excl_ndef_cback)) {
393     /* No ndef-handler handle, since this callback is not from
394      * RegisterNDefHandler */
395     ndef_data.ndef_type_handle = 0;
396     ndef_data.p_data = p_msg_buf;
397     ndef_data.len = len;
398     tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
399     nfa_ndef_evt_data.ndef_data = ndef_data;
400     (*p_cb->p_excl_ndef_cback)(NFA_NDEF_DATA_EVT, &nfa_ndef_evt_data);
401     return;
402   }
403 
404   /* Handle zero length - notify default handler */
405   if (len == 0) {
406     p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX];
407     if (p_handler != nullptr) {
408       DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
409           "Notifying default handler of zero-length NDEF message...");
410       ndef_data.ndef_type_handle = p_handler->ndef_type_handle;
411       ndef_data.p_data = nullptr; /* Start of record */
412       ndef_data.len = 0;
413       tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
414       nfa_ndef_evt_data.ndef_data = ndef_data;
415       (*p_handler->p_ndef_cback)(NFA_NDEF_DATA_EVT, &nfa_ndef_evt_data);
416     }
417     return;
418   }
419 
420   /* Validate the NDEF message */
421   ndef_status = NDEF_MsgValidate(p_msg_buf, len, true);
422   if (ndef_status != NDEF_OK) {
423     LOG(ERROR) << StringPrintf(
424         "Received invalid NDEF message. NDEF status=0x%x", ndef_status);
425     return;
426   }
427 
428   /* NDEF message received from backgound polling. Pass the NDEF message to the
429    * NDEF handlers */
430 
431   /* New NDEF message. Clear 'notified' flag for all the handlers */
432   nfa_dm_ndef_clear_notified_flag();
433 
434   /* Indicate that no handler has handled this entire NDEF message (e.g.
435    * connection-handover handler *) */
436   entire_message_handled = false;
437 
438   /* Get first record in message */
439   p_rec = p_ndef_start = p_msg_buf;
440 
441   /* Check each record in the NDEF message */
442   while (p_rec != nullptr) {
443     /* Get record type */
444     p_type = NDEF_RecGetType(p_rec, &tnf, &type_len);
445 
446     /* Indicate record not handled yet */
447     record_handled = false;
448 
449     /* Get pointer to record payload */
450     p_payload = NDEF_RecGetPayload(p_rec, &payload_len);
451 
452     /* Find first handler for this type */
453     p_handler = nfa_dm_ndef_find_next_handler(nullptr, tnf, p_type, type_len,
454                                               p_payload, payload_len);
455     if (p_handler == nullptr) {
456       /* Not a registered NDEF type. Use default handler */
457       p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX];
458       if (p_handler != nullptr) {
459         DLOG_IF(INFO, nfc_debug_enabled)
460             << StringPrintf("No handler found. Using default handler...");
461       }
462     }
463 
464     while (p_handler) {
465       /* If handler is for whole NDEF message, and it has already been notified,
466        * then skip notification */
467       if (p_handler->flags & NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED) {
468         /* Look for next handler */
469         p_handler = nfa_dm_ndef_find_next_handler(
470             p_handler, tnf, p_type, type_len, p_payload, payload_len);
471         continue;
472       }
473 
474       /* Get pointer to record payload */
475       DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
476           "Calling ndef type handler (%x)", p_handler->ndef_type_handle);
477 
478       ndef_data.ndef_type_handle = p_handler->ndef_type_handle;
479       ndef_data.p_data = p_rec; /* Start of record */
480 
481       /* Calculate length of NDEF record */
482       if (p_payload != nullptr)
483         ndef_data.len = payload_len + (uint32_t)(p_payload - p_rec);
484       else {
485         /* If no payload, calculate length of ndef record header */
486         p_rec_end = p_rec;
487 
488         /* First byte is the header flags */
489         rec_hdr_flags = *p_rec_end++;
490 
491         /* Next byte is the type field length */
492         type_len = *p_rec_end++;
493 
494         /* Next is the payload length (1 or 4 bytes) */
495         if (rec_hdr_flags & NDEF_SR_MASK) {
496           p_rec_end++;
497         } else {
498           p_rec_end += 4;
499         }
500 
501         /* ID field Length */
502         if (rec_hdr_flags & NDEF_IL_MASK)
503           id_len = *p_rec_end++;
504         else
505           id_len = 0;
506         p_rec_end += id_len;
507 
508         ndef_data.len = (uint32_t)(p_rec_end - p_rec);
509       }
510 
511       /* If handler wants entire ndef message, then pass pointer to start of
512        * message and  */
513       /* set 'notified' flag so handler won't get notified on subsequent records
514        * for this */
515       /* NDEF message. */
516       if (p_handler->flags & NFA_NDEF_FLAGS_HANDLE_WHOLE_MESSAGE) {
517         ndef_data.p_data = p_ndef_start; /* Start of NDEF message */
518         ndef_data.len = len;
519         p_handler->flags |= NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED;
520 
521         /* Indicate that at least one handler has received entire NDEF message
522          */
523         entire_message_handled = true;
524       }
525 
526       /* Notify NDEF type handler */
527       tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
528       nfa_ndef_evt_data.ndef_data = ndef_data;
529       (*p_handler->p_ndef_cback)(NFA_NDEF_DATA_EVT, &nfa_ndef_evt_data);
530 
531       /* Indicate that at lease one handler has received this record */
532       record_handled = true;
533 
534       /* Look for next handler */
535       p_handler = nfa_dm_ndef_find_next_handler(
536           p_handler, tnf, p_type, type_len, p_payload, payload_len);
537     }
538 
539     /* Check if at least one handler was notified of this record (only happens
540      * if no default handler was register) */
541     if ((!record_handled) && (!entire_message_handled)) {
542       /* Unregistered NDEF record type; no default handler */
543       LOG(WARNING) << StringPrintf("Unhandled NDEF record (#%i)", rec_count);
544     }
545 
546     rec_count++;
547     p_rec = NDEF_MsgGetNextRec(p_rec);
548   }
549 }
550