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