Add packaging directory
[platform/upstream/neard.git] / src / device.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 <errno.h>
29 #include <string.h>
30
31 #include <glib.h>
32
33 #include <gdbus.h>
34
35 #include "near.h"
36
37 struct near_device {
38         char *path;
39
40         uint32_t adapter_idx;
41         uint32_t target_idx;
42
43         uint8_t nfcid[NFC_MAX_NFCID1_LEN];
44         uint8_t nfcid_len;
45
46         size_t data_length;
47         uint8_t *data;
48
49         uint32_t n_records;
50         GList *records;
51
52         DBusMessage *push_msg; /* Push pending message */
53 };
54
55 static DBusConnection *connection = NULL;
56
57 static GHashTable *device_hash;
58
59 static GSList *driver_list = NULL;
60
61 static void free_device(gpointer data)
62 {
63         struct near_device *device = data;
64
65         DBG("device %p", device);
66
67         near_ndef_records_free(device->records);
68
69         g_dbus_unregister_interface(connection, device->path,
70                                                 NFC_DEVICE_INTERFACE);
71
72         g_free(device->path);
73         g_free(device->data);
74         g_free(device);
75 }
76
77 struct near_device *near_device_get_device(uint32_t adapter_idx,
78                                                 uint32_t target_idx)
79 {
80         struct near_device *device;
81         char *path;
82
83         DBG("");
84
85         path = g_strdup_printf("%s/nfc%d/device%d", NFC_PATH,
86                                         adapter_idx, target_idx);
87         if (!path)
88                 return NULL;
89
90         device = g_hash_table_lookup(device_hash, path);
91         g_free(path);
92
93         /* TODO refcount */
94         return device;
95 }
96
97 const char *__near_device_get_path(struct near_device *device)
98 {
99         return device->path;
100 }
101
102 uint32_t __neard_device_get_idx(struct near_device *device)
103 {
104         return device->target_idx;
105 }
106
107 static void push_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
108 {
109         struct near_device *device;
110         DBusConnection *conn;
111         DBusMessage *reply;
112
113         DBG("Push status %d", status);
114
115         conn = near_dbus_get_connection();
116         device = near_device_get_device(adapter_idx, target_idx);
117
118         if (!conn || !device)
119                 return;
120
121         if (status != 0) {
122                 reply = __near_error_failed(device->push_msg, -status);
123                 if (reply)
124                         g_dbus_send_message(conn, reply);
125         } else {
126                 g_dbus_send_reply(conn, device->push_msg, DBUS_TYPE_INVALID);
127         }
128
129         dbus_message_unref(device->push_msg);
130         device->push_msg = NULL;
131 }
132
133 static char *sn_from_message(DBusMessage *msg)
134 {
135         DBusMessageIter iter;
136         DBusMessageIter arr_iter;
137
138         DBG("");
139
140         dbus_message_iter_init(msg, &iter);
141         dbus_message_iter_recurse(&iter, &arr_iter);
142
143         while (dbus_message_iter_get_arg_type(&arr_iter) !=
144                                                 DBUS_TYPE_INVALID) {
145                 const char *key, *value;
146                 DBusMessageIter ent_iter;
147                 DBusMessageIter var_iter;
148
149                 dbus_message_iter_recurse(&arr_iter, &ent_iter);
150                 dbus_message_iter_get_basic(&ent_iter, &key);
151
152                 if (g_strcmp0(key, "Type") != 0) {
153                         dbus_message_iter_next(&arr_iter);
154                         continue;
155                 }
156
157                 dbus_message_iter_next(&ent_iter);
158                 dbus_message_iter_recurse(&ent_iter, &var_iter);
159
160                 switch (dbus_message_iter_get_arg_type(&var_iter)) {
161                 case DBUS_TYPE_STRING:
162                         dbus_message_iter_get_basic(&var_iter, &value);
163
164                         if (g_strcmp0(value, "Text") == 0)
165                                 return NEAR_DEVICE_SN_SNEP;
166                         else if (g_strcmp0(value, "URI") == 0)
167                                 return NEAR_DEVICE_SN_SNEP;
168                         else if (g_strcmp0(value, "SmartPoster") == 0)
169                                 return NEAR_DEVICE_SN_SNEP;
170                         else if (g_strcmp0(value, "Handover") == 0)
171                                 return NEAR_DEVICE_SN_HANDOVER;
172                         else if (g_strcmp0(value, "StaticHandover") == 0)
173                                 return NEAR_DEVICE_SN_HANDOVER;
174                         else if (g_strcmp0(value, "MIME") == 0)
175                                 return NEAR_DEVICE_SN_SNEP;
176                         else if (g_strcmp0(value, "Raw") == 0)
177                                 return NEAR_DEVICE_SN_SNEP;
178                         else
179                                 return NULL;
180
181                         break;
182                 }
183
184                 dbus_message_iter_next(&arr_iter);
185         }
186
187         return NULL;
188 }
189
190 static DBusMessage *push_ndef(DBusConnection *conn,
191                                 DBusMessage *msg, void *data)
192 {
193         struct near_device *device = data;
194         struct near_ndef_message *ndef;
195         char *service_name;
196         int err;
197
198         DBG("conn %p", conn);
199
200         if (device->push_msg)
201                 return __near_error_in_progress(msg);
202
203         device->push_msg = dbus_message_ref(msg);
204
205         service_name = sn_from_message(msg);
206         if (!service_name) {
207                 err = -EINVAL;
208                 goto error;
209         }
210
211         ndef = __ndef_build_from_message(msg);
212         if (!ndef) {
213                 err = -EINVAL;
214                 goto error;
215         }
216
217         err = __near_device_push(device, ndef, service_name, push_cb);
218         if (err < 0)
219                 goto error;
220
221         return NULL;
222
223 error:
224         dbus_message_unref(device->push_msg);
225         device->push_msg = NULL;
226
227         return __near_error_failed(msg, -err);
228 }
229
230 static gboolean property_get_adapter(const GDBusPropertyTable *property,
231                                         DBusMessageIter *iter, void *user_data)
232 {
233         struct near_device *device = user_data;
234         struct near_adapter *adapter;
235         const char *path;
236
237         adapter = __near_adapter_get(device->adapter_idx);
238         if (!adapter)
239                 return FALSE;
240
241         path = __near_adapter_get_path(adapter);
242         if (!path)
243                 return FALSE;
244
245         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
246
247         return TRUE;
248
249 }
250
251 static DBusMessage *dump_raw_ndef(DBusConnection *conn,
252                                 DBusMessage *msg, void *data)
253 {
254         struct near_device *device = data;
255         DBusMessage *reply;
256         DBusMessageIter iter, array;
257
258         DBG("");
259
260         reply = dbus_message_new_method_return(msg);
261         if (reply == NULL)
262                 return NULL;
263
264         dbus_message_iter_init_append(reply, &iter);
265
266         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
267                                                 DBUS_TYPE_BYTE_AS_STRING,
268                                                 &array);
269
270         __near_ndef_append_records(&array, device->records);
271
272         dbus_message_iter_close_container(&iter, &array);
273
274         return reply;
275 }
276
277 static const GDBusMethodTable device_methods[] = {
278         { GDBUS_ASYNC_METHOD("Push", GDBUS_ARGS({"attributes", "a{sv}"}),
279                                                         NULL, push_ndef) },
280         { GDBUS_METHOD("DumpRawNDEF",
281                                 NULL, GDBUS_ARGS({"NDEF", "ay"}),
282                                 dump_raw_ndef) },
283         { },
284 };
285
286 static const GDBusPropertyTable device_properties[] = {
287         { "Adapter", "o", property_get_adapter },
288
289         { }
290 };
291
292 void __near_device_remove(struct near_device *device)
293 {
294         char *path = device->path;
295
296         DBG("path %s", device->path);
297
298         if (device->push_msg)
299                 push_cb(device->adapter_idx, device->target_idx, EIO);
300
301         g_hash_table_remove(device_hash, path);
302 }
303
304 int near_device_add_data(uint32_t adapter_idx, uint32_t target_idx,
305                         uint8_t *data, size_t data_length)
306 {
307         struct near_device *device;
308
309         device = near_device_get_device(adapter_idx, target_idx);
310         if (!device)
311                 return -ENODEV;
312
313         device->data_length = data_length;
314         device->data = g_try_malloc0(data_length);
315         if (!device->data)
316                 return -ENOMEM;
317
318         if (data)
319                 memcpy(device->data, data, data_length);
320
321         return 0;
322 }
323
324 int near_device_add_records(struct near_device *device, GList *records,
325                                 near_device_io_cb cb, int status)
326 {
327         GList *list;
328         struct near_ndef_record *record;
329         char *path;
330
331         DBG("records %p", records);
332
333         near_ndef_records_free(device->records);
334         device->records = NULL;
335
336         for (list = records; list; list = list->next) {
337                 record = list->data;
338
339                 path = g_strdup_printf("%s/nfc%d/device%d/record%d",
340                                         NFC_PATH, device->adapter_idx,
341                                         device->target_idx, device->n_records);
342
343                 if (!path)
344                         continue;
345
346                 __near_ndef_record_register(record, path);
347
348                 device->n_records++;
349                 device->records = g_list_append(device->records, record);
350         }
351
352         __near_agent_ndef_parse_records(device->records);
353
354         if (cb)
355                 cb(device->adapter_idx, device->target_idx, status);
356
357         g_list_free(records);
358
359         return 0;
360 }
361
362 struct near_device *__near_device_add(uint32_t adapter_idx, uint32_t target_idx,
363                                         uint8_t *nfcid, uint8_t nfcid_len)
364 {
365         struct near_device *device;
366         char *path;
367
368         device = near_device_get_device(adapter_idx, target_idx);
369         if (device)
370                 return NULL;
371
372         device = g_try_malloc0(sizeof(struct near_device));
373         if (!device)
374                 return NULL;
375
376         device->path = g_strdup_printf("%s/nfc%d/device%d", NFC_PATH,
377                                         adapter_idx, target_idx);
378         if (!device->path) {
379                 g_free(device);
380                 return NULL;
381         }
382         device->adapter_idx = adapter_idx;
383         device->target_idx = target_idx;
384         device->n_records = 0;
385
386         if (nfcid_len <= NFC_MAX_NFCID1_LEN && nfcid_len > 0) {
387                 device->nfcid_len = nfcid_len;
388                 memcpy(device->nfcid, nfcid, nfcid_len);
389         }
390
391         path = g_strdup(device->path);
392         if (!path) {
393                 g_free(device);
394                 return NULL;
395         }
396
397         g_hash_table_insert(device_hash, path, device);
398
399         return device;
400 }
401
402 bool __near_device_register_interface(struct near_device *device)
403 {
404         DBG("connection %p", connection);
405
406         return g_dbus_register_interface(connection, device->path,
407                                         NFC_DEVICE_INTERFACE,
408                                         device_methods, NULL,
409                                         device_properties, device, NULL);
410 }
411
412 int __near_device_listen(struct near_device *device, near_device_io_cb cb)
413 {
414         GSList *list;
415
416         DBG("");
417
418         for (list = driver_list; list; list = list->next) {
419                 struct near_device_driver *driver = list->data;
420
421                 return driver->listen(device->adapter_idx, cb);
422         }
423
424         return 0;
425 }
426
427 int __near_device_push(struct near_device *device,
428                         struct near_ndef_message *ndef, char *service_name,
429                         near_device_io_cb cb)
430 {
431         GSList *list;
432
433         DBG("");
434
435         if (!__near_adapter_get_dep_state(device->adapter_idx)) {
436                 near_error("DEP link is not established");
437                 return -ENOLINK;
438         }
439
440         for (list = driver_list; list; list = list->next) {
441                 struct near_device_driver *driver = list->data;
442
443                 return driver->push(device->adapter_idx, device->target_idx,
444                                         ndef, service_name, cb);
445         }
446
447         return 0;
448 }
449
450 static gint cmp_prio(gconstpointer a, gconstpointer b)
451 {
452         const struct near_tag_driver *driver1 = a;
453         const struct near_tag_driver *driver2 = b;
454
455         return driver2->priority - driver1->priority;
456 }
457
458 int near_device_driver_register(struct near_device_driver *driver)
459 {
460         DBG("");
461
462         if (!driver->listen)
463                 return -EINVAL;
464
465         driver_list = g_slist_insert_sorted(driver_list, driver, cmp_prio);
466
467         __near_adapter_listen(driver);
468
469         return 0;
470 }
471
472 void near_device_driver_unregister(struct near_device_driver *driver)
473 {
474         DBG("");
475
476         driver_list = g_slist_remove(driver_list, driver);
477 }
478
479 int __near_device_init(void)
480 {
481         DBG("");
482
483         connection = near_dbus_get_connection();
484
485         device_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
486                                                 g_free, free_device);
487
488         return 0;
489 }
490
491 void __near_device_cleanup(void)
492 {
493         DBG("");
494
495         g_hash_table_destroy(device_hash);
496         device_hash = NULL;
497 }