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