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