/* * * 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 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "p2p.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) 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 bool 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) 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) { 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); near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_SUCCESS); return true; error: near_snep_core_response_noinfo(client_fd, NEAR_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 bool 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 + NEAR_SNEP_ACC_LENGTH_SIZE, snep_data->nfc_data_length - NEAR_SNEP_ACC_LENGTH_SIZE, NULL); if (g_list_length(records) != 1) { DBG("records number mismatch"); goto error; } recd = records->data; if (!recd) { g_list_free(records); goto error; } /* check if the acceptable length is higher than the data_len * otherwise returns a NEAR_SNEP_RESP_EXCESS */ 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, GINT_TO_POINTER(client_fd)); if (!incoming_ndefs) 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)) continue; if (!near_ndef_record_cmp_mime(recd, rec_store)) continue; /* Found a record, check the length */ if (acceptable_length >= near_ndef_data_length(rec_store)) { near_snep_core_response_with_info(client_fd, NEAR_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 near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_EXCESS); return true; } done: /* If not found */ near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_NOT_FOUND); return true; error: /* Not found */ near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_REJECT); return false; } /* This function is a wrapper to push post processing read functions */ static bool snep_validation_read(int client_fd, uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb, gpointer data) { DBG(""); return near_snep_core_read(client_fd, adapter_idx, target_idx, cb, snep_validation_server_req_get, snep_validation_server_req_put, data); } static void snep_validation_close(int client_fd, int err, gpointer data) { DBG(""); g_hash_table_remove(snep_validation_hash, GINT_TO_POINTER(client_fd)); /* Call core server close */ near_snep_core_close(client_fd, err, data); } struct near_p2p_driver validation_snep_driver = { .name = "VALIDATION_SNEP", .service_name = "urn:nfc:xsn:nfc-forum.org:snep-validation", .fallback_service_name = NULL, .sock_type = SOCK_STREAM, .read = snep_validation_read, .push = near_snep_core_push, .close = snep_validation_close, }; int snep_validation_init(void) { /* 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) { near_p2p_unregister(&validation_snep_driver); g_hash_table_destroy(snep_validation_hash); snep_validation_hash = NULL; }