• 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   if (gki_utils == nullptr) {
89     gki_utils = new GkiUtils();
90   }
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_utils->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("%s: Default NDEF handler being changed",
145                                    __func__);
146 
147       /* Free old registration info */
148       nfa_dm_ndef_dereg_hdlr_by_handle(
149           (tNFA_HANDLE)NFA_NDEF_DEFAULT_HANDLER_IDX);
150     }
151     LOG(VERBOSE) << StringPrintf(
152         "%s: Default NDEF handler successfully registered", __func__);
153     hdlr_idx = NFA_NDEF_DEFAULT_HANDLER_IDX;
154   }
155   /* Get available entry in ndef_handler table, and check if requested type is
156      already registered */
157   else {
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;
162          i++) {
163       /* If this is a free slot, then remember it */
164       if (p_cb->p_ndef_handler[i] == nullptr) {
165         hdlr_idx = i;
166         break;
167       }
168     }
169   }
170 
171   if (hdlr_idx != NFA_HANDLE_INVALID) {
172     /* Update the table */
173     p_cb->p_ndef_handler[hdlr_idx] = p_reg_info;
174 
175     p_reg_info->ndef_type_handle =
176         (tNFA_HANDLE)(NFA_HANDLE_GROUP_NDEF_HANDLER | hdlr_idx);
177 
178     ndef_register.ndef_type_handle = p_reg_info->ndef_type_handle;
179     ndef_register.status = NFA_STATUS_OK;
180 
181     LOG(VERBOSE) << StringPrintf(
182         "%s: NDEF handler successfully registered. Handle=0x%08x", __func__,
183         p_reg_info->ndef_type_handle);
184     tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
185     nfa_ndef_evt_data.ndef_reg = ndef_register;
186     (*(p_reg_info->p_ndef_cback))(NFA_NDEF_REGISTER_EVT, &nfa_ndef_evt_data);
187 
188     /* indicate that we will free message buffer when type_handler is
189      * deregistered */
190     return false;
191   } else {
192     /* Error */
193     LOG(ERROR) << StringPrintf("%s: NDEF handler failed to register", __func__);
194     ndef_register.ndef_type_handle = NFA_HANDLE_INVALID;
195     ndef_register.status = NFA_STATUS_FAILED;
196     tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
197     nfa_ndef_evt_data.ndef_reg = ndef_register;
198     (*(p_reg_info->p_ndef_cback))(NFA_NDEF_REGISTER_EVT, &nfa_ndef_evt_data);
199 
200     return true;
201   }
202 }
203 
204 /*******************************************************************************
205 **
206 ** Function         nfa_dm_ndef_dereg_hdlr
207 **
208 ** Description      Deregister NDEF record type handler
209 **
210 ** Returns          TRUE (message buffer to be freed by caller)
211 **
212 *******************************************************************************/
nfa_dm_ndef_dereg_hdlr(tNFA_DM_MSG * p_data)213 bool nfa_dm_ndef_dereg_hdlr(tNFA_DM_MSG* p_data) {
214   tNFA_DM_API_DEREG_NDEF_HDLR* p_dereginfo =
215       (tNFA_DM_API_DEREG_NDEF_HDLR*)p_data;
216 
217   /* Make sure this is a NDEF_HDLR handle */
218   if (((p_dereginfo->ndef_type_handle & NFA_HANDLE_GROUP_MASK) !=
219        NFA_HANDLE_GROUP_NDEF_HANDLER) ||
220       ((p_dereginfo->ndef_type_handle & NFA_HANDLE_MASK) >=
221        NFA_NDEF_MAX_HANDLERS)) {
222     LOG(ERROR) << StringPrintf(
223         "%s: Invalid handle for NDEF type handler=0x%08x", __func__,
224         p_dereginfo->ndef_type_handle);
225   } else {
226     nfa_dm_ndef_dereg_hdlr_by_handle(p_dereginfo->ndef_type_handle);
227   }
228 
229   return true;
230 }
231 
232 /*******************************************************************************
233 **
234 ** Function         nfa_dm_ndef_find_next_handler
235 **
236 ** Description      Find next ndef handler for a given record type
237 **
238 ** Returns          void
239 **
240 *******************************************************************************/
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)241 tNFA_DM_API_REG_NDEF_HDLR* nfa_dm_ndef_find_next_handler(
242     tNFA_DM_API_REG_NDEF_HDLR* p_init_handler, uint8_t tnf,
243     uint8_t* p_type_name, uint8_t type_name_len, uint8_t* p_payload,
244     uint32_t payload_len) {
245   tNFA_DM_CB* p_cb = &nfa_dm_cb;
246   uint8_t i;
247 
248   /* if init_handler is NULL, then start with the first non-default handler */
249   if (!p_init_handler)
250     i = NFA_NDEF_DEFAULT_HANDLER_IDX + 1;
251   else {
252     /* Point to handler index after p_init_handler */
253     i = (p_init_handler->ndef_type_handle & NFA_HANDLE_MASK) + 1;
254   }
255 
256   /* Look for next handler */
257   for (; i < NFA_NDEF_MAX_HANDLERS; i++) {
258     /* Check if TNF matches */
259     if ((p_cb->p_ndef_handler[i]) && (p_cb->p_ndef_handler[i]->tnf == tnf)) {
260       if (p_type_name == nullptr) {
261         break;
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         /* This is a handler for a specific URI type */
268         /* Check if this recurd is WKT URI */
269         if ((p_payload) && (type_name_len == 1) && (*p_type_name == 'U')) {
270           /* Check if URI prefix abrieviation matches */
271           if ((payload_len > 1) &&
272               (p_payload[0] == p_cb->p_ndef_handler[i]->uri_id)) {
273             /* URI prefix abrieviation matches */
274             /* If handler does not specify an absolute URI, then match found. */
275             /* If absolute URI, then compare URI for match (skip over uri_id in
276              * ndef payload) */
277             if ((p_cb->p_ndef_handler[i]->uri_id != NFA_NDEF_URI_ID_ABSOLUTE) ||
278                 ((payload_len > p_cb->p_ndef_handler[i]->name_len) &&
279                  (memcmp(&p_payload[1], p_cb->p_ndef_handler[i]->name,
280                          p_cb->p_ndef_handler[i]->name_len) == 0))) {
281               /* Handler found. */
282               break;
283             }
284           }
285           /* Check if handler is absolute URI but NDEF is using prefix
286              abrieviation */
287           else if ((p_cb->p_ndef_handler[i]->uri_id ==
288                     NFA_NDEF_URI_ID_ABSOLUTE) &&
289                    (p_payload[0] != NFA_NDEF_URI_ID_ABSOLUTE)) {
290             /* Handler is absolute URI but NDEF is using prefix abrieviation.
291              * Compare URI prefix */
292             if ((p_payload[0] < NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE) &&
293                 strlen(
294                     (const char*)nfa_dm_ndef_wkt_uri_str_tbl[p_payload[0]]) >=
295                     p_cb->p_ndef_handler[i]->name_len &&
296                 (memcmp(p_cb->p_ndef_handler[i]->name,
297                         (char*)nfa_dm_ndef_wkt_uri_str_tbl[p_payload[0]],
298                         p_cb->p_ndef_handler[i]->name_len) == 0)) {
299               /* Handler found. */
300               break;
301             }
302           }
303           /* Check if handler is using prefix abrieviation, but NDEF is using
304              absolute URI */
305           else if ((p_cb->p_ndef_handler[i]->uri_id !=
306                     NFA_NDEF_URI_ID_ABSOLUTE) &&
307                    (p_payload[0] == NFA_NDEF_URI_ID_ABSOLUTE)) {
308             /* Handler is using prefix abrieviation, but NDEF is using absolute
309              * URI. Compare URI prefix */
310             if ((p_cb->p_ndef_handler[i]->uri_id <
311                  NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE) &&
312                 payload_len > strlen((const char*)nfa_dm_ndef_wkt_uri_str_tbl
313                                          [p_cb->p_ndef_handler[i]->uri_id]) &&
314                 (memcmp(&p_payload[1],
315                         nfa_dm_ndef_wkt_uri_str_tbl[p_cb->p_ndef_handler[i]
316                                                         ->uri_id],
317                         strlen((const char*)nfa_dm_ndef_wkt_uri_str_tbl
318                                    [p_cb->p_ndef_handler[i]->uri_id])) == 0)) {
319               /* Handler found. */
320               break;
321             }
322           }
323         }
324       }
325       /* Not looking for specific URI. Check if type_name for this handler
326          matches the NDEF record's type_name */
327       else if (p_cb->p_ndef_handler[i]->name_len == type_name_len) {
328         if ((type_name_len == 0) || (memcmp(p_cb->p_ndef_handler[i]->name,
329                                             p_type_name, type_name_len) == 0)) {
330           /* Handler found */
331           break;
332         }
333       }
334     }
335   }
336 
337   if (i < NFA_NDEF_MAX_HANDLERS)
338     return (p_cb->p_ndef_handler[i]);
339   else
340     return (nullptr);
341 }
342 
343 /*******************************************************************************
344 **
345 ** Function         nfa_dm_ndef_clear_notified_flag
346 **
347 ** Description      Clear 'whole_message_notified' flag for all the handlers
348 **                  (flag used to indicate that this handler has already
349 **                  handled the entire incoming NDEF message)
350 **
351 ** Returns          void
352 **
353 *******************************************************************************/
nfa_dm_ndef_clear_notified_flag(void)354 void nfa_dm_ndef_clear_notified_flag(void) {
355   tNFA_DM_CB* p_cb = &nfa_dm_cb;
356   uint8_t i;
357 
358   for (i = 0; i < NFA_NDEF_MAX_HANDLERS; i++) {
359     if (p_cb->p_ndef_handler[i]) {
360       p_cb->p_ndef_handler[i]->flags &= ~NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED;
361     }
362   }
363 }
364 
365 /*******************************************************************************
366 **
367 ** Function         nfa_dm_ndef_handle_message
368 **
369 ** Description      Handle incoming ndef message
370 **
371 ** Returns          void
372 **
373 *******************************************************************************/
nfa_dm_ndef_handle_message(tNFA_STATUS status,uint8_t * p_msg_buf,uint32_t len)374 void nfa_dm_ndef_handle_message(tNFA_STATUS status, uint8_t* p_msg_buf,
375                                 uint32_t len) {
376   tNFA_DM_CB* p_cb = &nfa_dm_cb;
377   tNDEF_STATUS ndef_status;
378   uint8_t *p_rec, *p_ndef_start, *p_type, *p_payload, *p_rec_end;
379   uint32_t payload_len;
380   uint8_t tnf, type_len, rec_hdr_flags, id_len;
381   tNFA_DM_API_REG_NDEF_HDLR* p_handler;
382   tNFA_NDEF_DATA ndef_data;
383   uint8_t rec_count = 0;
384   bool record_handled, entire_message_handled;
385 
386   LOG(VERBOSE) << StringPrintf("%s: status=%i, len=%i", __func__, status, len);
387 
388   if (status != NFA_STATUS_OK) {
389     /* If problem reading NDEF message, then exit (no action required) */
390     return;
391   }
392 
393   /* If in exclusive RF mode is activer, then route NDEF message callback
394    * registered with NFA_StartExclusiveRfControl */
395   if ((p_cb->flags & NFA_DM_FLAGS_EXCL_RF_ACTIVE) &&
396       (p_cb->p_excl_ndef_cback)) {
397     /* No ndef-handler handle, since this callback is not from
398      * RegisterNDefHandler */
399     ndef_data.ndef_type_handle = 0;
400     ndef_data.p_data = p_msg_buf;
401     ndef_data.len = len;
402     tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
403     nfa_ndef_evt_data.ndef_data = ndef_data;
404     (*p_cb->p_excl_ndef_cback)(NFA_NDEF_DATA_EVT, &nfa_ndef_evt_data);
405     return;
406   }
407 
408   /* Handle zero length - notify default handler */
409   if (len == 0) {
410     p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX];
411     if (p_handler != nullptr) {
412       LOG(VERBOSE) << StringPrintf(
413           "%s: Notifying default handler of zero-length NDEF message...",
414           __func__);
415       ndef_data.ndef_type_handle = p_handler->ndef_type_handle;
416       ndef_data.p_data = nullptr; /* Start of record */
417       ndef_data.len = 0;
418       tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
419       nfa_ndef_evt_data.ndef_data = ndef_data;
420       (*p_handler->p_ndef_cback)(NFA_NDEF_DATA_EVT, &nfa_ndef_evt_data);
421     }
422     return;
423   }
424 
425   /* Validate the NDEF message */
426   ndef_status = NDEF_MsgValidate(p_msg_buf, len, true);
427   if (ndef_status != NDEF_OK) {
428     LOG(ERROR) << StringPrintf(
429         "%s: Received invalid NDEF message. NDEF status=0x%x", __func__,
430         ndef_status);
431     return;
432   }
433 
434   /* NDEF message received from backgound polling. Pass the NDEF message to the
435    * NDEF handlers */
436 
437   /* New NDEF message. Clear 'notified' flag for all the handlers */
438   nfa_dm_ndef_clear_notified_flag();
439 
440   /* Indicate that no handler has handled this entire NDEF message (e.g.
441    * connection-handover handler *) */
442   entire_message_handled = false;
443 
444   /* Get first record in message */
445   p_rec = p_ndef_start = p_msg_buf;
446 
447   /* Check each record in the NDEF message */
448   while (p_rec != nullptr) {
449     /* Get record type */
450     p_type = NDEF_RecGetType(p_rec, &tnf, &type_len);
451 
452     /* Indicate record not handled yet */
453     record_handled = false;
454 
455     /* Get pointer to record payload */
456     p_payload = NDEF_RecGetPayload(p_rec, &payload_len);
457 
458     /* Find first handler for this type */
459     p_handler = nfa_dm_ndef_find_next_handler(nullptr, tnf, p_type, type_len,
460                                               p_payload, payload_len);
461     if (p_handler == nullptr) {
462       /* Not a registered NDEF type. Use default handler */
463       p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX];
464       if (p_handler != nullptr) {
465         LOG(VERBOSE) << StringPrintf(
466             "%s: No handler found. Using default handler...", __func__);
467       }
468     }
469 
470     while (p_handler) {
471       /* If handler is for whole NDEF message, and it has already been notified,
472        * then skip notification */
473       if (p_handler->flags & NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED) {
474         /* Look for next handler */
475         p_handler = nfa_dm_ndef_find_next_handler(
476             p_handler, tnf, p_type, type_len, p_payload, payload_len);
477         continue;
478       }
479 
480       /* Get pointer to record payload */
481       LOG(VERBOSE) << StringPrintf("%s: Calling ndef type handler (%x)",
482                                    __func__, p_handler->ndef_type_handle);
483 
484       ndef_data.ndef_type_handle = p_handler->ndef_type_handle;
485       ndef_data.p_data = p_rec; /* Start of record */
486 
487       /* Calculate length of NDEF record */
488       if (p_payload != nullptr)
489         ndef_data.len = payload_len + (uint32_t)(p_payload - p_rec);
490       else {
491         /* If no payload, calculate length of ndef record header */
492         p_rec_end = p_rec;
493 
494         /* First byte is the header flags */
495         rec_hdr_flags = *p_rec_end++;
496 
497         /* Next byte is the type field length */
498         type_len = *p_rec_end++;
499 
500         /* Next is the payload length (1 or 4 bytes) */
501         if (rec_hdr_flags & NDEF_SR_MASK) {
502           p_rec_end++;
503         } else {
504           p_rec_end += 4;
505         }
506 
507         /* ID field Length */
508         if (rec_hdr_flags & NDEF_IL_MASK)
509           id_len = *p_rec_end++;
510         else
511           id_len = 0;
512         p_rec_end += id_len;
513 
514         ndef_data.len = (uint32_t)(p_rec_end - p_rec);
515       }
516 
517       /* If handler wants entire ndef message, then pass pointer to start of
518        * message and  */
519       /* set 'notified' flag so handler won't get notified on subsequent records
520        * for this */
521       /* NDEF message. */
522       if (p_handler->flags & NFA_NDEF_FLAGS_HANDLE_WHOLE_MESSAGE) {
523         ndef_data.p_data = p_ndef_start; /* Start of NDEF message */
524         ndef_data.len = len;
525         p_handler->flags |= NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED;
526 
527         /* Indicate that at least one handler has received entire NDEF message
528          */
529         entire_message_handled = true;
530       }
531 
532       /* Notify NDEF type handler */
533       tNFA_NDEF_EVT_DATA nfa_ndef_evt_data;
534       nfa_ndef_evt_data.ndef_data = ndef_data;
535       (*p_handler->p_ndef_cback)(NFA_NDEF_DATA_EVT, &nfa_ndef_evt_data);
536 
537       /* Indicate that at lease one handler has received this record */
538       record_handled = true;
539 
540       /* Look for next handler */
541       p_handler = nfa_dm_ndef_find_next_handler(
542           p_handler, tnf, p_type, type_len, p_payload, payload_len);
543     }
544 
545     /* Check if at least one handler was notified of this record (only happens
546      * if no default handler was register) */
547     if ((!record_handled) && (!entire_message_handled)) {
548       /* Unregistered NDEF record type; no default handler */
549       LOG(WARNING) << StringPrintf("%s: Unhandled NDEF record (#%i)", __func__,
550                                    rec_count);
551     }
552 
553     rec_count++;
554     p_rec = NDEF_MsgGetNextRec(p_rec);
555   }
556 }
557