3 * neard - Near Field Communication manager
5 * Copyright (C) 2011 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 RECORD_TNF_EMPTY = 0x00,
39 RECORD_TNF_WELLKNOWN = 0x01,
40 RECORD_TNF_MIME = 0x02,
41 RECORD_TNF_URI = 0x03,
42 RECORD_TNF_EXTERNAL = 0x04,
43 RECORD_TNF_UNKNOWN = 0x05,
44 RECORD_TNF_UNCHANGED = 0x06,
47 #define RECORD_ACTION_DO 0x00
48 #define RECORD_ACTION_SAVE 0x01
49 #define RECORD_ACTION_EDIT 0x02
51 #define RECORD_MB_BIT(val) ((val & 0x80) >> 7)
52 #define RECORD_ME_BIT(val) ((val & 0x40) >> 6)
53 #define RECORD_CF_BIT(val) ((val & 0x20) >> 5)
54 #define RECORD_SR_BIT(val) ((val & 0x10) >> 4)
55 #define RECORD_IL_BIT(val) ((val & 0x8) >> 3)
56 #define RECORD_TNF_BIT(val) (val & 0x7)
58 #define NDEF_MSG_MIN_LENGTH 0x03
59 #define NDEF_PAYLOAD_LENGTH_OFFSET 0x02
61 #define RECORD_MB 0x80
62 #define RECORD_ME 0x40
63 #define RECORD_CF 0x20
64 #define RECORD_SR 0x10
65 #define RECORD_IL 0x08
66 #define RECORD_TNF_EMPTY_SET(val) ((val & ~0x7) | RECORD_TNF_EMPTY)
67 #define RECORD_TNF_WKT_SET(val) ((val & ~0x7) | RECORD_TNF_WELLKNOWN)
68 #define RECORD_TNF_MIME_SET(val) ((val & ~0x7) | RECORD_TNF_MIME)
69 #define RECORD_TNF_URI_SET(val) ((val & ~0x7) | RECORD_TNF_URI)
70 #define RECORD_TNF_EXTERNAL_SET(val) ((val & ~0x7) | RECORD_TNF_EXTERNAL)
71 #define RECORD_TNF_UKNOWN_SET(val) ((val & ~0x7) | RECORD_TNF_UNKNOWN)
72 #define RECORD_TNF_UNCHANGED_SET(val) ((val & ~0x7) | RECORD_TNF_UNCHANGED)
74 #define NDEF_MSG_SHORT_RECORD_MAX_LENGTH 0xFF
75 #define NDEF_TEXT_RECORD_TYPE_NAME_HEX_VALUE 0x54
76 #define NDEF_TEXT_RECORD_UTF16_STATUS 0x80
79 RECORD_TYPE_WKT_SMART_POSTER = 0x01,
80 RECORD_TYPE_WKT_URI = 0x02,
81 RECORD_TYPE_WKT_TEXT = 0x03,
82 RECORD_TYPE_WKT_SIZE = 0x04,
83 RECORD_TYPE_WKT_TYPE = 0x05,
84 RECORD_TYPE_WKT_ACTION = 0x06,
85 RECORD_TYPE_WKT_HANDOVER_REQUEST = 0x07,
86 RECORD_TYPE_WKT_HANDOVER_SELECT = 0x08,
87 RECORD_TYPE_WKT_HANDOVER_CARRIER = 0x09,
88 RECORD_TYPE_WKT_ALTERNATIVE_CARRIER = 0x0a,
89 RECORD_TYPE_WKT_COLLISION_RESOLUTION = 0x0b,
90 RECORD_TYPE_WKT_ERROR = 0x0c,
91 RECORD_TYPE_MIME_TYPE = 0x0d,
92 RECORD_TYPE_UNKNOWN = 0xfe,
93 RECORD_TYPE_ERROR = 0xff
96 #define RECORD_TYPE_WKT "urn:nfc:wkt:"
97 #define RECORD_TYPE_EXTERNAL "urn:nfc:ext:"
99 struct near_ndef_record_header {
108 uint32_t payload_len;
111 enum record_type rec_type;
116 struct near_ndef_text_record {
122 struct near_ndef_uri_record {
125 uint32_t field_length;
129 struct near_ndef_sp_record {
130 struct near_ndef_uri_record *uri;
132 uint8_t number_of_title_records;
133 struct near_ndef_text_record **title_records;
135 uint32_t size; /* from Size record*/
136 char *type; /* from Type record*/
138 /* TODO add icon and other records fields*/
141 struct near_ndef_mime_record {
145 enum carrier_power_state {
148 CPS_ACTIVATING = 0x02,
152 /* Handover record definitions */
154 /* alternative record (AC) */
155 #define AC_RECORD_PAYLOAD_LEN 4
157 struct near_ndef_ac_record {
158 enum carrier_power_state cps; /* carrier power state */
160 uint8_t cdr_len; /* carrier data reference length: 0x01 */
161 uint8_t cdr; /* carrier data reference */
162 uint8_t adata_refcount; /* auxiliary data reference count */
164 /* !: if adata_refcount == 0, then there's no data reference */
165 uint16_t **adata; /* auxiliary data reference */
169 * carrier data (see cdr in near_ndef_ac_record )
170 * These settings can be retrieved from mime, carrier records, etc...
172 struct near_ndef_carrier_data {
173 uint8_t cdr; /* carrier data reference */
178 /* Default Handover version */
179 #define HANDOVER_VERSION 0x12
181 /* General Handover Request/Select record */
182 struct near_ndef_ho_record {
183 uint8_t version; /* version id */
184 uint16_t collision_record; /* collision record */
186 uint8_t number_of_ac_records; /* At least 1 ac is needed */
187 struct near_ndef_ac_record **ac_records;
189 /* Optional records */
190 uint16_t *err_record; /* not NULL if present */
192 uint8_t number_of_cfg_records; /* extra NDEF records */
193 struct near_ndef_mime_record **cfg_records;
196 struct near_ndef_record {
199 struct near_ndef_record_header *header;
202 struct near_ndef_text_record *text;
203 struct near_ndef_uri_record *uri;
204 struct near_ndef_sp_record *sp;
207 struct near_ndef_mime_record *mime;
210 struct near_ndef_ho_record *ho;
218 static DBusConnection *connection = NULL;
220 static inline void fillb8(uint8_t *ptr, uint32_t len)
222 (*(uint8_t *)(ptr)) = ((uint8_t)(len));
225 static inline void fillb16(uint8_t *ptr, uint32_t len)
227 fillb8((ptr), (uint16_t)(len) >> 8);
228 fillb8((uint8_t *)(ptr) + 1, len);
231 static inline void fillb32(uint8_t *ptr, uint32_t len)
233 fillb16((ptr), (uint32_t)(len) >> 16);
234 fillb16((uint8_t *)(ptr) + 2, (uint32_t)(len));
237 char *__near_ndef_record_get_path(struct near_ndef_record *record)
242 char *__near_ndef_record_get_type(struct near_ndef_record *record)
247 static void append_text_record(struct near_ndef_text_record *text,
248 DBusMessageIter *dict)
252 if (text == NULL || dict == NULL)
255 if (text->encoding != NULL)
256 near_dbus_dict_append_basic(dict, "Encoding",
260 if (text->language_code != NULL)
261 near_dbus_dict_append_basic(dict, "Language",
263 &(text->language_code));
265 if (text->data != NULL)
266 near_dbus_dict_append_basic(dict, "Representation",
271 static const char *uri_prefixes[NFC_MAX_URI_ID + 1] = {
279 "ftp://anonymous:anonymous@",
310 const char *__near_ndef_get_uri_prefix(uint8_t id)
312 if (id > NFC_MAX_URI_ID)
315 return uri_prefixes[id];
318 static void append_uri_record(struct near_ndef_uri_record *uri,
319 DBusMessageIter *dict)
322 const char *prefix = NULL;
326 if (uri == NULL || dict == NULL)
329 if (uri->identifier > NFC_MAX_URI_ID) {
330 near_error("Invalid URI identifier 0x%x", uri->identifier);
334 prefix = uri_prefixes[uri->identifier];
336 DBG("URI prefix %s", prefix);
338 value = g_strdup_printf("%s%.*s", prefix, uri->field_length,
341 near_dbus_dict_append_basic(dict, "URI", DBUS_TYPE_STRING, &value);
346 static void append_smart_poster_record(struct near_ndef_sp_record *sp,
347 DBusMessageIter *dict)
353 if (sp == NULL || dict == NULL)
356 if (sp->action != NULL)
357 near_dbus_dict_append_basic(dict, "Action", DBUS_TYPE_STRING,
361 append_uri_record(sp->uri, dict);
363 if (sp->title_records != NULL &&
364 sp->number_of_title_records > 0) {
365 for (i = 0; i < sp->number_of_title_records; i++)
366 append_text_record(sp->title_records[i], dict);
369 if (sp->type != NULL)
370 near_dbus_dict_append_basic(dict, "MIMEType", DBUS_TYPE_STRING,
374 near_dbus_dict_append_basic(dict, "Size", DBUS_TYPE_UINT32,
378 static void append_mime_record(struct near_ndef_mime_record *mime,
379 DBusMessageIter *dict)
383 if (mime == NULL || dict == NULL)
386 if (mime->type != NULL)
387 near_dbus_dict_append_basic(dict, "MIME",
392 static void append_record(struct near_ndef_record *record,
393 DBusMessageIter *dict)
399 if (record == NULL || dict == NULL)
402 switch (record->header->rec_type) {
403 case RECORD_TYPE_WKT_SIZE:
404 case RECORD_TYPE_WKT_TYPE:
405 case RECORD_TYPE_WKT_ACTION:
406 case RECORD_TYPE_WKT_ALTERNATIVE_CARRIER:
407 case RECORD_TYPE_WKT_COLLISION_RESOLUTION:
408 case RECORD_TYPE_WKT_ERROR:
409 case RECORD_TYPE_UNKNOWN:
410 case RECORD_TYPE_ERROR:
413 case RECORD_TYPE_WKT_TEXT:
415 near_dbus_dict_append_basic(dict, "Type",
416 DBUS_TYPE_STRING, &type);
417 append_text_record(record->text, dict);
420 case RECORD_TYPE_WKT_URI:
422 near_dbus_dict_append_basic(dict, "Type",
423 DBUS_TYPE_STRING, &type);
424 append_uri_record(record->uri, dict);
427 case RECORD_TYPE_WKT_SMART_POSTER:
428 type = "SmartPoster";
429 near_dbus_dict_append_basic(dict, "Type",
430 DBUS_TYPE_STRING, &type);
431 append_smart_poster_record(record->sp, dict);
434 case RECORD_TYPE_WKT_HANDOVER_REQUEST:
435 type = "HandoverRequest";
436 near_dbus_dict_append_basic(dict, "Type",
437 DBUS_TYPE_STRING, &type);
440 case RECORD_TYPE_WKT_HANDOVER_SELECT:
441 type = "HandoverSelect";
442 near_dbus_dict_append_basic(dict, "Type",
443 DBUS_TYPE_STRING, &type);
446 case RECORD_TYPE_WKT_HANDOVER_CARRIER:
447 type = "HandoverCarrier";
448 near_dbus_dict_append_basic(dict, "Type",
449 DBUS_TYPE_STRING, &type);
452 case RECORD_TYPE_MIME_TYPE:
453 type = "MIME Type (RFC 2046)";
454 near_dbus_dict_append_basic(dict, "Type",
455 DBUS_TYPE_STRING, &type);
456 append_mime_record(record->mime, dict);
461 static DBusMessage *get_properties(DBusConnection *conn,
462 DBusMessage *msg, void *data)
464 struct near_ndef_record *record = data;
466 DBusMessageIter array, dict;
468 DBG("conn %p", conn);
470 if (conn == NULL || msg == NULL ||
474 reply = dbus_message_new_method_return(msg);
478 dbus_message_iter_init_append(reply, &array);
480 near_dbus_dict_open(&array, &dict);
482 append_record(record, &dict);
484 near_dbus_dict_close(&array, &dict);
489 static const GDBusMethodTable record_methods[] = {
490 { GDBUS_METHOD("GetProperties",
491 NULL, GDBUS_ARGS({"properties", "a{sv}"}),
496 static void free_text_record(struct near_ndef_text_record *text)
501 g_free(text->encoding);
502 g_free(text->language_code);
509 static void free_uri_record(struct near_ndef_uri_record *uri)
520 static void free_sp_record(struct near_ndef_sp_record *sp)
527 free_uri_record(sp->uri);
529 if (sp->title_records != NULL) {
530 for (i = 0; i < sp->number_of_title_records; i++)
531 free_text_record(sp->title_records[i]);
534 g_free(sp->title_records);
542 static void free_mime_record(struct near_ndef_mime_record *mime)
553 static void free_ac_record(struct near_ndef_ac_record *ac)
563 static void free_ho_record(struct near_ndef_ho_record *ho)
570 if (ho->ac_records != NULL) {
571 for (i = 0; i < ho->number_of_ac_records; i++)
572 free_ac_record(ho->ac_records[i]);
575 g_free(ho->ac_records);
581 static void free_ndef_record(struct near_ndef_record *record)
586 g_free(record->path);
588 if (record->header != NULL) {
590 switch (record->header->rec_type) {
591 case RECORD_TYPE_WKT_SIZE:
592 case RECORD_TYPE_WKT_TYPE:
593 case RECORD_TYPE_WKT_ACTION:
594 case RECORD_TYPE_WKT_HANDOVER_CARRIER:
595 case RECORD_TYPE_WKT_ALTERNATIVE_CARRIER:
596 case RECORD_TYPE_WKT_COLLISION_RESOLUTION:
597 case RECORD_TYPE_WKT_ERROR:
598 case RECORD_TYPE_UNKNOWN:
599 case RECORD_TYPE_ERROR:
602 case RECORD_TYPE_WKT_HANDOVER_REQUEST:
603 case RECORD_TYPE_WKT_HANDOVER_SELECT:
604 free_ho_record(record->ho);
607 case RECORD_TYPE_WKT_TEXT:
608 free_text_record(record->text);
611 case RECORD_TYPE_WKT_URI:
612 free_uri_record(record->uri);
615 case RECORD_TYPE_WKT_SMART_POSTER:
616 free_sp_record(record->sp);
619 case RECORD_TYPE_MIME_TYPE:
620 free_mime_record(record->mime);
623 g_free(record->header->il_field);
624 g_free(record->header->type_name);
627 g_free(record->header);
628 g_free(record->type);
629 g_free(record->data);
634 void __near_ndef_record_free(struct near_ndef_record *record)
636 g_dbus_unregister_interface(connection, record->path,
637 NFC_RECORD_INTERFACE);
639 free_ndef_record(record);
642 static char *action_to_string(uint8_t action)
645 case RECORD_ACTION_DO:
647 case RECORD_ACTION_SAVE:
649 case RECORD_ACTION_EDIT:
652 near_error("Unknown action 0x%x", action);
658 * @brief returns record type for external type
659 * Validate type and type length and returns
662 * @param type Type name in hex format
663 * @param type_lenth Type name length
665 * @return enum record type
668 static enum record_type get_external_record_type(uint8_t *type,
673 if (strncmp((char *) type, BT_MIME_STRING_2_0,
674 strlen(BT_MIME_STRING_2_0)) == 0)
675 return RECORD_TYPE_MIME_TYPE;
677 return RECORD_TYPE_UNKNOWN;
681 * @brief returns record type
682 * Validate type name format, type and type length and returns
685 * @param tnf TypeNameFormat value
686 * @param type Type name in hex format
687 * @param type_lenth Type name length
689 * @return enum record type
692 static enum record_type get_record_type(enum record_tnf tnf,
693 uint8_t *type, size_t type_length)
698 case RECORD_TNF_EMPTY:
700 case RECORD_TNF_UNKNOWN:
701 case RECORD_TNF_UNCHANGED:
704 case RECORD_TNF_WELLKNOWN:
705 if (type_length == 1) {
707 return RECORD_TYPE_WKT_TEXT;
708 else if (type[0] == 'U')
709 return RECORD_TYPE_WKT_URI;
710 else if (type[0] == 's')
711 return RECORD_TYPE_WKT_SIZE;
712 else if (type[0] == 't')
713 return RECORD_TYPE_WKT_TYPE;
715 return RECORD_TYPE_UNKNOWN;
717 } else if (type_length == 2) {
718 if (strncmp((char *)type, "Sp", 2) == 0)
719 return RECORD_TYPE_WKT_SMART_POSTER;
720 else if (strncmp((char *) type, "Hr", 2) == 0)
721 return RECORD_TYPE_WKT_HANDOVER_REQUEST;
722 else if (strncmp((char *) type, "Hs", 2) == 0)
723 return RECORD_TYPE_WKT_HANDOVER_SELECT;
724 else if (strncmp((char *) type, "Hc", 2) == 0)
725 return RECORD_TYPE_WKT_HANDOVER_CARRIER;
726 else if (strncmp((char *) type, "ac", 2) == 0)
727 return RECORD_TYPE_WKT_ALTERNATIVE_CARRIER;
728 else if (strncmp((char *) type, "cr", 2) == 0)
729 return RECORD_TYPE_WKT_COLLISION_RESOLUTION;
731 return RECORD_TYPE_UNKNOWN;
733 } else if (type_length == 3) {
734 if (strncmp((char *)type, "act", 3) == 0)
735 return RECORD_TYPE_WKT_ACTION;
736 else if (strncmp((char *)type, "err", 3) == 0)
737 return RECORD_TYPE_WKT_ERROR;
739 return RECORD_TYPE_UNKNOWN;
743 case RECORD_TNF_MIME:
744 return RECORD_TYPE_MIME_TYPE;
746 case RECORD_TNF_EXTERNAL:
747 return get_external_record_type(type, type_length);
751 return RECORD_TYPE_UNKNOWN;
754 static int build_record_type_string(struct near_ndef_record *rec)
760 if (rec == NULL || rec->header == NULL)
763 tnf = rec->header->tnf;
765 if (rec->header->rec_type == RECORD_TYPE_WKT_SMART_POSTER) {
766 rec->type = g_strdup_printf(RECORD_TYPE_WKT "U");
771 case RECORD_TNF_EMPTY:
772 case RECORD_TNF_UNKNOWN:
773 case RECORD_TNF_UNCHANGED:
777 case RECORD_TNF_MIME:
778 rec->type = g_strndup(rec->header->type_name,
779 rec->header->type_len);
782 case RECORD_TNF_WELLKNOWN:
783 rec->type = g_strdup_printf(RECORD_TYPE_WKT "%s",
784 rec->header->type_name);
787 case RECORD_TNF_EXTERNAL:
788 rec->type = g_strdup_printf(RECORD_TYPE_EXTERNAL "%s",
789 rec->header->type_name);
796 static uint8_t validate_record_begin_and_end_bits(uint8_t *msg_mb,
797 uint8_t *msg_me, uint8_t rec_mb,
802 if (msg_mb == NULL || msg_me == NULL)
805 /* Validating record header begin and end bits
806 * eg: Single record: [mb:1,me:1]
807 * Two records: [mb:1,me:0 - mb:0,me:1]
808 * Three or more records [mb:1,me:0 - mb:0,me:0 .. mb:0,me:1]
835 * @brief Parse the ndef record header.
837 * Parse the ndef record header and cache the begin, end, chunkflag,
838 * short-record and type-name-format bits. ID length and field, record
839 * type, payload length and offset (where payload byte starts in input
840 * parameter). Validate offset for every step forward against total
843 * @note : Caller responsibility to free the memory.
845 * @param[in] rec ndef byte stream
846 * @param[in] offset record header offset
847 * @param[in] length total length in byte stream
849 * @return struct near_ndef_record_header * RecordHeader on Success
852 static struct near_ndef_record_header *parse_record_header(uint8_t *rec,
853 uint32_t offset, uint32_t length)
855 struct near_ndef_record_header *rec_header = NULL;
856 uint8_t *type = NULL;
857 uint32_t header_len = 0;
859 DBG("length %d", length);
861 if (rec == NULL || offset >= length)
864 /* This check is for empty record. */
865 if ((length - offset) < NDEF_MSG_MIN_LENGTH)
868 rec_header = g_try_malloc0(sizeof(struct near_ndef_record_header));
869 if (rec_header == NULL)
872 rec_header->mb = RECORD_MB_BIT(rec[offset]);
873 rec_header->me = RECORD_ME_BIT(rec[offset]);
874 rec_header->sr = RECORD_SR_BIT(rec[offset]);
875 rec_header->il = RECORD_IL_BIT(rec[offset]);
876 rec_header->tnf = RECORD_TNF_BIT(rec[offset]);
878 DBG("mb %d me %d sr %d il %d tnf %d",
879 rec_header->mb, rec_header->me, rec_header->sr,
880 rec_header->il, rec_header->tnf);
883 rec_header->type_len = rec[offset++];
884 header_len = 2; /* type length + header bits */
886 if (rec_header->sr == 1) {
887 rec_header->payload_len = rec[offset++];
890 rec_header->payload_len =
891 g_ntohl(*((uint32_t *)(rec + offset)));
895 if (offset >= length)
899 DBG("payload length %d", rec_header->payload_len);
901 if (rec_header->il == 1) {
902 rec_header->il_length = rec[offset++];
905 if (offset >= length)
909 if (rec_header->type_len > 0) {
910 if ((offset + rec_header->type_len) > length)
913 type = g_try_malloc0(rec_header->type_len);
917 memcpy(type, rec + offset, rec_header->type_len);
918 offset += rec_header->type_len;
919 header_len += rec_header->type_len;
921 if (offset >= length)
925 if (rec_header->il_length > 0) {
926 if ((offset + rec_header->il_length) > length)
929 rec_header->il_field = g_try_malloc0(rec_header->il_length);
930 if (rec_header->il_field == NULL)
933 memcpy(rec_header->il_field, rec + offset,
934 rec_header->il_length);
935 offset += rec_header->il_length;
936 header_len += rec_header->il_length;
938 if (offset >= length)
942 if ((offset + rec_header->payload_len) > length)
945 rec_header->rec_type = get_record_type(rec_header->tnf, type,
946 rec_header->type_len);
947 rec_header->offset = offset;
948 rec_header->header_len = header_len;
949 rec_header->type_name = g_strndup((char *) type, rec_header->type_len);
956 near_error("parsing record header failed");
959 g_free(rec_header->il_field);
960 g_free(rec_header->type_name);
967 * @brief Parse the Text record payload
969 * Parse the Text record.
971 * @param[in] rec NDEF pointer set to record payload first byte
972 * @param[in] length payload_len
974 * @return struct near_ndef_text_record * Record on Success
978 static struct near_ndef_text_record *
979 parse_text_record(uint8_t *rec, uint32_t length)
981 struct near_ndef_text_record *text_record = NULL;
982 uint8_t status, lang_length;
991 text_record = g_try_malloc0(sizeof(struct near_ndef_text_record));
992 if (text_record == NULL)
995 /* 0x80 is used to get 7th bit value (0th bit is LSB) */
996 status = ((rec[offset] & 0x80) >> 7);
998 text_record->encoding = (status == 0) ?
999 g_strdup("UTF-8") : g_strdup("UTF-16");
1001 /* 0x3F is used to get 5th-0th bits value (0th bit is LSB) */
1002 lang_length = (rec[offset] & 0x3F);
1005 if (lang_length > 0) {
1006 if ((offset + lang_length) >= length)
1009 text_record->language_code = g_strndup(
1010 (char *)(rec + offset),
1013 text_record->language_code = NULL;
1016 offset += lang_length;
1018 if ((length - lang_length - 1) > 0) {
1019 text_record->data = g_strndup((char *)(rec + offset),
1020 length - lang_length - 1);
1022 text_record->data = NULL;
1025 if (offset >= length)
1028 DBG("Encoding '%s'", text_record->encoding);
1029 DBG("Language Code '%s'", text_record->language_code);
1030 DBG("Data '%s'", text_record->data);
1035 near_error("text record parsing failed");
1036 free_text_record(text_record);
1042 * @brief Parse the URI record payload
1044 * Parse the URI record.
1046 * @param[in] rec NDEF pointer set to record payload first byte
1047 * @param[in] length Payload length
1049 * @return struct near_ndef_uri_record * Record on Success
1053 static struct near_ndef_uri_record *
1054 parse_uri_record(uint8_t *rec, uint32_t length)
1056 struct near_ndef_uri_record *uri_record = NULL;
1057 uint32_t index, offset;
1065 uri_record = g_try_malloc0(sizeof(struct near_ndef_uri_record));
1066 if (uri_record == NULL)
1069 uri_record->identifier = rec[offset];
1072 uri_record->field_length = length - 1;
1074 if (uri_record->field_length > 0) {
1075 uri_record->field = g_try_malloc0(uri_record->field_length);
1076 if (uri_record->field == NULL)
1079 memcpy(uri_record->field, rec + offset,
1080 uri_record->field_length);
1082 for (index = 0; index < uri_record->field_length; index++) {
1083 /* URI Record Type Definition 1.0 [3.2.3]
1084 * Any character value within the URI between
1085 * (and including) 0 and 31 SHALL be recorded as
1086 * an error, and the URI record to be discarded */
1087 if (uri_record->field[index] <= 31)
1093 DBG("Identifier '0X%X'", uri_record->identifier);
1094 DBG("Field '%.*s'", uri_record->field_length, uri_record->field);
1099 near_error("uri record parsing failed");
1100 free_uri_record(uri_record);
1106 * @brief Validate titles records language code in Smartposter.
1107 * There must not be two or more records with the same language identifier.
1109 * @param[in] GSList * list of title records (struct near_ndef_text_record *)
1111 * @return Zero on success
1112 * Negative value on failure
1115 static int8_t validate_language_code_in_sp_record(GSList *titles)
1117 uint8_t i, j, length;
1118 struct near_ndef_text_record *title1, *title2;
1125 length = g_slist_length(titles);
1127 for (i = 0; i < length; i++) {
1128 title1 = g_slist_nth_data(titles, i);
1130 for (j = i + 1; j < length; j++) {
1131 title2 = g_slist_nth_data(titles, j);
1133 if ((title1->language_code == NULL) &&
1134 (title2->language_code == NULL))
1137 if (g_strcmp0(title1->language_code,
1138 title2->language_code) == 0)
1147 * @brief Parse the smart poster record payload.
1149 * Parse the smart poster record and cache the
1150 * data in respective fields of smart poster structure.
1152 * @note Caller responsibility to free the memory.
1154 * @param[in] rec NDEF pointer set to record payload first byte
1155 * @param[in] length Record payload length
1157 * @return struct near_ndef_sp_record * Record on Success
1161 static struct near_ndef_sp_record *
1162 parse_smart_poster_record(uint8_t *rec, uint32_t length)
1164 struct near_ndef_sp_record *sp_record = NULL;
1165 struct near_ndef_record_header *rec_header = NULL;
1166 uint8_t mb = 0, me = 0, i;
1168 GSList *titles = NULL, *temp;
1176 sp_record = g_try_malloc0(sizeof(struct near_ndef_sp_record));
1177 if (sp_record == NULL)
1180 while (offset < length) {
1182 DBG("Record header : 0x%x", rec[offset]);
1184 rec_header = parse_record_header(rec, offset, length);
1185 if (rec_header == NULL)
1188 if (validate_record_begin_and_end_bits(&mb, &me,
1189 rec_header->mb, rec_header->me) != 0) {
1190 DBG("validate mb me failed");
1194 offset = rec_header->offset;
1196 switch (rec_header->rec_type) {
1197 case RECORD_TYPE_WKT_SMART_POSTER:
1198 case RECORD_TYPE_WKT_HANDOVER_REQUEST:
1199 case RECORD_TYPE_WKT_HANDOVER_SELECT:
1200 case RECORD_TYPE_WKT_HANDOVER_CARRIER:
1201 case RECORD_TYPE_WKT_ALTERNATIVE_CARRIER:
1202 case RECORD_TYPE_WKT_COLLISION_RESOLUTION:
1203 case RECORD_TYPE_MIME_TYPE:
1204 case RECORD_TYPE_WKT_ERROR:
1205 case RECORD_TYPE_UNKNOWN:
1206 case RECORD_TYPE_ERROR:
1209 case RECORD_TYPE_WKT_URI:
1210 /* URI record should be only one. */
1211 if (sp_record->uri != NULL)
1214 sp_record->uri = parse_uri_record(rec + offset,
1215 rec_header->payload_len);
1216 if (sp_record->uri == NULL)
1221 case RECORD_TYPE_WKT_TEXT:
1223 * Title records can zero or more. First fill the
1224 * records in list and validate language identifier
1225 * and then cache them into sp record structure.
1228 struct near_ndef_text_record *title;
1229 title = parse_text_record(rec + offset,
1230 rec_header->payload_len);
1234 titles = g_slist_append(titles, title);
1238 case RECORD_TYPE_WKT_SIZE:
1240 * If payload length is not exactly 4 bytes
1241 * then record is wrong.
1243 if (rec_header->payload_len != 4)
1247 g_ntohl(*((uint32_t *)(rec + offset)));
1250 case RECORD_TYPE_WKT_TYPE:
1252 if (rec_header->payload_len > 0) {
1253 sp_record->type = g_try_malloc0(
1254 rec_header->payload_len);
1255 if (sp_record->type == NULL)
1258 sp_record->type = g_strndup(
1259 (char *) rec + offset,
1260 rec_header->payload_len);
1265 case RECORD_TYPE_WKT_ACTION:
1267 * If the action record exists, payload should be
1268 * single byte, otherwise consider it as error.
1270 if (rec_header->payload_len != 1)
1274 g_strdup(action_to_string(rec[offset]));
1279 offset += rec_header->payload_len;
1280 g_free(rec_header->il_field);
1281 g_free(rec_header->type_name);
1287 * Code to fill smart poster record structure from
1293 if (validate_language_code_in_sp_record(titles) != 0) {
1294 DBG("language code validation failed");
1299 sp_record->number_of_title_records = g_slist_length(temp);
1300 sp_record->title_records = g_try_malloc0(
1301 sp_record->number_of_title_records *
1302 sizeof(struct near_ndef_text_record *));
1303 if (sp_record->title_records == NULL)
1306 for (i = 0; i < sp_record->number_of_title_records; i++) {
1307 sp_record->title_records[i] = temp->data;
1311 g_slist_free(titles);
1317 near_error("smart poster record parsing failed");
1319 if (rec_header != NULL) {
1320 g_free(rec_header->type_name);
1321 g_free(rec_header->il_field);
1325 free_sp_record(sp_record);
1326 g_slist_free(titles);
1331 static struct near_ndef_mime_record *
1332 parse_mime_type(struct near_ndef_record *record,
1333 uint8_t *ndef_data, size_t ndef_length, size_t offset,
1334 uint32_t payload_length, near_bool_t action)
1336 struct near_ndef_mime_record *mime = NULL;
1341 if ((ndef_data == NULL) || ((offset + payload_length) > ndef_length))
1344 mime = g_try_malloc0(sizeof(struct near_ndef_mime_record));
1348 mime->type = g_strdup(record->header->type_name);
1350 DBG("MIME Type '%s' action: %d", mime->type, action);
1351 if (strcmp(mime->type, BT_MIME_STRING_2_1) == 0) {
1352 err = __near_bluetooth_parse_oob_record(BT_MIME_V2_1,
1353 &ndef_data[offset], action);
1354 } else if (strcmp(mime->type, BT_MIME_STRING_2_0) == 0) {
1355 err = __near_bluetooth_parse_oob_record(BT_MIME_V2_0,
1356 &ndef_data[offset], action);
1360 DBG("Parsing mime error %d", err);
1369 /* Set the MB/ME bit in message header */
1370 static uint8_t near_ndef_set_mb_me(uint8_t *hdr, near_bool_t first_rec,
1371 near_bool_t last_rec)
1373 /* Reset bits 0x40 and 0x80*/
1374 *hdr &= (0xFF & (~(RECORD_MB | RECORD_ME)));
1377 if (first_rec == TRUE)
1379 if (last_rec == TRUE)
1386 * @brief Allocates ndef message structure
1388 * Allocates ndef message structure and fill message header byte,
1389 * type length byte, payload length and type name. Offset is payload
1390 * first byte (caller of this API can start filling their payload
1391 * from offset value).
1393 * @note : caller responsibility to free the input and output
1394 * parameters memory.
1396 * @param[in] type_name Record type name
1397 * @param[in] payload_len Record payload length
1398 * @param[in] payload_id Record payload id string
1399 * @param[in] payload_id_len Record payload id string length
1400 * @param[in] tnf Type name format to set
1401 * @param[in] first_rec Message begin (MB) flag
1402 * @param[in] last_rec Message end (ME) flag
1404 * @return struct near_ndef_message * - Success
1407 static struct near_ndef_message *ndef_message_alloc_complete(char *type_name,
1408 uint32_t payload_len,
1410 uint8_t payload_id_len,
1411 enum record_tnf tnf,
1412 near_bool_t first_rec,
1413 near_bool_t last_rec)
1415 struct near_ndef_message *msg;
1416 uint8_t hdr = 0, type_len, sr_bit, il_bit, id_len;
1418 msg = g_try_malloc0(sizeof(struct near_ndef_message));
1424 msg->length++; /* record header*/
1425 msg->length++; /* type name length byte*/
1427 type_len = (type_name != NULL) ? strlen(type_name) : 0;
1428 id_len = (payload_id != NULL) ? payload_id_len : 0;
1429 sr_bit = (payload_len <= NDEF_MSG_SHORT_RECORD_MAX_LENGTH)
1432 il_bit = (payload_id != NULL) ? TRUE : FALSE;
1434 msg->length += (sr_bit == TRUE) ? 1 : 4;
1435 msg->length += (il_bit == TRUE) ? 1 : 0;
1436 msg->length += type_len;
1437 msg->length += payload_len;
1438 msg->length += id_len;
1440 msg->data = g_try_malloc0(msg->length);
1441 if (msg->data == NULL)
1444 /* Set MB ME bits */
1445 hdr = near_ndef_set_mb_me(&hdr, first_rec, last_rec);
1450 hdr = RECORD_TNF_WKT_SET(hdr);
1455 case RECORD_TNF_EMPTY:
1456 hdr = RECORD_TNF_EMPTY_SET(hdr);
1459 case RECORD_TNF_URI:
1460 hdr = RECORD_TNF_URI_SET(hdr);
1463 case RECORD_TNF_EXTERNAL:
1464 hdr = RECORD_TNF_EXTERNAL_SET(hdr);
1466 case RECORD_TNF_UNKNOWN:
1467 hdr = RECORD_TNF_UKNOWN_SET(hdr);
1470 case RECORD_TNF_UNCHANGED:
1471 hdr = RECORD_TNF_UNCHANGED_SET(hdr);
1474 case RECORD_TNF_WELLKNOWN:
1475 hdr = RECORD_TNF_WKT_SET(hdr);
1478 case RECORD_TNF_MIME:
1479 hdr = RECORD_TNF_MIME_SET(hdr);
1483 msg->data[msg->offset++] = hdr;
1484 msg->data[msg->offset++] = type_len;
1486 if (sr_bit == TRUE) {
1487 msg->data[msg->offset++] = payload_len;
1489 fillb32((msg->data + msg->offset), payload_len);
1494 msg->data[msg->offset++] = payload_id_len;
1496 if (type_name != NULL) {
1497 memcpy(msg->data + msg->offset, type_name, type_len);
1498 msg->offset += type_len;
1501 if (il_bit == TRUE) {
1502 memcpy(msg->data + msg->offset, payload_id, payload_id_len);
1503 msg->offset += payload_id_len;
1509 near_error("ndef message struct allocation failed");
1517 * @brief Allocates ndef message structure
1519 * This is a wrapper to ndef_message_alloc, as, in most cases,
1520 * there's no payload id, and MB=TRUE and ME=TRUE. Default type name format
1521 * is also set to RECORD_TNF_WELLKNOWN
1524 static struct near_ndef_message *ndef_message_alloc(char* type_name,
1525 uint32_t payload_len)
1527 return ndef_message_alloc_complete(type_name, payload_len,
1529 RECORD_TNF_WELLKNOWN,
1533 static struct near_ndef_ac_record *parse_ac_record(uint8_t *rec,
1536 struct near_ndef_ac_record *ac_record = NULL;
1545 ac_record = g_try_malloc0(sizeof(struct near_ndef_ac_record));
1546 if (ac_record == NULL)
1550 ac_record->cps = rec[offset]; /* TODO Check enum */
1553 /* Carrier data reference length */
1554 ac_record->cdr_len = rec[offset];
1557 /* Carrier data reference */
1558 ac_record->cdr = rec[offset];
1559 offset = offset + ac_record->cdr_len;
1561 /* Auxiliary data reference count */
1562 ac_record->adata_refcount = rec[offset];
1565 if (ac_record->adata_refcount == 0)
1568 /* save the auxiliary data reference */
1569 ac_record->adata = g_try_malloc0(
1570 ac_record->adata_refcount * sizeof(uint16_t));
1571 if (ac_record->adata == NULL)
1574 memcpy(ac_record->adata, rec + offset,
1575 ac_record->adata_refcount * sizeof(uint16_t));
1581 near_error("ac record parsing failed");
1582 free_ac_record(ac_record);
1587 /* carrier power state & carrier reference */
1588 static struct near_ndef_message *near_ndef_prepare_ac_message(uint8_t cps,
1591 struct near_ndef_message *ac_msg;
1593 /* alloc "ac" message minus adata*/
1594 ac_msg = ndef_message_alloc_complete("ac", AC_RECORD_PAYLOAD_LEN,
1596 RECORD_TNF_WELLKNOWN,
1601 /* Prepare ac message */
1602 ac_msg->data[ac_msg->offset++] = cps;
1603 ac_msg->data[ac_msg->offset++] = 1; /* cdr_len def size */
1604 ac_msg->data[ac_msg->offset++] = cdr; /* cdr */
1605 ac_msg->data[ac_msg->offset] = 0; /* adata ref count */
1610 /* Collision Record message */
1611 static struct near_ndef_message *near_ndef_prepare_cr_message(uint16_t cr_id)
1613 struct near_ndef_message *cr_msg;
1615 cr_msg = ndef_message_alloc_complete("cr", sizeof(uint16_t),
1617 RECORD_TNF_WELLKNOWN,
1622 /* Prepare ac message */
1623 *(uint16_t *)(cr_msg->data + cr_msg->offset) = g_htons(cr_id);
1628 /* Prepare the bluetooth data record */
1629 static struct near_ndef_message *near_ndef_prepare_bt_message(uint8_t *bt_data,
1630 int bt_data_len, char cdr, uint8_t cdr_len)
1632 struct near_ndef_message *bt_msg = NULL;
1634 if (bt_data == NULL)
1637 bt_msg = ndef_message_alloc_complete(BT_MIME_STRING_2_1, bt_data_len,
1638 &cdr, cdr_len, RECORD_TNF_MIME,
1644 memcpy(bt_msg->data + bt_msg->offset, bt_data, bt_data_len);
1650 g_free(bt_msg->data);
1658 * @brief Prepare Handover select record with mandatory fields.
1660 * TODO: only mime (BT) are supported now... Wifi will come soon...
1661 * Only 1 ac record + 1 collision record+ Hr header
1663 struct near_ndef_message *near_ndef_prepare_handover_record(char* type_name,
1664 struct near_ndef_record *record,
1665 enum near_ndef_handover_carrier carrier)
1667 uint8_t *oob_data = NULL;
1669 struct near_ndef_message *hs_msg = NULL;
1670 struct near_ndef_message *ac_msg = NULL;
1671 struct near_ndef_message *cr_msg = NULL;
1672 struct near_ndef_message *bt_msg = NULL;
1675 char cdr = '0'; /* Carrier data reference */
1677 if (record->ho == NULL)
1680 collision = record->ho->collision_record;
1683 * Prepare records to be added
1684 * now prepare the cr message: MB=1 ME=0
1686 if (collision != 0) {
1687 cr_msg = near_ndef_prepare_cr_message(collision);
1693 * ac record: if only one: MB=0 ME=1
1694 * cps should be active
1696 ac_msg = near_ndef_prepare_ac_message(CPS_ACTIVE, cdr);
1701 case NEAR_CARRIER_BLUETOOTH:
1702 /* Retrieve the bluetooth settings */
1703 oob_data = __near_bluetooth_local_get_properties(&oob_size);
1704 if (oob_data == NULL) {
1705 near_error("Getting Bluetooth OOB data failed");
1709 bt_msg = near_ndef_prepare_bt_message(oob_data, oob_size,
1714 near_ndef_set_mb_me(bt_msg->data, FALSE, TRUE);
1718 case NEAR_CARRIER_WIFI:
1723 * Build the complete handover frame
1724 * Prepare Hs or Hr message (1 for version)
1726 hs_length = 1 + ac_msg->length;
1728 hs_length += cr_msg->length;
1731 hs_msg = ndef_message_alloc(type_name, hs_length +
1734 hs_msg = ndef_message_alloc(type_name, hs_length);
1739 * The handover payload length is not the *real* length.
1740 * The PL refers to the NDEF record, not the extra ones.
1741 * So, we have to fix the payload length in the header.
1743 hs_msg->data[NDEF_PAYLOAD_LENGTH_OFFSET] = hs_length;
1745 /* Fill the message .... */
1746 near_ndef_set_mb_me(hs_msg->data, TRUE, FALSE);
1749 hs_msg->data[hs_msg->offset++] = HANDOVER_VERSION;
1752 if (cr_msg != NULL) {
1753 near_ndef_set_mb_me(cr_msg->data, TRUE, FALSE);
1754 memcpy(hs_msg->data + hs_msg->offset, cr_msg->data,
1756 hs_msg->offset += cr_msg->length;
1761 near_ndef_set_mb_me(ac_msg->data, FALSE, TRUE);
1763 near_ndef_set_mb_me(ac_msg->data, TRUE, TRUE);
1765 memcpy(hs_msg->data + hs_msg->offset, ac_msg->data, ac_msg->length);
1766 hs_msg->offset += ac_msg->length;
1768 if (hs_msg->offset > hs_msg->length)
1772 * Additional NDEF (associated to the ac records)
1773 * Add the BT record which is not part in hs initial size
1775 if (bt_msg != NULL) {
1776 near_ndef_set_mb_me(hs_msg->data, TRUE, FALSE);
1778 memcpy(hs_msg->data + hs_msg->offset, bt_msg->data,
1782 if (ac_msg != NULL) {
1783 g_free(ac_msg->data);
1787 if (cr_msg != NULL) {
1788 g_free(cr_msg->data);
1792 if (bt_msg != NULL) {
1793 g_free(bt_msg->data);
1799 near_info("handover select record preparation OK");
1803 near_error("handover select record preparation failed");
1805 if (ac_msg != NULL) {
1806 g_free(ac_msg->data);
1810 if (cr_msg != NULL) {
1811 g_free(cr_msg->data);
1815 if (hs_msg != NULL) {
1816 g_free(hs_msg->data);
1820 if (bt_msg != NULL) {
1821 g_free(bt_msg->data);
1830 /* Code to fill hr record structure from acs and mimes lists */
1831 static int near_fill_ho_record(struct near_ndef_ho_record *ho,
1832 GSList *acs, GSList *mimes)
1838 rec_count = g_slist_length(acs);
1839 ho->ac_records = g_try_malloc0(rec_count *
1840 sizeof(struct near_ndef_ac_record *));
1841 if (ho->ac_records == NULL)
1844 for (i = 0; i < rec_count; i++) {
1845 ho->ac_records[i] = temp->data;
1848 ho->number_of_ac_records = rec_count;
1851 /* Same process for cfg mimes */
1852 rec_count = g_slist_length(mimes);
1853 ho->cfg_records = g_try_malloc0(rec_count *
1854 sizeof(struct near_ndef_mime_record *));
1855 if (ho->cfg_records == NULL)
1858 for (i = 0; i < rec_count; i++) {
1859 ho->cfg_records[i] = temp->data;
1863 ho->number_of_cfg_records = rec_count;
1864 g_slist_free(mimes);
1868 g_free(ho->ac_records);
1869 g_free(ho->cfg_records);
1870 ho->ac_records = NULL;
1871 ho->cfg_records = NULL;
1876 * @brief Parse the Handover request record
1877 * This function will parse an Hr record, retrieving sub records
1878 * like (ac, cr, er) but it will also get the associated
1879 * ndefs (eg: handover carrier record, mime type for BT)
1880 * In a handover frame, only the following types are expected:
1881 * RECORD_TYPE_WKT_HANDOVER_CARRIER:
1882 * RECORD_TYPE_WKT_COLLISION_RESOLUTION
1883 * RECORD_TYPE_MIME_TYPE
1884 * RECORD_TYPE_WKT_ALTERNATIVE_CARRIER
1886 static struct near_ndef_ho_record *parse_ho_record(enum record_type rec_type,
1887 uint8_t *rec, uint32_t ho_length, size_t frame_length,
1888 uint8_t ho_mb, uint8_t ho_me)
1890 struct near_ndef_ho_record *ho_record = NULL;
1891 struct near_ndef_ac_record *ac = NULL;
1892 struct near_ndef_mime_record *mime = NULL;
1893 struct near_ndef_record *trec = NULL;
1894 GSList *acs = NULL, *mimes = NULL;
1895 uint8_t mb = 0, me = 0;
1897 int16_t count_ac = 0;
1898 near_bool_t bt_pair;
1906 /* Create the handover record */
1907 ho_record = g_try_malloc0(sizeof(struct near_ndef_ho_record));
1908 if (ho_record == NULL)
1911 /* Version is the first mandatory field of hr record */
1912 ho_record->version = rec[offset];
1913 if (ho_record->version > HANDOVER_VERSION) {
1914 near_error("Unsupported version (%d)", ho_record->version);
1918 offset = offset + 1;
1919 frame_length = frame_length - 1; /* Remove Hr length size */
1921 /* We should work on the whole frame */
1922 ho_length = frame_length;
1924 while (offset < ho_length) {
1925 /* Create local record for mime parsing */
1926 trec = g_try_malloc0(sizeof(struct near_ndef_record));
1930 trec->header = parse_record_header(rec, offset, ho_length);
1932 if (trec->header == NULL)
1935 offset = trec->header->offset;
1937 switch (trec->header->rec_type) {
1938 case RECORD_TYPE_WKT_SMART_POSTER:
1939 case RECORD_TYPE_WKT_SIZE:
1940 case RECORD_TYPE_WKT_TEXT:
1941 case RECORD_TYPE_WKT_TYPE:
1942 case RECORD_TYPE_WKT_ACTION:
1943 case RECORD_TYPE_WKT_URI:
1944 case RECORD_TYPE_WKT_HANDOVER_REQUEST:
1945 case RECORD_TYPE_WKT_HANDOVER_SELECT:
1946 case RECORD_TYPE_WKT_ERROR:
1947 case RECORD_TYPE_UNKNOWN:
1948 case RECORD_TYPE_ERROR:
1951 case RECORD_TYPE_WKT_HANDOVER_CARRIER:
1952 DBG("HANDOVER_CARRIER");
1954 * TODO process Hc record too !!!
1955 * Used for Wifi session
1959 case RECORD_TYPE_MIME_TYPE:
1960 DBG("TYPE_MIME_TYPE");
1962 /* check mb/me bits */
1963 if (validate_record_begin_and_end_bits(&ho_mb, &ho_me,
1964 trec->header->mb, trec->header->me) != 0) {
1965 DBG("validate mb me failed");
1970 * In Handover, the mime type gives bluetooth handover
1971 * configuration datas.
1972 * If we initiated the session, the received Hs frame
1973 * is the signal to launch the pairing.
1975 if (rec_type == RECORD_TYPE_WKT_HANDOVER_SELECT)
1980 mime = parse_mime_type(trec, rec, frame_length,
1981 offset, trec->header->payload_len,
1986 /* add the mime to the list */
1987 mimes = g_slist_append(mimes, mime);
1993 case RECORD_TYPE_WKT_COLLISION_RESOLUTION:
1994 DBG("COLLISION_RESOLUTION");
1996 /* check nested mb/me bits */
1997 if (validate_record_begin_and_end_bits(&mb, &me,
1998 trec->header->mb, trec->header->me) != 0) {
1999 DBG("validate mb me failed");
2003 ho_record->collision_record =
2004 g_ntohs(*((uint16_t *)(rec + offset)));
2007 case RECORD_TYPE_WKT_ALTERNATIVE_CARRIER:
2008 DBG("ALTERNATIVE_CARRIER");
2010 /* check nested mb/me bits */
2011 if (validate_record_begin_and_end_bits(&mb, &me,
2012 trec->header->mb, trec->header->me) != 0) {
2013 DBG("validate mb me failed");
2017 ac = parse_ac_record(rec + offset,
2018 trec->header->payload_len);
2022 acs = g_slist_append(acs, ac);
2024 /* TODO check if adata are present */
2029 offset += trec->header->payload_len;
2030 g_free(trec->header->il_field);
2031 g_free(trec->header->type_name);
2032 g_free(trec->header);
2033 trec->header = NULL;
2038 if ((acs == NULL) || (mimes == NULL))
2041 /* Save the records */
2042 if (near_fill_ho_record(ho_record, acs, mimes) < 0)
2045 near_error("handover record parsing complete");
2049 near_error("handover record parsing failed");
2052 if (trec->header != NULL) {
2053 g_free(trec->header->type_name);
2054 g_free(trec->header->il_field);
2055 g_free(trec->header);
2060 free_ho_record(ho_record);
2065 int __near_ndef_record_register(struct near_ndef_record *record, char *path)
2067 record->path = path;
2069 g_dbus_register_interface(connection, record->path,
2070 NFC_RECORD_INTERFACE,
2078 GList *near_ndef_parse(uint8_t *ndef_data, size_t ndef_length)
2081 uint8_t p_mb = 0, p_me = 0, *record_start;
2083 struct near_ndef_record *record = NULL;
2089 if (ndef_data == NULL ||
2090 ndef_length < NDEF_MSG_MIN_LENGTH)
2093 while (offset < ndef_length) {
2095 DBG("Record Header : 0x%X", ndef_data[offset]);
2097 record = g_try_malloc0(sizeof(struct near_ndef_record));
2101 record->header = parse_record_header(ndef_data, offset,
2103 if (record->header == NULL)
2106 if (validate_record_begin_and_end_bits(&p_mb, &p_me,
2108 record->header->me) != 0) {
2109 DBG("validate mb me failed");
2113 record_start = ndef_data + offset;
2114 offset = record->header->offset;
2116 switch (record->header->rec_type) {
2117 case RECORD_TYPE_WKT_SIZE:
2118 case RECORD_TYPE_WKT_TYPE:
2119 case RECORD_TYPE_WKT_ACTION:
2120 case RECORD_TYPE_WKT_HANDOVER_CARRIER:
2121 case RECORD_TYPE_WKT_ALTERNATIVE_CARRIER:
2122 case RECORD_TYPE_WKT_COLLISION_RESOLUTION:
2123 case RECORD_TYPE_WKT_ERROR:
2124 case RECORD_TYPE_UNKNOWN:
2125 case RECORD_TYPE_ERROR:
2128 case RECORD_TYPE_WKT_HANDOVER_REQUEST:
2129 case RECORD_TYPE_WKT_HANDOVER_SELECT:
2131 * Handover frame are a little bit special as the NDEF
2132 * length (specified in the header) is not the real
2133 * frame size. The complete frame includes extra NDEF
2134 * following the initial handover NDEF
2136 record->ho = parse_ho_record(record->header->rec_type,
2138 record->header->payload_len,
2140 record->header->mb, record->header->me);
2141 if (record->ho == NULL)
2144 /* the complete frame is processed, break the loop */
2145 record->header->payload_len = ndef_length;
2148 case RECORD_TYPE_WKT_TEXT:
2149 record->text = parse_text_record(ndef_data + offset,
2150 record->header->payload_len);
2152 if (record->text == NULL)
2157 case RECORD_TYPE_WKT_URI:
2158 record->uri = parse_uri_record(ndef_data + offset,
2159 record->header->payload_len);
2161 if (record->uri == NULL)
2166 case RECORD_TYPE_WKT_SMART_POSTER:
2167 record->sp = parse_smart_poster_record(
2169 record->header->payload_len);
2171 if (record->sp == NULL)
2176 case RECORD_TYPE_MIME_TYPE:
2177 record->mime = parse_mime_type(record, ndef_data,
2178 ndef_length, offset,
2179 record->header->payload_len,
2183 if (record->mime == NULL)
2189 record->data_len = record->header->header_len +
2190 record->header->payload_len;
2192 record->data = g_try_malloc0(record->data_len);
2193 if (record->data == NULL)
2196 memcpy(record->data, record_start, record->data_len);
2198 records = g_list_append(records, record);
2200 build_record_type_string(record);
2202 offset += record->header->payload_len;
2208 near_error("ndef parsing failed");
2209 free_ndef_record(record);
2214 void near_ndef_records_free(GList *records)
2218 for (list = records; list; list = list->next) {
2219 struct near_ndef_record *record = list->data;
2221 __near_ndef_record_free(record);
2224 g_list_free(records);
2228 * @brief Compute an NDEF record length
2230 * Would compute ndef records length, even though the submitted frame
2231 * is incomplete. This code is used in the handover read function, as
2232 * we have to "guess" the final frame size.
2234 * Message size for SR=1 is:
2235 * 1 : ndef rec header (offset 0)
2236 * x : record type length (offset 1)
2237 * y : payload length (offset 2) 1 byte ONLY if SR=1
2238 * if SR=0: (4bytes) 32 bits
2239 * z : payload id length (offset 3) ONLY if il_length=1
2241 int near_ndef_record_length(uint8_t *ndef_in, size_t ndef_in_length)
2243 int ndef_size; /* default size for NDEF hdr + rec typ len + payl */
2249 if (ndef_in_length < 3)
2255 /* save header byte */
2256 hdr = ndef_in[offset];
2259 /* header->type_len */
2260 ndef_size += ndef_in[offset++];
2262 /* header->payload_len */
2263 if (RECORD_SR_BIT(hdr) == 1) {
2264 ndef_size += ndef_in[offset++];
2266 ndef_size += g_ntohl(*((uint32_t *)(ndef_in + offset)));
2269 if (offset >= ndef_in_length)
2274 ndef_size += RECORD_IL_BIT(hdr);
2276 /* header->il_length */
2277 if (RECORD_IL_BIT(hdr) == 1)
2278 ndef_size += ndef_in[offset++];
2280 DBG("near_ndef_message_length is %d", ndef_size);
2285 int near_ndef_count_records(uint8_t *ndef_in, size_t ndef_in_length,
2286 uint8_t record_type)
2288 uint8_t p_mb = 0, p_me = 0;
2291 struct near_ndef_record *record = NULL;
2292 int counted_records = 0 ;
2298 if (ndef_in == NULL || ndef_in_length < NDEF_MSG_MIN_LENGTH) {
2303 while (offset < ndef_in_length) {
2304 record = g_try_malloc0(sizeof(struct near_ndef_record));
2305 if (record == NULL) {
2310 /* Create a record */
2311 record->header = parse_record_header(ndef_in, offset,
2313 if (record->header == NULL) {
2318 /* Validate MB ME */
2319 if (validate_record_begin_and_end_bits(&p_mb, &p_me,
2321 record->header->me) != 0) {
2322 DBG("validate mb me failed");
2327 /* Is this what we want ? */
2328 if (record->header->rec_type == record_type)
2331 /* Jump to the next record */
2332 offset = record->header->offset + record->header->payload_len;
2334 free_ndef_record(record);
2337 DBG("Type %d Records found: %d", record_type, counted_records);
2339 return counted_records;
2342 near_error("ndef counting failed");
2343 free_ndef_record(record);
2348 * @brief Prepare Text ndef record
2350 * Prepare text ndef record with provided input data and return
2351 * ndef message structure (length and byte stream) in success or
2352 * NULL in failure case.
2354 * @note : caller responsibility to free the input and output
2355 * parameters memory.
2357 * @param[in] encoding Encoding (UTF-8 | UTF-16)
2358 * @param[in] language_code Language Code
2359 * @param[in] text Actual text
2361 * @return struct near_ndef_message * - Success
2364 struct near_ndef_message *near_ndef_prepare_text_record(char *encoding,
2365 char *language_code, char *text)
2367 struct near_ndef_message *msg;
2368 uint32_t text_len, payload_length;
2369 uint8_t code_len, status = 0;
2373 /* Validate input parameters*/
2374 if (((g_strcmp0(encoding, "UTF-8") != 0) &&
2375 (g_strcmp0(encoding, "UTF-16") != 0)) ||
2376 (language_code == NULL) ||
2381 code_len = strlen(language_code);
2382 text_len = strlen(text);
2383 payload_length = 1 + code_len + text_len;
2385 msg = ndef_message_alloc("T", payload_length);
2389 if (g_strcmp0(encoding, "UTF-16") == 0)
2390 status |= NDEF_TEXT_RECORD_UTF16_STATUS;
2392 status = status | code_len;
2393 msg->data[msg->offset++] = status;
2396 memcpy(msg->data + msg->offset, language_code, code_len);
2398 msg->offset += code_len;
2401 memcpy(msg->data + msg->offset, text, text_len);
2403 msg->offset += text_len;
2405 if (msg->offset > msg->length)
2411 near_error("text record preparation failed");
2419 * @brief Prepare URI ndef record
2421 * Prepare uri ndef record with provided input data and return
2422 * ndef message structure (length and byte stream) in success or
2423 * NULL in failure case.
2425 * @note : caller responsibility to free the input and output
2426 * parameters memory.
2428 * @param[in] identifier URI Identifier
2429 * @param[in] field_length URI field length
2430 * @param[in] field URI field
2432 * @return struct near_ndef_message * - Success
2435 struct near_ndef_message *near_ndef_prepare_uri_record(uint8_t identifier,
2436 uint32_t field_length, uint8_t *field)
2438 struct near_ndef_message *msg = NULL;
2439 uint32_t payload_length;
2443 /* Validate input parameters*/
2444 if ((field_length == 0 && field != NULL) ||
2445 (field_length != 0 && field == NULL)) {
2449 payload_length = field_length + 1;
2451 msg = ndef_message_alloc("U", payload_length);
2455 msg->data[msg->offset++] = identifier;
2457 if (field_length > 0) {
2458 memcpy(msg->data + msg->offset, field, field_length);
2459 msg->offset += field_length;
2462 if (msg->offset > msg->length)
2468 near_error("uri record preparation failed");
2476 * @brief Prepare Smartposter ndef record with mandatory URI fields.
2478 * Prepare smartposter ndef record with provided input data and
2479 * return ndef message structure (length and byte stream) in success or
2480 * NULL in failure case.
2482 * @note : caller responsibility to free the input and output
2483 * parameters memory.
2485 * @param[in] uri_identfier
2486 * @param[in] uri_field_length
2487 * @param[in] uri_field
2489 * @return struct near_ndef_message * - Success
2492 struct near_ndef_message *
2493 near_ndef_prepare_smartposter_record(uint8_t uri_identifier,
2494 uint32_t uri_field_length,
2497 struct near_ndef_message *msg = NULL, *uri = NULL;
2499 /* URI is mandatory in Smartposter */
2500 uri = near_ndef_prepare_uri_record(uri_identifier, uri_field_length,
2505 /* URI record length is equal to payload length of Sp record */
2506 msg = ndef_message_alloc("Sp", uri->length);
2510 memcpy(msg->data + msg->offset, uri->data, uri->length);
2511 msg->offset += uri->length;
2513 if (msg->offset > msg->length)
2524 near_error("smartposter record preparation failed");
2539 static char *get_text_field(DBusMessage *msg, char *text)
2541 DBusMessageIter iter, arr_iter;
2549 dbus_message_iter_init(msg, &iter);
2550 dbus_message_iter_recurse(&iter, &arr_iter);
2552 while (dbus_message_iter_get_arg_type(&arr_iter) !=
2553 DBUS_TYPE_INVALID) {
2555 DBusMessageIter ent_iter;
2556 DBusMessageIter var_iter;
2558 dbus_message_iter_recurse(&arr_iter, &ent_iter);
2559 dbus_message_iter_get_basic(&ent_iter, &key);
2560 dbus_message_iter_next(&ent_iter);
2561 dbus_message_iter_recurse(&ent_iter, &var_iter);
2563 switch (dbus_message_iter_get_arg_type(&var_iter)) {
2564 case DBUS_TYPE_STRING:
2565 if (g_strcmp0(key, text) == 0)
2566 dbus_message_iter_get_basic(&var_iter, &uri);
2571 dbus_message_iter_next(&arr_iter);
2577 static inline char *get_uri_field(DBusMessage *msg)
2579 return get_text_field(msg, "URI");
2582 static inline char *get_carrier_field(DBusMessage *msg)
2584 return get_text_field(msg, "Carrier");
2587 static struct near_ndef_message *build_text_record(DBusMessage *msg)
2589 DBusMessageIter iter, arr_iter;
2590 char *cod = NULL, *lang = NULL, *rep = NULL;
2594 dbus_message_iter_init(msg, &iter);
2595 dbus_message_iter_recurse(&iter, &arr_iter);
2597 while (dbus_message_iter_get_arg_type(&arr_iter) !=
2598 DBUS_TYPE_INVALID) {
2600 DBusMessageIter ent_iter;
2601 DBusMessageIter var_iter;
2603 dbus_message_iter_recurse(&arr_iter, &ent_iter);
2604 dbus_message_iter_get_basic(&ent_iter, &key);
2605 dbus_message_iter_next(&ent_iter);
2606 dbus_message_iter_recurse(&ent_iter, &var_iter);
2608 switch (dbus_message_iter_get_arg_type(&var_iter)) {
2609 case DBUS_TYPE_STRING:
2610 if (g_strcmp0(key, "Encoding") == 0)
2611 dbus_message_iter_get_basic(&var_iter, &cod);
2612 else if (g_strcmp0(key, "Language") == 0)
2613 dbus_message_iter_get_basic(&var_iter, &lang);
2614 else if (g_strcmp0(key, "Representation") == 0)
2615 dbus_message_iter_get_basic(&var_iter, &rep);
2620 dbus_message_iter_next(&arr_iter);
2623 return near_ndef_prepare_text_record(cod, lang, rep);
2626 static struct near_ndef_message *build_uri_record(DBusMessage *msg)
2629 const char *uri_prefix = NULL;
2635 uri = get_uri_field(msg);
2639 for (i = 1; i <= NFC_MAX_URI_ID; i++) {
2640 uri_prefix = __near_ndef_get_uri_prefix(i);
2642 if (uri_prefix != NULL &&
2643 g_str_has_prefix(uri, uri_prefix) == TRUE)
2647 /* If uri_prefix is NULL then ID will be zero */
2648 if (uri_prefix == NULL) {
2652 id_len = strlen(uri_prefix);
2654 uri_len = strlen(uri) - id_len;
2655 return near_ndef_prepare_uri_record(i, uri_len,
2656 (uint8_t *)(uri + id_len));
2659 static struct near_ndef_message *build_sp_record(DBusMessage *msg)
2662 const char *uri_prefix;
2669 * Currently this function supports only mandatory URI record,
2670 * TODO: Other records support.
2672 uri = get_uri_field(msg);
2676 for (i = 1; i <= NFC_MAX_URI_ID; i++) {
2677 uri_prefix = __near_ndef_get_uri_prefix(i);
2679 if (uri_prefix != NULL &&
2680 g_str_has_prefix(uri, uri_prefix) == TRUE)
2684 if (uri_prefix == NULL) {
2688 id_len = strlen(uri_prefix);
2690 uri_len = strlen(uri) - id_len;
2691 return near_ndef_prepare_smartposter_record(i, uri_len,
2692 (uint8_t *)(uri + id_len));
2695 static struct near_ndef_ac_record *build_ho_local_ac_record(void)
2697 struct near_ndef_ac_record *ac_record = NULL;
2701 /* Allocate ac record */
2702 ac_record = g_try_malloc0(sizeof(struct near_ndef_ac_record));
2703 if (ac_record == NULL)
2707 ac_record->cps = CPS_ACTIVE; /* TODO Should reflect BT state */
2709 /* Carrier data reference length */
2710 ac_record->cdr_len = 1;
2712 /* Carrier data reference */
2713 ac_record->cdr = '0';
2715 /* Auxiliary data reference count */
2716 ac_record->adata_refcount = 0;
2721 static struct near_ndef_message *build_ho_record(DBusMessage *msg)
2723 char *carrier_type = NULL;
2724 enum near_ndef_handover_carrier carrier;
2725 struct near_ndef_record *record = NULL;
2729 carrier_type = get_carrier_field(msg);
2730 if (carrier_type == NULL) {
2731 DBG("Empty carrier name");
2735 if (g_strcmp0(carrier_type, "bluetooth") == 0)
2736 carrier = NEAR_CARRIER_BLUETOOTH;
2737 else if (g_strcmp0(carrier_type, "wifi") == 0)
2738 carrier = NEAR_CARRIER_WIFI;
2740 DBG("Invalid carrier name");
2744 /* Build local record */
2745 record = g_try_malloc0(sizeof(struct near_ndef_record));
2750 record->ho = g_try_malloc0(sizeof(struct near_ndef_ho_record));
2751 if (record->ho == NULL)
2755 record->ho->version = HANDOVER_VERSION;
2757 record->ho->collision_record = 0x1664; /* TODO randomize it */
2758 record->ho->err_record = NULL;
2760 record->ho->number_of_ac_records = 1;
2761 record->ho->ac_records = g_try_malloc0(
2762 sizeof(struct near_ndef_ac_record *));
2763 if (record->ho->ac_records == NULL)
2765 record->ho->ac_records[0] = build_ho_local_ac_record();
2767 return near_ndef_prepare_handover_record("Hr", record, carrier);
2770 free_ho_record(record->ho);
2776 struct near_ndef_message *__ndef_build_from_message(DBusMessage *msg)
2778 DBusMessageIter iter;
2779 DBusMessageIter arr_iter;
2780 struct near_ndef_message *ndef;
2784 dbus_message_iter_init(msg, &iter);
2785 dbus_message_iter_recurse(&iter, &arr_iter);
2789 while (dbus_message_iter_get_arg_type(&arr_iter) !=
2790 DBUS_TYPE_INVALID) {
2791 const char *key, *value;
2792 DBusMessageIter ent_iter;
2793 DBusMessageIter var_iter;
2795 dbus_message_iter_recurse(&arr_iter, &ent_iter);
2796 dbus_message_iter_get_basic(&ent_iter, &key);
2798 if (g_strcmp0(key, "Type") != 0) {
2799 dbus_message_iter_next(&arr_iter);
2803 dbus_message_iter_next(&ent_iter);
2804 dbus_message_iter_recurse(&ent_iter, &var_iter);
2806 switch (dbus_message_iter_get_arg_type(&var_iter)) {
2807 case DBUS_TYPE_STRING:
2808 dbus_message_iter_get_basic(&var_iter, &value);
2810 if (g_strcmp0(value, "Text") == 0) {
2811 ndef = build_text_record(msg);
2813 } else if (g_strcmp0(value, "URI") == 0) {
2814 ndef = build_uri_record(msg);
2816 } else if (g_strcmp0(value, "SmartPoster") == 0) {
2817 ndef = build_sp_record(msg);
2819 } else if (g_strcmp0(value, "Handover") == 0) {
2820 ndef = build_ho_record(msg);
2823 near_error("%s not supported", value);
2831 dbus_message_iter_next(&arr_iter);
2837 int __near_ndef_init(void)
2841 connection = near_dbus_get_connection();
2846 void __near_ndef_cleanup(void)