/****************************************************************************** * * Copyright (C) 2010-2014 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * * Handle ndef messages * ******************************************************************************/ #include <string.h> #include "nfa_sys.h" #include "nfa_api.h" #include "nfa_dm_int.h" #include "nfa_sys_int.h" #include "nfc_api.h" #include "ndef_utils.h" /******************************************************************************* * URI Well-known-type prefixes *******************************************************************************/ const UINT8 *nfa_dm_ndef_wkt_uri_str_tbl[] = { NULL, /* 0x00 */ (const UINT8*) "http://www.", /* 0x01 */ (const UINT8*) "https://www.", /* 0x02 */ (const UINT8*) "http://", /* 0x03 */ (const UINT8*) "https://", /* 0x04 */ (const UINT8*) "tel:", /* 0x05 */ (const UINT8*) "mailto:", /* 0x06 */ (const UINT8*) "ftp://anonymous:anonymous@", /* 0x07 */ (const UINT8*) "ftp://ftp.", /* 0x08 */ (const UINT8*) "ftps://", /* 0x09 */ (const UINT8*) "sftp://", /* 0x0A */ (const UINT8*) "smb://", /* 0x0B */ (const UINT8*) "nfs://", /* 0x0C */ (const UINT8*) "ftp://", /* 0x0D */ (const UINT8*) "dav://", /* 0x0E */ (const UINT8*) "news:", /* 0x0F */ (const UINT8*) "telnet://", /* 0x10 */ (const UINT8*) "imap:", /* 0x11 */ (const UINT8*) "rtsp://", /* 0x12 */ (const UINT8*) "urn:", /* 0x13 */ (const UINT8*) "pop:", /* 0x14 */ (const UINT8*) "sip:", /* 0x15 */ (const UINT8*) "sips:", /* 0x16 */ (const UINT8*) "tftp:", /* 0x17 */ (const UINT8*) "btspp://", /* 0x18 */ (const UINT8*) "btl2cap://", /* 0x19 */ (const UINT8*) "btgoep://", /* 0x1A */ (const UINT8*) "tcpobex://", /* 0x1B */ (const UINT8*) "irdaobex://", /* 0x1C */ (const UINT8*) "file://", /* 0x1D */ (const UINT8*) "urn:epc:id:", /* 0x1E */ (const UINT8*) "urn:epc:tag:", /* 0x1F */ (const UINT8*) "urn:epc:pat:", /* 0x20 */ (const UINT8*) "urn:epc:raw:", /* 0x21 */ (const UINT8*) "urn:epc:", /* 0x22 */ (const UINT8*) "urn:nfc:" /* 0x23 */ }; #define NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE (sizeof (nfa_dm_ndef_wkt_uri_str_tbl) / sizeof (UINT8 *)) /******************************************************************************* ** ** Function nfa_dm_ndef_dereg_hdlr_by_handle ** ** Description Deregister NDEF record type handler ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ void nfa_dm_ndef_dereg_hdlr_by_handle (tNFA_HANDLE ndef_type_handle) { tNFA_DM_CB *p_cb = &nfa_dm_cb; UINT16 hdlr_idx; hdlr_idx = (UINT16) (ndef_type_handle & NFA_HANDLE_MASK); if (p_cb->p_ndef_handler[hdlr_idx]) { GKI_freebuf (p_cb->p_ndef_handler[hdlr_idx]); p_cb->p_ndef_handler[hdlr_idx] = NULL; } } /******************************************************************************* ** ** Function nfa_dm_ndef_dereg_all ** ** Description Deregister all NDEF record type handlers (called during ** shutdown(. ** ** Returns Nothing ** *******************************************************************************/ void nfa_dm_ndef_dereg_all (void) { tNFA_DM_CB *p_cb = &nfa_dm_cb; UINT32 i; for (i = 0; i < NFA_NDEF_MAX_HANDLERS; i++) { /* If this is a free slot, then remember it */ if (p_cb->p_ndef_handler[i] != NULL) { GKI_freebuf (p_cb->p_ndef_handler[i]); p_cb->p_ndef_handler[i] = NULL; } } } /******************************************************************************* ** ** Function nfa_dm_ndef_reg_hdlr ** ** Description Register NDEF record type handler ** ** Returns TRUE if message buffer is to be freed by caller ** *******************************************************************************/ BOOLEAN nfa_dm_ndef_reg_hdlr (tNFA_DM_MSG *p_data) { tNFA_DM_CB *p_cb = &nfa_dm_cb; UINT32 hdlr_idx, i; tNFA_DM_API_REG_NDEF_HDLR *p_reg_info = (tNFA_DM_API_REG_NDEF_HDLR *) p_data; tNFA_NDEF_REGISTER ndef_register; /* If registering default handler, check to see if one is already registered */ if (p_reg_info->tnf == NFA_TNF_DEFAULT) { /* check if default handler is already registered */ if (p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX]) { NFA_TRACE_WARNING0 ("Default NDEF handler being changed."); /* Free old registration info */ nfa_dm_ndef_dereg_hdlr_by_handle ((tNFA_HANDLE) NFA_NDEF_DEFAULT_HANDLER_IDX); } NFA_TRACE_DEBUG0 ("Default NDEF handler successfully registered."); hdlr_idx = NFA_NDEF_DEFAULT_HANDLER_IDX; } /* Get available entry in ndef_handler table, and check if requested type is already registered */ else { hdlr_idx = NFA_HANDLE_INVALID; /* Check if this type is already registered */ for (i = (NFA_NDEF_DEFAULT_HANDLER_IDX+1); i < NFA_NDEF_MAX_HANDLERS; i++) { /* If this is a free slot, then remember it */ if (p_cb->p_ndef_handler[i] == NULL) { hdlr_idx = i; break; } } } if (hdlr_idx != NFA_HANDLE_INVALID) { /* Update the table */ p_cb->p_ndef_handler[hdlr_idx] = p_reg_info; p_reg_info->ndef_type_handle = (tNFA_HANDLE) (NFA_HANDLE_GROUP_NDEF_HANDLER | hdlr_idx); ndef_register.ndef_type_handle = p_reg_info->ndef_type_handle; ndef_register.status = NFA_STATUS_OK; NFA_TRACE_DEBUG1 ("NDEF handler successfully registered. Handle=0x%08x", p_reg_info->ndef_type_handle); (*(p_reg_info->p_ndef_cback)) (NFA_NDEF_REGISTER_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_register); return FALSE; /* indicate that we will free message buffer when type_handler is deregistered */ } else { /* Error */ NFA_TRACE_ERROR0 ("NDEF handler failed to register."); ndef_register.ndef_type_handle = NFA_HANDLE_INVALID; ndef_register.status = NFA_STATUS_FAILED; (*(p_reg_info->p_ndef_cback)) (NFA_NDEF_REGISTER_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_register); return TRUE; } } /******************************************************************************* ** ** Function nfa_dm_ndef_dereg_hdlr ** ** Description Deregister NDEF record type handler ** ** Returns TRUE (message buffer to be freed by caller) ** *******************************************************************************/ BOOLEAN nfa_dm_ndef_dereg_hdlr (tNFA_DM_MSG *p_data) { tNFA_DM_API_DEREG_NDEF_HDLR *p_dereginfo = (tNFA_DM_API_DEREG_NDEF_HDLR *) p_data; /* Make sure this is a NDEF_HDLR handle */ if ( ((p_dereginfo->ndef_type_handle & NFA_HANDLE_GROUP_MASK) != NFA_HANDLE_GROUP_NDEF_HANDLER) ||((p_dereginfo->ndef_type_handle & NFA_HANDLE_MASK) >= NFA_NDEF_MAX_HANDLERS) ) { NFA_TRACE_ERROR1 ("Invalid handle for NDEF type handler: 0x%08x", p_dereginfo->ndef_type_handle); } else { nfa_dm_ndef_dereg_hdlr_by_handle (p_dereginfo->ndef_type_handle); } return TRUE; } /******************************************************************************* ** ** Function nfa_dm_ndef_find_next_handler ** ** Description Find next ndef handler for a given record type ** ** Returns void ** *******************************************************************************/ tNFA_DM_API_REG_NDEF_HDLR *nfa_dm_ndef_find_next_handler (tNFA_DM_API_REG_NDEF_HDLR *p_init_handler, UINT8 tnf, UINT8 *p_type_name, UINT8 type_name_len, UINT8 *p_payload, UINT32 payload_len) { tNFA_DM_CB *p_cb = &nfa_dm_cb; UINT8 i; /* if init_handler is NULL, then start with the first non-default handler */ if (!p_init_handler) i=NFA_NDEF_DEFAULT_HANDLER_IDX+1; else { /* Point to handler index after p_init_handler */ i = (p_init_handler->ndef_type_handle & NFA_HANDLE_MASK) + 1; } /* Look for next handler */ for (; i < NFA_NDEF_MAX_HANDLERS; i++) { /* Check if TNF matches */ if ( (p_cb->p_ndef_handler[i]) &&(p_cb->p_ndef_handler[i]->tnf == tnf) ) { /* TNF matches. */ /* If handler is for a specific URI type, check if type is WKT URI, */ /* and that the URI prefix abrieviation for this handler matches */ if (p_cb->p_ndef_handler[i]->flags & NFA_NDEF_FLAGS_WKT_URI) { /* This is a handler for a specific URI type */ /* Check if this recurd is WKT URI */ if ((p_payload) && (type_name_len == 1) && (*p_type_name == 'U')) { /* Check if URI prefix abrieviation matches */ if ((payload_len>1) && (p_payload[0] == p_cb->p_ndef_handler[i]->uri_id)) { /* URI prefix abrieviation matches */ /* If handler does not specify an absolute URI, then match found. */ /* If absolute URI, then compare URI for match (skip over uri_id in ndef payload) */ if ( (p_cb->p_ndef_handler[i]->uri_id != NFA_NDEF_URI_ID_ABSOLUTE) ||(memcmp (&p_payload[1], p_cb->p_ndef_handler[i]->name, p_cb->p_ndef_handler[i]->name_len) == 0) ) { /* Handler found. */ break; } } /* Check if handler is absolute URI but NDEF is using prefix abrieviation */ else if ((p_cb->p_ndef_handler[i]->uri_id == NFA_NDEF_URI_ID_ABSOLUTE) && (p_payload[0] != NFA_NDEF_URI_ID_ABSOLUTE)) { /* Handler is absolute URI but NDEF is using prefix abrieviation. Compare URI prefix */ if ( (p_payload[0]<NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE) &&(memcmp (p_cb->p_ndef_handler[i]->name, (char *) nfa_dm_ndef_wkt_uri_str_tbl[p_payload[0]], p_cb->p_ndef_handler[i]->name_len) == 0) ) { /* Handler found. */ break; } } /* Check if handler is using prefix abrieviation, but NDEF is using absolute URI */ else if ((p_cb->p_ndef_handler[i]->uri_id != NFA_NDEF_URI_ID_ABSOLUTE) && (p_payload[0] == NFA_NDEF_URI_ID_ABSOLUTE)) { /* Handler is using prefix abrieviation, but NDEF is using absolute URI. Compare URI prefix */ if ( (p_cb->p_ndef_handler[i]->uri_id<NFA_DM_NDEF_WKT_URI_STR_TBL_SIZE) &&(memcmp (&p_payload[1], nfa_dm_ndef_wkt_uri_str_tbl[p_cb->p_ndef_handler[i]->uri_id], strlen ((const char*) nfa_dm_ndef_wkt_uri_str_tbl[p_cb->p_ndef_handler[i]->uri_id])) == 0) ) { /* Handler found. */ break; } } } } /* Not looking for specific URI. Check if type_name for this handler matches the NDEF record's type_name */ else if (p_cb->p_ndef_handler[i]->name_len == type_name_len) { if ( (type_name_len == 0) ||(memcmp(p_cb->p_ndef_handler[i]->name, p_type_name, type_name_len) == 0) ) { /* Handler found */ break; } } } } if (i < NFA_NDEF_MAX_HANDLERS) return (p_cb->p_ndef_handler[i]); else return (NULL); } /******************************************************************************* ** ** Function nfa_dm_ndef_clear_notified_flag ** ** Description Clear 'whole_message_notified' flag for all the handlers ** (flag used to indicate that this handler has already ** handled the entire incoming NDEF message) ** ** Returns void ** *******************************************************************************/ void nfa_dm_ndef_clear_notified_flag (void) { tNFA_DM_CB *p_cb = &nfa_dm_cb; UINT8 i; for (i = 0; i < NFA_NDEF_MAX_HANDLERS; i++) { if (p_cb->p_ndef_handler[i]) { p_cb->p_ndef_handler[i]->flags &= ~NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED; } } } /******************************************************************************* ** ** Function nfa_dm_ndef_handle_message ** ** Description Handle incoming ndef message ** ** Returns void ** *******************************************************************************/ void nfa_dm_ndef_handle_message (tNFA_STATUS status, UINT8 *p_msg_buf, UINT32 len) { tNFA_DM_CB *p_cb = &nfa_dm_cb; tNDEF_STATUS ndef_status; UINT8 *p_rec, *p_ndef_start, *p_type, *p_payload, *p_rec_end; UINT32 payload_len; UINT8 tnf, type_len, rec_hdr_flags, id_len; tNFA_DM_API_REG_NDEF_HDLR *p_handler; tNFA_NDEF_DATA ndef_data; UINT8 rec_count = 0; BOOLEAN record_handled, entire_message_handled; NFA_TRACE_DEBUG3 ("nfa_dm_ndef_handle_message status=%i, msgbuf=%08x, len=%i", status, p_msg_buf, len); if (status != NFA_STATUS_OK) { /* If problem reading NDEF message, then exit (no action required) */ return; } /* If in exclusive RF mode is activer, then route NDEF message callback registered with NFA_StartExclusiveRfControl */ if ((p_cb->flags & NFA_DM_FLAGS_EXCL_RF_ACTIVE) && (p_cb->p_excl_ndef_cback)) { ndef_data.ndef_type_handle = 0; /* No ndef-handler handle, since this callback is not from RegisterNDefHandler */ ndef_data.p_data = p_msg_buf; ndef_data.len = len; (*p_cb->p_excl_ndef_cback) (NFA_NDEF_DATA_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_data); return; } /* Handle zero length - notify default handler */ if (len == 0) { if ((p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX]) != NULL) { NFA_TRACE_DEBUG0 ("Notifying default handler of zero-length NDEF message..."); ndef_data.ndef_type_handle = p_handler->ndef_type_handle; ndef_data.p_data = NULL; /* Start of record */ ndef_data.len = 0; (*p_handler->p_ndef_cback) (NFA_NDEF_DATA_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_data); } return; } /* Validate the NDEF message */ if ((ndef_status = NDEF_MsgValidate (p_msg_buf, len, TRUE)) != NDEF_OK) { NFA_TRACE_ERROR1 ("Received invalid NDEF message. NDEF status=0x%x", ndef_status); return; } /* NDEF message received from backgound polling. Pass the NDEF message to the NDEF handlers */ /* New NDEF message. Clear 'notified' flag for all the handlers */ nfa_dm_ndef_clear_notified_flag (); /* Indicate that no handler has handled this entire NDEF message (e.g. connection-handover handler *) */ entire_message_handled = FALSE; /* Get first record in message */ p_rec = p_ndef_start = p_msg_buf; /* Check each record in the NDEF message */ while (p_rec != NULL) { /* Get record type */ p_type = NDEF_RecGetType (p_rec, &tnf, &type_len); /* Indicate record not handled yet */ record_handled = FALSE; /* Get pointer to record payload */ p_payload = NDEF_RecGetPayload (p_rec, &payload_len); /* Find first handler for this type */ if ((p_handler = nfa_dm_ndef_find_next_handler (NULL, tnf, p_type, type_len, p_payload, payload_len)) == NULL) { /* Not a registered NDEF type. Use default handler */ if ((p_handler = p_cb->p_ndef_handler[NFA_NDEF_DEFAULT_HANDLER_IDX]) != NULL) { NFA_TRACE_DEBUG0 ("No handler found. Using default handler..."); } } while (p_handler) { /* If handler is for whole NDEF message, and it has already been notified, then skip notification */ if (p_handler->flags & NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED) { /* Look for next handler */ p_handler = nfa_dm_ndef_find_next_handler (p_handler, tnf, p_type, type_len, p_payload, payload_len); continue; } /* Get pointer to record payload */ NFA_TRACE_DEBUG1 ("Calling ndef type handler (%x)", p_handler->ndef_type_handle); ndef_data.ndef_type_handle = p_handler->ndef_type_handle; ndef_data.p_data = p_rec; /* Start of record */ /* Calculate length of NDEF record */ if (p_payload != NULL) ndef_data.len = payload_len + (UINT32) (p_payload - p_rec); else { /* If no payload, calculate length of ndef record header */ p_rec_end = p_rec; /* First byte is the header flags */ rec_hdr_flags = *p_rec_end++; /* Next byte is the type field length */ type_len = *p_rec_end++; /* Next is the payload length (1 or 4 bytes) */ if (rec_hdr_flags & NDEF_SR_MASK) { p_rec_end++; } else { p_rec_end+=4; } /* ID field Length */ if (rec_hdr_flags & NDEF_IL_MASK) id_len = *p_rec_end++; else id_len = 0; p_rec_end+=id_len; ndef_data.len = (UINT32) (p_rec_end - p_rec); } /* If handler wants entire ndef message, then pass pointer to start of message and */ /* set 'notified' flag so handler won't get notified on subsequent records for this */ /* NDEF message. */ if (p_handler->flags & NFA_NDEF_FLAGS_HANDLE_WHOLE_MESSAGE) { ndef_data.p_data = p_ndef_start; /* Start of NDEF message */ ndef_data.len = len; p_handler->flags |= NFA_NDEF_FLAGS_WHOLE_MESSAGE_NOTIFIED; /* Indicate that at least one handler has received entire NDEF message */ entire_message_handled = TRUE; } /* Notify NDEF type handler */ (*p_handler->p_ndef_cback) (NFA_NDEF_DATA_EVT, (tNFA_NDEF_EVT_DATA *) &ndef_data); /* Indicate that at lease one handler has received this record */ record_handled = TRUE; /* Look for next handler */ p_handler = nfa_dm_ndef_find_next_handler (p_handler, tnf, p_type, type_len, p_payload, payload_len); } /* Check if at least one handler was notified of this record (only happens if no default handler was register) */ if ((!record_handled) && (!entire_message_handled)) { /* Unregistered NDEF record type; no default handler */ NFA_TRACE_WARNING1 ("Unhandled NDEF record (#%i)", rec_count); } rec_count++; p_rec = NDEF_MsgGetNextRec (p_rec); } }