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