8ba550aa7c4d9ea2096dd9e671ca17dc0eb769ef
[profile/ivi/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 #include <linux/nfc.h>
33
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       4
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         g_free(ndef);
94 }
95
96 static void handover_close(int client_fd, int err)
97 {
98         struct hr_ndef *ndef;
99
100         DBG("");
101
102         ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
103         if (ndef == NULL)
104                 return;
105
106         g_hash_table_remove(hr_ndef_hash, GINT_TO_POINTER(client_fd));
107 }
108
109 /* Parse an incoming handover buffer*/
110 static int handover_ndef_parse(int client_fd, struct hr_ndef *ndef)
111 {
112         int err;
113         GList *records;
114         struct near_ndef_message *msg;
115
116         DBG("");
117
118         if ((ndef->ndef == NULL) ||
119                         (ndef->cur_ptr < NDEF_HR_MSG_MIN_LENGTH)) {
120                 err = -EINVAL;
121                 goto fail;
122         }
123
124         /* call the global parse function */
125         records = near_ndef_parse(ndef->ndef, ndef->cur_ptr);
126         if (records == NULL) {
127                 err = -ENOMEM;
128                 goto fail;
129         }
130
131         /*
132          * If we receive a request, we should reply with a Hs but
133          * if the initial frame is Hs (it means we initiated the
134          * exchange with a Hr), so we have to do some actions (e.g.:
135          * pairing with bluetooth)
136          */
137         if (strncmp((char *)(ndef->ndef + FRAME_TYPE_OFFSET), "Hr", 2) == 0) {
138                 /*
139                  * The first entry on the record list is the Hr record.
140                  * We build the Hs based on it.
141                  */
142                 msg = near_ndef_prepare_handover_record("Hs", records->data,
143                                                         NEAR_CARRIER_BLUETOOTH);
144
145                 near_info("Send Hs frame");
146                 err = send(client_fd, msg->data, msg->length, MSG_DONTWAIT);
147                 if (err >= 0)
148                         err = 0;
149
150                 g_free(msg->data);
151                 g_free(msg);
152         } else {
153                 err = 0;
154         }
155
156         near_ndef_records_free(records);
157
158         return err;
159
160 fail:
161         near_error("ndef parsing failed (%d)", err);
162
163         handover_close(client_fd, 0);
164
165         return err;
166 }
167
168 static near_bool_t handover_recv_error(void)
169 {
170         near_error("%s", strerror(errno));
171
172         if (errno == EAGAIN)
173                 return TRUE;
174
175         return FALSE;
176 }
177
178 /* Add extra records right after the end of the "Hr" ndef record */
179 static near_bool_t handover_read_cfg_records(int client_fd,
180                                 uint32_t adapter_idx, uint32_t target_idx,
181                                 near_tag_io_cb cb)
182 {
183         struct hr_ndef *ndef;
184         int bytes_recv;
185         int ndef_size;
186
187         ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
188         if (ndef == NULL) {
189                 near_error("hr_ndef should exist !!!");
190                 return FALSE;
191         }
192
193         if (ndef->in_extra_read == TRUE) {
194                 /* Next prepare read to complete the Hr */
195                 ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len +
196                                 NDEF_HR_MSG_MIN_LENGTH);
197                 if (ndef == NULL)
198                         return FALSE;
199
200                 /* Read header bytes */
201                 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
202                                 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
203                 if (bytes_recv < 0)
204                         return handover_recv_error();
205
206                 /* Now, check the ndef payload size plus header bytes */
207                 ndef_size = near_ndef_record_length(ndef->ndef + ndef->cur_ptr,
208                                                                 bytes_recv);
209                 if (ndef_size < 0)
210                         goto fail;
211
212                 ndef->cur_ptr += bytes_recv;
213                 ndef->missing_bytes = ndef_size - bytes_recv;
214
215                 /* Next prepare read to complete the NDEF */
216                 ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len
217                                                                 + ndef_size);
218                 if (ndef->ndef == NULL) {
219                         g_free(ndef);
220                         return FALSE;
221                 }
222                 ndef->cur_record_len += ndef_size;
223                 ndef->in_extra_read = FALSE;
224
225                 return TRUE;
226         }
227
228         /* Read remaining bytes */
229         bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
230                                         ndef->missing_bytes, MSG_DONTWAIT);
231         if (bytes_recv < 0)
232                 return handover_recv_error();
233
234         ndef->cur_ptr += bytes_recv;
235         ndef->missing_bytes -= bytes_recv;
236
237         /* Is the NDEF read complete ? */
238         if (ndef->missing_bytes)
239                 return TRUE;    /* more bytes to come... */
240
241         ndef->extra_ndef_count--;
242         ndef->in_extra_read = TRUE;
243
244         if (ndef->extra_ndef_count == 0) {
245                 /* All the bytes are read so now, parse the frame */
246                 handover_ndef_parse(client_fd, ndef);
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 near_bool_t 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         return TRUE;
303
304 fail:
305         near_error("Handover read failed");
306         return FALSE;
307 }
308
309 static near_bool_t handover_read_initialize(int client_fd,
310                 uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb)
311 {
312         int bytes_recv;
313         struct hr_ndef *ndef;
314
315         DBG("");
316
317         /* Allocate the ndef structure */
318         ndef = g_try_malloc0(sizeof(struct hr_ndef));
319         if (ndef == NULL)
320                 goto fail;
321
322         /* Allocate and read frame header (6 bytes) */
323         ndef->ndef = g_try_malloc0(NDEF_HR_MSG_MIN_LENGTH);
324         if (ndef->ndef == NULL)
325                 goto fail;
326
327         /* Initialize default values */
328         ndef->cur_ptr = 0;
329         ndef->cur_record_len = -1;
330         ndef->adapter_idx = adapter_idx;
331         ndef->target_idx = target_idx;
332         ndef->cb = cb;
333         ndef->cfg_record_state = FALSE;
334
335         g_hash_table_insert(hr_ndef_hash, GINT_TO_POINTER(client_fd), ndef);
336
337         /* Read header bytes (6) */
338         bytes_recv = recv(client_fd, ndef->ndef,
339                                 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
340         if (bytes_recv < 0)
341                 return handover_recv_error();
342
343         /* Now, check the ndef payload size plus header bytes */
344         ndef->cur_record_len = near_ndef_record_length(ndef->ndef, bytes_recv);
345         if (ndef->cur_record_len < 0)
346                 goto fail;
347
348         ndef->cur_ptr += bytes_recv;
349         ndef->missing_bytes = ndef->cur_record_len - bytes_recv;
350
351         DBG("Handover frame size is %d", ndef->cur_ptr);
352
353         /* Next prepare read to complete the read */
354         ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len);
355         if (ndef->ndef == NULL)
356                 goto fail;
357
358         return TRUE;
359
360 fail:
361         free_hr_ndef(ndef);
362
363         return FALSE;
364 }
365
366 /*
367  * This function is a "dispatcher", to read Hr/Hs messages,
368  * and/or additional NDEF messages
369  */
370 static near_bool_t handover_read(int client_fd,
371                 uint32_t adapter_idx, uint32_t target_idx,
372                 near_tag_io_cb cb)
373 {
374         struct hr_ndef *ndef;
375
376         ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
377         if (ndef == NULL) {
378                 /* First call: allocate and read header bytes*/
379                 return handover_read_initialize(client_fd, adapter_idx,
380                                                 target_idx, cb);
381         }
382
383         if (ndef->cfg_record_state == TRUE) {
384                 return handover_read_cfg_records(client_fd, adapter_idx,
385                                                         target_idx, cb);
386         }
387
388         return handover_read_hr(client_fd, adapter_idx, target_idx, cb);
389 }
390
391 static void free_hr_push_client(struct hr_push_client *client, int status)
392 {
393         DBG("");
394
395         handover_close(client->fd, 0);
396         close(client->fd);
397
398         if (client->cb)
399                 client->cb(client->adapter_idx, client->target_idx, status);
400
401         if (client->watch > 0)
402                 g_source_remove(client->watch);
403
404         g_free(client);
405 }
406
407 static gboolean handover_push_event(GIOChannel *channel,
408                                 GIOCondition condition, gpointer data)
409 {
410         near_bool_t ret;
411         struct hr_push_client *client = (struct hr_push_client *)data;
412
413         DBG("condition 0x%x", condition);
414
415         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
416                 near_error("Error with Handover client");
417
418                 free_hr_push_client(client, -EIO);
419
420                 return FALSE;
421         }
422
423         ret = handover_read(client->fd,
424                         client->adapter_idx, client->target_idx,
425                         client->cb);
426
427         if (ret == FALSE)
428                 free_hr_push_client(client, 0);
429
430         return ret;
431 }
432
433 static int handover_push(int client_fd,
434                         uint32_t adapter_idx, uint32_t target_idx,
435                         struct near_ndef_message *ndef,
436                         near_device_io_cb cb)
437 {
438         int err;
439         struct hr_push_client *client;
440         GIOChannel *channel;
441
442         DBG("");
443
444         client = g_try_malloc0(sizeof(struct hr_push_client));
445         if (client == NULL)
446                 return -ENOMEM;
447
448         channel = g_io_channel_unix_new(client_fd);
449         g_io_channel_set_close_on_unref(channel, TRUE);
450
451         client->fd = client_fd;
452         client->adapter_idx = adapter_idx;
453         client->target_idx = target_idx;
454         client->cb = cb;
455         client->watch = g_io_add_watch(channel,
456                                         G_IO_IN | G_IO_HUP | G_IO_NVAL |
457                                         G_IO_ERR, handover_push_event,
458                                         (gpointer) client);
459
460         err = send(client_fd, ndef->data, ndef->length, MSG_DONTWAIT);
461         if (err < 0)
462                 free_hr_push_client(client, err);
463
464         return err;
465 }
466
467 struct near_p2p_driver handover_driver = {
468         .name = "Handover",
469         .service_name = NEAR_DEVICE_SN_HANDOVER,
470         .read = handover_read,
471         .push = handover_push,
472         .close = handover_close,
473 };
474
475 int handover_init(void)
476 {
477         hr_ndef_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
478                                                         NULL, free_hr_ndef);
479
480         return near_p2p_register(&handover_driver);
481 }
482
483 void handover_exit(void)
484 {
485         near_p2p_unregister(&handover_driver);
486
487         g_hash_table_destroy(hr_ndef_hash);
488         hr_ndef_hash = NULL;
489 }