2ec0af6d88f4af4bc72815b258125360acf63d6b
[profile/ivi/neard.git] / src / adapter.c
1 /*
2  *
3  *  neard - Near Field Communication manager
4  *
5  *  Copyright (C) 2011  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 <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <string.h>
31
32 #include <glib.h>
33
34 #include <gdbus.h>
35
36 #include "near.h"
37
38 /* We check for the tag being present every 2 seconds */
39 #define CHECK_PRESENCE_PERIOD 2
40
41 static DBusConnection *connection = NULL;
42
43 static GHashTable *adapter_hash;
44
45 #define NEAR_ADAPTER_MODE_INITIATOR 0x1
46 #define NEAR_ADAPTER_MODE_TARGET    0x2
47 #define NEAR_ADAPTER_MODE_DUAL      0x3
48
49 struct near_adapter {
50         char *path;
51
52         char *name;
53         uint32_t idx;
54         uint32_t protocols;
55         uint32_t poll_mode;
56         uint32_t rf_mode;
57
58         near_bool_t powered;
59         near_bool_t polling;
60         near_bool_t constant_poll;
61         near_bool_t dep_up;
62
63         GHashTable *tags;
64         struct near_tag *tag_link;
65         int tag_sock;
66
67         GHashTable *devices;
68         struct near_device *device_link;
69         int device_sock;
70
71         GIOChannel *channel;
72         guint watch;
73         GList *ioreq_list;
74
75         guint presence_timeout;
76 };
77
78 struct near_adapter_ioreq {
79         uint32_t target_idx;
80         near_recv cb;
81         unsigned char buf[1024];
82         size_t len;
83         void *data;
84 };
85
86 /* HACK HACK */
87 #ifndef AF_NFC
88 #define AF_NFC 39
89 #endif
90
91 static void free_adapter(gpointer data)
92 {
93         struct near_adapter *adapter = data;
94
95         if (adapter->presence_timeout > 0)
96                 g_source_remove(adapter->presence_timeout);
97
98         g_free(adapter->name);
99         g_free(adapter->path);
100         g_free(adapter);
101 }
102
103 static void free_tag(gpointer data)
104 {
105         struct near_tag *tag = data;
106
107         __near_tag_remove(tag);
108 }
109
110 static void free_device(gpointer data)
111 {
112         struct near_device *device = data;
113
114         __near_device_remove(device);
115 }
116
117 static void polling_changed(struct near_adapter *adapter)
118 {
119
120         near_dbus_property_changed_basic(adapter->path,
121                                         NFC_ADAPTER_INTERFACE, "Polling",
122                                         DBUS_TYPE_BOOLEAN, &adapter->polling);
123 }
124
125 static int adapter_start_poll(struct near_adapter *adapter)
126 {
127         int err;
128         uint32_t im_protos, tm_protos;
129
130         if (g_hash_table_size(adapter->tags) > 0) {
131                 DBG("Clearing tags");
132
133                 g_hash_table_remove_all(adapter->tags);
134                 __near_adapter_tags_changed(adapter->idx);
135         }
136
137         if (g_hash_table_size(adapter->devices) > 0) {
138                 DBG("Clearing devices");
139
140                 g_hash_table_remove_all(adapter->devices);
141                 __near_adapter_devices_changed(adapter->idx);
142         }
143
144         DBG("Poll mode 0x%x", adapter->poll_mode);
145
146         im_protos = tm_protos = 0;
147
148         if (adapter->poll_mode & NEAR_ADAPTER_MODE_INITIATOR)
149                 im_protos = adapter->protocols;
150
151         if (adapter->poll_mode & NEAR_ADAPTER_MODE_TARGET)
152                 tm_protos = adapter->protocols;
153
154         err = __near_netlink_start_poll(adapter->idx, im_protos, tm_protos);
155         if (err < 0)
156                 return err;
157
158         adapter->polling = TRUE;
159
160         polling_changed(adapter);
161
162         return 0;
163 }
164
165 static void append_path(gpointer key, gpointer value, gpointer user_data)
166 {
167         struct near_adapter *adapter = value;
168         DBusMessageIter *iter = user_data;
169
170         DBG("%s", adapter->path);
171
172         if (adapter->path == NULL)
173                 return;
174
175         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
176                                                         &adapter->path);
177 }
178
179 void __near_adapter_list(DBusMessageIter *iter, void *user_data)
180 {
181         g_hash_table_foreach(adapter_hash, append_path, iter);
182 }
183
184 static void append_protocols(DBusMessageIter *iter, void *user_data)
185 {
186         struct near_adapter *adapter = user_data;
187         const char *str;
188
189         DBG("protocols 0x%x", adapter->protocols);
190
191         if (adapter->protocols & NFC_PROTO_FELICA_MASK) {
192                 str = "Felica";
193
194                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
195         }
196
197         if (adapter->protocols & NFC_PROTO_MIFARE_MASK) {
198                 str = "MIFARE";
199
200                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
201         }
202
203         if (adapter->protocols & NFC_PROTO_JEWEL_MASK) {
204                 str = "Jewel";
205
206                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
207         }
208
209         if (adapter->protocols & NFC_PROTO_ISO14443_MASK) {
210                 str = "ISO-DEP";
211
212                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
213         }
214
215         if (adapter->protocols & NFC_PROTO_NFC_DEP_MASK) {
216                 str = "NFC-DEP";
217
218                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
219         }
220 }
221
222 static void append_tag_path(gpointer key, gpointer value, gpointer user_data)
223 {
224         struct near_tag *tag = value;
225         DBusMessageIter *iter = user_data;
226         const char *tag_path;
227
228         tag_path = __near_tag_get_path(tag);
229         if (tag_path == NULL)
230                 return;
231
232         DBG("%s", tag_path);
233
234         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &tag_path);
235 }
236
237 static void append_tags(DBusMessageIter *iter, void *user_data)
238 {
239         struct near_adapter *adapter = user_data;
240
241         DBG("");
242
243         g_hash_table_foreach(adapter->tags, append_tag_path, iter);
244 }
245
246 static void append_device_path(gpointer key, gpointer value, gpointer user_data)
247 {
248         struct near_device *device = value;
249         DBusMessageIter *iter = user_data;
250         const char *device_path;
251
252         device_path = __near_device_get_path(device);
253         if (device_path == NULL)
254                 return;
255
256         DBG("%s", device_path);
257
258         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
259                                                         &device_path);
260 }
261
262 static void append_devices(DBusMessageIter *iter, void *user_data)
263 {
264         struct near_adapter *adapter = user_data;
265
266         DBG("");
267
268         g_hash_table_foreach(adapter->devices, append_device_path, iter);
269 }
270
271 void __near_adapter_tags_changed(uint32_t adapter_idx)
272 {
273         struct near_adapter *adapter;
274
275         DBG("");
276
277         adapter = g_hash_table_lookup(adapter_hash,
278                                         GINT_TO_POINTER(adapter_idx));
279         if (adapter == NULL)
280                 return;
281
282         near_dbus_property_changed_array(adapter->path,
283                                         NFC_ADAPTER_INTERFACE, "Tags",
284                                         DBUS_TYPE_OBJECT_PATH, append_tags,
285                                         adapter);
286 }
287
288 void __near_adapter_devices_changed(uint32_t adapter_idx)
289 {
290         struct near_adapter *adapter;
291
292         DBG("");
293
294         adapter = g_hash_table_lookup(adapter_hash,
295                                         GINT_TO_POINTER(adapter_idx));
296         if (adapter == NULL)
297                 return;
298
299         near_dbus_property_changed_array(adapter->path,
300                                         NFC_ADAPTER_INTERFACE, "Devices",
301                                         DBUS_TYPE_OBJECT_PATH, append_devices,
302                                         adapter);
303 }
304
305 static DBusMessage *get_properties(DBusConnection *conn,
306                                         DBusMessage *msg, void *data)
307 {
308         struct near_adapter *adapter = data;
309         DBusMessage *reply;
310         DBusMessageIter array, dict;
311
312         DBG("conn %p", conn);
313
314         reply = dbus_message_new_method_return(msg);
315         if (reply == NULL)
316                 return NULL;
317
318         dbus_message_iter_init_append(reply, &array);
319
320         near_dbus_dict_open(&array, &dict);
321
322         near_dbus_dict_append_basic(&dict, "Powered",
323                                     DBUS_TYPE_BOOLEAN, &adapter->powered);
324
325         near_dbus_dict_append_basic(&dict, "Polling",
326                                     DBUS_TYPE_BOOLEAN, &adapter->polling);
327
328         near_dbus_dict_append_array(&dict, "Protocols",
329                                 DBUS_TYPE_STRING, append_protocols, adapter);
330
331         near_dbus_dict_append_array(&dict, "Tags",
332                                 DBUS_TYPE_OBJECT_PATH, append_tags, adapter);
333
334         near_dbus_dict_append_array(&dict, "Devices",
335                                 DBUS_TYPE_OBJECT_PATH, append_devices, adapter);
336
337         near_dbus_dict_close(&array, &dict);
338
339         return reply;
340 }
341
342 static DBusMessage *set_property(DBusConnection *conn,
343                                         DBusMessage *msg, void *data)
344 {
345         struct near_adapter *adapter = data;
346         DBusMessageIter iter, value;
347         const char *name;
348         int type, err;
349
350         DBG("conn %p", conn);
351
352         if (dbus_message_iter_init(msg, &iter) == FALSE)
353                 return __near_error_invalid_arguments(msg);
354
355         dbus_message_iter_get_basic(&iter, &name);
356         dbus_message_iter_next(&iter);
357         dbus_message_iter_recurse(&iter, &value);
358
359         type = dbus_message_iter_get_arg_type(&value);
360
361         if (g_str_equal(name, "Powered") == TRUE) {
362                 near_bool_t powered;
363
364                 if (type != DBUS_TYPE_BOOLEAN)
365                         return __near_error_invalid_arguments(msg);
366
367                 dbus_message_iter_get_basic(&value, &powered);
368
369                 err = __near_netlink_adapter_enable(adapter->idx, powered);
370                 if (err < 0) {
371                         if (err == -EALREADY)
372                                 return __near_error_already_enabled(msg);
373
374                         return __near_error_failed(msg, -err);
375                 }
376
377                 adapter->powered = powered;
378         } else {
379                 return __near_error_invalid_property(msg);
380         }
381
382         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
383 }
384
385 static DBusMessage *start_poll_loop(DBusConnection *conn,
386                                         DBusMessage *msg, void *data)
387 {
388         struct near_adapter *adapter = data;
389         const char *dbus_mode;
390         int err;
391
392         DBG("conn %p", conn);
393
394         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &dbus_mode,
395                                                         DBUS_TYPE_INVALID);
396
397         DBG("Mode %s", dbus_mode);
398
399         if (g_strcmp0(dbus_mode, "Initiator") == 0)
400                 adapter->poll_mode = NEAR_ADAPTER_MODE_INITIATOR;
401         else if (g_strcmp0(dbus_mode, "Target") == 0)
402                 adapter->poll_mode = NEAR_ADAPTER_MODE_TARGET;
403         else if (g_strcmp0(dbus_mode, "Dual") == 0)
404                 adapter->poll_mode = NEAR_ADAPTER_MODE_DUAL;
405         else
406                 adapter->poll_mode = NEAR_ADAPTER_MODE_INITIATOR;
407
408         err = adapter_start_poll(adapter);
409         if (err < 0)
410                 return __near_error_failed(msg, -err);
411
412         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
413 }
414
415 static DBusMessage *stop_poll_loop(DBusConnection *conn,
416                                         DBusMessage *msg, void *data)
417 {
418         struct near_adapter *adapter = data;
419         int err;
420
421         DBG("conn %p", conn);
422
423         err = __near_netlink_stop_poll(adapter->idx);
424         if (err < 0)
425                 return __near_error_failed(msg, -err);
426
427         adapter->polling = FALSE;
428
429         polling_changed(adapter);
430
431         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
432 }
433
434 static void tag_present_cb(uint32_t adapter_idx, uint32_t target_idx,
435                                                                 int status);
436
437 static gboolean check_presence(gpointer user_data)
438 {
439         struct near_adapter *adapter = user_data;
440         struct near_tag *tag;
441         int err;
442
443         DBG("");
444
445         if (adapter == NULL)
446                 return FALSE;
447
448         tag = adapter->tag_link;
449         if (tag == NULL)
450                 goto out_err;
451
452         err = __near_tag_check_presence(tag, tag_present_cb);
453         if (err < 0) {
454                 DBG("Could not check target presence");
455                 goto out_err;
456         }
457
458         return FALSE;
459
460 out_err:
461         near_adapter_disconnect(adapter->idx);
462         if (adapter->constant_poll == TRUE)
463                 adapter_start_poll(adapter);
464
465         return FALSE;
466 }
467
468 static void tag_present_cb(uint32_t adapter_idx, uint32_t target_idx,
469                                                                 int status)
470 {
471         struct near_adapter *adapter;
472
473         DBG("");
474
475         adapter = g_hash_table_lookup(adapter_hash,
476                                         GINT_TO_POINTER(adapter_idx));
477         if (adapter == NULL)
478                 return;
479
480         if (status < 0) {
481                 DBG("Tag is gone");
482
483                 near_adapter_disconnect(adapter->idx);
484                 if (adapter->constant_poll == TRUE)
485                         adapter_start_poll(adapter);
486
487                 return;
488         }
489
490         adapter->presence_timeout =
491                 g_timeout_add_seconds(CHECK_PRESENCE_PERIOD,
492                                         check_presence, adapter);
493 }
494
495 static const GDBusMethodTable adapter_methods[] = {
496         { GDBUS_METHOD("GetProperties",
497                                 NULL, GDBUS_ARGS({"properties", "a{sv}"}),
498                                 get_properties) },
499         { GDBUS_METHOD("SetProperty",
500                                 GDBUS_ARGS({"name", "s"}, {"value", "v"}),
501                                 NULL, set_property) },
502         { GDBUS_METHOD("StartPollLoop", GDBUS_ARGS({"name", "s"}), NULL,
503                                                         start_poll_loop) },
504         { GDBUS_METHOD("StopPollLoop", NULL, NULL, stop_poll_loop) },
505         { },
506 };
507
508 static const GDBusSignalTable adapter_signals[] = {
509         { GDBUS_SIGNAL("PropertyChanged",
510                                 GDBUS_ARGS({"name", "s"}, {"value", "v"})) },
511         { GDBUS_SIGNAL("TagFound", GDBUS_ARGS({"address", "o"})) },
512         { GDBUS_SIGNAL("TagLost", GDBUS_ARGS({"address", "o"})) },
513         { }
514 };
515
516 struct near_adapter * __near_adapter_create(uint32_t idx,
517                 const char *name, uint32_t protocols, near_bool_t powered)
518 {
519         struct near_adapter *adapter;
520
521         adapter = g_try_malloc0(sizeof(struct near_adapter));
522         if (adapter == NULL)
523                 return NULL;
524
525         adapter->name = g_strdup(name);
526         if (adapter->name == NULL) {
527                 g_free(adapter);
528                 return NULL;
529         }
530         adapter->idx = idx;
531         adapter->protocols = protocols;
532         adapter->powered = powered;
533         adapter->constant_poll = near_setting_get_bool("ConstantPoll");
534         adapter->dep_up = FALSE;
535         adapter->tags = g_hash_table_new_full(g_direct_hash, g_direct_equal,
536                                                         NULL, free_tag);
537         adapter->tag_sock = -1;
538
539         adapter->devices = g_hash_table_new_full(g_direct_hash, g_direct_equal,
540                                                         NULL, free_device);
541         adapter->device_sock = -1;
542
543         adapter->path = g_strdup_printf("%s/nfc%d", NFC_PATH, idx);
544
545         return adapter;
546 }
547
548 void __near_adapter_destroy(struct near_adapter *adapter)
549 {
550         DBG("");
551
552         free_adapter(adapter);
553 }
554
555 const char *__near_adapter_get_path(struct near_adapter *adapter)
556 {
557         return adapter->path;
558 }
559
560 struct near_adapter *__near_adapter_get(uint32_t idx)
561 {
562         return g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
563 }
564
565 int __near_adapter_set_dep_state(uint32_t idx, near_bool_t dep)
566 {
567         struct near_adapter *adapter;
568
569         DBG("idx %d", idx);
570
571         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
572         if (adapter == NULL)
573                 return -ENODEV;
574
575         adapter->dep_up = dep;
576
577         if (dep == FALSE && adapter->constant_poll == TRUE)
578                 adapter_start_poll(adapter);
579
580         return 0;
581 }
582
583 near_bool_t __near_adapter_get_dep_state(uint32_t idx)
584 {
585         struct near_adapter *adapter;
586
587         DBG("idx %d", idx);
588
589         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
590         if (adapter == NULL)
591                 return FALSE;
592
593         return adapter->dep_up;
594 }
595
596 int __near_adapter_add(struct near_adapter *adapter)
597 {
598         uint32_t idx = adapter->idx;
599
600         DBG("%s", adapter->path);
601
602         if (g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx)) != NULL)
603                 return -EEXIST;
604
605         g_hash_table_insert(adapter_hash, GINT_TO_POINTER(idx), adapter);
606
607         DBG("connection %p", connection);
608
609         g_dbus_register_interface(connection, adapter->path,
610                                         NFC_ADAPTER_INTERFACE,
611                                         adapter_methods, adapter_signals,
612                                         NULL, adapter, NULL);
613
614         return 0;
615 }
616
617 void __near_adapter_remove(struct near_adapter *adapter)
618 {
619         DBG("%s", adapter->path);
620
621         g_dbus_unregister_interface(connection, adapter->path,
622                                                 NFC_ADAPTER_INTERFACE);
623
624         g_hash_table_remove(adapter_hash, GINT_TO_POINTER(adapter->idx));
625 }
626
627 static void tag_read_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
628 {
629         struct near_adapter *adapter;
630
631         DBG("status %d", status);
632
633         adapter = g_hash_table_lookup(adapter_hash,
634                                         GINT_TO_POINTER(adapter_idx));
635         if (adapter == NULL)
636                 return;
637
638         if (status < 0) {
639                 near_adapter_disconnect(adapter->idx);
640                 if (adapter->constant_poll == TRUE)
641                         adapter_start_poll(adapter);
642
643                 return;
644         }
645
646         __near_adapter_tags_changed(adapter_idx);
647
648         adapter->presence_timeout =
649                 g_timeout_add_seconds(CHECK_PRESENCE_PERIOD,
650                                         check_presence, adapter);
651 }
652
653 static void device_read_cb(uint32_t adapter_idx, uint32_t target_idx,
654                                                                 int status)
655 {
656         struct near_adapter *adapter;
657
658         DBG("status %d", status);
659
660         adapter = g_hash_table_lookup(adapter_hash,
661                                         GINT_TO_POINTER(adapter_idx));
662         if (adapter == NULL)
663                 return;
664
665         if (status < 0) {
666                 if (adapter->device_link != NULL) {
667                         __near_netlink_dep_link_down(adapter->idx);
668                         adapter->device_link = NULL;
669                 }
670
671                 if (adapter->constant_poll == TRUE)
672                         adapter_start_poll(adapter);
673
674                 return;
675         }
676
677         __near_adapter_devices_changed(adapter_idx);
678 }
679
680 static int adapter_add_tag(struct near_adapter *adapter, uint32_t target_idx,
681                         uint32_t protocols,
682                         uint16_t sens_res, uint8_t sel_res,
683                         uint8_t *nfcid, uint8_t nfcid_len)
684 {
685         struct near_tag *tag;
686         uint32_t tag_type;
687         int err;
688
689         tag = __near_tag_add(adapter->idx, target_idx, protocols,
690                                 sens_res, sel_res,
691                                 nfcid, nfcid_len);
692         if (tag == NULL)
693                 return -ENODEV;
694
695         g_hash_table_insert(adapter->tags, GINT_TO_POINTER(target_idx), tag);
696
697         tag_type = __near_tag_get_type(tag);
698
699         err = near_adapter_connect(adapter->idx, target_idx, tag_type);
700         if (err < 0) {
701                 near_error("Could not connect");
702                 return err;
703         }
704
705         return __near_tag_read(tag, tag_read_cb);
706 }
707
708 static int adapter_add_device(struct near_adapter *adapter,
709                                 uint32_t target_idx,
710                                 uint8_t *nfcid, uint8_t nfcid_len)
711 {
712         struct near_device *device;
713         int err;
714
715         device = __near_device_add(adapter->idx, target_idx, nfcid, nfcid_len);
716         if (device == NULL)
717                 return -ENODEV;
718
719         g_hash_table_insert(adapter->devices, GINT_TO_POINTER(target_idx),
720                                                                 device);
721
722         /* For p2p, reading is listening for an incoming connection */
723         err = __near_device_listen(device, device_read_cb);
724         if (err < 0) {
725                 near_error("Could not read device");
726                 return err;
727         }
728
729         adapter->device_link = device;
730
731         if (adapter->dep_up == TRUE)
732                 return 0;
733
734         err = __near_netlink_dep_link_up(adapter->idx, target_idx,
735                                         NFC_COMM_ACTIVE, NFC_RF_INITIATOR);
736
737         if (err < 0)
738                 adapter->device_link = NULL;
739
740         return err;
741 }
742
743 int __near_adapter_add_target(uint32_t idx, uint32_t target_idx,
744                         uint32_t protocols, uint16_t sens_res, uint8_t sel_res,
745                         uint8_t *nfcid, uint8_t nfcid_len)
746 {
747         struct near_adapter *adapter;
748
749         DBG("idx %d", idx);
750
751         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
752         if (adapter == NULL)
753                 return -ENODEV;
754
755         adapter->polling = FALSE;
756         polling_changed(adapter);
757
758         if (protocols & NFC_PROTO_NFC_DEP_MASK)
759                 return adapter_add_device(adapter, target_idx,
760                                                 nfcid, nfcid_len);
761         else
762                 return adapter_add_tag(adapter, target_idx, protocols,
763                                         sens_res, sel_res, nfcid, nfcid_len);
764 }
765
766 int __near_adapter_remove_target(uint32_t idx, uint32_t target_idx)
767 {
768         struct near_adapter *adapter;
769
770         DBG("idx %d", idx);
771
772         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
773         if (adapter == NULL)
774                 return -ENODEV;
775
776         if (g_hash_table_remove(adapter->tags,
777                         GINT_TO_POINTER(target_idx)) == TRUE) {
778                 __near_adapter_tags_changed(idx);
779
780                 return 0;
781         }
782
783         if (g_hash_table_remove(adapter->devices,
784                         GINT_TO_POINTER(target_idx)) == TRUE) {
785                 __near_adapter_devices_changed(idx);
786
787                 return 0;
788         }
789
790         return 0;
791 }
792
793 int __near_adapter_add_device(uint32_t idx, uint8_t *nfcid, uint8_t nfcid_len)
794 {
795         struct near_adapter *adapter;
796
797         DBG("idx %d", idx);
798
799         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
800         if (adapter == NULL)
801                 return -ENODEV;
802
803         adapter->polling = FALSE;
804         adapter->dep_up = TRUE;
805         polling_changed(adapter);
806
807         return adapter_add_device(adapter, 0, nfcid, nfcid_len);
808 }
809
810 int __near_adapter_remove_device(uint32_t idx)
811 {
812         struct near_adapter *adapter;
813         uint32_t device_idx = 0;
814
815         DBG("idx %d", idx);
816
817         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
818         if (adapter == NULL)
819                 return -ENODEV;
820
821         if (g_hash_table_remove(adapter->devices,
822                         GINT_TO_POINTER(device_idx)) == FALSE)
823                 return 0;
824
825         __near_adapter_devices_changed(idx);
826
827         adapter->dep_up = FALSE;
828
829         if (adapter->constant_poll == TRUE)
830                 adapter_start_poll(adapter);
831
832         return 0;
833 }
834
835 static void adapter_flush_rx(struct near_adapter *adapter, int error)
836 {
837         GList *list;
838
839         for (list = adapter->ioreq_list; list; list = list->next) {
840                 struct near_adapter_ioreq *req = list->data;
841
842                 if (req == NULL)
843                         continue;
844
845                 req->cb(NULL, error, req->data);
846                 g_free(req);
847         }
848
849         g_list_free(adapter->ioreq_list);
850         adapter->ioreq_list = NULL;
851 }
852
853 static gboolean execute_recv_cb(gpointer user_data)
854 {
855         struct near_adapter_ioreq *req = user_data;
856
857         DBG("data %p", req->data);
858
859         req->cb(req->buf, req->len, req->data);
860
861         g_free(req);
862
863         return FALSE;
864 }
865
866 static gboolean adapter_recv_event(GIOChannel *channel, GIOCondition condition,
867                                                         gpointer user_data)
868 {
869         struct near_adapter *adapter = user_data;
870         struct near_adapter_ioreq *req;
871         GList *first;
872         int sk;
873
874         DBG("condition 0x%x", condition);
875
876         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
877                 near_error("Error while reading NFC bytes");
878
879                 adapter_flush_rx(adapter, -EIO);
880
881                 near_adapter_disconnect(adapter->idx);
882
883                 adapter->presence_timeout =
884                         g_timeout_add_seconds(2 * CHECK_PRESENCE_PERIOD,
885                                               check_presence, adapter);
886                 return FALSE;
887         }
888
889         sk = g_io_channel_unix_get_fd(channel);
890         first = g_list_first(adapter->ioreq_list);
891         if (first == NULL)
892                 return TRUE;
893
894         req = first->data;
895         req->len = recv(sk, req->buf, sizeof(req->buf), 0);
896
897         adapter->ioreq_list = g_list_remove(adapter->ioreq_list, req);
898
899         g_idle_add(execute_recv_cb, req);
900
901         return TRUE;
902 }
903
904 int near_adapter_connect(uint32_t idx, uint32_t target_idx, uint8_t protocol)
905 {
906         struct near_adapter *adapter;
907         struct near_tag *tag;
908         struct sockaddr_nfc addr;
909         int err, sock;
910
911         DBG("idx %d", idx);
912
913         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
914         if (adapter == NULL)
915                 return -ENODEV;
916
917         if (adapter->tag_sock != -1)
918                 return -EALREADY;
919
920         tag = g_hash_table_lookup(adapter->tags,
921                                 GINT_TO_POINTER(target_idx));
922         if (tag == NULL)
923                 return -ENOLINK;
924
925         sock = socket(AF_NFC, SOCK_SEQPACKET, NFC_SOCKPROTO_RAW);
926         if (sock == -1)
927                 return sock;
928
929         addr.sa_family = AF_NFC;
930         addr.dev_idx = idx;
931         addr.target_idx = target_idx;
932         addr.nfc_protocol = protocol;
933
934         err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
935         if (err) {
936                 close(sock);
937                 return err;
938         }
939
940         adapter->tag_sock = sock;
941         adapter->tag_link = tag;
942
943         if (adapter->channel == NULL)
944                 adapter->channel = g_io_channel_unix_new(adapter->tag_sock);
945
946         g_io_channel_set_flags(adapter->channel, G_IO_FLAG_NONBLOCK, NULL);
947         g_io_channel_set_close_on_unref(adapter->channel, TRUE);
948
949         if (adapter->watch == 0)
950                 adapter->watch = g_io_add_watch(adapter->channel,
951                                 G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
952                                                 adapter_recv_event, adapter);
953
954         return 0;
955 }
956
957 int near_adapter_disconnect(uint32_t idx)
958 {
959         struct near_adapter *adapter;
960         uint32_t target_idx;
961         uint16_t tag_type;
962
963         DBG("idx %d", idx);
964
965         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
966         if (adapter == NULL)
967                 return -ENODEV;
968
969         DBG("link %p", adapter->tag_link);
970
971         if (adapter->tag_link == NULL)
972                 return -ENOLINK;
973
974         tag_type = __near_tag_get_type(adapter->tag_link);
975         target_idx = __near_tag_get_idx(adapter->tag_link);
976
977         DBG("tag type %d", tag_type);
978
979         __near_adapter_remove_target(adapter->idx, target_idx);
980
981         if (adapter->tag_sock == -1)
982                 return -ENOLINK;
983
984         if (adapter->watch > 0) {
985                 g_source_remove(adapter->watch);
986                 adapter->watch = 0;
987         }
988
989         g_io_channel_unref(adapter->channel);
990         adapter->channel = NULL;
991         adapter->tag_sock = -1;
992         adapter->tag_link = NULL;
993
994         return 0;
995 }
996
997 int near_adapter_send(uint32_t idx, uint8_t *buf, size_t length,
998                         near_recv cb, void *data)
999 {
1000         struct near_adapter *adapter;
1001         struct near_adapter_ioreq *req = NULL;
1002         int err;
1003
1004         DBG("idx %d", idx);
1005
1006         adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
1007         if (adapter == NULL)
1008                 return -ENODEV;
1009
1010         if (adapter->tag_sock == -1 || adapter->tag_link == NULL)
1011                 return -ENOLINK;
1012
1013         if (cb != NULL && adapter->watch != 0) {
1014                 req = g_try_malloc0(sizeof(*req));
1015                 if (req == NULL)
1016                         return -ENOMEM;
1017
1018                 DBG("req %p cb %p data %p", req, cb, data);
1019
1020                 req->target_idx = __near_tag_get_idx(adapter->tag_link);
1021                 req->cb = cb;
1022                 req->data = data;
1023
1024                 adapter->ioreq_list =
1025                         g_list_append(adapter->ioreq_list, req);
1026         }
1027
1028         err = send(adapter->tag_sock, buf, length, 0);
1029         if (err < 0)
1030                 goto out_err;
1031
1032         return err;
1033
1034 out_err:
1035         if (req != NULL) {
1036                 GList *last = g_list_last(adapter->ioreq_list);
1037
1038                 g_free(req);
1039                 adapter->ioreq_list =
1040                                 g_list_delete_link(adapter->ioreq_list, last);
1041         }
1042
1043         return err;
1044 }
1045
1046 static void adapter_listen(gpointer key, gpointer value, gpointer user_data)
1047 {
1048         struct near_adapter *adapter = value;
1049         struct near_device_driver *driver = user_data;
1050
1051         DBG("%s", adapter->path);
1052
1053         if (adapter->path == NULL)
1054                 return;
1055
1056         driver->listen(adapter->idx, device_read_cb);
1057 }
1058
1059 void __near_adapter_listen(struct near_device_driver *driver)
1060 {
1061         g_hash_table_foreach(adapter_hash, adapter_listen, driver);
1062 }
1063
1064 int __near_adapter_init(void)
1065 {
1066         DBG("");
1067
1068         connection = near_dbus_get_connection();
1069
1070         adapter_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1071                                                         NULL, free_adapter);
1072
1073         return 0;
1074 }
1075
1076 void __near_adapter_cleanup(void)
1077 {
1078         DBG("");
1079
1080         g_hash_table_destroy(adapter_hash);
1081         adapter_hash = NULL;
1082 }