Free allocated path value
[connman] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  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 <errno.h>
27 #include <gdbus.h>
28
29 #include "connman.h"
30
31 struct connman_device {
32         struct connman_element element;
33         enum connman_device_type type;
34         enum connman_device_mode mode;
35         enum connman_device_policy policy;
36         gboolean powered;
37         gboolean carrier;
38         gboolean scanning;
39         char *path;
40         char *interface;
41
42         struct connman_device_driver *driver;
43         void *driver_data;
44
45         GHashTable *networks;
46 };
47
48 static const char *type2description(enum connman_device_type type)
49 {
50         switch (type) {
51         case CONNMAN_DEVICE_TYPE_ETHERNET:
52                 return "Ethernet";
53         case CONNMAN_DEVICE_TYPE_WIFI:
54                 return "Wireless";
55         case CONNMAN_DEVICE_TYPE_WIMAX:
56                 return "WiMAX";
57         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
58                 return "Bluetooth";
59         case CONNMAN_DEVICE_TYPE_HSO:
60                 return "Cellular";
61         default:
62                 return NULL;
63         }
64 }
65
66 static const char *type2string(enum connman_device_type type)
67 {
68         switch (type) {
69         case CONNMAN_DEVICE_TYPE_ETHERNET:
70                 return "ethernet";
71         case CONNMAN_DEVICE_TYPE_WIFI:
72                 return "wifi";
73         case CONNMAN_DEVICE_TYPE_WIMAX:
74                 return "wimax";
75         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
76                 return "bluetooth";
77         case CONNMAN_DEVICE_TYPE_HSO:
78                 return "cellular";
79         default:
80                 return NULL;
81         }
82 }
83
84 static const char *policy2string(enum connman_device_policy policy)
85 {
86         switch (policy) {
87         case CONNMAN_DEVICE_POLICY_IGNORE:
88                 return "ignore";
89         case CONNMAN_DEVICE_POLICY_OFF:
90                 return "off";
91         case CONNMAN_DEVICE_POLICY_AUTO:
92                 return "auto";
93         case CONNMAN_DEVICE_POLICY_MANUAL:
94                 return "manual";
95         default:
96                 return NULL;
97         }
98 }
99
100 static enum connman_device_policy string2policy(const char *policy)
101 {
102         if (g_str_equal(policy, "ignore") == TRUE)
103                 return CONNMAN_DEVICE_POLICY_IGNORE;
104         else if (g_str_equal(policy, "off") == TRUE)
105                 return CONNMAN_DEVICE_POLICY_OFF;
106         else if (g_str_equal(policy, "auto") == TRUE)
107                 return CONNMAN_DEVICE_POLICY_AUTO;
108         else if (g_str_equal(policy, "manual") == TRUE)
109                 return CONNMAN_DEVICE_POLICY_MANUAL;
110         else
111                 return CONNMAN_DEVICE_POLICY_UNKNOWN;
112 }
113
114 static int set_powered(struct connman_device *device, gboolean powered)
115 {
116         struct connman_device_driver *driver = device->driver;
117         int err;
118
119         DBG("device %p powered %d", device, powered);
120
121         if (!driver)
122                 return -EINVAL;
123
124         if (powered == TRUE) {
125                 if (driver->enable)
126                         err = driver->enable(device);
127                 else
128                         err = -EINVAL;
129         } else {
130                 g_hash_table_remove_all(device->networks);
131
132                 if (driver->disable)
133                         err = driver->disable(device);
134                 else
135                         err = -EINVAL;
136         }
137
138         return err;
139 }
140
141 static int set_policy(DBusConnection *connection,
142                                 struct connman_device *device,
143                                         enum connman_device_policy policy)
144 {
145         DBusMessage *signal;
146         DBusMessageIter entry, value;
147         const char *str, *key = "Policy";
148         int err = 0;
149
150         DBG("device %p policy %d", device, policy);
151
152         if (device->policy == policy)
153                 return 0;
154
155         switch (policy) {
156         case CONNMAN_DEVICE_POLICY_OFF:
157                 if (device->powered == TRUE)
158                         err = set_powered(device, FALSE);
159                 break;
160         case CONNMAN_DEVICE_POLICY_AUTO:
161         case CONNMAN_DEVICE_POLICY_MANUAL:
162                 if (device->powered == FALSE)
163                         err = set_powered(device, TRUE);
164                 break;
165         default:
166                 break;
167         }
168
169         if (err < 0)
170                 return err;
171
172         device->policy = policy;
173
174         signal = dbus_message_new_signal(device->element.path,
175                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
176         if (signal == NULL)
177                 return 0;
178
179         dbus_message_iter_init_append(signal, &entry);
180
181         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
182
183         str = policy2string(policy);
184
185         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
186                                         DBUS_TYPE_STRING_AS_STRING, &value);
187         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
188         dbus_message_iter_close_container(&entry, &value);
189
190         g_dbus_send_message(connection, signal);
191
192         return 0;
193 }
194
195 static void append_networks(struct connman_device *device,
196                                                 DBusMessageIter *entry)
197 {
198         DBusMessageIter value, iter;
199         const char *key = "Networks";
200
201         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
202
203         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
204                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
205                                                                 &value);
206
207         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
208                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
209         __connman_element_list((struct connman_element *) device,
210                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
211         dbus_message_iter_close_container(&value, &iter);
212
213         dbus_message_iter_close_container(entry, &value);
214 }
215
216 static DBusMessage *get_properties(DBusConnection *conn,
217                                         DBusMessage *msg, void *data)
218 {
219         struct connman_device *device = data;
220         DBusMessage *reply;
221         DBusMessageIter array, dict, entry;
222         const char *str;
223
224         DBG("conn %p", conn);
225
226         reply = dbus_message_new_method_return(msg);
227         if (reply == NULL)
228                 return NULL;
229
230         dbus_message_iter_init_append(reply, &array);
231
232         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
233                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
234                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
235                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
236
237         str = type2description(device->type);
238         if (str != NULL && device->interface != NULL) {
239                 char *name = g_strdup_printf("%s (%s)", str, device->interface);
240                 if (name != NULL)
241                         connman_dbus_dict_append_variant(&dict, "Name",
242                                                 DBUS_TYPE_STRING, &name);
243                 g_free(name);
244         }
245
246         str = type2string(device->type);
247         if (str != NULL)
248                 connman_dbus_dict_append_variant(&dict, "Type",
249                                                 DBUS_TYPE_STRING, &str);
250
251         if (device->interface != NULL)
252                 connman_dbus_dict_append_variant(&dict, "Interface",
253                                         DBUS_TYPE_STRING, &device->interface);
254
255         str = policy2string(device->policy);
256         if (str != NULL)
257                 connman_dbus_dict_append_variant(&dict, "Policy",
258                                                 DBUS_TYPE_STRING, &str);
259
260         connman_dbus_dict_append_variant(&dict, "Powered",
261                                         DBUS_TYPE_BOOLEAN, &device->powered);
262
263         if (device->driver && device->driver->scan)
264                 connman_dbus_dict_append_variant(&dict, "Scanning",
265                                         DBUS_TYPE_BOOLEAN, &device->scanning);
266
267         if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK) {
268                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
269                                                                 NULL, &entry);
270                 append_networks(device, &entry);
271                 dbus_message_iter_close_container(&dict, &entry);
272         }
273
274         dbus_message_iter_close_container(&array, &dict);
275
276         return reply;
277 }
278
279 static DBusMessage *set_property(DBusConnection *conn,
280                                         DBusMessage *msg, void *data)
281 {
282         struct connman_device *device = data;
283         DBusMessageIter iter, value;
284         const char *name;
285
286         DBG("conn %p", conn);
287
288         if (dbus_message_iter_init(msg, &iter) == FALSE)
289                 return __connman_error_invalid_arguments(msg);
290
291         dbus_message_iter_get_basic(&iter, &name);
292         dbus_message_iter_next(&iter);
293         dbus_message_iter_recurse(&iter, &value);
294
295         if (__connman_security_check_privileges(msg) < 0)
296                 return __connman_error_permission_denied(msg);
297
298         if (g_str_equal(name, "Powered") == TRUE) {
299                 gboolean powered;
300                 int err;
301
302                 dbus_message_iter_get_basic(&value, &powered);
303
304                 if (device->powered == powered)
305                         return __connman_error_invalid_arguments(msg);
306
307                 err = set_powered(device, powered);
308                 if (err < 0 && err != -EINPROGRESS)
309                         return __connman_error_failed(msg);
310         } else if (g_str_equal(name, "Policy") == TRUE) {
311                 enum connman_device_policy policy;
312                 const char *str;
313                 int err;
314
315                 dbus_message_iter_get_basic(&value, &str);
316                 policy = string2policy(str);
317                 if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN)
318                         return __connman_error_invalid_arguments(msg);
319
320                 err = set_policy(conn, device, policy);
321                 if (err < 0)
322                         return __connman_error_failed(msg);
323         }
324
325         __connman_element_store(&device->element);
326
327         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
328 }
329
330 static DBusMessage *create_network(DBusConnection *conn,
331                                         DBusMessage *msg, void *data)
332 {
333         DBG("conn %p", conn);
334
335         if (__connman_security_check_privileges(msg) < 0)
336                 return __connman_error_permission_denied(msg);
337
338         return __connman_error_invalid_arguments(msg);
339 }
340
341 static DBusMessage *remove_network(DBusConnection *conn,
342                                         DBusMessage *msg, void *data)
343 {
344         DBG("conn %p", conn);
345
346         if (__connman_security_check_privileges(msg) < 0)
347                 return __connman_error_permission_denied(msg);
348
349         return __connman_error_invalid_arguments(msg);
350 }
351
352 static DBusMessage *propose_scan(DBusConnection *conn,
353                                         DBusMessage *msg, void *data)
354 {
355         struct connman_device *device = data;
356         int err;
357
358         DBG("conn %p", conn);
359
360         if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK)
361                 return __connman_error_not_supported(msg);
362
363         if (!device->driver || !device->driver->scan)
364                 return __connman_error_not_supported(msg);
365
366         err = device->driver->scan(device);
367         if (err < 0)
368                 return __connman_error_failed(msg);
369
370         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
371 }
372
373 static GDBusMethodTable device_methods[] = {
374         { "GetProperties", "",      "a{sv}", get_properties },
375         { "SetProperty",   "sv",    "",      set_property   },
376         { "CreateNetwork", "a{sv}", "o",     create_network },
377         { "RemoveNetwork", "o",     "",      remove_network },
378         { "ProposeScan",   "",      "",      propose_scan   },
379         { },
380 };
381
382 static GDBusSignalTable device_signals[] = {
383         { "PropertyChanged", "sv" },
384         { },
385 };
386
387 static DBusConnection *connection;
388
389 static void append_devices(DBusMessageIter *entry)
390 {
391         DBusMessageIter value, iter;
392         const char *key = "Devices";
393
394         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
395
396         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
397                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
398                                                                 &value);
399
400         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
401                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
402         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
403         dbus_message_iter_close_container(&value, &iter);
404
405         dbus_message_iter_close_container(entry, &value);
406 }
407
408 static void emit_devices_signal(void)
409 {
410         DBusMessage *signal;
411         DBusMessageIter entry;
412
413         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
414                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
415         if (signal == NULL)
416                 return;
417
418         dbus_message_iter_init_append(signal, &entry);
419
420         append_devices(&entry);
421
422         g_dbus_send_message(connection, signal);
423 }
424
425 static int register_interface(struct connman_element *element)
426 {
427         struct connman_device *device = element->device;
428
429         if (g_dbus_register_interface(connection, element->path,
430                                         CONNMAN_DEVICE_INTERFACE,
431                                         device_methods, device_signals,
432                                         NULL, device, NULL) == FALSE) {
433                 connman_error("Failed to register %s device", element->path);
434                 return -EIO;
435         }
436
437         emit_devices_signal();
438
439         return 0;
440 }
441
442 static void unregister_interface(struct connman_element *element)
443 {
444         emit_devices_signal();
445
446         g_dbus_unregister_interface(connection, element->path,
447                                                 CONNMAN_DEVICE_INTERFACE);
448 }
449
450 static GSList *driver_list = NULL;
451
452 static gint compare_priority(gconstpointer a, gconstpointer b)
453 {
454         const struct connman_device_driver *driver1 = a;
455         const struct connman_device_driver *driver2 = b;
456
457         return driver2->priority - driver1->priority;
458 }
459
460 /**
461  * connman_device_driver_register:
462  * @driver: device driver definition
463  *
464  * Register a new device driver
465  *
466  * Returns: %0 on success
467  */
468 int connman_device_driver_register(struct connman_device_driver *driver)
469 {
470         DBG("driver %p name %s", driver, driver->name);
471
472         driver_list = g_slist_insert_sorted(driver_list, driver,
473                                                         compare_priority);
474
475         //__connman_driver_rescan(&device_driver);
476
477         return 0;
478 }
479
480 /**
481  * connman_device_driver_unregister:
482  * @driver: device driver definition
483  *
484  * Remove a previously registered device driver
485  */
486 void connman_device_driver_unregister(struct connman_device_driver *driver)
487 {
488         DBG("driver %p name %s", driver, driver->name);
489
490         driver_list = g_slist_remove(driver_list, driver);
491 }
492
493 static void unregister_network(gpointer data)
494 {
495         struct connman_network *network = data;
496
497         DBG("network %p", network);
498
499         connman_element_unregister((struct connman_element *) network);
500
501         connman_network_unref(network);
502 }
503
504 static void device_destruct(struct connman_element *element)
505 {
506         struct connman_device *device = element->device;
507
508         DBG("element %p name %s", element, element->name);
509
510         g_free(device->path);
511         g_free(device->interface);
512
513         g_hash_table_destroy(device->networks);
514 }
515
516 /**
517  * connman_device_create:
518  * @node: device node name (for example an address)
519  * @type: device type
520  *
521  * Allocate a new device of given #type and assign the #node name to it.
522  *
523  * Returns: a newly-allocated #connman_device structure
524  */
525 struct connman_device *connman_device_create(const char *node,
526                                                 enum connman_device_type type)
527 {
528         struct connman_device *device;
529
530         DBG("node %s type %d", node, type);
531
532         device = g_try_new0(struct connman_device, 1);
533         if (device == NULL)
534                 return NULL;
535
536         DBG("device %p", device);
537
538         device->element.refcount = 1;
539
540         device->element.name = g_strdup(node);
541         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
542         device->element.index = -1;
543
544         switch (type) {
545         case CONNMAN_DEVICE_TYPE_ETHERNET:
546                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_ETHERNET;
547                 break;
548         default:
549                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
550                 break;
551         }
552
553         device->element.device = device;
554         device->element.destruct = device_destruct;
555
556         device->type = type;
557         device->mode = CONNMAN_DEVICE_MODE_NO_NETWORK;
558         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
559
560         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
561                                                 g_free, unregister_network);
562
563         return device;
564 }
565
566 /**
567  * connman_device_ref:
568  * @device: device structure
569  *
570  * Increase reference counter of device
571  */
572 struct connman_device *connman_device_ref(struct connman_device *device)
573 {
574         if (connman_element_ref(&device->element) == NULL)
575                 return NULL;
576
577         return device;
578 }
579
580 /**
581  * connman_device_unref:
582  * @device: device structure
583  *
584  * Decrease reference counter of device
585  */
586 void connman_device_unref(struct connman_device *device)
587 {
588         connman_element_unref(&device->element);
589 }
590
591 /**
592  * connman_device_set_path:
593  * @device: device structure
594  * @path: path name
595  *
596  * Set path name of device
597  */
598 void connman_device_set_path(struct connman_device *device, const char *path)
599 {
600         g_free(device->element.devpath);
601         device->element.devpath = g_strdup(path);
602
603         g_free(device->path);
604         device->path = g_strdup(path);
605 }
606
607 /**
608  * connman_device_get_path:
609  * @device: device structure
610  *
611  * Get path name of device
612  */
613 const char *connman_device_get_path(struct connman_device *device)
614 {
615         return device->path;
616 }
617
618 /**
619  * connman_device_set_index:
620  * @device: device structure
621  * @index: index number
622  *
623  * Set index number of device
624  */
625 void connman_device_set_index(struct connman_device *device, int index)
626 {
627         device->element.index = index;
628 }
629
630 /**
631  * connman_device_get_index:
632  * @device: device structure
633  *
634  * Get index number of device
635  */
636 int connman_device_get_index(struct connman_device *device)
637 {
638         return device->element.index;
639 }
640
641 /**
642  * connman_device_set_interface:
643  * @device: device structure
644  * @interface: interface name
645  *
646  * Set interface name of device
647  */
648 void connman_device_set_interface(struct connman_device *device,
649                                                         const char *interface)
650 {
651         g_free(device->element.devname);
652         device->element.devname = g_strdup(interface);
653
654         g_free(device->interface);
655         device->interface = g_strdup(interface);
656 }
657
658 /**
659  * connman_device_get_interface:
660  * @device: device structure
661  *
662  * Get interface name of device
663  */
664 const char *connman_device_get_interface(struct connman_device *device)
665 {
666         return device->interface;
667 }
668
669 /**
670  * connman_device_set_policy:
671  * @device: device structure
672  * @policy: power and connection policy
673  *
674  * Change power and connection policy of device
675  */
676 void connman_device_set_policy(struct connman_device *device,
677                                         enum connman_device_policy policy)
678 {
679         device->policy = policy;
680 }
681
682 /**
683  * connman_device_set_mode:
684  * @device: device structure
685  * @mode: network mode
686  *
687  * Change network mode of device
688  */
689 void connman_device_set_mode(struct connman_device *device,
690                                                 enum connman_device_mode mode)
691 {
692         device->mode = mode;
693 }
694
695 /**
696  * connman_device_set_powered:
697  * @device: device structure
698  * @powered: powered state
699  *
700  * Change power state of device
701  */
702 int connman_device_set_powered(struct connman_device *device,
703                                                 connman_bool_t powered)
704 {
705         DBusMessage *signal;
706         DBusMessageIter entry, value;
707         const char *key = "Powered";
708
709         DBG("driver %p powered %d", device, powered);
710
711         if (device->powered == powered)
712                 return -EALREADY;
713
714         device->powered = powered;
715
716         signal = dbus_message_new_signal(device->element.path,
717                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
718         if (signal == NULL)
719                 return 0;
720
721         dbus_message_iter_init_append(signal, &entry);
722
723         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
724
725         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
726                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
727         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
728         dbus_message_iter_close_container(&entry, &value);
729
730         g_dbus_send_message(connection, signal);
731
732         return 0;
733 }
734
735 /**
736  * connman_device_set_carrier:
737  * @device: device structure
738  * @carrier: carrier state
739  *
740  * Change carrier state of device (only for device without scanning)
741  */
742 int connman_device_set_carrier(struct connman_device *device,
743                                                 connman_bool_t carrier)
744 {
745         DBG("driver %p carrier %d", device, carrier);
746
747         if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK)
748                 return -EINVAL;
749
750         if (device->carrier == carrier)
751                 return -EALREADY;
752
753         device->carrier = carrier;
754
755         if (carrier == TRUE) {
756                 struct connman_element *element;
757
758                 element = connman_element_create(NULL);
759                 if (element != NULL) {
760                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
761                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
762                         element->index   = device->element.index;
763
764                         if (connman_element_register(element,
765                                                         &device->element) < 0)
766                                 connman_element_unref(element);
767                 }
768         } else
769                 connman_element_unregister_children(&device->element);
770
771         return 0;
772 }
773
774 /**
775  * connman_device_set_scanning:
776  * @device: device structure
777  * @scanning: scanning state
778  *
779  * Change scanning state of device
780  */
781 int connman_device_set_scanning(struct connman_device *device,
782                                                 connman_bool_t scanning)
783 {
784         DBusMessage *signal;
785         DBusMessageIter entry, value;
786         const char *key = "Scanning";
787
788         DBG("driver %p scanning %d", device, scanning);
789
790         if (!device->driver || !device->driver->scan)
791                 return -EINVAL;
792
793         if (device->scanning == scanning)
794                 return -EALREADY;
795
796         device->scanning = scanning;
797
798         signal = dbus_message_new_signal(device->element.path,
799                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
800         if (signal == NULL)
801                 return 0;
802
803         dbus_message_iter_init_append(signal, &entry);
804
805         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
806
807         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
808                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
809         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
810         dbus_message_iter_close_container(&entry, &value);
811
812         g_dbus_send_message(connection, signal);
813
814         return 0;
815 }
816
817 /**
818  * connman_device_add_network:
819  * @device: device structure
820  * @network: network structure
821  *
822  * Add new network to the device
823  */
824 int connman_device_add_network(struct connman_device *device,
825                                         struct connman_network *network)
826 {
827         const char *identifier = connman_network_get_identifier(network);
828         int err;
829
830         DBG("device %p network %p", device, network);
831
832         if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK)
833                 return -EINVAL;
834
835         err = connman_element_register((struct connman_element *) network,
836                                                         &device->element);
837         if (err < 0)
838                 return err;
839
840         __connman_network_set_device(network, device);
841
842         g_hash_table_insert(device->networks, g_strdup(identifier),
843                                                                 network);
844
845         return 0;
846 }
847
848 /**
849  * connman_device_get_network:
850  * @device: device structure
851  * @identifier: network identifier
852  *
853  * Get network for given identifier
854  */
855 struct connman_network *connman_device_get_network(struct connman_device *device,
856                                                         const char *identifier)
857 {
858         DBG("device %p identifier %s", device, identifier);
859
860         return g_hash_table_lookup(device->networks, identifier);
861 }
862
863 /**
864  * connman_device_remove_network:
865  * @device: device structure
866  * @identifier: network identifier
867  *
868  * Remove network for given identifier
869  */
870 int connman_device_remove_network(struct connman_device *device,
871                                                         const char *identifier)
872 {
873         DBG("device %p identifier %s", device, identifier);
874
875         g_hash_table_remove(device->networks, identifier);
876
877         return 0;
878 }
879
880 /**
881  * connman_device_register:
882  * @device: device structure
883  *
884  * Register device with the system
885  */
886 int connman_device_register(struct connman_device *device)
887 {
888         return connman_element_register(&device->element, NULL);
889 }
890
891 /**
892  * connman_device_unregister:
893  * @device: device structure
894  *
895  * Unregister device with the system
896  */
897 void connman_device_unregister(struct connman_device *device)
898 {
899         connman_element_unregister(&device->element);
900 }
901
902 /**
903  * connman_device_get_data:
904  * @device: device structure
905  *
906  * Get private device data pointer
907  */
908 void *connman_device_get_data(struct connman_device *device)
909 {
910         return device->driver_data;
911 }
912
913 /**
914  * connman_device_set_data:
915  * @device: device structure
916  * @data: data pointer
917  *
918  * Set private device data pointer
919  */
920 void connman_device_set_data(struct connman_device *device, void *data)
921 {
922         device->driver_data = data;
923 }
924
925 static void device_enable(struct connman_device *device)
926 {
927         DBG("device %p", device);
928
929         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
930                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
931                 return;
932
933         if (device->powered == TRUE)
934                 return;
935
936         if (device->driver->enable)
937                 device->driver->enable(device);
938 }
939
940 static void device_disable(struct connman_device *device)
941 {
942         DBG("device %p", device);
943
944         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
945                 return;
946
947         if (device->powered == FALSE)
948                 return;
949
950         g_hash_table_remove_all(device->networks);
951
952         if (device->driver->disable)
953                 device->driver->disable(device);
954 }
955
956 static gboolean match_driver(struct connman_device *device,
957                                         struct connman_device_driver *driver)
958 {
959         if (device->type == driver->type ||
960                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
961                 return TRUE;
962
963         return FALSE;
964 }
965
966 static int device_probe(struct connman_element *element)
967 {
968         struct connman_device *device = element->device;
969         GSList *list;
970         int err;
971
972         DBG("element %p name %s", element, element->name);
973
974         if (device == NULL)
975                 return -ENODEV;
976
977         for (list = driver_list; list; list = list->next) {
978                 struct connman_device_driver *driver = list->data;
979
980                 if (match_driver(device, driver) == FALSE)
981                         continue;
982
983                 DBG("driver %p name %s", driver, driver->name);
984
985                 if (driver->probe(device) == 0) {
986                         device->driver = driver;
987                         break;
988                 }
989         }
990
991         if (!device->driver)
992                 return -ENODEV;
993
994         err = register_interface(element);
995         if (err < 0) {
996                 if (device->driver->remove)
997                         device->driver->remove(device);
998                 return err;
999         }
1000
1001         device_enable(device);
1002
1003         return 0;
1004 }
1005
1006 static void device_remove(struct connman_element *element)
1007 {
1008         struct connman_device *device = element->device;
1009
1010         DBG("element %p name %s", element, element->name);
1011
1012         if (device == NULL)
1013                 return;
1014
1015         if (!device->driver)
1016                 return;
1017
1018         device_disable(device);
1019
1020         unregister_interface(element);
1021
1022         if (device->driver->remove)
1023                 device->driver->remove(device);
1024 }
1025
1026 static struct connman_driver device_driver = {
1027         .name           = "device",
1028         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1029         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1030         .probe          = device_probe,
1031         .remove         = device_remove,
1032 };
1033
1034 int __connman_device_init(void)
1035 {
1036         DBG("");
1037
1038         connection = connman_dbus_get_connection();
1039
1040         return connman_driver_register(&device_driver);
1041 }
1042
1043 void __connman_device_cleanup(void)
1044 {
1045         DBG("");
1046
1047         connman_driver_unregister(&device_driver);
1048
1049         dbus_connection_unref(connection);
1050 }