Add another D-Bus helper for properties with arrays
[platform/upstream/connman.git] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <string.h>
28
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection = NULL;
34
35 struct connman_device {
36         struct connman_element element;
37         enum connman_device_type type;
38         enum connman_device_mode mode;
39         connman_bool_t offlinemode;
40         connman_bool_t blocked;
41         connman_bool_t powered;
42         connman_bool_t powered_pending;
43         connman_bool_t powered_persistent;
44         connman_bool_t scanning;
45         connman_bool_t disconnected;
46         connman_bool_t reconnect;
47         connman_uint16_t scan_interval;
48         char *name;
49         char *node;
50         char *address;
51         char *interface;
52         char *control;
53         char *ident;
54         int phyindex;
55         unsigned int connections;
56         guint scan_timeout;
57
58         struct connman_device_driver *driver;
59         void *driver_data;
60
61         connman_bool_t registered;
62
63         char *last_network;
64         struct connman_network *network;
65         GHashTable *networks;
66
67         DBusMessage *pending;
68         guint timeout;
69 };
70
71 static gboolean device_scan_trigger(gpointer user_data)
72 {
73         struct connman_device *device = user_data;
74
75         DBG("device %p", device);
76
77         if (device->driver == NULL) {
78                 device->scan_timeout = 0;
79                 return FALSE;
80         }
81
82         if (device->driver->scan)
83                 device->driver->scan(device);
84
85         return TRUE;
86 }
87
88 static void clear_scan_trigger(struct connman_device *device)
89 {
90         if (device->scan_timeout > 0) {
91                 g_source_remove(device->scan_timeout);
92                 device->scan_timeout = 0;
93         }
94 }
95
96 static void reset_scan_trigger(struct connman_device *device)
97 {
98         clear_scan_trigger(device);
99
100         if (device->scan_interval > 0) {
101                 guint interval = device->scan_interval;
102                 device->scan_timeout = g_timeout_add_seconds(interval,
103                                         device_scan_trigger, device);
104         }
105 }
106
107 static void force_scan_trigger(struct connman_device *device)
108 {
109         clear_scan_trigger(device);
110
111         device->scan_timeout = g_timeout_add_seconds(5,
112                                         device_scan_trigger, device);
113 }
114
115 void connman_device_schedule_scan(struct connman_device *device)
116 {
117         reset_scan_trigger(device);
118 }
119
120 static const char *type2description(enum connman_device_type type)
121 {
122         switch (type) {
123         case CONNMAN_DEVICE_TYPE_UNKNOWN:
124         case CONNMAN_DEVICE_TYPE_VENDOR:
125                 break;
126         case CONNMAN_DEVICE_TYPE_ETHERNET:
127                 return "Ethernet";
128         case CONNMAN_DEVICE_TYPE_WIFI:
129                 return "Wireless";
130         case CONNMAN_DEVICE_TYPE_WIMAX:
131                 return "WiMAX";
132         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
133                 return "Bluetooth";
134         case CONNMAN_DEVICE_TYPE_GPS:
135                 return "GPS";
136         case CONNMAN_DEVICE_TYPE_CELLULAR:
137         case CONNMAN_DEVICE_TYPE_MBM:
138         case CONNMAN_DEVICE_TYPE_HSO:
139                 return "Cellular";
140         }
141
142         return NULL;
143 }
144
145 static const char *type2string(enum connman_device_type type)
146 {
147         switch (type) {
148         case CONNMAN_DEVICE_TYPE_UNKNOWN:
149         case CONNMAN_DEVICE_TYPE_VENDOR:
150                 break;
151         case CONNMAN_DEVICE_TYPE_ETHERNET:
152                 return "ethernet";
153         case CONNMAN_DEVICE_TYPE_WIFI:
154                 return "wifi";
155         case CONNMAN_DEVICE_TYPE_WIMAX:
156                 return "wimax";
157         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
158                 return "bluetooth";
159         case CONNMAN_DEVICE_TYPE_GPS:
160                 return "gps";
161         case CONNMAN_DEVICE_TYPE_CELLULAR:
162         case CONNMAN_DEVICE_TYPE_MBM:
163         case CONNMAN_DEVICE_TYPE_HSO:
164                 return "cellular";
165         }
166
167         return NULL;
168 }
169
170 enum connman_service_type __connman_device_get_service_type(struct connman_device *device)
171 {
172         enum connman_device_type type = connman_device_get_type(device);
173
174         switch (type) {
175         case CONNMAN_DEVICE_TYPE_UNKNOWN:
176         case CONNMAN_DEVICE_TYPE_VENDOR:
177         case CONNMAN_DEVICE_TYPE_GPS:
178                 break;
179         case CONNMAN_DEVICE_TYPE_ETHERNET:
180                 return CONNMAN_SERVICE_TYPE_ETHERNET;
181         case CONNMAN_DEVICE_TYPE_WIFI:
182                 return CONNMAN_SERVICE_TYPE_WIFI;
183         case CONNMAN_DEVICE_TYPE_WIMAX:
184                 return CONNMAN_SERVICE_TYPE_WIMAX;
185         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
186                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
187         case CONNMAN_DEVICE_TYPE_CELLULAR:
188         case CONNMAN_DEVICE_TYPE_MBM:
189         case CONNMAN_DEVICE_TYPE_HSO:
190                 return CONNMAN_SERVICE_TYPE_CELLULAR;
191         }
192
193         return CONNMAN_SERVICE_TYPE_UNKNOWN;
194 }
195
196 static int powered_changed(struct connman_device *device)
197 {
198         DBusMessage *signal;
199         DBusMessageIter entry, value;
200         const char *key = "Powered";
201
202         signal = dbus_message_new_signal(device->element.path,
203                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
204         if (signal == NULL)
205                 return -ENOMEM;
206
207         dbus_message_iter_init_append(signal, &entry);
208
209         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
210
211         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
212                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
213         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
214                                                         &device->powered);
215         dbus_message_iter_close_container(&entry, &value);
216
217         g_dbus_send_message(connection, signal);
218
219         return 0;
220 }
221
222 static int set_powered(struct connman_device *device, connman_bool_t powered)
223 {
224         struct connman_device_driver *driver = device->driver;
225         enum connman_service_type type;
226         int err;
227
228         DBG("device %p powered %d", device, powered);
229
230         if (device->powered_pending == powered)
231                 return -EALREADY;
232
233         if (!driver)
234                 return -EINVAL;
235
236         type = __connman_device_get_service_type(device);
237
238         if (powered == TRUE) {
239                 if (driver->enable) {
240                         device->powered_pending = powered;
241
242                         err = driver->enable(device);
243                         if (err == 0)
244                                 __connman_notifier_enable(type);
245                 } else
246                         err = -EINVAL;
247         } else {
248                 device->powered_pending = powered;
249
250                 device->reconnect = FALSE;
251
252                 clear_scan_trigger(device);
253
254                 g_hash_table_remove_all(device->networks);
255
256                 if (driver->disable) {
257                         err = driver->disable(device);
258                         if (err == 0)
259                                 __connman_notifier_disable(type);
260                 } else
261                         err = -EINVAL;
262         }
263
264         if (err == 0) {
265                 device->powered = powered;
266
267                 if (device->registered == TRUE)
268                         powered_changed(device);
269         }
270
271         return err;
272 }
273
274 void __connman_device_list(DBusMessageIter *iter)
275 {
276         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, iter);
277 }
278
279 static void append_path(gpointer key, gpointer value, gpointer user_data)
280 {
281         struct connman_element *element = value;
282         DBusMessageIter *iter = user_data;
283
284         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
285                                                         &element->path);
286 }
287
288 static void append_networks(struct connman_device *device,
289                                                 DBusMessageIter *entry)
290 {
291         DBusMessageIter value, iter;
292         const char *key = "Networks";
293
294         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
295
296         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
297                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
298                                                                 &value);
299
300         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
301                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
302         g_hash_table_foreach(device->networks, append_path, &iter);
303         dbus_message_iter_close_container(&value, &iter);
304
305         dbus_message_iter_close_container(entry, &value);
306 }
307
308 static DBusMessage *get_properties(DBusConnection *conn,
309                                         DBusMessage *msg, void *data)
310 {
311         struct connman_device *device = data;
312         DBusMessage *reply;
313         DBusMessageIter array, dict, entry;
314         const char *str;
315
316         DBG("conn %p", conn);
317
318         if (__connman_security_check_privilege(msg,
319                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
320                 return __connman_error_permission_denied(msg);
321
322         reply = dbus_message_new_method_return(msg);
323         if (reply == NULL)
324                 return NULL;
325
326         dbus_message_iter_init_append(reply, &array);
327
328         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
329                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
330                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
331                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
332
333         if (device->name != NULL)
334                 connman_dbus_dict_append_variant(&dict, "Name",
335                                         DBUS_TYPE_STRING, &device->name);
336
337         str = type2string(device->type);
338         if (str != NULL)
339                 connman_dbus_dict_append_variant(&dict, "Type",
340                                                 DBUS_TYPE_STRING, &str);
341
342         if (device->address != NULL)
343                 connman_dbus_dict_append_variant(&dict, "Address",
344                                         DBUS_TYPE_STRING, &device->address);
345
346         if (device->interface != NULL)
347                 connman_dbus_dict_append_variant(&dict, "Interface",
348                                         DBUS_TYPE_STRING, &device->interface);
349
350         connman_dbus_dict_append_variant(&dict, "Powered",
351                                         DBUS_TYPE_BOOLEAN, &device->powered);
352
353         if (device->driver && device->driver->scan)
354                 connman_dbus_dict_append_variant(&dict, "Scanning",
355                                         DBUS_TYPE_BOOLEAN, &device->scanning);
356
357         switch (device->mode) {
358         case CONNMAN_DEVICE_MODE_UNKNOWN:
359                 break;
360         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
361         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
362                 if (device->scan_interval > 0)
363                         connman_dbus_dict_append_variant(&dict, "ScanInterval",
364                                 DBUS_TYPE_UINT16, &device->scan_interval);
365
366                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
367                                                                 NULL, &entry);
368                 append_networks(device, &entry);
369                 dbus_message_iter_close_container(&dict, &entry);
370                 break;
371         }
372
373         dbus_message_iter_close_container(&array, &dict);
374
375         return reply;
376 }
377
378 static gboolean powered_timeout(gpointer user_data)
379 {
380         struct connman_device *device = user_data;
381
382         DBG("device %p", device);
383
384         device->timeout = 0;
385
386         if (device->pending != NULL) {
387                 DBusMessage *reply;
388
389                 reply = __connman_error_operation_timeout(device->pending);
390                 if (reply != NULL)
391                         g_dbus_send_message(connection, reply);
392
393                 dbus_message_unref(device->pending);
394                 device->pending = NULL;
395         }
396
397         return FALSE;
398 }
399
400 static DBusMessage *set_property(DBusConnection *conn,
401                                         DBusMessage *msg, void *data)
402 {
403         struct connman_device *device = data;
404         DBusMessageIter iter, value;
405         const char *name;
406         int type;
407
408         DBG("conn %p", conn);
409
410         if (dbus_message_iter_init(msg, &iter) == FALSE)
411                 return __connman_error_invalid_arguments(msg);
412
413         dbus_message_iter_get_basic(&iter, &name);
414         dbus_message_iter_next(&iter);
415         dbus_message_iter_recurse(&iter, &value);
416
417         if (__connman_security_check_privilege(msg,
418                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
419                 return __connman_error_permission_denied(msg);
420
421         type = dbus_message_iter_get_arg_type(&value);
422
423         if (g_str_equal(name, "Powered") == TRUE) {
424                 connman_bool_t powered;
425                 int err;
426
427                 if (type != DBUS_TYPE_BOOLEAN)
428                         return __connman_error_invalid_arguments(msg);
429
430                 dbus_message_iter_get_basic(&value, &powered);
431
432                 device->powered_persistent = powered;
433
434                 __connman_storage_save_device(device);
435
436                 if (device->powered == powered)
437                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
438
439                 if (device->pending != NULL)
440                         return __connman_error_in_progress(msg);
441
442                 err = set_powered(device, powered);
443                 if (err < 0) {
444                         if (err != -EINPROGRESS)
445                                 return __connman_error_failed(msg, -err);
446
447                         device->pending = dbus_message_ref(msg);
448
449                         device->timeout = g_timeout_add_seconds(15,
450                                                 powered_timeout, device);
451
452                         return NULL;
453                 }
454         } else if (g_str_equal(name, "ScanInterval") == TRUE) {
455                 connman_uint16_t interval;
456
457                 switch (device->mode) {
458                 case CONNMAN_DEVICE_MODE_UNKNOWN:
459                 case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
460                 case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
461                         break;
462                 }
463
464                 if (type != DBUS_TYPE_UINT16)
465                         return __connman_error_invalid_arguments(msg);
466
467                 dbus_message_iter_get_basic(&value, &interval);
468
469                 if (device->scan_interval != interval) {
470                         device->scan_interval = interval;
471
472                         __connman_storage_save_device(device);
473
474                         reset_scan_trigger(device);
475                 }
476         } else
477                 return __connman_error_invalid_property(msg);
478
479         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
480 }
481
482 static DBusMessage *propose_scan(DBusConnection *conn,
483                                         DBusMessage *msg, void *data)
484 {
485         struct connman_device *device = data;
486         int err;
487
488         DBG("conn %p", conn);
489
490         switch (device->mode) {
491         case CONNMAN_DEVICE_MODE_UNKNOWN:
492                 return __connman_error_not_supported(msg);
493         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
494         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
495                 break;
496         }
497
498         err = __connman_device_scan(device);
499         if (err < 0)
500                 return __connman_error_failed(msg, -err);
501
502         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
503 }
504
505 static GDBusMethodTable device_methods[] = {
506         { "GetProperties", "",      "a{sv}", get_properties },
507         { "SetProperty",   "sv",    "",      set_property,
508                                                 G_DBUS_METHOD_FLAG_ASYNC },
509         { "ProposeScan",   "",      "",      propose_scan   },
510         { },
511 };
512
513 static GDBusSignalTable device_signals[] = {
514         { "PropertyChanged", "sv" },
515         { },
516 };
517
518 static void append_devices(DBusMessageIter *entry)
519 {
520         DBusMessageIter value, iter;
521         const char *key = "Devices";
522
523         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
524
525         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
526                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
527                                                                 &value);
528
529         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
530                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
531         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
532         dbus_message_iter_close_container(&value, &iter);
533
534         dbus_message_iter_close_container(entry, &value);
535 }
536
537 static void emit_devices_signal(void)
538 {
539         DBusMessage *signal;
540         DBusMessageIter entry;
541
542         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
543                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
544         if (signal == NULL)
545                 return;
546
547         dbus_message_iter_init_append(signal, &entry);
548
549         append_devices(&entry);
550
551         g_dbus_send_message(connection, signal);
552 }
553
554 static int register_interface(struct connman_element *element)
555 {
556         struct connman_device *device = element->device;
557
558         DBG("element %p name %s", element, element->name);
559
560         if (g_dbus_register_interface(connection, element->path,
561                                         CONNMAN_DEVICE_INTERFACE,
562                                         device_methods, device_signals,
563                                         NULL, device, NULL) == FALSE) {
564                 connman_error("Failed to register %s device", element->path);
565                 return -EIO;
566         }
567
568         device->registered = TRUE;
569
570         emit_devices_signal();
571
572         return 0;
573 }
574
575 static void unregister_interface(struct connman_element *element)
576 {
577         struct connman_device *device = element->device;
578
579         DBG("element %p name %s", element, element->name);
580
581         device->registered = FALSE;
582
583         emit_devices_signal();
584
585         g_dbus_unregister_interface(connection, element->path,
586                                                 CONNMAN_DEVICE_INTERFACE);
587 }
588
589 static int setup_device(struct connman_device *device)
590 {
591         enum connman_service_type type;
592         int err;
593
594         DBG("device %p", device);
595
596         err = register_interface(&device->element);
597         if (err < 0) {
598                 if (device->driver->remove)
599                         device->driver->remove(device);
600                 device->driver = NULL;
601                 return err;
602         }
603
604         type = __connman_device_get_service_type(device);
605         __connman_notifier_register(type);
606
607         switch (device->mode) {
608         case CONNMAN_DEVICE_MODE_UNKNOWN:
609         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
610         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
611                 break;
612         }
613
614         if (device->offlinemode == FALSE &&
615                                 device->powered_persistent == TRUE)
616                 __connman_device_enable(device);
617
618         return 0;
619 }
620
621 static void probe_driver(struct connman_element *element, gpointer user_data)
622 {
623         struct connman_device_driver *driver = user_data;
624
625         DBG("element %p name %s", element, element->name);
626
627         if (element->device == NULL)
628                 return;
629
630         if (element->device->driver != NULL)
631                 return;
632
633         if (driver->type != element->device->type)
634                 return;
635
636         if (driver->probe(element->device) < 0)
637                 return;
638
639         element->device->driver = driver;
640
641         setup_device(element->device);
642 }
643
644 static void remove_device(struct connman_device *device)
645 {
646         enum connman_service_type type;
647
648         DBG("device %p", device);
649
650         __connman_device_disable(device);
651
652         switch (device->mode) {
653         case CONNMAN_DEVICE_MODE_UNKNOWN:
654         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
655         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
656                 break;
657         }
658
659         type = __connman_device_get_service_type(device);
660         __connman_notifier_unregister(type);
661
662         unregister_interface(&device->element);
663
664         if (device->driver->remove)
665                 device->driver->remove(device);
666
667         device->driver = NULL;
668 }
669
670 static void remove_driver(struct connman_element *element, gpointer user_data)
671 {
672         struct connman_device_driver *driver = user_data;
673
674         DBG("element %p name %s", element, element->name);
675
676         if (element->device == NULL)
677                 return;
678
679         if (element->device->driver == driver)
680                 remove_device(element->device);
681 }
682
683 connman_bool_t __connman_device_has_driver(struct connman_device *device)
684 {
685         if (device == NULL || device->driver == NULL)
686                 return FALSE;
687
688         return device->registered;
689 }
690
691 static GSList *driver_list = NULL;
692
693 static gint compare_priority(gconstpointer a, gconstpointer b)
694 {
695         const struct connman_device_driver *driver1 = a;
696         const struct connman_device_driver *driver2 = b;
697
698         return driver2->priority - driver1->priority;
699 }
700
701 /**
702  * connman_device_driver_register:
703  * @driver: device driver definition
704  *
705  * Register a new device driver
706  *
707  * Returns: %0 on success
708  */
709 int connman_device_driver_register(struct connman_device_driver *driver)
710 {
711         DBG("driver %p name %s", driver, driver->name);
712
713         driver_list = g_slist_insert_sorted(driver_list, driver,
714                                                         compare_priority);
715
716         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
717                                                 probe_driver, driver);
718
719         return 0;
720 }
721
722 /**
723  * connman_device_driver_unregister:
724  * @driver: device driver definition
725  *
726  * Remove a previously registered device driver
727  */
728 void connman_device_driver_unregister(struct connman_device_driver *driver)
729 {
730         DBG("driver %p name %s", driver, driver->name);
731
732         driver_list = g_slist_remove(driver_list, driver);
733
734         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
735                                                 remove_driver, driver);
736 }
737
738 static void unregister_network(gpointer data)
739 {
740         struct connman_network *network = data;
741
742         DBG("network %p", network);
743
744         connman_element_unregister((struct connman_element *) network);
745
746         connman_network_unref(network);
747 }
748
749 static void device_destruct(struct connman_element *element)
750 {
751         struct connman_device *device = element->device;
752
753         DBG("element %p name %s", element, element->name);
754
755         if (device->timeout > 0) {
756                 g_source_remove(device->timeout);
757                 device->timeout = 0;
758         }
759
760         clear_scan_trigger(device);
761
762         if (device->pending != NULL) {
763                 dbus_message_unref(device->pending);
764                 device->pending = NULL;
765         }
766
767         g_free(device->ident);
768         g_free(device->node);
769         g_free(device->name);
770         g_free(device->address);
771         g_free(device->control);
772         g_free(device->interface);
773
774         g_free(device->last_network);
775
776         g_hash_table_destroy(device->networks);
777         device->networks = NULL;
778 }
779
780 /**
781  * connman_device_create:
782  * @node: device node name (for example an address)
783  * @type: device type
784  *
785  * Allocate a new device of given #type and assign the #node name to it.
786  *
787  * Returns: a newly-allocated #connman_device structure
788  */
789 struct connman_device *connman_device_create(const char *node,
790                                                 enum connman_device_type type)
791 {
792         struct connman_device *device;
793         const char *str;
794
795         DBG("node %s type %d", node, type);
796
797         device = g_try_new0(struct connman_device, 1);
798         if (device == NULL)
799                 return NULL;
800
801         DBG("device %p", device);
802
803         __connman_element_initialize(&device->element);
804
805         device->element.name = g_strdup(node);
806         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
807
808         device->element.device = device;
809         device->element.destruct = device_destruct;
810
811         str = type2string(type);
812         if (str != NULL)
813                 connman_element_set_string(&device->element,
814                                         CONNMAN_PROPERTY_ID_TYPE, str);
815
816         device->element.ipv4.method = CONNMAN_IPCONFIG_METHOD_DHCP;
817
818         device->type = type;
819         device->name = g_strdup(type2description(device->type));
820         device->mode = CONNMAN_DEVICE_MODE_UNKNOWN;
821
822         device->powered_persistent = TRUE;
823
824         device->phyindex = -1;
825
826         switch (type) {
827         case CONNMAN_DEVICE_TYPE_UNKNOWN:
828         case CONNMAN_DEVICE_TYPE_VENDOR:
829                 device->scan_interval = 0;
830                 break;
831         case CONNMAN_DEVICE_TYPE_ETHERNET:
832         case CONNMAN_DEVICE_TYPE_WIFI:
833                 device->scan_interval = 300;
834                 break;
835         case CONNMAN_DEVICE_TYPE_WIMAX:
836                 device->scan_interval = 0;
837                 break;
838         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
839                 device->scan_interval = 0;
840                 break;
841         case CONNMAN_DEVICE_TYPE_GPS:
842                 device->scan_interval = 0;
843                 break;
844         case CONNMAN_DEVICE_TYPE_CELLULAR:
845         case CONNMAN_DEVICE_TYPE_MBM:
846         case CONNMAN_DEVICE_TYPE_HSO:
847                 device->scan_interval = 0;
848                 break;
849         }
850
851         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
852                                                 g_free, unregister_network);
853
854         return device;
855 }
856
857 /**
858  * connman_device_ref:
859  * @device: device structure
860  *
861  * Increase reference counter of device
862  */
863 struct connman_device *connman_device_ref(struct connman_device *device)
864 {
865         if (connman_element_ref(&device->element) == NULL)
866                 return NULL;
867
868         return device;
869 }
870
871 /**
872  * connman_device_unref:
873  * @device: device structure
874  *
875  * Decrease reference counter of device
876  */
877 void connman_device_unref(struct connman_device *device)
878 {
879         connman_element_unref(&device->element);
880 }
881
882 const char *__connman_device_get_type(struct connman_device *device)
883 {
884         return type2string(device->type);
885 }
886
887 /**
888  * connman_device_get_type:
889  * @device: device structure
890  *
891  * Get type of device
892  */
893 enum connman_device_type connman_device_get_type(struct connman_device *device)
894 {
895         return device->type;
896 }
897
898 /**
899  * connman_device_get_name:
900  * @device: device structure
901  *
902  * Get unique name of device
903  */
904 const char *connman_device_get_name(struct connman_device *device)
905 {
906         return device->element.name;
907 }
908
909 /**
910  * connman_device_get_path:
911  * @device: device structure
912  *
913  * Get path name of device
914  */
915 const char *connman_device_get_path(struct connman_device *device)
916 {
917         return device->element.path;
918 }
919
920 /**
921  * connman_device_set_index:
922  * @device: device structure
923  * @index: index number
924  *
925  * Set index number of device
926  */
927 void connman_device_set_index(struct connman_device *device, int index)
928 {
929         device->element.index = index;
930 }
931
932 /**
933  * connman_device_get_index:
934  * @device: device structure
935  *
936  * Get index number of device
937  */
938 int connman_device_get_index(struct connman_device *device)
939 {
940         return device->element.index;
941 }
942
943 int __connman_device_get_phyindex(struct connman_device *device)
944 {
945         return device->phyindex;
946 }
947
948 void __connman_device_set_phyindex(struct connman_device *device,
949                                                         int phyindex)
950 {
951         device->phyindex = phyindex;
952 }
953
954 /**
955  * connman_device_set_interface:
956  * @device: device structure
957  * @interface: interface name
958  * @control: control interface
959  *
960  * Set interface name of device
961  */
962 void connman_device_set_interface(struct connman_device *device,
963                                 const char *interface, const char *control)
964 {
965         g_free(device->element.devname);
966         device->element.devname = g_strdup(interface);
967
968         g_free(device->interface);
969         device->interface = g_strdup(interface);
970
971         g_free(device->control);
972         device->control = g_strdup(control);
973
974         if (device->name == NULL) {
975                 const char *str = type2description(device->type);
976                 if (str != NULL && device->interface != NULL)
977                         device->name = g_strdup_printf("%s (%s)", str,
978                                                         device->interface);
979         }
980 }
981
982 const char *connman_device_get_control(struct connman_device *device)
983 {
984         return device->control;
985 }
986
987 /**
988  * connman_device_set_ident:
989  * @device: device structure
990  * @ident: unique identifier
991  *
992  * Set unique identifier of device
993  */
994 void connman_device_set_ident(struct connman_device *device,
995                                                         const char *ident)
996 {
997         g_free(device->ident);
998         device->ident = g_strdup(ident);
999 }
1000
1001 const char *__connman_device_get_ident(struct connman_device *device)
1002 {
1003         return device->ident;
1004 }
1005
1006 /**
1007  * connman_device_set_mode:
1008  * @device: device structure
1009  * @mode: network mode
1010  *
1011  * Change network mode of device
1012  */
1013 void connman_device_set_mode(struct connman_device *device,
1014                                                 enum connman_device_mode mode)
1015 {
1016         device->mode = mode;
1017 }
1018
1019 /**
1020  * connman_device_get_mode:
1021  * @device: device structure
1022  *
1023  * Get network mode of device
1024  */
1025 enum connman_device_mode connman_device_get_mode(struct connman_device *device)
1026 {
1027         return device->mode;
1028 }
1029
1030 /**
1031  * connman_device_set_powered:
1032  * @device: device structure
1033  * @powered: powered state
1034  *
1035  * Change power state of device
1036  */
1037 int connman_device_set_powered(struct connman_device *device,
1038                                                 connman_bool_t powered)
1039 {
1040         enum connman_service_type type;
1041
1042         DBG("driver %p powered %d", device, powered);
1043
1044         if (device->timeout > 0) {
1045                 g_source_remove(device->timeout);
1046                 device->timeout = 0;
1047         }
1048
1049         if (device->pending != NULL) {
1050                 g_dbus_send_reply(connection, device->pending,
1051                                                         DBUS_TYPE_INVALID);
1052
1053                 dbus_message_unref(device->pending);
1054                 device->pending = NULL;
1055         }
1056
1057         if (device->powered == powered)
1058                 return -EALREADY;
1059
1060         device->powered = powered;
1061         device->powered_pending = powered;
1062
1063         type = __connman_device_get_service_type(device);
1064
1065         if (device->powered == TRUE)
1066                 __connman_notifier_enable(type);
1067         else
1068                 __connman_notifier_disable(type);
1069
1070         if (device->registered == FALSE)
1071                 return 0;
1072
1073         powered_changed(device);
1074
1075         if (powered == FALSE)
1076                 return 0;
1077
1078         reset_scan_trigger(device);
1079
1080         if (device->driver->scan)
1081                 device->driver->scan(device);
1082
1083         return 0;
1084 }
1085
1086 int __connman_device_set_blocked(struct connman_device *device,
1087                                                 connman_bool_t blocked)
1088 {
1089         connman_bool_t powered;
1090
1091         DBG("device %p blocked %d", device, blocked);
1092
1093         device->blocked = blocked;
1094
1095         if (device->offlinemode == TRUE)
1096                 return 0;
1097
1098         connman_info("%s {rfkill} blocked %d", device->interface, blocked);
1099
1100         if (blocked == FALSE)
1101                 powered = device->powered_persistent;
1102         else
1103                 powered = FALSE;
1104
1105         return set_powered(device, powered);
1106 }
1107
1108 int __connman_device_scan(struct connman_device *device)
1109 {
1110         if (!device->driver || !device->driver->scan)
1111                 return -EOPNOTSUPP;
1112
1113         if (device->powered == FALSE)
1114                 return -ENOLINK;
1115
1116         reset_scan_trigger(device);
1117
1118         return device->driver->scan(device);
1119 }
1120
1121 int __connman_device_enable(struct connman_device *device)
1122 {
1123         enum connman_service_type type;
1124         int err;
1125
1126         DBG("device %p", device);
1127
1128         if (!device->driver || !device->driver->enable)
1129                 return -EOPNOTSUPP;
1130
1131         if (device->powered_pending == TRUE)
1132                 return -EALREADY;
1133
1134         device->powered_pending = TRUE;
1135
1136         err = device->driver->enable(device);
1137         if (err < 0)
1138                 return err;
1139
1140         device->powered = TRUE;
1141
1142         type = __connman_device_get_service_type(device);
1143         __connman_notifier_enable(type);
1144
1145         return 0;
1146 }
1147
1148 int __connman_device_enable_persistent(struct connman_device *device)
1149 {
1150         DBG("device %p", device);
1151
1152         device->powered_persistent = TRUE;
1153
1154         __connman_storage_save_device(device);
1155
1156         return __connman_device_enable(device);
1157 }
1158
1159 int __connman_device_disable(struct connman_device *device)
1160 {
1161         enum connman_service_type type;
1162         int err;
1163
1164         DBG("device %p", device);
1165
1166         if (!device->driver || !device->driver->disable)
1167                 return -EOPNOTSUPP;
1168
1169         if (device->powered == FALSE)
1170                 return -ENOLINK;
1171
1172         if (device->powered_pending == FALSE)
1173                 return -EALREADY;
1174
1175         device->powered_pending = FALSE;
1176
1177         device->reconnect = FALSE;
1178
1179         clear_scan_trigger(device);
1180
1181         g_hash_table_remove_all(device->networks);
1182
1183         err = device->driver->disable(device);
1184         if (err < 0)
1185                 return err;
1186
1187         device->powered = FALSE;
1188
1189         type = __connman_device_get_service_type(device);
1190         __connman_notifier_disable(type);
1191
1192         return 0;
1193 }
1194
1195 int __connman_device_disable_persistent(struct connman_device *device)
1196 {
1197         DBG("device %p", device);
1198
1199         device->powered_persistent = FALSE;
1200
1201         __connman_storage_save_device(device);
1202
1203         return __connman_device_disable(device);
1204 }
1205
1206 int __connman_device_disconnect(struct connman_device *device)
1207 {
1208         GHashTableIter iter;
1209         gpointer key, value;
1210
1211         DBG("device %p", device);
1212
1213         connman_device_set_disconnected(device, TRUE);
1214
1215         g_hash_table_iter_init(&iter, device->networks);
1216
1217         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1218                 struct connman_network *network = value;
1219
1220                 if (__connman_network_get_connecting(network) == TRUE) {
1221                         /*
1222                          * Skip network in the process of connecting.
1223                          * This is a workaround for WiFi networks serviced
1224                          * by the supplicant plugin that hold a reference
1225                          * to the network.  If we disconnect the network
1226                          * here then the referenced object will not be
1227                          * registered and usage (like launching DHCP client)
1228                          * will fail.  There is nothing to be gained by
1229                          * removing the network here anyway.
1230                          */
1231                         connman_warn("Skipping disconnect of %s",
1232                                 connman_network_get_identifier(network));
1233                         continue;
1234                 }
1235
1236                 __connman_network_disconnect(network);
1237         }
1238
1239         return 0;
1240 }
1241
1242 static void mark_network_unavailable(gpointer key, gpointer value,
1243                                                         gpointer user_data)
1244 {
1245         struct connman_network *network = value;
1246
1247         if (connman_network_get_connected(network) == TRUE)
1248                 return;
1249
1250         connman_network_set_available(network, FALSE);
1251 }
1252
1253 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1254                                                         gpointer user_data)
1255 {
1256         struct connman_network *network = value;
1257
1258         if (connman_network_get_connected(network) == TRUE)
1259                 return FALSE;
1260
1261         if (connman_network_get_available(network) == TRUE)
1262                 return FALSE;
1263
1264         return TRUE;
1265 }
1266
1267 void __connman_device_cleanup_networks(struct connman_device *device)
1268 {
1269         g_hash_table_foreach_remove(device->networks,
1270                                         remove_unavailable_network, NULL);
1271 }
1272
1273 static void scanning_changed(struct connman_device *device)
1274 {
1275         DBusMessage *signal;
1276         DBusMessageIter entry, value;
1277         const char *key = "Scanning";
1278
1279         signal = dbus_message_new_signal(device->element.path,
1280                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1281         if (signal == NULL)
1282                 return;
1283
1284         dbus_message_iter_init_append(signal, &entry);
1285
1286         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1287
1288         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1289                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1290         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
1291                                                         &device->scanning);
1292         dbus_message_iter_close_container(&entry, &value);
1293
1294         g_dbus_send_message(connection, signal);
1295 }
1296
1297 static void mark_network_available(gpointer key, gpointer value,
1298                                                 gpointer user_data)
1299 {
1300         struct connman_network *network = value;
1301
1302         connman_network_set_available(network, TRUE);
1303 }
1304
1305 void connman_device_cleanup_scanning(struct connman_device *device)
1306 {
1307         device->scanning = FALSE;
1308
1309         scanning_changed(device);
1310
1311         g_hash_table_foreach(device->networks,
1312                                 mark_network_available, NULL);
1313 }
1314
1315 /**
1316  * connman_device_set_scanning:
1317  * @device: device structure
1318  * @scanning: scanning state
1319  *
1320  * Change scanning state of device
1321  */
1322 int connman_device_set_scanning(struct connman_device *device,
1323                                                 connman_bool_t scanning)
1324 {
1325         DBG("device %p scanning %d", device, scanning);
1326
1327         if (!device->driver || !device->driver->scan)
1328                 return -EINVAL;
1329
1330         if (device->scanning == scanning)
1331                 return -EALREADY;
1332
1333         device->scanning = scanning;
1334
1335         scanning_changed(device);
1336
1337         if (scanning == TRUE) {
1338                 reset_scan_trigger(device);
1339
1340                 g_hash_table_foreach(device->networks,
1341                                         mark_network_unavailable, NULL);
1342
1343                 return 0;
1344         }
1345
1346         __connman_device_cleanup_networks(device);
1347
1348         if (device->connections > 0)
1349                 return 0;
1350
1351         if (device->disconnected == TRUE)
1352                 return 0;
1353
1354         __connman_service_auto_connect();
1355
1356         return 0;
1357 }
1358
1359 /**
1360  * connman_device_set_disconnected:
1361  * @device: device structure
1362  * @disconnected: disconnected state
1363  *
1364  * Change disconnected state of device (only for device with networks)
1365  */
1366 int connman_device_set_disconnected(struct connman_device *device,
1367                                                 connman_bool_t disconnected)
1368 {
1369         DBG("device %p disconnected %d", device, disconnected);
1370
1371         switch (device->mode) {
1372         case CONNMAN_DEVICE_MODE_UNKNOWN:
1373                 return -EINVAL;
1374         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1375         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1376                 break;
1377         }
1378
1379         if (device->disconnected == disconnected)
1380                 return -EALREADY;
1381
1382         device->disconnected = disconnected;
1383
1384         if (disconnected == TRUE)
1385                 force_scan_trigger(device);
1386
1387         return 0;
1388 }
1389
1390 /**
1391  * connman_device_get_disconnected:
1392  * @device: device structure
1393  *
1394  * Get device disconnected state
1395  */
1396 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
1397 {
1398         return device->disconnected;
1399 }
1400
1401 /**
1402  * connman_device_set_string:
1403  * @device: device structure
1404  * @key: unique identifier
1405  * @value: string value
1406  *
1407  * Set string value for specific key
1408  */
1409 int connman_device_set_string(struct connman_device *device,
1410                                         const char *key, const char *value)
1411 {
1412         DBG("device %p key %s value %s", device, key, value);
1413
1414         if (g_str_equal(key, "Address") == TRUE) {
1415                 g_free(device->address);
1416                 device->address = g_strdup(value);
1417         } else if (g_str_equal(key, "Name") == TRUE) {
1418                 g_free(device->name);
1419                 device->name = g_strdup(value);
1420         } else if (g_str_equal(key, "Node") == TRUE) {
1421                 g_free(device->node);
1422                 device->node = g_strdup(value);
1423         }
1424
1425         return connman_element_set_string(&device->element, key, value);
1426 }
1427
1428 /**
1429  * connman_device_get_string:
1430  * @device: device structure
1431  * @key: unique identifier
1432  *
1433  * Get string value for specific key
1434  */
1435 const char *connman_device_get_string(struct connman_device *device,
1436                                                         const char *key)
1437 {
1438         DBG("device %p key %s", device, key);
1439
1440         if (g_str_equal(key, "Address") == TRUE)
1441                 return device->address;
1442         else if (g_str_equal(key, "Name") == TRUE)
1443                 return device->name;
1444         else if (g_str_equal(key, "Node") == TRUE)
1445                 return device->node;
1446
1447         return connman_element_get_string(&device->element, key);
1448 }
1449
1450 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1451 {
1452         struct connman_device *device = element->device;
1453         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1454         connman_bool_t powered;
1455
1456         DBG("element %p name %s", element, element->name);
1457
1458         if (device == NULL)
1459                 return;
1460
1461         device->offlinemode = offlinemode;
1462
1463         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1464
1465         if (device->powered == powered)
1466                 return;
1467
1468         if (device->powered_persistent == FALSE)
1469                 powered = FALSE;
1470
1471         set_powered(device, powered);
1472 }
1473
1474 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1475 {
1476         DBG("offlinmode %d", offlinemode);
1477
1478         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1479                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1480
1481         __connman_notifier_offlinemode(offlinemode);
1482
1483         return 0;
1484 }
1485
1486 void __connman_device_increase_connections(struct connman_device *device)
1487 {
1488         device->connections++;
1489 }
1490
1491 void __connman_device_decrease_connections(struct connman_device *device)
1492 {
1493         device->connections--;
1494 }
1495
1496 /**
1497  * connman_device_add_network:
1498  * @device: device structure
1499  * @network: network structure
1500  *
1501  * Add new network to the device
1502  */
1503 int connman_device_add_network(struct connman_device *device,
1504                                         struct connman_network *network)
1505 {
1506         const char *identifier = connman_network_get_identifier(network);
1507         int err;
1508
1509         DBG("device %p network %p", device, network);
1510
1511         if (identifier == NULL)
1512                 return -EINVAL;
1513
1514         switch (device->mode) {
1515         case CONNMAN_DEVICE_MODE_UNKNOWN:
1516                 return -EINVAL;
1517         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1518         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1519                 break;
1520         }
1521
1522         __connman_network_set_device(network, device);
1523
1524         err = connman_element_register((struct connman_element *) network,
1525                                                         &device->element);
1526         if (err < 0) {
1527                 __connman_network_set_device(network, NULL);
1528                 return err;
1529         }
1530
1531         g_hash_table_insert(device->networks, g_strdup(identifier),
1532                                                                 network);
1533
1534         return 0;
1535 }
1536
1537 /**
1538  * connman_device_get_network:
1539  * @device: device structure
1540  * @identifier: network identifier
1541  *
1542  * Get network for given identifier
1543  */
1544 struct connman_network *connman_device_get_network(struct connman_device *device,
1545                                                         const char *identifier)
1546 {
1547         DBG("device %p identifier %s", device, identifier);
1548
1549         return g_hash_table_lookup(device->networks, identifier);
1550 }
1551
1552 /**
1553  * connman_device_remove_network:
1554  * @device: device structure
1555  * @identifier: network identifier
1556  *
1557  * Remove network for given identifier
1558  */
1559 int connman_device_remove_network(struct connman_device *device,
1560                                                         const char *identifier)
1561 {
1562         DBG("device %p identifier %s", device, identifier);
1563
1564         g_hash_table_remove(device->networks, identifier);
1565
1566         return 0;
1567 }
1568
1569 void connman_device_remove_all_networks(struct connman_device *device)
1570 {
1571         g_hash_table_remove_all(device->networks);
1572 }
1573
1574 void __connman_device_set_network(struct connman_device *device,
1575                                         struct connman_network *network)
1576 {
1577         const char *name;
1578
1579         if (device->network == network)
1580                 return;
1581
1582         if (device->network != NULL)
1583                 connman_network_unref(device->network);
1584
1585         if (network != NULL) {
1586                 name = connman_network_get_string(network,
1587                                                 CONNMAN_PROPERTY_ID_NAME);
1588                 g_free(device->last_network);
1589                 device->last_network = g_strdup(name);
1590
1591                 device->network = connman_network_ref(network);
1592         } else {
1593                 g_free(device->last_network);
1594                 device->last_network = NULL;
1595
1596                 device->network = NULL;
1597         }
1598 }
1599
1600 void __connman_device_set_reconnect(struct connman_device *device,
1601                                                 connman_bool_t reconnect)
1602 {
1603         device->reconnect = reconnect;
1604 }
1605
1606 connman_bool_t  __connman_device_get_reconnect(
1607                                 struct connman_device *device)
1608 {
1609         return device->reconnect;
1610 }
1611
1612 /**
1613  * connman_device_register:
1614  * @device: device structure
1615  *
1616  * Register device with the system
1617  */
1618 int connman_device_register(struct connman_device *device)
1619 {
1620         __connman_storage_load_device(device);
1621
1622         device->offlinemode = __connman_profile_get_offlinemode();
1623
1624         return connman_element_register(&device->element, NULL);
1625 }
1626
1627 /**
1628  * connman_device_unregister:
1629  * @device: device structure
1630  *
1631  * Unregister device with the system
1632  */
1633 void connman_device_unregister(struct connman_device *device)
1634 {
1635         __connman_storage_save_device(device);
1636
1637         connman_element_unregister(&device->element);
1638 }
1639
1640 /**
1641  * connman_device_get_data:
1642  * @device: device structure
1643  *
1644  * Get private device data pointer
1645  */
1646 void *connman_device_get_data(struct connman_device *device)
1647 {
1648         return device->driver_data;
1649 }
1650
1651 /**
1652  * connman_device_set_data:
1653  * @device: device structure
1654  * @data: data pointer
1655  *
1656  * Set private device data pointer
1657  */
1658 void connman_device_set_data(struct connman_device *device, void *data)
1659 {
1660         device->driver_data = data;
1661 }
1662
1663 static gboolean match_driver(struct connman_device *device,
1664                                         struct connman_device_driver *driver)
1665 {
1666         if (device->type == driver->type ||
1667                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1668                 return TRUE;
1669
1670         return FALSE;
1671 }
1672
1673 static int device_probe(struct connman_element *element)
1674 {
1675         struct connman_device *device = element->device;
1676         GSList *list;
1677
1678         DBG("element %p name %s", element, element->name);
1679
1680         if (device == NULL)
1681                 return -ENODEV;
1682
1683         if (device->driver != NULL)
1684                 return -EALREADY;
1685
1686         for (list = driver_list; list; list = list->next) {
1687                 struct connman_device_driver *driver = list->data;
1688
1689                 if (match_driver(device, driver) == FALSE)
1690                         continue;
1691
1692                 DBG("driver %p name %s", driver, driver->name);
1693
1694                 if (driver->probe(device) == 0) {
1695                         device->driver = driver;
1696                         break;
1697                 }
1698         }
1699
1700         if (device->driver == NULL)
1701                 return -ENODEV;
1702
1703         return setup_device(device);
1704 }
1705
1706 static void device_remove(struct connman_element *element)
1707 {
1708         struct connman_device *device = element->device;
1709
1710         DBG("element %p name %s", element, element->name);
1711
1712         if (device == NULL)
1713                 return;
1714
1715         if (device->driver == NULL)
1716                 return;
1717
1718         remove_device(device);
1719 }
1720
1721 static struct connman_driver device_driver = {
1722         .name           = "device",
1723         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1724         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1725         .probe          = device_probe,
1726         .remove         = device_remove,
1727 };
1728
1729 static int device_load(struct connman_device *device)
1730 {
1731         const char *ident = __connman_profile_active_ident();
1732         GKeyFile *keyfile;
1733         GError *error = NULL;
1734         gchar *identifier;
1735         connman_bool_t powered;
1736         int val;
1737
1738         DBG("device %p", device);
1739
1740         keyfile = __connman_storage_open_profile(ident);
1741         if (keyfile == NULL)
1742                 return 0;
1743
1744         identifier = g_strdup_printf("device_%s", device->element.name);
1745         if (identifier == NULL)
1746                 goto done;
1747
1748         powered = g_key_file_get_boolean(keyfile, identifier,
1749                                                 "Powered", &error);
1750         if (error == NULL)
1751                 device->powered_persistent = powered;
1752         g_clear_error(&error);
1753
1754         switch (device->mode) {
1755         case CONNMAN_DEVICE_MODE_UNKNOWN:
1756                 break;
1757         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1758         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1759                 val = g_key_file_get_integer(keyfile, identifier,
1760                                                 "ScanInterval", &error);
1761                 if (error == NULL && val > 0)
1762                         device->scan_interval = val;
1763                 g_clear_error(&error);
1764                 break;
1765         }
1766
1767 done:
1768         g_free(identifier);
1769
1770         __connman_storage_close_profile(ident, keyfile, FALSE);
1771
1772         return 0;
1773 }
1774
1775 static int device_save(struct connman_device *device)
1776 {
1777         const char *ident = __connman_profile_active_ident();
1778         GKeyFile *keyfile;
1779         gchar *identifier;
1780
1781         DBG("device %p", device);
1782
1783         keyfile = __connman_storage_open_profile(ident);
1784         if (keyfile == NULL)
1785                 return 0;
1786
1787         identifier = g_strdup_printf("device_%s", device->element.name);
1788         if (identifier == NULL)
1789                 goto done;
1790
1791         g_key_file_set_boolean(keyfile, identifier,
1792                                         "Powered", device->powered_persistent);
1793
1794         switch (device->mode) {
1795         case CONNMAN_DEVICE_MODE_UNKNOWN:
1796                 break;
1797         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1798         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1799                 if (device->scan_interval > 0)
1800                         g_key_file_set_integer(keyfile, identifier,
1801                                         "ScanInterval", device->scan_interval);
1802                 break;
1803         }
1804
1805 done:
1806         g_free(identifier);
1807
1808         __connman_storage_close_profile(ident, keyfile, TRUE);
1809
1810         return 0;
1811 }
1812
1813 static struct connman_storage device_storage = {
1814         .name           = "device",
1815         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1816         .device_load    = device_load,
1817         .device_save    = device_save,
1818 };
1819
1820 int __connman_device_init(void)
1821 {
1822         DBG("");
1823
1824         connection = connman_dbus_get_connection();
1825
1826         if (connman_storage_register(&device_storage) < 0)
1827                 connman_error("Failed to register device storage");
1828
1829         return connman_driver_register(&device_driver);
1830 }
1831
1832 void __connman_device_cleanup(void)
1833 {
1834         DBG("");
1835
1836         connman_driver_unregister(&device_driver);
1837
1838         connman_storage_unregister(&device_storage);
1839
1840         dbus_connection_unref(connection);
1841 }