84be26ea1411b86e31f0263c75797f5ac8d3c447
[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         DBG("element %p name %s", element, element->name);
430
431         if (g_dbus_register_interface(connection, element->path,
432                                         CONNMAN_DEVICE_INTERFACE,
433                                         device_methods, device_signals,
434                                         NULL, device, NULL) == FALSE) {
435                 connman_error("Failed to register %s device", element->path);
436                 return -EIO;
437         }
438
439         emit_devices_signal();
440
441         return 0;
442 }
443
444 static void unregister_interface(struct connman_element *element)
445 {
446         DBG("element %p name %s", element, element->name);
447
448         emit_devices_signal();
449
450         g_dbus_unregister_interface(connection, element->path,
451                                                 CONNMAN_DEVICE_INTERFACE);
452 }
453
454 static GSList *driver_list = NULL;
455
456 static gint compare_priority(gconstpointer a, gconstpointer b)
457 {
458         const struct connman_device_driver *driver1 = a;
459         const struct connman_device_driver *driver2 = b;
460
461         return driver2->priority - driver1->priority;
462 }
463
464 /**
465  * connman_device_driver_register:
466  * @driver: device driver definition
467  *
468  * Register a new device driver
469  *
470  * Returns: %0 on success
471  */
472 int connman_device_driver_register(struct connman_device_driver *driver)
473 {
474         DBG("driver %p name %s", driver, driver->name);
475
476         driver_list = g_slist_insert_sorted(driver_list, driver,
477                                                         compare_priority);
478
479         //__connman_driver_rescan(&device_driver);
480
481         return 0;
482 }
483
484 /**
485  * connman_device_driver_unregister:
486  * @driver: device driver definition
487  *
488  * Remove a previously registered device driver
489  */
490 void connman_device_driver_unregister(struct connman_device_driver *driver)
491 {
492         DBG("driver %p name %s", driver, driver->name);
493
494         driver_list = g_slist_remove(driver_list, driver);
495 }
496
497 static void unregister_network(gpointer data)
498 {
499         struct connman_network *network = data;
500
501         DBG("network %p", network);
502
503         connman_element_unregister((struct connman_element *) network);
504
505         connman_network_unref(network);
506 }
507
508 static void device_destruct(struct connman_element *element)
509 {
510         struct connman_device *device = element->device;
511
512         DBG("element %p name %s", element, element->name);
513
514         g_free(device->path);
515         g_free(device->interface);
516
517         g_hash_table_destroy(device->networks);
518 }
519
520 /**
521  * connman_device_create:
522  * @node: device node name (for example an address)
523  * @type: device type
524  *
525  * Allocate a new device of given #type and assign the #node name to it.
526  *
527  * Returns: a newly-allocated #connman_device structure
528  */
529 struct connman_device *connman_device_create(const char *node,
530                                                 enum connman_device_type type)
531 {
532         struct connman_device *device;
533
534         DBG("node %s type %d", node, type);
535
536         device = g_try_new0(struct connman_device, 1);
537         if (device == NULL)
538                 return NULL;
539
540         DBG("device %p", device);
541
542         device->element.refcount = 1;
543
544         device->element.name = g_strdup(node);
545         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
546         device->element.index = -1;
547
548         switch (type) {
549         case CONNMAN_DEVICE_TYPE_ETHERNET:
550                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_ETHERNET;
551                 break;
552         default:
553                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
554                 break;
555         }
556
557         device->element.device = device;
558         device->element.destruct = device_destruct;
559
560         device->type = type;
561         device->mode = CONNMAN_DEVICE_MODE_NO_NETWORK;
562         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
563
564         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
565                                                 g_free, unregister_network);
566
567         return device;
568 }
569
570 /**
571  * connman_device_ref:
572  * @device: device structure
573  *
574  * Increase reference counter of device
575  */
576 struct connman_device *connman_device_ref(struct connman_device *device)
577 {
578         if (connman_element_ref(&device->element) == NULL)
579                 return NULL;
580
581         return device;
582 }
583
584 /**
585  * connman_device_unref:
586  * @device: device structure
587  *
588  * Decrease reference counter of device
589  */
590 void connman_device_unref(struct connman_device *device)
591 {
592         connman_element_unref(&device->element);
593 }
594
595 /**
596  * connman_device_set_path:
597  * @device: device structure
598  * @path: path name
599  *
600  * Set path name of device
601  */
602 void connman_device_set_path(struct connman_device *device, const char *path)
603 {
604         g_free(device->element.devpath);
605         device->element.devpath = g_strdup(path);
606
607         g_free(device->path);
608         device->path = g_strdup(path);
609 }
610
611 /**
612  * connman_device_get_path:
613  * @device: device structure
614  *
615  * Get path name of device
616  */
617 const char *connman_device_get_path(struct connman_device *device)
618 {
619         return device->path;
620 }
621
622 /**
623  * connman_device_set_index:
624  * @device: device structure
625  * @index: index number
626  *
627  * Set index number of device
628  */
629 void connman_device_set_index(struct connman_device *device, int index)
630 {
631         device->element.index = index;
632 }
633
634 /**
635  * connman_device_get_index:
636  * @device: device structure
637  *
638  * Get index number of device
639  */
640 int connman_device_get_index(struct connman_device *device)
641 {
642         return device->element.index;
643 }
644
645 /**
646  * connman_device_set_interface:
647  * @device: device structure
648  * @interface: interface name
649  *
650  * Set interface name of device
651  */
652 void connman_device_set_interface(struct connman_device *device,
653                                                         const char *interface)
654 {
655         g_free(device->element.devname);
656         device->element.devname = g_strdup(interface);
657
658         g_free(device->interface);
659         device->interface = g_strdup(interface);
660 }
661
662 /**
663  * connman_device_get_interface:
664  * @device: device structure
665  *
666  * Get interface name of device
667  */
668 const char *connman_device_get_interface(struct connman_device *device)
669 {
670         return device->interface;
671 }
672
673 /**
674  * connman_device_set_policy:
675  * @device: device structure
676  * @policy: power and connection policy
677  *
678  * Change power and connection policy of device
679  */
680 void connman_device_set_policy(struct connman_device *device,
681                                         enum connman_device_policy policy)
682 {
683         device->policy = policy;
684 }
685
686 /**
687  * connman_device_set_mode:
688  * @device: device structure
689  * @mode: network mode
690  *
691  * Change network mode of device
692  */
693 void connman_device_set_mode(struct connman_device *device,
694                                                 enum connman_device_mode mode)
695 {
696         device->mode = mode;
697 }
698
699 /**
700  * connman_device_set_powered:
701  * @device: device structure
702  * @powered: powered state
703  *
704  * Change power state of device
705  */
706 int connman_device_set_powered(struct connman_device *device,
707                                                 connman_bool_t powered)
708 {
709         DBusMessage *signal;
710         DBusMessageIter entry, value;
711         const char *key = "Powered";
712
713         DBG("driver %p powered %d", device, powered);
714
715         if (device->powered == powered)
716                 return -EALREADY;
717
718         device->powered = powered;
719
720         signal = dbus_message_new_signal(device->element.path,
721                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
722         if (signal == NULL)
723                 return 0;
724
725         dbus_message_iter_init_append(signal, &entry);
726
727         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
728
729         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
730                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
731         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
732         dbus_message_iter_close_container(&entry, &value);
733
734         g_dbus_send_message(connection, signal);
735
736         return 0;
737 }
738
739 /**
740  * connman_device_set_carrier:
741  * @device: device structure
742  * @carrier: carrier state
743  *
744  * Change carrier state of device (only for device without scanning)
745  */
746 int connman_device_set_carrier(struct connman_device *device,
747                                                 connman_bool_t carrier)
748 {
749         DBG("driver %p carrier %d", device, carrier);
750
751         if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK)
752                 return -EINVAL;
753
754         if (device->carrier == carrier)
755                 return -EALREADY;
756
757         device->carrier = carrier;
758
759         if (carrier == TRUE) {
760                 struct connman_element *element;
761
762                 element = connman_element_create(NULL);
763                 if (element != NULL) {
764                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
765                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
766                         element->index   = device->element.index;
767
768                         if (connman_element_register(element,
769                                                         &device->element) < 0)
770                                 connman_element_unref(element);
771                 }
772         } else
773                 connman_element_unregister_children(&device->element);
774
775         return 0;
776 }
777
778 /**
779  * connman_device_set_scanning:
780  * @device: device structure
781  * @scanning: scanning state
782  *
783  * Change scanning state of device
784  */
785 int connman_device_set_scanning(struct connman_device *device,
786                                                 connman_bool_t scanning)
787 {
788         DBusMessage *signal;
789         DBusMessageIter entry, value;
790         const char *key = "Scanning";
791
792         DBG("driver %p scanning %d", device, scanning);
793
794         if (!device->driver || !device->driver->scan)
795                 return -EINVAL;
796
797         if (device->scanning == scanning)
798                 return -EALREADY;
799
800         device->scanning = scanning;
801
802         signal = dbus_message_new_signal(device->element.path,
803                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
804         if (signal == NULL)
805                 return 0;
806
807         dbus_message_iter_init_append(signal, &entry);
808
809         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
810
811         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
812                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
813         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
814         dbus_message_iter_close_container(&entry, &value);
815
816         g_dbus_send_message(connection, signal);
817
818         return 0;
819 }
820
821 /**
822  * connman_device_add_network:
823  * @device: device structure
824  * @network: network structure
825  *
826  * Add new network to the device
827  */
828 int connman_device_add_network(struct connman_device *device,
829                                         struct connman_network *network)
830 {
831         const char *identifier = connman_network_get_identifier(network);
832         int err;
833
834         DBG("device %p network %p", device, network);
835
836         if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK)
837                 return -EINVAL;
838
839         __connman_network_set_device(network, device);
840
841         err = connman_element_register((struct connman_element *) network,
842                                                         &device->element);
843         if (err < 0) {
844                 __connman_network_set_device(network, NULL);
845                 return err;
846         }
847
848         g_hash_table_insert(device->networks, g_strdup(identifier),
849                                                                 network);
850
851         return 0;
852 }
853
854 /**
855  * connman_device_get_network:
856  * @device: device structure
857  * @identifier: network identifier
858  *
859  * Get network for given identifier
860  */
861 struct connman_network *connman_device_get_network(struct connman_device *device,
862                                                         const char *identifier)
863 {
864         DBG("device %p identifier %s", device, identifier);
865
866         return g_hash_table_lookup(device->networks, identifier);
867 }
868
869 /**
870  * connman_device_remove_network:
871  * @device: device structure
872  * @identifier: network identifier
873  *
874  * Remove network for given identifier
875  */
876 int connman_device_remove_network(struct connman_device *device,
877                                                         const char *identifier)
878 {
879         DBG("device %p identifier %s", device, identifier);
880
881         g_hash_table_remove(device->networks, identifier);
882
883         return 0;
884 }
885
886 /**
887  * connman_device_register:
888  * @device: device structure
889  *
890  * Register device with the system
891  */
892 int connman_device_register(struct connman_device *device)
893 {
894         return connman_element_register(&device->element, NULL);
895 }
896
897 /**
898  * connman_device_unregister:
899  * @device: device structure
900  *
901  * Unregister device with the system
902  */
903 void connman_device_unregister(struct connman_device *device)
904 {
905         connman_element_unregister(&device->element);
906 }
907
908 /**
909  * connman_device_get_data:
910  * @device: device structure
911  *
912  * Get private device data pointer
913  */
914 void *connman_device_get_data(struct connman_device *device)
915 {
916         return device->driver_data;
917 }
918
919 /**
920  * connman_device_set_data:
921  * @device: device structure
922  * @data: data pointer
923  *
924  * Set private device data pointer
925  */
926 void connman_device_set_data(struct connman_device *device, void *data)
927 {
928         device->driver_data = data;
929 }
930
931 static void device_enable(struct connman_device *device)
932 {
933         DBG("device %p", device);
934
935         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
936                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
937                 return;
938
939         if (device->powered == TRUE)
940                 return;
941
942         if (device->driver->enable)
943                 device->driver->enable(device);
944 }
945
946 static void device_disable(struct connman_device *device)
947 {
948         DBG("device %p", device);
949
950         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
951                 return;
952
953         if (device->powered == FALSE)
954                 return;
955
956         g_hash_table_remove_all(device->networks);
957
958         if (device->driver->disable)
959                 device->driver->disable(device);
960 }
961
962 static gboolean match_driver(struct connman_device *device,
963                                         struct connman_device_driver *driver)
964 {
965         if (device->type == driver->type ||
966                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
967                 return TRUE;
968
969         return FALSE;
970 }
971
972 static int device_probe(struct connman_element *element)
973 {
974         struct connman_device *device = element->device;
975         GSList *list;
976         int err;
977
978         DBG("element %p name %s", element, element->name);
979
980         if (device == NULL)
981                 return -ENODEV;
982
983         for (list = driver_list; list; list = list->next) {
984                 struct connman_device_driver *driver = list->data;
985
986                 if (match_driver(device, driver) == FALSE)
987                         continue;
988
989                 DBG("driver %p name %s", driver, driver->name);
990
991                 if (driver->probe(device) == 0) {
992                         device->driver = driver;
993                         break;
994                 }
995         }
996
997         if (device->driver == NULL)
998                 return -ENODEV;
999
1000         err = register_interface(element);
1001         if (err < 0) {
1002                 if (device->driver->remove)
1003                         device->driver->remove(device);
1004                 return err;
1005         }
1006
1007         device_enable(device);
1008
1009         return 0;
1010 }
1011
1012 static void device_remove(struct connman_element *element)
1013 {
1014         struct connman_device *device = element->device;
1015
1016         DBG("element %p name %s", element, element->name);
1017
1018         if (device == NULL)
1019                 return;
1020
1021         if (device->driver == NULL)
1022                 return;
1023
1024         device_disable(device);
1025
1026         unregister_interface(element);
1027
1028         if (device->driver->remove)
1029                 device->driver->remove(device);
1030 }
1031
1032 static struct connman_driver device_driver = {
1033         .name           = "device",
1034         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1035         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1036         .probe          = device_probe,
1037         .remove         = device_remove,
1038 };
1039
1040 int __connman_device_init(void)
1041 {
1042         DBG("");
1043
1044         connection = connman_dbus_get_connection();
1045
1046         return connman_driver_register(&device_driver);
1047 }
1048
1049 void __connman_device_cleanup(void)
1050 {
1051         DBG("");
1052
1053         connman_driver_unregister(&device_driver);
1054
1055         dbus_connection_unref(connection);
1056 }