summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArron Wang <arron.wang@intel.com>2013-04-03 11:04:46 +0800
committerArron Wang <arron.wang@intel.com>2013-04-03 11:04:46 +0800
commit4080c327934424c70492de849d756410d988f5f5 (patch)
tree333633be9d6f0a2df1d2f1b0ec0b7491fdc4d286
parent8004bfc5283ab8e547f1248ccdd5255aae432527 (diff)
parenta2db085bd113f6285431827da60bb60cd410637f (diff)
downloadneard-4080c327934424c70492de849d756410d988f5f5.tar.gz
neard-4080c327934424c70492de849d756410d988f5f5.tar.bz2
neard-4080c327934424c70492de849d756410d988f5f5.zip
Merge branch 'upstream'
-rw-r--r--AUTHORS2
-rw-r--r--Makefile.am11
-rw-r--r--configure.ac21
-rw-r--r--neard.pc.in4
-rw-r--r--plugins/p2p.c107
-rw-r--r--plugins/p2p.h1
-rw-r--r--plugins/snep-validation.c2
-rw-r--r--src/main.c14
-rw-r--r--src/ndef.c240
-rw-r--r--tools/nfctool/llcp-decode.c72
-rw-r--r--tools/nfctool/netlink.c9
-rw-r--r--tools/nfctool/sniffer.c21
-rw-r--r--tools/nfctool/sniffer.h4
-rw-r--r--unit/test-ndef-build.c2
-rw-r--r--unit/test-ndef-parse.c8
-rw-r--r--unit/test-snep-read.c961
-rw-r--r--unit/test-utils.c40
-rw-r--r--unit/test-utils.h150
18 files changed, 1363 insertions, 306 deletions
diff --git a/AUTHORS b/AUTHORS
index 22f10d3..c891905 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,3 +11,5 @@ Dorota Moskal <dorota.moskal@tieto.com>
Krzysztof Lyczkowski <krzysztof.lyczkowski@tieto.com>
Christophe Prigent <christophe.prigent@intel.com>
Marcin MaƂagowski <marcin.malagowski@mobica.com>
+Guillem Jover <guillem@hadrons.org>
+Marcin Malagowski <marcin.malagowski@mobica.com>
diff --git a/Makefile.am b/Makefile.am
index a276ed3..c4f1346 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -40,7 +40,7 @@ src_neard_SOURCES = $(gdbus_sources) $(gweb_sources) $(builtin_sources) \
src/tag.c src/plugin.c src/netlink.c src/ndef.c \
src/tlv.c src/bluetooth.c src/agent.c src/snep.c
-src_neard_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @NETLINK_LIBS@ -lresolv -ldl
+src_neard_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @NETLINK_LIBS@ -ldl
src_neard_LDFLAGS = -Wl,--export-dynamic
@@ -111,7 +111,7 @@ tools_nfctool_nfctool_SOURCES = tools/nfctool/main.c \
tools_nfctool_nfctool_LDADD = @GLIB_LIBS@ @NETLINK_LIBS@
-unit_tests = unit/test-ndef-parse unit/test-ndef-build
+unit_tests = unit/test-ndef-parse unit/test-ndef-build unit/test-snep-read
unit_test_ndef_parse_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \
src/agent.c src/bluetooth.c \
@@ -123,6 +123,13 @@ unit_test_ndef_build_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \
src/ndef.c unit/test-ndef-build.c
unit_test_ndef_build_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
+unit_test_snep_read_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \
+ src/agent.c src/bluetooth.c \
+ src/ndef.c src/snep.c \
+ unit/test-snep-read.c unit/test-utils.c \
+ unit/test-utils.h
+unit_test_snep_read_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
+
noinst_PROGRAMS += $(unit_tests)
TESTS = $(unit_tests)
diff --git a/configure.ac b/configure.ac
index 76d77eb..cb655a9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,34 +59,45 @@ AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
AC_CHECK_LIB(dl, dlopen, dummy=yes,
AC_MSG_ERROR(dynamic linking loader is required))
-PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
+GLIB_DEPS="glib-2.0 >= 2.28"
+PKG_CHECK_MODULES(GLIB, [${GLIB_DEPS}], dummy=yes,
AC_MSG_ERROR(GLib >= 2.28 is required))
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
+AC_SUBST(GLIB_DEPS)
-PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.2, dummy=yes,
+DBUS_DEPS="dbus-1 >= 1.2"
+PKG_CHECK_MODULES(DBUS, [${DBUS_DEPS}], dummy=yes,
AC_MSG_ERROR(D-Bus >= 1.2 is required))
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
+AC_SUBST(DBUS_DEPS)
-PKG_CHECK_MODULES(LIBNL3, libnl-3.0 libnl-genl-3.0, [
+LIBNL3_DEPS="libnl-3.0 libnl-genl-3.0"
+PKG_CHECK_MODULES(LIBNL3, [${LIBNL3_DEPS}], [
NETLINK_CFLAGS=${LIBNL3_CFLAGS}
NETLINK_LIBS=${LIBNL3_LIBS}
+ NETLINK_DEPS=${LIBNL3_DEPS}
], [
- PKG_CHECK_MODULES(LIBNL2, libnl-2.0, [
+ LIBNL2_DEPS="libnl-2.0"
+ PKG_CHECK_MODULES(LIBNL2, [${LIBNL2_DEPS}], [
NETLINK_CFLAGS=${LIBNL2_CFLAGS}
NETLINK_LIBS=${LIBNL2_LIBS}
+ NETLINK_DEPS=${LIBNL2_DEPS}
], [
- PKG_CHECK_MODULES(LIBNL1, libnl-1, dummy=yes,
+ LIBNL1_DEPS="libnl-1"
+ PKG_CHECK_MODULES(LIBNL1, [${LIBNL1_DEPS}], dummy=yes,
AC_MSG_ERROR(Netlink library is required))
AC_DEFINE(NEED_LIBNL_COMPAT, 1,
[Define to 1 if you need libnl-1 compat functions.])
NETLINK_CFLAGS=${LIBNL1_CFLAGS}
NETLINK_LIBS=${LIBNL1_LIBS}
+ NETLINK_DEPS=${LIBNL1_DEPS}
])
])
AC_SUBST(NETLINK_CFLAGS)
AC_SUBST(NETLINK_LIBS)
+AC_SUBST(NETLINK_DEPS)
AC_ARG_ENABLE(test, AC_HELP_STRING([--enable-test],
[enable test/example scripts]),
diff --git a/neard.pc.in b/neard.pc.in
index 3a46466..22a494c 100644
--- a/neard.pc.in
+++ b/neard.pc.in
@@ -7,7 +7,7 @@ plugindir=${libdir}/neard/plugins
Name: neard
Description: NFC daemon
-Requires: glib-2.0 dbus-1 libnl
+Requires: @GLIB_DEPS@ @DBUS_DEPS@ @NETLINK_DEPS@
Version: @VERSION@
Libs: -module -avoid-version -export-symbols-regex neard_plugin_desc
-Cflags: -I${includedir} \ No newline at end of file
+Cflags: -I${includedir}
diff --git a/plugins/p2p.c b/plugins/p2p.c
index 378db87..26d9f18 100644
--- a/plugins/p2p.c
+++ b/plugins/p2p.c
@@ -58,6 +58,57 @@ struct p2p_data {
GList *client_list;
};
+static int __p2p_bind(struct p2p_data *server_data, GIOFunc listener)
+{
+ int err, fd = server_data->fd;
+ struct sockaddr_nfc_llcp addr;
+ GIOChannel *channel;
+ struct near_p2p_driver *driver = server_data->driver;
+
+ DBG("Binding %s", driver->name);
+
+ memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
+ addr.sa_family = AF_NFC;
+ addr.dev_idx = server_data->adapter_idx;
+ addr.nfc_protocol = NFC_PROTO_NFC_DEP;
+ addr.service_name_len = strlen(driver->service_name);
+ strcpy(addr.service_name, driver->service_name);
+
+ err = bind(fd, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr_nfc_llcp));
+ if (err < 0) {
+ if (errno == EADDRINUSE) {
+ DBG("%s is already bound", driver->name);
+ close(fd);
+ return 0;
+ }
+
+ near_error("%s bind failed %d %d", driver->name, err, errno);
+ close(fd);
+ return err;
+ }
+
+ err = listen(fd, 10);
+ if (err < 0) {
+ near_error("%s listen failed %d", driver->name, err);
+ close(fd);
+ return err;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ server_data->watch = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+ listener, (gpointer) server_data);
+ g_io_channel_unref(channel);
+
+ return 0;
+}
+
+static gboolean p2p_listener_event(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data);
+
static gboolean p2p_client_event(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
@@ -90,6 +141,13 @@ static gboolean p2p_client_event(GIOChannel *channel, GIOCondition condition,
g_list_remove(server_data->client_list,
client_data);
+ if (client_data->driver->single_connection) {
+ server_data->fd = socket(AF_NFC, SOCK_STREAM,
+ NFC_SOCKPROTO_LLCP);
+ if (server_data->fd > 0)
+ __p2p_bind(server_data, p2p_listener_event);
+ }
+
g_free(client_data);
return FALSE;
@@ -206,53 +264,19 @@ static gboolean p2p_listener_event(GIOChannel *channel, GIOCondition condition,
server_data->client_list = g_list_append(server_data->client_list, client_data);
- return TRUE;
+ return !driver->single_connection;
}
static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
near_device_io_cb cb)
{
int err, fd;
- struct sockaddr_nfc_llcp addr;
- GIOChannel *channel;
struct p2p_data *server_data;
- DBG("Binding %s", driver->name);
-
fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
if (fd < 0)
return -errno;
- memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
- addr.sa_family = AF_NFC;
- addr.dev_idx = adapter_idx;
- addr.nfc_protocol = NFC_PROTO_NFC_DEP;
- addr.service_name_len = strlen(driver->service_name);
- strcpy(addr.service_name, driver->service_name);
-
- err = bind(fd, (struct sockaddr *) &addr,
- sizeof(struct sockaddr_nfc_llcp));
- if (err < 0) {
- if (errno == EADDRINUSE) {
- DBG("%s is already bound", driver->name);
- close(fd);
- return 0;
- }
-
- near_error("%s bind failed %d %d", driver->name, err, errno);
-
- close(fd);
- return err;
- }
-
- err = listen(fd, 10);
- if (err < 0) {
- near_error("%s listen failed %d", driver->name, err);
-
- close(fd);
- return err;
- }
-
server_data = g_try_malloc0(sizeof(struct p2p_data));
if (server_data == NULL) {
close(fd);
@@ -264,14 +288,11 @@ static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
server_data->fd = fd;
server_data->cb = cb;
- channel = g_io_channel_unix_new(fd);
- g_io_channel_set_close_on_unref(channel, TRUE);
-
- server_data->watch = g_io_add_watch(channel,
- G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
- p2p_listener_event,
- (gpointer) server_data);
- g_io_channel_unref(channel);
+ err = __p2p_bind(server_data, p2p_listener_event);
+ if (err < 0) {
+ g_free(server_data);
+ return err;
+ }
server_list = g_list_append(server_list, server_data);
diff --git a/plugins/p2p.h b/plugins/p2p.h
index 0b5349c..214dbe3 100644
--- a/plugins/p2p.h
+++ b/plugins/p2p.h
@@ -27,6 +27,7 @@ struct near_p2p_driver {
const char *name;
const char *service_name;
const char *fallback_service_name;
+ near_bool_t single_connection;
near_bool_t (*read)(int client_fd,
uint32_t adapter_idx, uint32_t target_idx,
near_device_io_cb cb);
diff --git a/plugins/snep-validation.c b/plugins/snep-validation.c
index 2094630..682a090 100644
--- a/plugins/snep-validation.c
+++ b/plugins/snep-validation.c
@@ -152,7 +152,7 @@ static near_bool_t snep_validation_server_req_get(int client_fd, void *data)
/* check if the acceptable length is higher than the data_len
* otherwise returns a NEAR_SNEP_RESP_EXCESS
*/
- acceptable_length = GUINT32_FROM_BE(*(uint32_t *)snep_data->nfc_data);
+ acceptable_length = near_get_be32(snep_data->nfc_data);
/* Look if there are some incoming ndef stored */
incoming_ndefs = g_hash_table_lookup(snep_validation_hash,
diff --git a/src/main.c b/src/main.c
index a121f63..b9f94c5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -172,13 +172,6 @@ int main(int argc, char *argv[])
exit(0);
}
- if (option_detach == TRUE) {
- if (daemon(0, 0)) {
- perror("Can't start daemon");
- exit(1);
- }
- }
-
main_loop = g_main_loop_new(NULL, FALSE);
dbus_error_init(&err);
@@ -218,6 +211,13 @@ int main(int argc, char *argv[])
__near_plugin_init(option_plugin, option_noplugin);
+ if (option_detach == TRUE) {
+ if (daemon(0, 0)) {
+ perror("Can't start daemon");
+ exit(1);
+ }
+ }
+
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_term;
sigaction(SIGINT, &sa, NULL);
diff --git a/src/ndef.c b/src/ndef.c
index 266f2e5..930af3e 100644
--- a/src/ndef.c
+++ b/src/ndef.c
@@ -678,41 +678,18 @@ static char *action_to_string(uint8_t action)
}
}
-/**
- * @brief returns record type for external type
- * Validate type and type length and returns
- * type.
- *
- * @param type Type name in hex format
- * @param type_lenth Type name length
- *
- * @return enum record type
- */
-
static enum record_type get_external_record_type(uint8_t *type,
size_t type_length)
{
DBG("");
if (strncmp((char *) type, BT_MIME_STRING_2_0,
- strlen(BT_MIME_STRING_2_0)) == 0)
+ sizeof(BT_MIME_STRING_2_0) - 1) == 0)
return RECORD_TYPE_MIME_TYPE;
else
return RECORD_TYPE_UNKNOWN;
}
-/**
- * @brief returns record type
- * Validate type name format, type and type length and returns
- * type.
- *
- * @param tnf TypeNameFormat value
- * @param type Type name in hex format
- * @param type_lenth Type name length
- *
- * @return enum record type
- */
-
static enum record_type get_record_type(enum record_tnf tnf,
uint8_t *type, size_t type_length)
{
@@ -855,23 +832,12 @@ static uint8_t validate_record_begin_and_end_bits(uint8_t *msg_mb,
return 0;
}
-/**
- * @brief Parse the ndef record header.
- *
+/*
* Parse the ndef record header and cache the begin, end, chunkflag,
* short-record and type-name-format bits. ID length and field, record
* type, payload length and offset (where payload byte starts in input
* parameter). Validate offset for every step forward against total
* available length.
- *
- * @note : Caller responsibility to free the memory.
- *
- * @param[in] rec ndef byte stream
- * @param[in] offset record header offset
- * @param[in] length total length in byte stream
- *
- * @return struct near_ndef_record_header * RecordHeader on Success
- * NULL on Failure
*/
static struct near_ndef_record_header *parse_record_header(uint8_t *rec,
uint32_t offset, uint32_t length)
@@ -983,18 +949,6 @@ fail:
return NULL;
}
-/**
- * @brief Parse the Text record payload
- *
- * Parse the Text payload.
- *
- * @param[in] payload NDEF pointer set to record payload first byte
- * @param[in] length payload_len
- *
- * @return struct near_ndef_text_payload * Payload on Success
- * NULL on Failure
- */
-
static struct near_ndef_text_payload *
parse_text_payload(uint8_t *payload, uint32_t length)
{
@@ -1058,18 +1012,6 @@ fail:
return NULL;
}
-/**
- * @brief Parse the URI record payload
- *
- * Parse the URI payload.
- *
- * @param[in] payload NDEF pointer set to record payload first byte
- * @param[in] length Payload length
- *
- * @return struct near_ndef_uri_payload * payload on Success
- * NULL on Failure
- */
-
static struct near_ndef_uri_payload *
parse_uri_payload(uint8_t *payload, uint32_t length)
{
@@ -1122,16 +1064,10 @@ fail:
return NULL;
}
-/**
- * @brief Validate titles records language code in Smartposter.
+/*
+ * Validate titles records language code in Smartposter.
* There must not be two or more records with the same language identifier.
- *
- * @param[in] GSList * list of title records (struct near_ndef_text_payload *)
- *
- * @return Zero on success
- * Negative value on failure
*/
-
static int8_t validate_language_code_in_sp_record(GSList *titles)
{
uint8_t i, j, length;
@@ -1163,21 +1099,6 @@ static int8_t validate_language_code_in_sp_record(GSList *titles)
return 0;
}
-/**
- * @brief Parse the smart poster record payload.
- *
- * Parse the smart poster payload and cache the
- * data in respective fields of smart poster structure.
- *
- * @note Caller responsibility to free the memory.
- *
- * @param[in] payload NDEF pointer set to record payload first byte
- * @param[in] length Record payload length
- *
- * @return struct near_ndef_sp_payload * Record on Success
- * NULL on Failure
- */
-
static struct near_ndef_sp_payload *
parse_sp_payload(uint8_t *payload, uint32_t length)
{
@@ -1492,28 +1413,7 @@ static uint8_t near_ndef_set_mb_me(uint8_t *hdr, near_bool_t first_rec,
return near_ndef_set_me(hdr, last_rec);
}
-/**
- * @brief Allocates ndef message structure
- *
- * Allocates ndef message structure and fill message header byte,
- * type length byte, payload length and type name. Offset is payload
- * first byte (caller of this API can start filling their payload
- * from offset value).
- *
- * @note : caller responsibility to free the input and output
- * parameters memory.
- *
- * @param[in] type_name Record type name
- * @param[in] payload_len Record payload length
- * @param[in] payload_id Record payload id string
- * @param[in] payload_id_len Record payload id string length
- * @param[in] tnf Type name format to set
- * @param[in] first_rec Message begin (MB) flag
- * @param[in] last_rec Message end (ME) flag
- *
- * @return struct near_ndef_message * - Success
- * NULL - Failure
- */
+/* Caller should put own payload starting from offset value */
static struct near_ndef_message *ndef_message_alloc_complete(char *type_name,
uint32_t payload_len,
char *payload_id,
@@ -1623,8 +1523,6 @@ fail:
}
/*
- * @brief Allocates ndef message structure
- *
* This is a wrapper to ndef_message_alloc, as, in most cases,
* there's no payload id, and MB=TRUE and ME=TRUE. Default type name format
* is also set to RECORD_TNF_WELLKNOWN
@@ -1776,22 +1674,16 @@ static int near_ndef_prepare_ac_and_cfg_records(enum handover_carrier carrier,
struct near_ndef_mime_payload *mime,
struct carrier_data *remote_carrier)
{
- struct carrier_data *local_carrier = NULL;
+ struct carrier_data *local_carrier;
char cdr;
char *mime_type, *carrier_string;
uint16_t prop;
- int err;
DBG("");
if (ac == NULL || cfg == NULL)
return -EINVAL;
- /* to be safe side */
- *ac = NULL;
- *cfg = NULL;
- carrier_string = NULL;
-
switch (carrier) {
case NEAR_CARRIER_BLUETOOTH:
cdr = '0';
@@ -1818,40 +1710,29 @@ static int near_ndef_prepare_ac_and_cfg_records(enum handover_carrier carrier,
case NEAR_CARRIER_EMPTY:
case NEAR_CARRIER_UNKNOWN:
- carrier_string = "Unkknown";
- err = -EINVAL;
- goto fail;
+ default:
+ return -EINVAL;
}
if (local_carrier == NULL) {
DBG("Unable to retrieve local carrier %s data", carrier_string);
- err = -ESRCH;
- goto fail;
+ return -ESRCH;
}
*cfg = near_ndef_prepare_cfg_message(mime_type, local_carrier->data,
local_carrier->size, cdr, 1);
- if (*cfg == NULL) {
- err = -ENOMEM;
- goto fail;
- }
-
*ac = near_ndef_prepare_ac_message(local_carrier->state, cdr);
- if (*ac == NULL) {
- err = -EINVAL;
- goto fail;
- }
g_free(local_carrier);
- return 0;
+ if (*cfg == NULL || *ac == NULL) {
+ free_ndef_message(*ac);
+ free_ndef_message(*cfg);
-fail:
- g_free(local_carrier);
- free_ndef_message(*ac);
- free_ndef_message(*cfg);
+ return -ENOMEM;
+ }
- return err;
+ return 0;
}
static void free_ndef_list(gpointer data)
@@ -1913,7 +1794,7 @@ static void copy_ac_records(struct near_ndef_message *ho, GList *acs)
ac = temp->data;
memcpy(ho->data + ho->offset, ac->data, ac->length);
/*
- * AC records are part of handover message payoad,
+ * AC records are part of handover message payload,
* so modifying offset.
*/
ho->offset += ac->length;
@@ -1937,7 +1818,7 @@ static void copy_cfg_records(struct near_ndef_message *ho, GList *cfgs)
memcpy(ho->data + offset, cfg->data, cfg->length);
/*
* Configuration records (e.g. bt or wifi) records are not part
- * of handover payoad, they are consecutive ndef msgs. So
+ * of handover payload, they are consecutive ndef msgs. So
* here we are not modifying ho->offset.
*/
offset += cfg->length;
@@ -2007,7 +1888,7 @@ static struct near_ndef_message *near_ndef_prepare_hs_message(
DBG("");
/*
- * Preparing empty Hs message incase remote devices has zero
+ * Preparing empty Hs message in case remote devices has zero
* alternative carries or unknown mime types or unknown
* configuration data.
*/
@@ -2037,7 +1918,7 @@ static struct near_ndef_message *near_ndef_prepare_hs_message(
}
if (g_list_length(ac_msgs) == 0) {
- DBG("no alterative carriers, so preparing empty Hs message");
+ DBG("no alternative carriers, so preparing empty Hs message");
return near_ndef_prepare_empty_hs_message();
}
@@ -2130,7 +2011,7 @@ static struct near_ndef_message *near_ndef_prepare_hr_message(GSList *carriers)
DBG("");
- /* Hr message should have atleast one carrier */
+ /* Hr message should have at least one carrier */
while (carriers) {
ret = near_ndef_prepare_ac_and_cfg_records(
string2carrier(carriers->data),
@@ -2144,7 +2025,7 @@ static struct near_ndef_message *near_ndef_prepare_hr_message(GSList *carriers)
}
if (g_list_length(ac_msgs) == 0) {
- DBG("no alterative carriers to prepare Hr message");
+ DBG("no alternative carriers to prepare Hr message");
goto fail;
}
@@ -2265,10 +2146,9 @@ fail:
}
/*
- * @brief Parse the Handover request record payload
- * This function will parse an Hr record payload, retrieving sub records
- * like (ac, cr, er) but it will also get the associated
- * ndefs (eg: handover carrier record, mime type for BT)
+ * This function will parse an handover record payload, retrieving sub records
+ * like (ac, cr, er) but it will also get the associated ndefs
+ * (eg: handover carrier record, mime type for BT)
* In a handover frame, only the following types are expected:
* RECORD_TYPE_WKT_HANDOVER_CARRIER:
* RECORD_TYPE_WKT_COLLISION_RESOLUTION
@@ -2445,7 +2325,7 @@ static struct near_ndef_ho_payload *parse_ho_payload(enum record_type rec_type,
}
/*
- * Incase of multiple carriers, handover with any carrier
+ * In case of multiple carriers, handover with any carrier
* gets done then leave the loop.
*/
if (action == TRUE) {
@@ -2591,16 +2471,6 @@ uint8_t *near_ndef_data_ptr(struct near_ndef_record *rec)
return rec->data;
}
-/**
- * @brief Parse message represented by bytes block
-GList *near_ndef_parse(uint8_t *ndef_data, size_t ndef_length,
- struct near_ndef_message **reply)
- *
- * @param[in] ndef_data pointer on data representing ndef message
- * @param[in] ndef_length size of ndef_data
- * @param[out] records list, contains all the records
- * from parsed message
- */
GList *near_ndef_parse_msg(uint8_t *ndef_data, size_t ndef_length,
struct near_ndef_message **reply)
{
@@ -2760,11 +2630,9 @@ void near_ndef_records_free(GList *records)
}
/*
- * @brief Compute an NDEF record length
- *
- * Would compute ndef records length, even though the submitted frame
- * is incomplete. This code is used in the handover read function, as
- * we have to "guess" the final frame size.
+ * Compute ndef records length, even though the submitted frame is incomplete.
+ * This code is used in the handover read function, as we have to "guess" the
+ * final frame size.
*
* Message size for SR=1 is:
* 1 : ndef rec header (offset 0)
@@ -2879,23 +2747,7 @@ fail:
return err;
}
-/**
- * @brief Prepare Text ndef record
- *
- * Prepare text ndef record with provided input data and return
- * ndef message structure (length and byte stream) in success or
- * NULL in failure case.
- *
- * @note : caller responsibility to free the input and output
- * parameters memory.
- *
- * @param[in] encoding Encoding (UTF-8 | UTF-16)
- * @param[in] language_code Language Code
- * @param[in] text Actual text
- *
- * @return struct near_ndef_message * - Success
- * NULL - Failure
- */
+/* Possible encoding "UTF-8" or "UTF-16" */
struct near_ndef_message *near_ndef_prepare_text_record(char *encoding,
char *language_code, char *text)
{
@@ -2949,23 +2801,6 @@ fail:
return NULL;
}
-/**
- * @brief Prepare URI ndef record
- *
- * Prepare uri ndef record with provided input data and return
- * ndef message structure (length and byte stream) in success or
- * NULL in failure case.
- *
- * @note : caller responsibility to free the input and output
- * parameters memory.
- *
- * @param[in] identifier URI Identifier
- * @param[in] field_length URI field length
- * @param[in] field URI field
- *
- * @return struct near_ndef_message * - Success
- * NULL - Failure
- */
struct near_ndef_message *near_ndef_prepare_uri_record(uint8_t identifier,
uint32_t field_length, uint8_t *field)
{
@@ -3005,23 +2840,6 @@ fail:
return NULL;
}
-/**
- * @brief Prepare Smartposter ndef record with mandatory URI fields.
- *
- * Prepare smartposter ndef record with provided input data and
- * return ndef message structure (length and byte stream) in success or
- * NULL in failure case.
- *
- * @note : caller responsibility to free the input and output
- * parameters memory.
- *
- * @param[in] uri_identfier
- * @param[in] uri_field_length
- * @param[in] uri_field
- *
- * @return struct near_ndef_message * - Success
- * NULL - Failure
- */
struct near_ndef_message *
near_ndef_prepare_smartposter_record(uint8_t uri_identifier,
uint32_t uri_field_length,
diff --git a/tools/nfctool/llcp-decode.c b/tools/nfctool/llcp-decode.c
index 30f9aa9..aa701c7 100644
--- a/tools/nfctool/llcp-decode.c
+++ b/tools/nfctool/llcp-decode.c
@@ -275,31 +275,66 @@ static int llcp_print_sequence(guint8 *data, guint32 data_len)
return 0;
}
-static int llcp_print_agf(guint8 *data, guint8 data_len,
- struct timeval *timestamp)
+static int llcp_print_agf(guint8 *data, guint32 data_len, guint adapter_idx,
+ guint8 direction, struct timeval *timestamp)
{
- guint16 len;
- guint16 offset = 0;
+ guint8 *pdu;
+ gsize pdu_size;
+ gsize size;
+ guint16 offset;
+ guint16 count;
+ int err;
- if (data_len < 2)
+ if (data_len < 2) {
+ print_error("Error parsing AGF PDU");
return -EINVAL;
+ }
+
+ printf("\n");
+
+ pdu = NULL;
+ pdu_size = 0;
+ offset = 0;
+ count = 0;
while (offset < data_len - 2) {
- len = (data[offset] << 8) | data[offset + 1];
+ size = (data[offset] << 8) | data[offset + 1];
+
offset += 2;
- if (offset + len > data_len)
- return -EINVAL;
+ if (size == 0 || offset + size > data_len) {
+ print_error("Error parsing AGF PDU");
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (size + NFC_LLCP_RAW_HEADER_SIZE > pdu_size) {
+ pdu_size = size + NFC_LLCP_RAW_HEADER_SIZE;
+ pdu = g_realloc(pdu, pdu_size);
+
+ pdu[0] = adapter_idx;
+ pdu[1] = direction;
+ }
+
+ memcpy(pdu + NFC_LLCP_RAW_HEADER_SIZE, data + offset, size);
+
+ printf("-- AGF LLC PDU %02u:\n", count++);
- llcp_print_pdu(data + offset, len, timestamp);
+ llcp_print_pdu(pdu, size + NFC_LLCP_RAW_HEADER_SIZE, timestamp);
- offset += len;
+ offset += size;
}
- return 0;
+ printf("-- End of AGF LLC PDUs\n");
+
+ err = 0;
+exit:
+ g_free(pdu);
+
+ return err;
}
-static int llcp_print_dm(guint8 *data, guint8 data_len)
+static int llcp_print_dm(guint8 *data, guint32 data_len)
{
gchar *reason;
@@ -347,17 +382,17 @@ static int llcp_print_dm(guint8 *data, guint8 data_len)
return 0;
}
-static int llcp_print_i(guint8 *data, guint8 data_len)
+static int llcp_print_i(guint8 *data, guint32 data_len)
{
if (llcp_print_sequence(data, data_len))
return -EINVAL;
- sniffer_print_hexdump(stdout, data + 1, data_len - 1, " ");
+ sniffer_print_hexdump(stdout, data + 1, data_len - 1, " ", TRUE);
return 0;
}
-static int llcp_print_frmr(guint8 *data, guint8 data_len)
+static int llcp_print_frmr(guint8 *data, guint32 data_len)
{
guint8 val;
@@ -436,8 +471,8 @@ int llcp_print_pdu(guint8 *data, guint32 data_len, struct timeval *timestamp)
switch (llcp.ptype) {
case LLCP_PTYPE_AGF:
- llcp_print_agf(llcp.data, llcp.data_len, timestamp);
- printf(" End of AGF frame\n");
+ llcp_print_agf(llcp.data, llcp.data_len,
+ adapter_idx, direction, timestamp);
break;
case LLCP_PTYPE_I:
@@ -465,7 +500,8 @@ int llcp_print_pdu(guint8 *data, guint32 data_len, struct timeval *timestamp)
break;
default:
- sniffer_print_hexdump(stdout, llcp.data, llcp.data_len, " ");
+ sniffer_print_hexdump(stdout, llcp.data, llcp.data_len, " ",
+ TRUE);
break;
}
diff --git a/tools/nfctool/netlink.c b/tools/nfctool/netlink.c
index dd0bef6..1d4e2bf 100644
--- a/tools/nfctool/netlink.c
+++ b/tools/nfctool/netlink.c
@@ -671,6 +671,7 @@ static int nl_nfc_event_cb(struct nl_msg *n, void *arg)
guint32 idx = INVALID_ADAPTER_IDX;
struct nlattr *attr[NFC_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(n));
+ guint32 cmd = gnlh->cmd;
nfc_event_cb_t cb = NULL;
DBG("Received cmd %d", gnlh->cmd);
@@ -682,12 +683,12 @@ static int nl_nfc_event_cb(struct nl_msg *n, void *arg)
idx = nla_get_u32(attr[NFC_ATTR_DEVICE_INDEX]);
if (handlers != NULL)
- cb = g_hash_table_lookup(handlers, GINT_TO_POINTER(gnlh->cmd));
+ cb = g_hash_table_lookup(handlers, GINT_TO_POINTER(cmd));
if (cb == NULL)
return NL_SKIP;
- switch (gnlh->cmd) {
+ switch (cmd) {
case NFC_EVENT_LLC_SDRES:
DBG("Received NFC_EVENT_LLC_SDRES\n");
nl_nfc_send_sdres_event(idx, attr[NFC_ATTR_LLC_SDP], cb);
@@ -726,8 +727,10 @@ static gboolean nl_gio_handler(GIOChannel *channel,
void nl_add_event_handler(guint8 cmd, nfc_event_cb_t cb)
{
+ guint32 c = cmd;
+
if (handlers != NULL)
- g_hash_table_replace(handlers, GINT_TO_POINTER(cmd), cb);
+ g_hash_table_replace(handlers, GINT_TO_POINTER(c), cb);
}
void nl_cleanup(void)
diff --git a/tools/nfctool/sniffer.c b/tools/nfctool/sniffer.c
index c48e053..2e89ddc 100644
--- a/tools/nfctool/sniffer.c
+++ b/tools/nfctool/sniffer.c
@@ -157,14 +157,14 @@ static void pcap_file_cleanup(void)
* 00000000: 01 01 43 20 30 70 72 6F 70 65 72 74 69 65 73 20 |..C 0properties |
*
*/
-void sniffer_print_hexdump(FILE *file, unsigned char *data, int len,
- char *line_prefix)
+void sniffer_print_hexdump(FILE *file, guint8 *data, guint32 len,
+ gchar *line_prefix, gboolean print_len)
{
- int digits;
- int offset;
- int total;
- char line[LINE_SIZE];
- char *hexa = NULL, *human = NULL;
+ guint8 digits;
+ guint32 offset;
+ guint32 total;
+ gchar line[LINE_SIZE];
+ gchar *hexa = NULL, *human = NULL;
if (len <= 0)
return;
@@ -173,6 +173,13 @@ void sniffer_print_hexdump(FILE *file, unsigned char *data, int len,
digits = 0;
total = 0;
+ if (print_len) {
+ if (line_prefix)
+ fprintf(file, "%s", line_prefix);
+
+ fprintf(file, "Total length: %u bytes\n", len);
+ }
+
while (total < len) {
if (digits == 0) {
memset(line, ' ', HUMAN_READABLE_OFFSET);
diff --git a/tools/nfctool/sniffer.h b/tools/nfctool/sniffer.h
index cfa0eb4..2f3603a 100644
--- a/tools/nfctool/sniffer.h
+++ b/tools/nfctool/sniffer.h
@@ -30,7 +30,7 @@ int sniffer_init(void);
void sniffer_cleanup(void);
-void sniffer_print_hexdump(FILE *file, unsigned char *data, int len,
- char *line_prefix);
+void sniffer_print_hexdump(FILE *file, guint8 *data, guint32 len,
+ gchar *line_prefix, gboolean print_len);
#endif /* __SNIFFER_H */
diff --git a/unit/test-ndef-build.c b/unit/test-ndef-build.c
index 777d11d..a658224 100644
--- a/unit/test-ndef-build.c
+++ b/unit/test-ndef-build.c
@@ -54,7 +54,7 @@ int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
- g_test_add_func("/testndefbuild/Test Text NDEF", test_ndef_text_build);
+ g_test_add_func("/testNDEF-build/Test Text NDEF", test_ndef_text_build);
return g_test_run();
}
diff --git a/unit/test-ndef-parse.c b/unit/test-ndef-parse.c
index ec3607f..bfabfdf 100644
--- a/unit/test-ndef-parse.c
+++ b/unit/test-ndef-parse.c
@@ -306,11 +306,11 @@ int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
- g_test_add_func("/testndefparse/Test URI NDEF", test_ndef_uri);
- g_test_add_func("/testndefparse/Test Text NDEF", test_ndef_text);
- g_test_add_func("/testndefparse/Test Single record SmartPoster NDEF",
+ g_test_add_func("/testNDEF-parse/Test URI NDEF", test_ndef_uri);
+ g_test_add_func("/testNDEF-parse/Test Text NDEF", test_ndef_text);
+ g_test_add_func("/testNDEF-parse/Test Single record SmartPoster NDEF",
test_ndef_single_sp);
- g_test_add_func("/testndefparse/Test Title record SmartPoster NDEF",
+ g_test_add_func("/testNDEF-parse/Test Title record SmartPoster NDEF",
test_ndef_title_sp);
return g_test_run();
diff --git a/unit/test-snep-read.c b/unit/test-snep-read.c
new file mode 100644
index 0000000..c008376
--- /dev/null
+++ b/unit/test-snep-read.c
@@ -0,0 +1,961 @@
+/*
+ * neard - Near Field Communication manager
+ *
+ * Copyright (C) 2013 Mobica Limited. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/socket.h>
+
+#include <near/types.h>
+
+#include "test-utils.h"
+
+#define TEST_SNEP_LOG(fmt, ...) do { \
+ if (g_test_verbose()) {\
+ g_printf("[SNEP unit] " fmt, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define TEST_SNEP_PTR_UNUSED(x) do { if ((void *)x != NULL) {} } while (0)
+
+static const char *short_text = "neard";
+
+static const char *long_text = "The Linux NFC project aims to provide a " \
+ "full NFC support for Linux. It is based on the neard NFC user space "\
+ "stack running on top of the Linux kernel NFC subsystem. NFC stands " \
+ "Near Field Communication. It is a short-range (a few centimeters)"\
+ "radio technology that enables communication between devices that " \
+ "either touch or are momentarily held close together. NFC is an open "\
+ "technology standardized by the NFC Forum. It is based on RFID. ";
+
+/* 'neard' - UTF-8 - en-US Text NDEF */
+static uint8_t text[] = { 0xd1, 0x1, 0xb, 0x54, 0x5, 0x65, 0x6e,
+ 0x2d, 0x55, 0x53, 0x6e, 0x65, 0x61, 0x72, 0x64 };
+
+/* sockets */
+static int sockfd[2];
+static int client;
+static int server;
+
+struct test_snep_context {
+ uint8_t snep_version;
+ uint32_t req_info_len;
+ uint32_t payload_len;
+ uint8_t *req_info;
+
+ uint32_t acc_len; /* req GET specific */
+
+ struct near_ndef_message *test_recd_msg;
+};
+
+/* variables used in dummy_req_{get|put} */
+static struct test_snep_context *gcontext;
+static struct near_ndef_record *stored_recd;
+static GSList *test_fragments;
+
+/* GET/PUT server functions */
+
+/*
+ * @brief Utility: Dummy PUT request handler
+ */
+static near_bool_t test_snep_dummy_req_put(int fd, void *data)
+{
+ struct p2p_snep_data *snep_data = data;
+ GList *records;
+ uint8_t *nfc_data;
+ uint32_t nfc_data_length;
+ uint32_t offset = 0;
+
+ TEST_SNEP_LOG(">> dummy_req_put entry %p\n", data);
+
+ if (snep_data == NULL)
+ goto error;
+
+ if (stored_recd)
+ TEST_SNEP_LOG("\tdummy_req_put already stored record\n");
+
+ test_fragments = g_slist_append(test_fragments, snep_data);
+
+ if (snep_data->nfc_data_length > snep_data->nfc_data_current_length)
+ return TRUE;
+
+ nfc_data_length = 0;
+ nfc_data = g_try_malloc0(snep_data->nfc_data_length);
+ g_assert(nfc_data != NULL);
+
+ while (g_slist_length(test_fragments) > 0) {
+ static int frag_cnt;
+ struct p2p_snep_data *fragment = test_fragments->data;
+
+ TEST_SNEP_LOG("\tdummy_req_put frag=%d, len=%d, current=%d\n",
+ frag_cnt, fragment->nfc_data_length,
+ fragment->nfc_data_current_length);
+ test_fragments = g_slist_remove(test_fragments, fragment);
+
+ memcpy(nfc_data + offset, fragment->nfc_data,
+ fragment->nfc_data_current_length - nfc_data_length);
+
+ offset += fragment->nfc_data_current_length - nfc_data_length;
+ nfc_data_length = offset;
+
+ frag_cnt++;
+ }
+
+ records = near_ndef_parse_msg(nfc_data, nfc_data_length, NULL);
+ if (records == NULL) {
+ TEST_SNEP_LOG("\tdummy_req_put parsing ndef failed\n");
+ goto error;
+ }
+
+ if (g_list_length(records) != 1) {
+ TEST_SNEP_LOG("\tdummy_req_put records number mismatch");
+ goto error;
+ }
+
+ g_free(nfc_data);
+
+ stored_recd = records->data;
+
+ TEST_SNEP_LOG("\t\tdummy_req_put STORED REC data=%p length=%zu\n",
+ stored_recd->data, stored_recd->data_len);
+
+ near_snep_core_response_noinfo(fd, NEAR_SNEP_RESP_SUCCESS);
+ return TRUE;
+
+error:
+ TEST_SNEP_LOG("\tdummy_req_put error!!!\n");
+ return FALSE;
+}
+
+/*
+ * @brief Utility: Dummy GET request handler
+ */
+static near_bool_t test_snep_dummy_req_get(int fd, void *data)
+{
+ struct p2p_snep_data *snep_data = data;
+
+ TEST_SNEP_LOG(">> dummy_req_get entry %p\n", data);
+
+ if (snep_data == NULL)
+ goto error;
+
+ TEST_SNEP_LOG("\t\tdummy_req_get STORED REC data=%p length=%zu\n",
+ stored_recd->data, stored_recd->data_len);
+
+ near_snep_core_response_with_info(fd, NEAR_SNEP_RESP_SUCCESS,
+ near_ndef_data_ptr(stored_recd),
+ near_ndef_data_length(stored_recd));
+ return TRUE;
+
+error:
+ TEST_SNEP_LOG("\tdummy_req_get error!!!\n");
+ return FALSE;
+}
+
+static void test_snep_init(gpointer context, gconstpointer data)
+{
+ struct test_snep_context *ctx = context;
+ struct timeval tv;
+ int ret;
+ const char *test_data = data;
+
+ g_assert(socketpair(PF_LOCAL, SOCK_STREAM, 0, sockfd) == 0);
+
+ client = 0;
+ server = 1;
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ ret = setsockopt(sockfd[client], SOL_SOCKET, SO_RCVTIMEO,
+ (const void *) &tv, sizeof(tv));
+ if (ret != 0)
+ TEST_SNEP_LOG("set sock SO_RCVTIMEO failed");
+
+ __near_snep_core_init();
+
+ stored_recd = NULL;
+
+ ctx->test_recd_msg = test_ndef_create_test_record(test_data);
+
+ ctx->snep_version = NEAR_SNEP_VERSION;
+ ctx->req_info = ctx->test_recd_msg->data;
+ ctx->req_info_len = ctx->test_recd_msg->length;
+ ctx->payload_len = ctx->test_recd_msg->length;
+ ctx->acc_len = 64;
+
+ gcontext = ctx;
+}
+
+static void test_snep_cleanup(gpointer context, gconstpointer data)
+{
+ struct test_snep_context *ctx = context;
+
+ __near_snep_core_cleanup();
+
+ if (stored_recd)
+ test_ndef_free_record(stored_recd);
+
+ if (ctx->test_recd_msg) {
+ g_free(ctx->test_recd_msg->data);
+ g_free(ctx->test_recd_msg);
+ }
+
+ g_slist_free(test_fragments);
+
+ close(sockfd[client]);
+ close(sockfd[server]);
+
+ gcontext = NULL;
+}
+
+/*
+ * @brief Utility: Allocate and build SNEP request frame.
+ *
+ * @param[in] frame_len Size of the entire frame
+ * @param[in] ver SNEP protocol version field
+ * @param[in] resp_type SNEP response code field
+ * @param[in] info_len SNEP info length field
+ * @param[in] data SNEP info field
+ * @param[in] payload_len Size of the payload to be inserted
+ * @return p2p_snep_resp_frame
+ */
+static struct p2p_snep_req_frame *test_snep_build_req_frame(
+ size_t frame_len, uint8_t ver, uint8_t req_type,
+ uint32_t info_len, uint8_t *data, uint32_t payload_len)
+{
+ struct p2p_snep_req_frame *req;
+
+ req = g_try_malloc0(frame_len);
+ g_assert(req != NULL);
+
+ req->version = ver;
+ req->request = req_type;
+ req->length = GUINT_TO_BE(info_len);
+ memcpy(req->ndef, data, payload_len);
+
+ return req;
+}
+
+/*
+ * @brief Utility: Allocate and build SNEP GET request frame.
+ *
+ * @param[in] frame_len Size of the entire frame
+ * @param[in] ver SNEP protocol version field
+ * @param[in] resp_type SNEP response code field
+ * @param[in] info_len SNEP info length field
+ * @param[in] data SNEP info field
+ * @param[in] acc_len SNEP acceptable length field
+ * @param[in] payload_len Size of the payload to be inserted
+ * @return p2p_snep_resp_frame
+ */
+static struct p2p_snep_req_frame *test_snep_build_req_get_frame(
+ size_t frame_len, uint8_t ver, uint8_t req_type,
+ uint32_t info_len, uint32_t acc_len, uint8_t *data,
+ uint32_t payload_len)
+{
+ struct p2p_snep_req_frame *req;
+ uint32_t acc_len_be = GUINT_TO_BE(acc_len);
+
+ req = g_try_malloc0(frame_len);
+ g_assert(req != NULL);
+
+ req->version = ver;
+ req->request = req_type;
+ req->length = GUINT_TO_BE(info_len);
+ memcpy(req->ndef, &acc_len_be, sizeof(acc_len_be));
+ memcpy(req->ndef + sizeof(acc_len_be), data, payload_len);
+
+ return req;
+}
+
+/*
+ * @brief Utility: Allocate and build SNEP response frame.
+ *
+ * @param[in] frame_len Size of the entire frame
+ * @param[in] ver SNEP protocol version field
+ * @param[in] resp_type SNEP response code field
+ * @param[in] info_len SNEP info length field
+ * @param[in] data SNEP info field
+ * @return p2p_snep_resp_frame
+ */
+static struct p2p_snep_resp_frame *test_snep_build_resp_frame(
+ size_t frame_len, uint8_t ver, uint8_t resp_type,
+ uint32_t info_len, uint8_t *data)
+{
+ struct p2p_snep_resp_frame *resp;
+
+ resp = g_try_malloc0(frame_len);
+ g_assert(resp != NULL);
+
+ resp->version = ver;
+ resp->response = resp_type;
+ resp->length = GUINT_TO_BE(info_len);
+ memcpy(resp->info, data, info_len);
+
+ return resp;
+}
+
+/*
+ * @brief Utility: Send the \p req frame to the socket and call
+ * near_snep_core_read
+ *
+ * @param[in] req Request frame to send
+ * @param[in] frame_len Size of the frame
+ * @param[in] req_get GET server function
+ * @param[in] req_put PUT server function
+ * @return near_bool_t returned by near_snep_core_read
+ */
+static near_bool_t test_snep_read_req_common(
+ struct p2p_snep_req_frame *req, size_t frame_len,
+ near_server_io req_get, near_server_io req_put)
+{
+ near_bool_t ret;
+ size_t nbytes;
+
+ nbytes = send(sockfd[client], req, frame_len, 0);
+ g_assert(nbytes == frame_len);
+
+ TEST_SNEP_LOG("sent 0x%02X request\n", req->request);
+
+ ret = near_snep_core_read(sockfd[server], 0, 0, NULL, req_get, req_put);
+
+ return ret;
+}
+
+/*
+ * @brief Utility: Send \p frame_len bytes of the fragment \p data
+ * to the socket and call near_snep_core_read
+ *
+ * @param[in] frag_len
+ * @param[in] data
+ * @return near_bool_t returned by near_snep_core_read
+ *
+ * @note does not call near_snep_core_read for now, since it can't handle
+ * frame without SNEP header
+ */
+static near_bool_t test_snep_read_send_fragment(size_t frag_len,
+ uint8_t *data)
+{
+ size_t nbytes;
+
+ nbytes = send(sockfd[client], data, frag_len, 0);
+ g_assert(nbytes == frag_len);
+
+ /*
+ * TODO fragment has no SNEP header. snep_core_read will fail:
+ * ret = near_snep_core_read(sockfd[server], 0, 0, NULL,
+ * test_snep_dummy_req_get, test_snep_dummy_req_put);
+ */
+ return TRUE;
+}
+
+/*
+ * @brief Utility: Receive remaining fragments and store in \p data_recvd
+ *
+ * @param[in] frag_len
+ * @param[in] remaining_bytes
+ * @param[out] data Must be preallocated
+ */
+static void test_snep_read_recv_fragments(uint32_t frag_len,
+ uint32_t remaining_bytes, void *data_recvd)
+{
+ struct p2p_snep_resp_frame *resp;
+ uint32_t offset = 0;
+ int nbytes;
+
+ g_assert(data_recvd);
+
+ resp = g_try_malloc0(frag_len);
+ g_assert(resp != NULL);
+
+ do {
+ memset(resp, 0, frag_len);
+
+ /* receive remaining fragments */
+ nbytes = recv(sockfd[client], resp, frag_len, 0);
+ g_assert(nbytes > 0); /* TODO use explicit value? */
+
+ /* store received data (no header this time) */
+ memcpy(data_recvd + offset, resp, nbytes);
+ offset += nbytes;
+ } while (offset < remaining_bytes);
+
+ g_free(resp);
+}
+
+/*
+ * @brief Utility: Confirm that server didn't send any response
+ */
+static void test_snep_read_no_response(void)
+{
+ struct p2p_snep_resp_frame *resp;
+ int nbytes;
+
+ resp = g_try_malloc0(sizeof(*resp));
+ g_assert(resp != NULL);
+
+ nbytes = recv(sockfd[client], resp, sizeof(*resp), MSG_DONTWAIT);
+ g_assert(nbytes < 0);
+ g_assert(errno == EAGAIN);
+
+ g_free(resp);
+}
+
+/*
+ * @brief Utility: Verify response sent by the server
+ *
+ * @param[in] exp_resp_code Expected response code
+ * @param[in] exp_resp_info_len Expected response info length
+ * @param[in] exp_resp_info Expected response info
+ */
+static void test_snep_read_verify_resp(int exp_resp_code,
+ uint32_t exp_resp_info_len, uint8_t *exp_resp_info)
+{
+ struct p2p_snep_resp_frame *resp;
+ size_t nbytes, frame_len;
+
+ frame_len = NEAR_SNEP_RESP_HEADER_LENGTH + exp_resp_info_len;
+ resp = test_snep_build_resp_frame(frame_len, 0, 0, 0, NULL);
+ g_assert(resp != NULL);
+
+ nbytes = recv(sockfd[client], resp, frame_len, 0);
+ g_assert(nbytes == frame_len);
+
+ TEST_SNEP_LOG("received response = 0x%02X, exp = 0x%02X\n",
+ resp->response, exp_resp_code);
+
+ g_assert(resp->version == NEAR_SNEP_VERSION);
+ g_assert(resp->response == exp_resp_code);
+ g_assert(resp->length == GUINT_TO_BE(exp_resp_info_len));
+ g_assert(!memcmp(resp->info, exp_resp_info, exp_resp_info_len));
+
+ g_free(resp);
+}
+
+/*
+ * @brief Utility: Verify code of the response sent by the server
+ *
+ * @param[in] exp_resp_code Expected response code
+ */
+static void test_snep_read_verify_resp_code(int exp_resp_code)
+{
+ test_snep_read_verify_resp(exp_resp_code, 0, NULL);
+}
+
+/*
+ * @brief Test: Confirm that server is able to handle PUT request
+ *
+ * Steps:
+ * - Send well-formed PUT request
+ * - Verify server responded with SUCCESS
+ */
+static void test_snep_read_put_req_ok(gpointer context, gconstpointer gp)
+{
+ struct test_snep_context *ctx = context;
+ struct p2p_snep_req_frame *req;
+ uint32_t frame_len, payload_len;
+ near_bool_t ret;
+
+ payload_len = ctx->req_info_len;
+ frame_len = NEAR_SNEP_REQ_PUT_HEADER_LENGTH + payload_len;
+
+ req = test_snep_build_req_frame(frame_len, NEAR_SNEP_VERSION,
+ NEAR_SNEP_REQ_PUT, ctx->req_info_len,
+ ctx->req_info, payload_len);
+
+ ret = test_snep_read_req_common(req, frame_len, test_snep_dummy_req_get,
+ test_snep_dummy_req_put);
+ g_assert(ret);
+
+ test_snep_read_verify_resp_code(NEAR_SNEP_RESP_SUCCESS);
+
+ g_free(req);
+}
+
+/*
+ * @brief Test: Confirm that server checks the version field of the request.
+ *
+ * Steps:
+ * - Send PUT request with incorrect version field
+ * - Verify server responded with UNSUPPORTED VERSION
+ */
+static void test_snep_read_put_req_unsupp_ver(gpointer context,
+ gconstpointer gp)
+{
+ struct test_snep_context *ctx = context;
+ struct p2p_snep_req_frame *req;
+ uint32_t frame_len, payload_len;
+ near_bool_t ret;
+
+ payload_len = ctx->req_info_len;
+ frame_len = NEAR_SNEP_REQ_PUT_HEADER_LENGTH + payload_len;
+
+ req = test_snep_build_req_frame(frame_len, 0xF8, NEAR_SNEP_REQ_PUT,
+ ctx->req_info_len, ctx->req_info, payload_len);
+
+ ret = test_snep_read_req_common(req, frame_len, test_snep_dummy_req_get,
+ test_snep_dummy_req_put);
+ g_assert(ret);
+
+ test_snep_read_verify_resp_code(NEAR_SNEP_RESP_VERSION);
+
+ g_free(req);
+}
+
+/*
+ * @brief Test: Confirm that server responds about no support for the
+ * functionality in request message
+ *
+ * Steps:
+ * - Send PUT request
+ * - Pass NULL PUT request handler to the near_snep_core_read
+ * - Verify server responded with NOT IMPLEMENTED
+ */
+static void test_snep_read_put_req_not_impl(gpointer context,
+ gconstpointer gp)
+{
+ struct test_snep_context *ctx = context;
+ struct p2p_snep_req_frame *req;
+ uint32_t frame_len, payload_len;
+ near_bool_t ret;
+
+ payload_len = ctx->req_info_len;
+ frame_len = NEAR_SNEP_REQ_PUT_HEADER_LENGTH + payload_len;
+
+ req = test_snep_build_req_frame(frame_len, NEAR_SNEP_VERSION,
+ NEAR_SNEP_REQ_PUT, ctx->req_info_len,
+ ctx->req_info, payload_len);
+
+ ret = test_snep_read_req_common(req, frame_len, test_snep_dummy_req_get,
+ NULL);
+ g_assert(ret);
+
+ test_snep_read_verify_resp_code(NEAR_SNEP_RESP_NOT_IMPL);
+
+ g_free(req);
+}
+
+/*
+ * @brief Test: Confirm that server is able to receive fragmented request msg
+ *
+ * Steps:
+ * - Send PUT request with incomplete data
+ * - Verify server responded with CONTINUE
+ * - Send second fragment of the message
+ * - Verify server didn't respond
+ * - Send last fragment of the message
+ * - Verify server responded with SUCCESS
+ */
+static void test_snep_read_put_req_fragmented(gpointer context,
+ gconstpointer gp)
+{
+ struct test_snep_context *ctx = context;
+ struct p2p_snep_req_frame *req;
+ uint32_t frame_len, payload_len;
+ near_bool_t ret;
+
+ payload_len = ctx->req_info_len / 3;
+ frame_len = NEAR_SNEP_REQ_PUT_HEADER_LENGTH + payload_len;
+
+ req = test_snep_build_req_frame(frame_len, NEAR_SNEP_VERSION,
+ NEAR_SNEP_REQ_PUT, ctx->req_info_len,
+ ctx->req_info, payload_len);
+
+ /* send 1st fragment within PUT request */
+ ret = test_snep_read_req_common(req, frame_len, test_snep_dummy_req_get,
+ test_snep_dummy_req_put);
+ g_assert(ret);
+
+ test_snep_read_verify_resp_code(NEAR_SNEP_RESP_CONTINUE);
+
+ /* send 2nd fragment */
+ ret = test_snep_read_send_fragment(payload_len,
+ ctx->req_info + payload_len);
+ g_assert(ret);
+
+ /* do not expect a response */
+ test_snep_read_no_response();
+
+ /* send last fragment */
+ ret = test_snep_read_send_fragment(ctx->req_info_len - 2 * payload_len,
+ ctx->req_info + 2 * payload_len);
+ g_assert(ret);
+
+ /*
+ * TODO expected SUCCESS response:
+ * test_snep_read_verify_resp_code(NEAR_SNEP_RESP_SUCCESS);
+ */
+
+ TEST_SNEP_LOG("EXPECTED FAIL: fragments are not received by SNEP\n");
+
+ g_free(req);
+}
+
+/*
+ * @brief Test: Confirm that server is able to handle GET request
+ *
+ * Steps:
+ * - Send PUT request with some data
+ * - Send GET request
+ * - Verify server responded with SUCCESS and correct data
+ */
+static void test_snep_read_get_req_ok(gpointer context, gconstpointer gp)
+{
+ struct test_snep_context *ctx = context;
+ struct p2p_snep_req_frame *req;
+ uint32_t frame_len, payload_len, info_len;
+ near_bool_t ret;
+
+ /* send some data to the server */
+ test_snep_read_put_req_ok(context, gp);
+
+ info_len = ctx->req_info_len + NEAR_SNEP_ACC_LENGTH_SIZE;
+ payload_len = ctx->req_info_len;
+
+ frame_len = NEAR_SNEP_REQ_GET_HEADER_LENGTH + payload_len;
+
+ req = test_snep_build_req_get_frame(frame_len, NEAR_SNEP_VERSION,
+ NEAR_SNEP_REQ_GET, info_len,
+ ctx->acc_len, ctx->req_info, payload_len);
+
+ ret = test_snep_read_req_common(req, frame_len, test_snep_dummy_req_get,
+ test_snep_dummy_req_put);
+ g_assert(ret);
+
+ test_snep_read_verify_resp(NEAR_SNEP_RESP_SUCCESS, ctx->req_info_len,
+ ctx->req_info);
+
+ g_free(req);
+}
+
+/*
+ * @brief Test: Confirm that server responds about no support for the
+ * functionality in request message
+ *
+ * Steps:
+ * - Send PUT request with some data
+ * - Send GET request
+ * - Pass NULL GET request handler to the near_snep_core_read
+ * - Verify server responded with NOT IMPLEMENTED
+ */
+static void test_snep_read_get_req_not_impl(gpointer context,
+ gconstpointer gp)
+{
+ struct test_snep_context *ctx = context;
+ struct p2p_snep_req_frame *req;
+ uint32_t frame_len, payload_len;
+ near_bool_t ret;
+
+ /* send some data to the server */
+ test_snep_read_put_req_ok(context, gp);
+
+ payload_len = ctx->req_info_len;
+ frame_len = NEAR_SNEP_REQ_GET_HEADER_LENGTH + payload_len;
+
+ /* build REQ GET frame */
+ req = test_snep_build_req_get_frame(frame_len, NEAR_SNEP_VERSION,
+ NEAR_SNEP_REQ_GET, ctx->req_info_len, ctx->acc_len,
+ ctx->req_info, payload_len);
+
+ /* call snep_core_read with NULL req_get handler */
+ ret = test_snep_read_req_common(req, frame_len, NULL,
+ test_snep_dummy_req_put);
+ g_assert(ret);
+
+ test_snep_read_verify_resp_code(NEAR_SNEP_RESP_NOT_IMPL);
+
+ g_free(req);
+}
+
+/*
+ * @brief Test: Confirm that server is able to respond with fragmented message
+ *
+ * Steps:
+ * - Send PUT request with some data
+ * - Send GET request with Acceptable Length less than actual data length
+ * - Verify that server returned with incomplete data
+ * - Send CONTINUE or REJECT request (depending on \p client_resp param)
+ * - If REJECT requested, verify that server didn't respond
+ * - If CONTINUE requested, receive remaining fragments and verify data
+ */
+static void test_snep_read_get_req_frags_client_resp(gpointer context,
+ gconstpointer gp, uint8_t client_resp)
+{
+ struct test_snep_context *ctx = context;
+ struct p2p_snep_req_frame *req;
+ struct p2p_snep_resp_frame *resp;
+ uint32_t frame_len, payload_len;
+ near_bool_t ret;
+ size_t nbytes;
+ uint8_t *data_recvd;
+ uint32_t offset;
+ uint32_t frag_len, info_len;
+
+ /* send some data to the server */
+ test_snep_read_put_req_ok(context, gp);
+
+ payload_len = ctx->req_info_len;
+ frame_len = NEAR_SNEP_REQ_GET_HEADER_LENGTH + payload_len;
+
+ /* force fragmentation */
+ ctx->acc_len = 60;
+ g_assert(ctx->acc_len < ctx->req_info_len);
+ g_assert(NEAR_SNEP_REQ_MAX_FRAGMENT_LENGTH < ctx->req_info_len);
+
+ /* TODO frag_len should be calculated based on SNEP acc_len */
+ TEST_SNEP_LOG("WORKAROUND: SNEP core ignores the acceptable length\n");
+ frag_len = NEAR_SNEP_REQ_MAX_FRAGMENT_LENGTH;
+
+ info_len = ctx->req_info_len + NEAR_SNEP_ACC_LENGTH_SIZE;
+
+ req = test_snep_build_req_get_frame(frame_len, NEAR_SNEP_VERSION,
+ NEAR_SNEP_REQ_GET, info_len,
+ ctx->acc_len, ctx->req_info, payload_len);
+
+ /* send GET request */
+ ret = test_snep_read_req_common(req, frame_len, test_snep_dummy_req_get,
+ test_snep_dummy_req_put);
+ g_assert(ret);
+ g_free(req);
+
+ frame_len = NEAR_SNEP_RESP_HEADER_LENGTH + payload_len;
+ resp = test_snep_build_resp_frame(frame_len, 0, 0, 0, NULL);
+
+ /* start receiving fragments */
+ nbytes = recv(sockfd[client], resp, frame_len, 0);
+ g_assert(nbytes == frag_len);
+ g_assert(resp->length == GUINT_TO_BE(ctx->req_info_len));
+ g_assert(resp->info != NULL);
+
+ data_recvd = g_try_malloc0(ctx->req_info_len);
+ g_assert(data_recvd != NULL);
+
+ /* store received info field */
+ memcpy(data_recvd, resp->info, nbytes - NEAR_SNEP_RESP_HEADER_LENGTH);
+ g_free(resp);
+
+ offset = nbytes - NEAR_SNEP_RESP_HEADER_LENGTH;
+
+ /* 1st fragment has been received, so request resp=CONTINUE/REJECT */
+ frame_len = NEAR_SNEP_REQ_PUT_HEADER_LENGTH;
+ req = test_snep_build_req_frame(frame_len, NEAR_SNEP_VERSION,
+ client_resp, 0, NULL, 0);
+
+ ret = test_snep_read_req_common(req, frame_len, NULL, NULL);
+ g_free(req);
+
+ if (client_resp == NEAR_SNEP_REQ_REJECT) {
+ /*
+ * TODO server shall not send any response:
+ * g_assert(ret);
+ * test_snep_read_no_response();
+ */
+
+ TEST_SNEP_LOG("EXPECTED FAIL: REJECT not handled by SNEP\n");
+ } else if (client_resp == NEAR_SNEP_REQ_CONTINUE) {
+ g_assert(ret);
+
+ /* receive remaining fragments */
+ test_snep_read_recv_fragments(frag_len,
+ ctx->req_info_len - offset,
+ data_recvd + offset);
+
+ /* verify data */
+ g_assert(!memcmp(data_recvd, ctx->req_info,
+ ctx->req_info_len));
+ }
+
+ g_free(data_recvd);
+}
+
+/* Refer to the test_snep_read_get_req_frags_client_resp for description */
+static void test_snep_read_get_frags_continue(gpointer context,
+ gconstpointer gp)
+{
+ test_snep_read_get_req_frags_client_resp(context, gp,
+ NEAR_SNEP_REQ_CONTINUE);
+}
+
+/* Refer to the test_snep_read_get_req_frags_client_resp for description */
+static void test_snep_read_get_frags_reject(gpointer context,
+ gconstpointer gp)
+{
+ test_snep_read_get_req_frags_client_resp(context, gp,
+ NEAR_SNEP_REQ_REJECT);
+}
+
+/*
+ * @brief Test: Confirm that server is able to send simple response
+ */
+static void test_snep_response_noinfo(gpointer context, gconstpointer gp)
+{
+ int bytes_recv;
+ struct p2p_snep_resp_frame resp;
+
+ near_snep_core_response_noinfo(sockfd[client], NEAR_SNEP_RESP_SUCCESS);
+
+ bytes_recv = recv(sockfd[server], &resp, sizeof(resp), 0);
+ g_assert(bytes_recv == NEAR_SNEP_RESP_HEADER_LENGTH);
+ g_assert(resp.version == NEAR_SNEP_VERSION);
+ g_assert(resp.response == NEAR_SNEP_RESP_SUCCESS);
+ g_assert(resp.length == 0);
+}
+
+/*
+ * @brief Test: Confirm that server is able to communicate with the client
+ */
+static void test_snep_response_put_get_ndef(gpointer context,
+ gconstpointer gp)
+{
+ size_t nbytes;
+
+ struct p2p_snep_req_frame *req;
+ struct p2p_snep_resp_frame *resp;
+ struct near_ndef_message *ndef;
+
+ near_bool_t ret;
+ uint frame_len;
+
+ ndef = near_ndef_prepare_text_record("UTF-8", "en-US", "neard");
+ g_assert(ndef);
+ g_assert(ndef->data);
+ g_assert(ndef->length > 0);
+
+ frame_len = NEAR_SNEP_RESP_HEADER_LENGTH + ndef->length;
+
+ req = g_try_malloc0(frame_len);
+ g_assert(req);
+
+ req->version = 0x10;
+ req->request = NEAR_SNEP_REQ_PUT;
+ req->length = GUINT_TO_BE(ndef->length);
+ memcpy(req->ndef, ndef->data, ndef->length);
+
+ /* Send PUT request with text record */
+ nbytes = send(sockfd[server], req, frame_len, 0);
+ g_assert(nbytes == frame_len);
+
+ /* UUT */
+ ret = near_snep_core_read(sockfd[client], 0, 0, NULL,
+ test_snep_dummy_req_get, test_snep_dummy_req_put);
+ g_assert(ret != FALSE);
+
+ resp = g_try_malloc0(frame_len);
+ g_assert(resp);
+
+ /* Get response from server */
+ nbytes = recv(sockfd[server], resp, frame_len, 0);
+ g_assert(nbytes > 0);
+ g_assert(resp->response == NEAR_SNEP_RESP_SUCCESS);
+
+ /* Send GET request to retrieve a record */
+ req->request = NEAR_SNEP_REQ_GET;
+ req->length = 0;
+ nbytes = send(sockfd[server], req, NEAR_SNEP_RESP_HEADER_LENGTH, 0);
+ g_assert(nbytes > 0);
+
+ /* UUT */
+ ret = near_snep_core_read(sockfd[client], 0, 0, NULL,
+ test_snep_dummy_req_get, test_snep_dummy_req_put);
+ g_assert(ret != FALSE);
+
+ /* Get response and verify */
+ nbytes = recv(sockfd[server], resp, frame_len, 0);
+ g_assert(nbytes > 0);
+ g_assert(resp->response == NEAR_SNEP_RESP_SUCCESS);
+ g_assert(resp->length == GUINT_TO_BE(ndef->length));
+ g_assert(!memcmp(resp->info, text, ndef->length));
+
+ g_free(req);
+ g_free(resp);
+ g_free(ndef->data);
+ g_free(ndef);
+}
+
+int main(int argc, char **argv)
+{
+ GTestSuite *ts;
+ GTestFixtureFunc init = test_snep_init;
+ GTestFixtureFunc exit = test_snep_cleanup;
+ size_t fs = sizeof(struct test_snep_context);
+
+ g_test_init(&argc, &argv, NULL);
+
+ ts = g_test_create_suite("testSNEP-response");
+ g_test_suite_add(ts,
+ g_test_create_case("noinfo", fs, short_text,
+ init, test_snep_response_noinfo, exit));
+
+ g_test_suite_add_suite(g_test_get_root(), ts);
+
+ ts = g_test_create_suite("testSNEP-readGET");
+ g_test_suite_add(ts,
+ g_test_create_case("Request ok", fs, short_text,
+ init, test_snep_read_get_req_ok, exit));
+ g_test_suite_add(ts,
+ g_test_create_case("Request not implemented", fs, short_text,
+ init, test_snep_read_get_req_not_impl, exit));
+ g_test_suite_add(ts,
+ g_test_create_case("Request fragmented CONTINUE",
+ fs, long_text, init,
+ test_snep_read_get_frags_continue, exit));
+ g_test_suite_add(ts,
+ g_test_create_case("Request fragmented REJECT",
+ fs, long_text, init,
+ test_snep_read_get_frags_reject, exit));
+
+ g_test_suite_add_suite(g_test_get_root(), ts);
+
+ ts = g_test_create_suite("testSNEP-readPUT");
+ g_test_suite_add(ts,
+ g_test_create_case("Request ok", fs, short_text,
+ init, test_snep_read_put_req_ok, exit));
+ g_test_suite_add(ts,
+ g_test_create_case("Request unsupported ver", fs, short_text,
+ init, test_snep_read_put_req_unsupp_ver, exit));
+ g_test_suite_add(ts,
+ g_test_create_case("Request not implemented", fs, short_text,
+ init, test_snep_read_put_req_not_impl, exit));
+ g_test_suite_add(ts,
+ g_test_create_case("Request fragmented", fs, long_text,
+ init, test_snep_read_put_req_fragmented, exit));
+
+ g_test_suite_add_suite(g_test_get_root(), ts);
+
+ ts = g_test_create_suite("testSNEP-misc");
+ g_test_suite_add(ts,
+ g_test_create_case("PUT and GET request NDEF",
+ fs, short_text, init,
+ test_snep_response_put_get_ndef, exit));
+
+ g_test_suite_add_suite(g_test_get_root(), ts);
+
+ return g_test_run();
+}
diff --git a/unit/test-utils.c b/unit/test-utils.c
new file mode 100644
index 0000000..fe25656
--- /dev/null
+++ b/unit/test-utils.c
@@ -0,0 +1,40 @@
+/*
+ * neard - Near Field Communication manager
+ *
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "test-utils.h"
+
+void test_ndef_free_record(struct near_ndef_record *record)
+{
+ g_free(record->header);
+ g_free(record->type);
+ g_free(record->data);
+ g_free(record);
+}
+
+struct near_ndef_message *test_ndef_create_test_record(const char *str)
+{
+ struct near_ndef_message *ndef;
+
+ ndef = near_ndef_prepare_text_record("UTF-8", "en-US", (char *) str);
+ g_assert(ndef);
+ g_assert(ndef->data);
+
+ return ndef;
+}
diff --git a/unit/test-utils.h b/unit/test-utils.h
new file mode 100644
index 0000000..c371d56
--- /dev/null
+++ b/unit/test-utils.h
@@ -0,0 +1,150 @@
+/*
+ * neard - Near Field Communication manager
+ *
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef UNIT_TEST_UTILS_H
+#define UNIT_TEST_UTILS_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <src/near.h>
+#include <near/nfc_copy.h>
+#include <near/types.h>
+#include <near/ndef.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+
+/* SNEP specific types */
+struct snep_fragment {
+ uint32_t len;
+ uint8_t *data;
+};
+
+struct p2p_snep_put_req_data {
+ uint8_t fd;
+ uint32_t adapter_idx;
+ uint32_t target_idx;
+ near_device_io_cb cb;
+ guint watch;
+
+ GSList *fragments;
+};
+
+struct p2p_snep_req_frame {
+ uint8_t version;
+ uint8_t request;
+ uint32_t length;
+ uint8_t ndef[];
+} __attribute__((packed));
+
+struct p2p_snep_resp_frame {
+ uint8_t version;
+ uint8_t response;
+ uint32_t length;
+ uint8_t info[];
+} __attribute__((packed));
+
+/* NDEF specific types */
+enum record_type {
+ RECORD_TYPE_WKT_SMART_POSTER = 0x01,
+ RECORD_TYPE_WKT_URI = 0x02,
+ RECORD_TYPE_WKT_TEXT = 0x03,
+ RECORD_TYPE_WKT_SIZE = 0x04,
+ RECORD_TYPE_WKT_TYPE = 0x05,
+ RECORD_TYPE_WKT_ACTION = 0x06,
+ RECORD_TYPE_WKT_HANDOVER_REQUEST = 0x07,
+ RECORD_TYPE_WKT_HANDOVER_SELECT = 0x08,
+ RECORD_TYPE_WKT_HANDOVER_CARRIER = 0x09,
+ RECORD_TYPE_WKT_ALTERNATIVE_CARRIER = 0x0a,
+ RECORD_TYPE_WKT_COLLISION_RESOLUTION = 0x0b,
+ RECORD_TYPE_WKT_ERROR = 0x0c,
+ RECORD_TYPE_MIME_TYPE = 0x0d,
+ RECORD_TYPE_UNKNOWN = 0xfe,
+ RECORD_TYPE_ERROR = 0xff
+};
+
+struct near_ndef_record_header {
+ uint8_t mb;
+ uint8_t me;
+ uint8_t cf;
+ uint8_t sr;
+ uint8_t il;
+ uint8_t tnf;
+ uint8_t il_length;
+ uint8_t *il_field;
+ uint32_t payload_len;
+ uint32_t offset;
+ uint8_t type_len;
+ enum record_type rec_type;
+ char *type_name;
+ uint32_t header_len;
+};
+
+struct near_ndef_text_payload {
+ char *encoding;
+ char *language_code;
+ char *data;
+};
+
+struct near_ndef_uri_payload {
+ uint8_t identifier;
+
+ uint32_t field_length;
+ uint8_t *field;
+};
+
+struct near_ndef_sp_payload {
+ struct near_ndef_uri_payload *uri;
+
+ uint8_t number_of_title_records;
+ struct near_ndef_text_payload **title_records;
+
+ uint32_t size; /* from Size record*/
+ char *type; /* from Type record*/
+ char *action;
+};
+
+struct near_ndef_record {
+ char *path;
+
+ struct near_ndef_record_header *header;
+
+ /* specific payloads */
+ struct near_ndef_text_payload *text;
+ struct near_ndef_uri_payload *uri;
+ struct near_ndef_sp_payload *sp;
+ struct near_ndef_mime_payload *mime;
+ struct near_ndef_ho_payload *ho; /* handover payload */
+
+ char *type;
+
+ uint8_t *data;
+ size_t data_len;
+};
+
+void test_ndef_free_record(struct near_ndef_record *record);
+
+struct near_ndef_message *test_ndef_create_test_record(const char *str);
+
+#endif