summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorOlivier Guiter <olivier.guiter@linux.intel.com>2013-01-09 15:15:12 +0100
committerSamuel Ortiz <sameo@linux.intel.com>2013-01-09 18:39:20 +0100
commit8fdb45b93475b8e5d37b8f520b206db0fdf8d999 (patch)
tree79f019f3496d122c0ce031ae768f7fcd046308f0 /plugins
parent8cd0eefd096f1232eb20b62b4f5cf47b56708b5a (diff)
downloadneard-8fdb45b93475b8e5d37b8f520b206db0fdf8d999.tar.gz
neard-8fdb45b93475b8e5d37b8f520b206db0fdf8d999.tar.bz2
neard-8fdb45b93475b8e5d37b8f520b206db0fdf8d999.zip
snep: SNEP validation test server implementation
NFC forum defined a SNEP Validation specification. This set of patches makes neard to pass all the SNEP test cases, providing a SNEP validation server as a default one.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/snep-core.c3
-rw-r--r--plugins/snep-validation.c262
2 files changed, 265 insertions, 0 deletions
diff --git a/plugins/snep-core.c b/plugins/snep-core.c
index ab65094..2155a75 100644
--- a/plugins/snep-core.c
+++ b/plugins/snep-core.c
@@ -818,12 +818,15 @@ int snep_core_init(void)
g_direct_equal, NULL,
free_snep_core_client);
snep_init();
+ snep_validation_init();
return 0;
}
void snep_core_exit(void)
{
+ snep_validation_exit();
+
g_hash_table_destroy(snep_client_hash);
snep_client_hash = NULL;
}
diff --git a/plugins/snep-validation.c b/plugins/snep-validation.c
new file mode 100644
index 0000000..b1ab7fd
--- /dev/null
+++ b/plugins/snep-validation.c
@@ -0,0 +1,262 @@
+/*
+ *
+ * neard - Near Field Communication manager
+ *
+ * Copyright (C) 2012 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <linux/socket.h>
+#include <linux/nfc.h>
+
+#include <near/plugin.h>
+#include <near/log.h>
+#include <near/types.h>
+#include <near/adapter.h>
+#include <near/device.h>
+#include <near/ndef.h>
+#include <near/tlv.h>
+
+#include "p2p.h"
+#include "snep-core.h"
+
+/* Would store incoming ndefs per client */
+static GHashTable *snep_validation_hash = NULL;
+
+/* Callback: free validation data */
+static void free_snep_validation_client(gpointer data)
+{
+ GList *old_ndefs = data;
+
+ if (old_ndefs != NULL)
+ g_list_free(old_ndefs);
+}
+
+/* Validation Server REQ_PUT function
+ * The validation server shall accept PUT and GET requests. A PUT request shall
+ * cause the server to store the ndef message transmitted with the request.
+ * */
+static near_bool_t snep_validation_server_req_put(int client_fd, void *data)
+{
+ struct p2p_snep_data *snep_data = data;
+ GList *records;
+ struct near_ndef_record *recd;
+ GList *incoming_ndefs;
+
+ DBG("");
+
+ if (snep_data->nfc_data == NULL)
+ goto error;
+
+ /*
+ * We received a ndef, parse it, check if there's only
+ * 1 record (a mime type !) with an ID
+ */
+ records = near_ndef_parse_msg(snep_data->nfc_data,
+ snep_data->nfc_data_length, NULL);
+
+ if (g_list_length(records) != 1) {
+ DBG("records number mismatch");
+ goto error;
+ }
+
+ recd = records->data;
+
+ if (recd == NULL) {
+ g_list_free(records);
+ goto error;
+ }
+
+ /* Save the record but look if there are some incoming ndef stored */
+ incoming_ndefs = g_hash_table_lookup(snep_validation_hash,
+ GINT_TO_POINTER(client_fd));
+
+ incoming_ndefs = g_list_append(incoming_ndefs, recd);
+
+ /* remove existing one silently */
+ g_hash_table_steal(snep_validation_hash, GINT_TO_POINTER(client_fd));
+ /* push the new one */
+ g_hash_table_insert(snep_validation_hash, GINT_TO_POINTER(client_fd),
+ incoming_ndefs);
+
+
+ snep_core_response_noinfo(client_fd, SNEP_RESP_SUCCESS);
+
+ return TRUE;
+
+error:
+ snep_core_response_noinfo(client_fd, SNEP_RESP_REJECT);
+
+ return TRUE;
+}
+
+/*
+ * Validation Server REQ_GET function
+ * The validation server shall accept PUT and GET requests. A GET request shall
+ * cause the server to return a previously stored NDEF message of the same NDEF
+ * message type and identifier as transmitted with the request.
+ * */
+static near_bool_t snep_validation_server_req_get(int client_fd, void *data)
+{
+ struct p2p_snep_data *snep_data = data;
+ struct near_ndef_record *recd, *rec_store;
+ uint32_t acceptable_length;
+ GList *records;
+ GList *iter;
+ GList *incoming_ndefs;
+
+ DBG("");
+
+ /*
+ * We received a ndef, parse it, check if there's only
+ * 1 record (a mime type !) with an ID
+ */
+ records = near_ndef_parse_msg(snep_data->nfc_data +
+ SNEP_ACC_LENGTH_SIZE,
+ snep_data->nfc_data_length - SNEP_ACC_LENGTH_SIZE,
+ NULL);
+
+ if (g_list_length(records) != 1) {
+ DBG("records number mismatch");
+ goto error;
+ }
+
+ recd = records->data;
+ if (recd == NULL) {
+ g_list_free(records);
+ goto error;
+ }
+
+ /* check if the acceptable length is higher than the data_len
+ * otherwise returns a SNEP_RESP_EXCESS
+ */
+ acceptable_length = GUINT32_FROM_BE(*(uint32_t *)snep_data->nfc_data);
+
+ /* Look if there are some incoming ndef stored */
+ incoming_ndefs = g_hash_table_lookup(snep_validation_hash,
+ GINT_TO_POINTER(client_fd));
+
+ if (incoming_ndefs == NULL)
+ goto done;
+
+ /* Now, loop to find the the associated record */
+ for (iter = incoming_ndefs; iter; iter = iter->next) {
+
+ rec_store = iter->data;
+ /* Same mime type and same id ?*/
+
+ if (near_ndef_record_cmp_id(recd, rec_store) == FALSE)
+ continue;
+
+ if (near_ndef_record_cmp_mime(recd, rec_store) == FALSE)
+ continue;
+
+ /* Found a record, check the length */
+ if (acceptable_length >= near_ndef_data_length(rec_store)) {
+ snep_core_response_with_info(client_fd,
+ SNEP_RESP_SUCCESS,
+ near_ndef_data_ptr(rec_store),
+ near_ndef_data_length(rec_store));
+
+ incoming_ndefs = g_list_remove(incoming_ndefs,
+ iter->data);
+ /* remove existing one silently */
+ g_hash_table_steal(snep_validation_hash,
+ GINT_TO_POINTER(client_fd));
+ /* push the new one */
+ g_hash_table_insert(snep_validation_hash,
+ GINT_TO_POINTER(client_fd),
+ incoming_ndefs);
+
+ } else
+ snep_core_response_noinfo(client_fd, SNEP_RESP_EXCESS);
+
+ return TRUE;
+ }
+
+done:
+ /* If not found */
+ snep_core_response_noinfo(client_fd, SNEP_RESP_NOT_FOUND);
+ return TRUE;
+
+error:
+ /* Not found */
+ snep_core_response_noinfo(client_fd, SNEP_RESP_REJECT);
+ return FALSE;
+}
+
+/* This function is a wrapper to push post processing read functions */
+static near_bool_t snep_validation_read(int client_fd, uint32_t adapter_idx,
+ uint32_t target_idx,
+ near_tag_io_cb cb)
+{
+ DBG("");
+
+ return snep_core_read(client_fd, adapter_idx, target_idx, cb,
+ snep_validation_server_req_get,
+ snep_validation_server_req_put);
+
+}
+
+static void snep_validation_close(int client_fd, int err)
+{
+ DBG("");
+
+ g_hash_table_remove(snep_validation_hash, GINT_TO_POINTER(client_fd));
+
+ /* Call core server close */
+ snep_core_close(client_fd, err);
+}
+
+struct near_p2p_driver validation_snep_driver = {
+ .name = "VALIDATION_SNEP",
+ .service_name = "urn:nfc:xsn:nfc-forum.org:snep-validation",
+ .fallback_service_name = NULL,
+ .read = snep_validation_read,
+ .push = snep_core_push,
+ .close = snep_validation_close,
+};
+
+int snep_validation_init(void)
+{
+ DBG("");
+
+ /* Would store incoming ndefs per client */
+ snep_validation_hash = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL,
+ free_snep_validation_client);
+
+ return near_p2p_register(&validation_snep_driver);
+}
+
+void snep_validation_exit(void)
+{
+ DBG("");
+
+ near_p2p_unregister(&validation_snep_driver);
+
+ g_hash_table_destroy(snep_validation_hash);
+ snep_validation_hash = NULL;
+}