8eee61ffdf46e62d43494d2d71f417cc431bb07c
[platform/upstream/neard.git] / plugins / handover.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/types.h>
36 #include <near/log.h>
37 #include <near/adapter.h>
38 #include <near/device.h>
39 #include <near/tag.h>
40 #include <near/ndef.h>
41 #include <near/tlv.h>
42
43 #include "p2p.h"
44
45 #define NDEF_HR_MSG_MIN_LENGTH 0x06
46 #define HR_HEADER_SIZE  6               /* header (1) + type len (1) +
47                                         *  payload len (1) + rec type (2) 'Hx'
48                                         *  + version (1)
49                                         */
50
51 #define RECORD_TYPE_WKT_ALTERNATIVE_CARRIER 0x0a
52 #define FRAME_TYPE_OFFSET       3
53
54 enum loop_stage_flag {
55         STATE_MAIN_NDEF         = 0x00,
56         STATE_CFG_RECORD        = 0x01,
57 };
58
59 static GHashTable *hr_ndef_hash = NULL;
60
61 struct extra_ndef {
62         uint8_t *ndef;
63         uint8_t length;
64 };
65
66 struct hr_ndef {
67         uint8_t *ndef;
68         uint16_t cur_ptr;
69         int cur_record_len;
70         int missing_bytes;
71         uint32_t adapter_idx;
72         uint32_t target_idx;
73         near_tag_io_cb cb;
74         int extra_ndef_count;
75         int block_free_size;
76         bool cfg_record_state;
77         bool in_extra_read;
78 };
79
80 struct hr_push_client {
81         uint8_t fd;
82         uint32_t adapter_idx;
83         uint32_t target_idx;
84         near_device_io_cb cb;
85         guint watch;
86 };
87
88 static void free_hr_ndef(gpointer data)
89 {
90         struct hr_ndef *ndef = data;
91
92         if (ndef != NULL)
93                 g_free(ndef->ndef);
94
95         g_free(ndef);
96 }
97
98 static void handover_close(int client_fd, int err)
99 {
100         struct hr_ndef *ndef;
101
102         DBG("");
103
104         ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
105         if (ndef == NULL)
106                 return;
107
108         g_hash_table_remove(hr_ndef_hash, GINT_TO_POINTER(client_fd));
109 }
110
111 /* Parse an incoming handover buffer*/
112 static int handover_ndef_parse(int client_fd, struct hr_ndef *ndef)
113 {
114         int err;
115         GList *records;
116         struct near_ndef_message *msg = NULL;
117
118         DBG("");
119
120         if ((ndef->ndef == NULL) ||
121                         (ndef->cur_ptr < NDEF_HR_MSG_MIN_LENGTH)) {
122                 err = -EINVAL;
123                 goto fail;
124         }
125
126         /* call the global parse function */
127         records = near_ndef_parse_msg(ndef->ndef, ndef->cur_ptr, &msg);
128         if (records == NULL) {
129                 err = -ENOMEM;
130                 goto fail;
131         }
132
133         near_ndef_records_free(records);
134
135         if (msg) {
136                 near_info("Send Hs frame");
137                 err = send(client_fd, msg->data, msg->length, MSG_DONTWAIT);
138
139                 g_free(msg->data);
140                 g_free(msg);
141         } else {
142                 err = 0;
143         }
144
145         return err;
146
147 fail:
148         near_error("ndef parsing failed %d", err);
149
150         handover_close(client_fd, 0);
151
152         return err;
153 }
154
155 static bool handover_recv_error(void)
156 {
157         near_error("%s", strerror(errno));
158
159         if (errno == EAGAIN)
160                 return true;
161
162         return false;
163 }
164
165 /* Add extra records right after the end of the "Hr" ndef record */
166 static bool handover_read_cfg_records(int client_fd,
167                                 uint32_t adapter_idx, uint32_t target_idx,
168                                 near_tag_io_cb cb)
169 {
170         struct hr_ndef *ndef;
171         uint8_t *new_ndef;
172         int bytes_recv;
173         int ndef_size;
174         int err;
175
176         ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
177         if (ndef == NULL) {
178                 near_error("hr_ndef should exist");
179                 return false;
180         }
181
182         if (ndef->in_extra_read) {
183                 /* Next prepare read to complete the Hr */
184                 new_ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len +
185                                 NDEF_HR_MSG_MIN_LENGTH);
186                 if (new_ndef == NULL)
187                         return false;
188
189                 ndef->ndef = new_ndef;
190
191                 /* Read header bytes */
192                 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
193                                 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
194                 if (bytes_recv < 0)
195                         return handover_recv_error();
196
197                 /* Now, check the ndef payload size plus header bytes */
198                 ndef_size = near_ndef_record_length(ndef->ndef + ndef->cur_ptr,
199                                                                 bytes_recv);
200                 if (ndef_size < 0)
201                         goto fail;
202
203                 ndef->cur_ptr += bytes_recv;
204                 ndef->missing_bytes = ndef_size - bytes_recv;
205
206                 /* Next prepare read to complete the NDEF */
207                 new_ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len
208                                                                 + ndef_size);
209                 if (new_ndef == NULL)
210                         return false;
211
212                 ndef->ndef = new_ndef;
213
214                 ndef->cur_record_len += ndef_size;
215                 ndef->in_extra_read = false;
216
217                 return true;
218         }
219
220         /* Read remaining bytes */
221         bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
222                                         ndef->missing_bytes, MSG_DONTWAIT);
223         if (bytes_recv < 0)
224                 return handover_recv_error();
225
226         ndef->cur_ptr += bytes_recv;
227         ndef->missing_bytes -= bytes_recv;
228
229         /* Is the NDEF read complete ? */
230         if (ndef->missing_bytes)
231                 return true;    /* more bytes to come... */
232
233         if (ndef->extra_ndef_count > 0)
234                 ndef->extra_ndef_count--;
235
236         ndef->in_extra_read = true;
237
238         if (ndef->extra_ndef_count == 0) {
239                 /* All the bytes are read so now, parse the frame */
240                 err = handover_ndef_parse(client_fd, ndef);
241                 if (err > 0) {
242                         /* clean memory */
243                         handover_close(client_fd, 0);
244                         return true;
245                 }
246
247                 return false;
248         }
249
250         /* Process the next NDEF */
251         return true;
252
253 fail:
254         near_error("Handover read NDEFs failed");
255         return false;
256 }
257
258 static bool handover_read_hr(int client_fd,
259                 uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb)
260 {
261         int bytes_recv;
262         int extra_ndefs;
263         struct hr_ndef *ndef;
264
265         DBG("");
266
267         ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
268         if (ndef == NULL)
269                 return false;
270
271         /* Read remaining bytes */
272         bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
273                         ndef->missing_bytes, MSG_DONTWAIT);
274         if (bytes_recv < 0)
275                 return handover_recv_error();
276
277         ndef->cur_ptr += bytes_recv;
278         ndef->missing_bytes -= bytes_recv;
279
280         /* Is the ndef "Hr" read complete or should we loop */
281         if (ndef->missing_bytes)
282                 return true;
283
284         /*
285          * The first NDEF frame is read. We now should determine how many
286          * extra records follow the NDEF frame.
287          * We skip the first 6 bytes (Hr header) to jump on the first record
288          */
289         extra_ndefs = near_ndef_count_records(ndef->ndef + HR_HEADER_SIZE,
290                         ndef->cur_record_len - HR_HEADER_SIZE,
291                         RECORD_TYPE_WKT_ALTERNATIVE_CARRIER);
292         if (extra_ndefs < 0)
293                 goto fail;
294
295         /* There's still some extra ndefs to read */
296         ndef->extra_ndef_count = extra_ndefs;
297
298         /* End of Handover message - now process extra records */
299         ndef->in_extra_read = true;
300         ndef->cfg_record_state = true;
301
302         /* But, if there's no ac record, we jump to the parsing */
303         if (ndef->extra_ndef_count == 0) {
304                 handover_ndef_parse(client_fd, ndef);
305                 return false;
306         }
307
308         return true;
309
310 fail:
311         near_error("Handover read failed");
312         return false;
313 }
314
315 static bool handover_read_initialize(int client_fd,
316                 uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb)
317 {
318         int bytes_recv;
319         struct hr_ndef *ndef;
320
321         DBG("");
322
323         /* Allocate the ndef structure */
324         ndef = g_try_malloc0(sizeof(struct hr_ndef));
325         if (ndef == NULL)
326                 goto fail;
327
328         /* Allocate and read frame header (6 bytes) */
329         ndef->ndef = g_try_malloc0(NDEF_HR_MSG_MIN_LENGTH);
330         if (ndef->ndef == NULL)
331                 goto fail;
332
333         /* Initialize default values */
334         ndef->cur_ptr = 0;
335         ndef->cur_record_len = -1;
336         ndef->adapter_idx = adapter_idx;
337         ndef->target_idx = target_idx;
338         ndef->cb = cb;
339         ndef->cfg_record_state = false;
340
341         g_hash_table_insert(hr_ndef_hash, GINT_TO_POINTER(client_fd), ndef);
342
343         /* Read header bytes (6) */
344         bytes_recv = recv(client_fd, ndef->ndef,
345                                 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
346         if (bytes_recv < 0)
347                 return handover_recv_error();
348
349         /* Now, check the ndef payload size plus header bytes */
350         ndef->cur_record_len = near_ndef_record_length(ndef->ndef, bytes_recv);
351         if (ndef->cur_record_len < 0)
352                 goto fail;
353
354         ndef->cur_ptr += bytes_recv;
355         ndef->missing_bytes = ndef->cur_record_len - bytes_recv;
356
357         if (ndef->cur_record_len == NDEF_HR_MSG_MIN_LENGTH) {
358                 handover_ndef_parse(client_fd, ndef);
359                 return false;
360         }
361
362         DBG("Handover frame size is %d", ndef->cur_ptr);
363
364         /* Next prepare read to complete the read */
365         ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len);
366         if (ndef->ndef == NULL)
367                 goto fail;
368
369         return true;
370
371 fail:
372         free_hr_ndef(ndef);
373
374         return false;
375 }
376
377 /*
378  * This function is a "dispatcher", to read Hr/Hs messages,
379  * and/or additional NDEF messages
380  */
381 static bool handover_read(int client_fd,
382                 uint32_t adapter_idx, uint32_t target_idx,
383                 near_tag_io_cb cb)
384 {
385         struct hr_ndef *ndef;
386
387         ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
388         if (ndef == NULL) {
389                 /* First call: allocate and read header bytes */
390                 return handover_read_initialize(client_fd, adapter_idx,
391                                                 target_idx, cb);
392         }
393
394         if (ndef->cfg_record_state) {
395                 return handover_read_cfg_records(client_fd, adapter_idx,
396                                                         target_idx, cb);
397         }
398
399         return handover_read_hr(client_fd, adapter_idx, target_idx, cb);
400 }
401
402 static void free_hr_push_client(struct hr_push_client *client, int status)
403 {
404         DBG("");
405
406         handover_close(client->fd, 0);
407
408         if (client->cb)
409                 client->cb(client->adapter_idx, client->target_idx, status);
410
411         if (client->watch > 0)
412                 g_source_remove(client->watch);
413
414         g_free(client);
415 }
416
417 static gboolean handover_push_event(GIOChannel *channel,
418                                 GIOCondition condition, gpointer data)
419 {
420         bool ret;
421         struct hr_push_client *client = (struct hr_push_client *) data;
422
423         DBG("condition 0x%x", condition);
424
425         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
426                 near_error("Error with Handover client");
427
428                 free_hr_push_client(client, -EIO);
429
430                 return FALSE;
431         }
432
433         ret = handover_read(client->fd,
434                         client->adapter_idx, client->target_idx,
435                         client->cb);
436
437         if (!ret)
438                 free_hr_push_client(client, 0);
439
440         return ret;
441 }
442
443 static int handover_push(int client_fd,
444                         uint32_t adapter_idx, uint32_t target_idx,
445                         struct near_ndef_message *ndef,
446                         near_device_io_cb cb)
447 {
448         int err;
449         struct hr_push_client *client;
450         GIOChannel *channel;
451
452         DBG("");
453
454         client = g_try_malloc0(sizeof(struct hr_push_client));
455         if (client == NULL)
456                 return -ENOMEM;
457
458         channel = g_io_channel_unix_new(client_fd);
459         g_io_channel_set_close_on_unref(channel, TRUE);
460
461         client->fd = client_fd;
462         client->adapter_idx = adapter_idx;
463         client->target_idx = target_idx;
464         client->cb = cb;
465         client->watch = g_io_add_watch(channel,
466                                         G_IO_IN | G_IO_HUP | G_IO_NVAL |
467                                         G_IO_ERR, handover_push_event,
468                                         (gpointer) client);
469
470         g_io_channel_unref(channel);
471
472         err = send(client_fd, ndef->data, ndef->length, MSG_DONTWAIT);
473         if (err < 0) {
474                 free_hr_push_client(client, err);
475                 g_io_channel_unref(channel);
476         }
477
478         return err;
479 }
480
481 struct near_p2p_driver handover_driver = {
482         .name = "Handover",
483         .service_name = NEAR_DEVICE_SN_HANDOVER,
484         .fallback_service_name = NEAR_DEVICE_SN_SNEP,
485         .sock_type = SOCK_STREAM,
486         .read = handover_read,
487         .push = handover_push,
488         .close = handover_close,
489 };
490
491 int handover_init(void)
492 {
493         hr_ndef_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
494                                                         NULL, free_hr_ndef);
495
496         return near_p2p_register(&handover_driver);
497 }
498
499 void handover_exit(void)
500 {
501         near_p2p_unregister(&handover_driver);
502
503         g_hash_table_destroy(hr_ndef_hash);
504         hr_ndef_hash = NULL;
505 }