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