Add packaging directory
[platform/upstream/neard.git] / plugins / snep-validation.c
1 /*
2  *
3  *  neard - Near Field Communication manager
4  *
5  *  Copyright (C) 2012  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdint.h>
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <string.h>
30 #include <sys/socket.h>
31
32 #include <linux/socket.h>
33
34 #include <near/nfc_copy.h>
35 #include <near/plugin.h>
36 #include <near/log.h>
37 #include <near/types.h>
38 #include <near/adapter.h>
39 #include <near/device.h>
40 #include <near/ndef.h>
41 #include <near/tlv.h>
42 #include <near/snep.h>
43
44 #include "p2p.h"
45
46 /* Would store incoming ndefs per client */
47 static GHashTable *snep_validation_hash = NULL;
48
49 /* Callback: free validation data */
50 static void free_snep_validation_client(gpointer data)
51 {
52         GList *old_ndefs = data;
53
54         if (old_ndefs)
55                 g_list_free(old_ndefs);
56 }
57
58 /* Validation Server REQ_PUT function
59  * The validation server shall accept PUT and GET requests. A PUT request shall
60  * cause the server to store the ndef message transmitted with the request.
61  * */
62 static bool snep_validation_server_req_put(int client_fd, void *data)
63 {
64         struct p2p_snep_data *snep_data = data;
65         GList *records;
66         struct near_ndef_record *recd;
67         GList *incoming_ndefs;
68
69         DBG("");
70
71         if (!snep_data->nfc_data)
72                 goto error;
73
74         /*
75          * We received a ndef, parse it, check if there's only
76          * 1 record (a mime type !) with an ID
77          */
78         records = near_ndef_parse_msg(snep_data->nfc_data,
79                                         snep_data->nfc_data_length, NULL);
80
81         if (g_list_length(records) != 1) {
82                 DBG("records number mismatch");
83                 goto error;
84         }
85
86         recd = records->data;
87
88         if (!recd) {
89                 g_list_free(records);
90                 goto error;
91         }
92
93         /* Save the record but look if there are some incoming ndef stored */
94         incoming_ndefs = g_hash_table_lookup(snep_validation_hash,
95                                                 GINT_TO_POINTER(client_fd));
96
97         incoming_ndefs = g_list_append(incoming_ndefs, recd);
98
99         /* remove existing one silently */
100         g_hash_table_steal(snep_validation_hash, GINT_TO_POINTER(client_fd));
101         /* push the new one */
102         g_hash_table_insert(snep_validation_hash, GINT_TO_POINTER(client_fd),
103                                                         incoming_ndefs);
104
105
106         near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_SUCCESS);
107
108         return true;
109
110 error:
111         near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_REJECT);
112
113         return true;
114 }
115
116 /*
117  * Validation Server REQ_GET function
118  * The validation server shall accept PUT and GET requests. A GET request shall
119  * cause the server to return a previously stored NDEF message of the same NDEF
120  * message type and identifier as transmitted with the request.
121  * */
122 static bool snep_validation_server_req_get(int client_fd, void *data)
123 {
124         struct p2p_snep_data *snep_data = data;
125         struct near_ndef_record *recd, *rec_store;
126         uint32_t acceptable_length;
127         GList *records;
128         GList *iter;
129         GList *incoming_ndefs;
130
131         DBG("");
132
133         /*
134          * We received a ndef, parse it, check if there's only
135          * 1 record (a mime type !) with an ID
136          */
137         records = near_ndef_parse_msg(snep_data->nfc_data +
138                         NEAR_SNEP_ACC_LENGTH_SIZE,
139                         snep_data->nfc_data_length - NEAR_SNEP_ACC_LENGTH_SIZE,
140                         NULL);
141
142         if (g_list_length(records) != 1) {
143                 DBG("records number mismatch");
144                 goto error;
145         }
146
147         recd = records->data;
148         if (!recd) {
149                 g_list_free(records);
150                 goto error;
151         }
152
153         /* check if the acceptable length is higher than the data_len
154          * otherwise returns a NEAR_SNEP_RESP_EXCESS
155          */
156         acceptable_length = near_get_be32(snep_data->nfc_data);
157
158         /* Look if there are some incoming ndef stored */
159         incoming_ndefs = g_hash_table_lookup(snep_validation_hash,
160                                                 GINT_TO_POINTER(client_fd));
161
162         if (!incoming_ndefs)
163                 goto done;
164
165         /* Now, loop to find the the associated record */
166         for (iter = incoming_ndefs; iter; iter = iter->next) {
167
168                 rec_store = iter->data;
169                 /* Same mime type and same id ?*/
170
171                 if (!near_ndef_record_cmp_id(recd, rec_store))
172                         continue;
173
174                 if (!near_ndef_record_cmp_mime(recd, rec_store))
175                         continue;
176
177                 /* Found a record, check the length */
178                 if (acceptable_length >= near_ndef_data_length(rec_store)) {
179                         near_snep_core_response_with_info(client_fd,
180                                         NEAR_SNEP_RESP_SUCCESS,
181                                         near_ndef_data_ptr(rec_store),
182                                         near_ndef_data_length(rec_store));
183
184                         incoming_ndefs = g_list_remove(incoming_ndefs,
185                                                                 iter->data);
186                         /* remove existing one silently */
187                         g_hash_table_steal(snep_validation_hash,
188                                                 GINT_TO_POINTER(client_fd));
189                         /* push the new one */
190                         g_hash_table_insert(snep_validation_hash,
191                                                 GINT_TO_POINTER(client_fd),
192                                                         incoming_ndefs);
193
194                 } else
195                         near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_EXCESS);
196
197                 return true;
198         }
199
200 done:
201         /* If not found */
202         near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_NOT_FOUND);
203         return true;
204
205 error:
206          /* Not found */
207         near_snep_core_response_noinfo(client_fd, NEAR_SNEP_RESP_REJECT);
208         return false;
209 }
210
211 /* This function is a wrapper to push post processing read functions */
212 static bool snep_validation_read(int client_fd, uint32_t adapter_idx,
213                                                         uint32_t target_idx,
214                                                         near_tag_io_cb cb,
215                                                         gpointer data)
216 {
217         DBG("");
218
219         return near_snep_core_read(client_fd, adapter_idx, target_idx, cb,
220                                                 snep_validation_server_req_get,
221                                                 snep_validation_server_req_put,
222                                                 data);
223
224 }
225
226 static void snep_validation_close(int client_fd, int err, gpointer data)
227 {
228         DBG("");
229
230         g_hash_table_remove(snep_validation_hash, GINT_TO_POINTER(client_fd));
231
232         /* Call core server close */
233         near_snep_core_close(client_fd, err, data);
234 }
235
236 struct near_p2p_driver validation_snep_driver = {
237         .name = "VALIDATION_SNEP",
238         .service_name = "urn:nfc:xsn:nfc-forum.org:snep-validation",
239         .fallback_service_name = NULL,
240         .sock_type = SOCK_STREAM,
241         .read = snep_validation_read,
242         .push = near_snep_core_push,
243         .close = snep_validation_close,
244 };
245
246 int snep_validation_init(void)
247 {
248         /* Would store incoming ndefs per client */
249         snep_validation_hash = g_hash_table_new_full(g_direct_hash,
250                                                 g_direct_equal, NULL,
251                                                 free_snep_validation_client);
252
253         return near_p2p_register(&validation_snep_driver);
254 }
255
256 void snep_validation_exit(void)
257 {
258         near_p2p_unregister(&validation_snep_driver);
259
260         g_hash_table_destroy(snep_validation_hash);
261         snep_validation_hash = NULL;
262 }