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