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