Don't try to re-connect to networks out of range
[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         connman_device_set_disconnected(device, TRUE);
1040
1041         g_hash_table_iter_init(&iter, device->networks);
1042
1043         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1044                 struct connman_network *network = value;
1045
1046                 if (connman_network_get_connected(network) == TRUE)
1047                         __connman_network_disconnect(network);
1048         }
1049 }
1050
1051 static void connect_known_network(struct connman_device *device)
1052 {
1053         struct connman_network *network = NULL;
1054         GHashTableIter iter;
1055         gpointer key, value;
1056         unsigned int count = 0;
1057
1058         DBG("device %p", device);
1059
1060         g_hash_table_iter_init(&iter, device->networks);
1061
1062         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1063                 connman_uint8_t old_priority, new_priority;
1064                 connman_uint8_t old_strength, new_strength;
1065                 const char *name;
1066
1067                 count++;
1068
1069                 if (connman_network_get_available(value) == FALSE)
1070                         continue;
1071
1072                 name = connman_network_get_string(value, "Name");
1073                 if (name != NULL && device->last_network != NULL) {
1074                         if (g_str_equal(name, device->last_network) == TRUE) {
1075                                 network = value;
1076                                 break;
1077                         }
1078                 }
1079
1080                 if (connman_network_get_remember(value) == FALSE)
1081                         continue;
1082
1083                 if (network == NULL) {
1084                         network = value;
1085                         continue;
1086                 }
1087
1088                 old_priority = connman_network_get_uint8(network, "Priority");
1089                 new_priority = connman_network_get_uint8(value, "Priority");
1090
1091                 if (new_priority != old_priority) {
1092                         if (new_priority > old_priority)
1093                                 network = value;
1094                         continue;
1095                 }
1096
1097                 old_strength = connman_network_get_uint8(network, "Strength");
1098                 new_strength = connman_network_get_uint8(value, "Strength");
1099
1100                 if (new_strength > old_strength)
1101                         network = value;
1102         }
1103
1104         if (network != NULL) {
1105                 int err;
1106
1107                 err = connman_network_connect(network);
1108                 if (err == 0 || err == -EINPROGRESS)
1109                         return;
1110         }
1111
1112         if (count > 0)
1113                 return;
1114
1115         if (device->driver && device->driver->scan)
1116                 device->driver->scan(device);
1117 }
1118
1119 static void mark_network_unavailable(gpointer key, gpointer value,
1120                                                         gpointer user_data)
1121 {
1122         struct connman_network *network = value;
1123
1124         if (connman_network_get_connected(network) == TRUE)
1125                 return;
1126
1127         connman_network_set_available(network, FALSE);
1128 }
1129
1130 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1131                                                         gpointer user_data)
1132 {
1133         struct connman_network *network = value;
1134
1135         if (connman_network_get_connected(network) == TRUE)
1136                 return FALSE;
1137
1138         if (connman_network_get_remember(network) == TRUE)
1139                 return FALSE;
1140
1141         if (connman_network_get_available(network) == TRUE)
1142                 return FALSE;
1143
1144         return TRUE;
1145 }
1146
1147 /**
1148  * connman_device_set_scanning:
1149  * @device: device structure
1150  * @scanning: scanning state
1151  *
1152  * Change scanning state of device
1153  */
1154 int connman_device_set_scanning(struct connman_device *device,
1155                                                 connman_bool_t scanning)
1156 {
1157         DBusMessage *signal;
1158         DBusMessageIter entry, value;
1159         const char *key = "Scanning";
1160
1161         DBG("driver %p scanning %d", device, scanning);
1162
1163         if (!device->driver || !device->driver->scan)
1164                 return -EINVAL;
1165
1166         if (device->scanning == scanning)
1167                 return -EALREADY;
1168
1169         device->scanning = scanning;
1170
1171         signal = dbus_message_new_signal(device->element.path,
1172                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1173         if (signal == NULL)
1174                 return 0;
1175
1176         dbus_message_iter_init_append(signal, &entry);
1177
1178         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1179
1180         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1181                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1182         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1183         dbus_message_iter_close_container(&entry, &value);
1184
1185         g_dbus_send_message(connection, signal);
1186
1187         if (scanning == TRUE) {
1188                 g_hash_table_foreach(device->networks,
1189                                         mark_network_unavailable, NULL);
1190                 return 0;
1191         }
1192
1193         g_hash_table_foreach_remove(device->networks,
1194                                         remove_unavailable_network, NULL);
1195
1196         if (device->connections > 0)
1197                 return 0;
1198
1199         if (device->disconnected == TRUE)
1200                 return 0;
1201
1202         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1203                 return 0;
1204
1205         connect_known_network(device);
1206
1207         return 0;
1208 }
1209
1210 /**
1211  * connman_device_set_disconnected:
1212  * @device: device structure
1213  * @disconnected: disconnected state
1214  *
1215  * Change disconnected state of device (only for device with networks)
1216  */
1217 int connman_device_set_disconnected(struct connman_device *device,
1218                                                 connman_bool_t disconnected)
1219 {
1220         DBG("driver %p disconnected %d", device, disconnected);
1221
1222         switch (device->mode) {
1223         case CONNMAN_DEVICE_MODE_UNKNOWN:
1224         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1225                 return -EINVAL;
1226         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1227         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1228                 break;
1229         }
1230
1231         if (device->disconnected == disconnected)
1232                 return -EALREADY;
1233
1234         device->disconnected = disconnected;
1235
1236         return 0;
1237 }
1238
1239 /**
1240  * connman_device_set_string:
1241  * @device: device structure
1242  * @key: unique identifier
1243  * @value: string value
1244  *
1245  * Set string value for specific key
1246  */
1247 int connman_device_set_string(struct connman_device *device,
1248                                         const char *key, const char *value)
1249 {
1250         DBG("device %p key %s value %s", device, key, value);
1251
1252         if (g_str_equal(key, "Name") == TRUE) {
1253                 g_free(device->name);
1254                 device->name = g_strdup(value);
1255         } else if (g_str_equal(key, "Node") == TRUE) {
1256                 g_free(device->node);
1257                 device->node = g_strdup(value);
1258         }
1259
1260         return 0;
1261 }
1262
1263 /**
1264  * connman_device_get_string:
1265  * @device: device structure
1266  * @key: unique identifier
1267  *
1268  * Get string value for specific key
1269  */
1270 const char *connman_device_get_string(struct connman_device *device,
1271                                                         const char *key)
1272 {
1273         DBG("device %p key %s", device, key);
1274
1275         if (g_str_equal(key, "Name") == TRUE)
1276                 return device->name;
1277         else if (g_str_equal(key, "Node") == TRUE)
1278                 return device->node;
1279
1280         return NULL;
1281 }
1282
1283 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1284 {
1285         struct connman_device *device = element->device;
1286         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1287         connman_bool_t powered;
1288
1289         DBG("element %p name %s", element, element->name);
1290
1291         if (device == NULL)
1292                 return;
1293
1294         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1295
1296         if (device->powered == powered)
1297                 return;
1298
1299         set_powered(device, powered);
1300 }
1301
1302 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1303 {
1304         DBG("offlinmode %d", offlinemode);
1305
1306         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1307                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1308
1309         return 0;
1310 }
1311
1312 void __connman_device_increase_connections(struct connman_device *device)
1313 {
1314         device->connections++;
1315 }
1316
1317 void __connman_device_decrease_connections(struct connman_device *device)
1318 {
1319         device->connections--;
1320 }
1321
1322 /**
1323  * connman_device_add_network:
1324  * @device: device structure
1325  * @network: network structure
1326  *
1327  * Add new network to the device
1328  */
1329 int connman_device_add_network(struct connman_device *device,
1330                                         struct connman_network *network)
1331 {
1332         const char *identifier = connman_network_get_identifier(network);
1333         int err;
1334
1335         DBG("device %p network %p", device, network);
1336
1337         switch (device->mode) {
1338         case CONNMAN_DEVICE_MODE_UNKNOWN:
1339         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1340                 return -EINVAL;
1341         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1342         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1343                 break;
1344         }
1345
1346         __connman_network_set_device(network, device);
1347
1348         __connman_storage_load_network(network);
1349
1350         err = connman_element_register((struct connman_element *) network,
1351                                                         &device->element);
1352         if (err < 0) {
1353                 __connman_network_set_device(network, NULL);
1354                 return err;
1355         }
1356
1357         g_hash_table_insert(device->networks, g_strdup(identifier),
1358                                                                 network);
1359
1360         return 0;
1361 }
1362
1363 /**
1364  * connman_device_get_network:
1365  * @device: device structure
1366  * @identifier: network identifier
1367  *
1368  * Get network for given identifier
1369  */
1370 struct connman_network *connman_device_get_network(struct connman_device *device,
1371                                                         const char *identifier)
1372 {
1373         DBG("device %p identifier %s", device, identifier);
1374
1375         return g_hash_table_lookup(device->networks, identifier);
1376 }
1377
1378 /**
1379  * connman_device_remove_network:
1380  * @device: device structure
1381  * @identifier: network identifier
1382  *
1383  * Remove network for given identifier
1384  */
1385 int connman_device_remove_network(struct connman_device *device,
1386                                                         const char *identifier)
1387 {
1388         DBG("device %p identifier %s", device, identifier);
1389
1390         g_hash_table_remove(device->networks, identifier);
1391
1392         return 0;
1393 }
1394
1395 void __connman_device_set_network(struct connman_device *device,
1396                                         struct connman_network *network)
1397 {
1398         const char *name;
1399
1400         if (network != NULL) {
1401                 name = connman_network_get_string(network, "Name");
1402                 device->last_network = g_strdup(name);
1403         }
1404
1405         device->network = network;
1406 }
1407
1408 /**
1409  * connman_device_register:
1410  * @device: device structure
1411  *
1412  * Register device with the system
1413  */
1414 int connman_device_register(struct connman_device *device)
1415 {
1416         __connman_storage_load_device(device);
1417
1418         switch (device->mode) {
1419         case CONNMAN_DEVICE_MODE_UNKNOWN:
1420         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1421                 break;
1422         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1423         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1424                 __connman_storage_init_network(device);
1425                 break;
1426         }
1427
1428         return connman_element_register(&device->element, NULL);
1429 }
1430
1431 /**
1432  * connman_device_unregister:
1433  * @device: device structure
1434  *
1435  * Unregister device with the system
1436  */
1437 void connman_device_unregister(struct connman_device *device)
1438 {
1439         __connman_storage_save_device(device);
1440
1441         connman_element_unregister(&device->element);
1442 }
1443
1444 /**
1445  * connman_device_get_data:
1446  * @device: device structure
1447  *
1448  * Get private device data pointer
1449  */
1450 void *connman_device_get_data(struct connman_device *device)
1451 {
1452         return device->driver_data;
1453 }
1454
1455 /**
1456  * connman_device_set_data:
1457  * @device: device structure
1458  * @data: data pointer
1459  *
1460  * Set private device data pointer
1461  */
1462 void connman_device_set_data(struct connman_device *device, void *data)
1463 {
1464         device->driver_data = data;
1465 }
1466
1467 static gboolean match_driver(struct connman_device *device,
1468                                         struct connman_device_driver *driver)
1469 {
1470         if (device->type == driver->type ||
1471                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1472                 return TRUE;
1473
1474         return FALSE;
1475 }
1476
1477 static int device_probe(struct connman_element *element)
1478 {
1479         struct connman_device *device = element->device;
1480         GSList *list;
1481
1482         DBG("element %p name %s", element, element->name);
1483
1484         if (device == NULL)
1485                 return -ENODEV;
1486
1487         if (device->driver != NULL)
1488                 return -EALREADY;
1489
1490         for (list = driver_list; list; list = list->next) {
1491                 struct connman_device_driver *driver = list->data;
1492
1493                 if (match_driver(device, driver) == FALSE)
1494                         continue;
1495
1496                 DBG("driver %p name %s", driver, driver->name);
1497
1498                 if (driver->probe(device) == 0) {
1499                         device->driver = driver;
1500                         break;
1501                 }
1502         }
1503
1504         if (device->driver == NULL)
1505                 return -ENODEV;
1506
1507         return setup_device(device);
1508 }
1509
1510 static void device_remove(struct connman_element *element)
1511 {
1512         struct connman_device *device = element->device;
1513
1514         DBG("element %p name %s", element, element->name);
1515
1516         if (device == NULL)
1517                 return;
1518
1519         if (device->driver == NULL)
1520                 return;
1521
1522         remove_device(device);
1523 }
1524
1525 static struct connman_driver device_driver = {
1526         .name           = "device",
1527         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1528         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1529         .probe          = device_probe,
1530         .remove         = device_remove,
1531 };
1532
1533 static int device_load(struct connman_device *device)
1534 {
1535         GKeyFile *keyfile;
1536         gchar *pathname, *data = NULL;
1537         gsize length;
1538         char *str;
1539         int val;
1540
1541         DBG("device %p", device);
1542
1543         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1544                                                         device->element.name);
1545         if (pathname == NULL)
1546                 return -ENOMEM;
1547
1548         keyfile = g_key_file_new();
1549
1550         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1551                 g_free(pathname);
1552                 return -ENOENT;
1553         }
1554
1555         g_free(pathname);
1556
1557         if (g_key_file_load_from_data(keyfile, data, length,
1558                                                         0, NULL) == FALSE) {
1559                 g_free(data);
1560                 return -EILSEQ;
1561         }
1562
1563         g_free(data);
1564
1565         str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL);
1566         if (str != NULL) {
1567                 device->policy = string2policy(str);
1568                 g_free(str);
1569         }
1570
1571         val = g_key_file_get_integer(keyfile, "Configuration",
1572                                                         "Priority", NULL);
1573         if (val > 0)
1574                 device->priority = val;
1575
1576         str = g_key_file_get_string(keyfile, "Configuration",
1577                                                         "LastNetwork", NULL);
1578         if (str != NULL)
1579                 device->last_network = str;
1580
1581         g_key_file_free(keyfile);
1582
1583         return 0;
1584 }
1585
1586 static int device_save(struct connman_device *device)
1587 {
1588         GKeyFile *keyfile;
1589         gchar *pathname, *data = NULL;
1590         gsize length;
1591         const char *str;
1592
1593         DBG("device %p", device);
1594
1595         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1596                                                         device->element.name);
1597         if (pathname == NULL)
1598                 return -ENOMEM;
1599
1600         keyfile = g_key_file_new();
1601
1602         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1603                 goto update;
1604
1605         if (length > 0) {
1606                 if (g_key_file_load_from_data(keyfile, data, length,
1607                                                         0, NULL) == FALSE)
1608                         goto done;
1609         }
1610
1611         g_free(data);
1612
1613 update:
1614         str = policy2string(device->policy);
1615         if (str != NULL)
1616                 g_key_file_set_string(keyfile, "Configuration", "Policy", str);
1617
1618         if (device->priority > 0)
1619                 g_key_file_set_integer(keyfile, "Configuration",
1620                                                 "Priority", device->priority);
1621
1622         if (device->last_network != NULL)
1623                 g_key_file_set_string(keyfile, "Configuration",
1624                                         "LastNetwork", device->last_network);
1625
1626         data = g_key_file_to_data(keyfile, &length, NULL);
1627
1628         g_file_set_contents(pathname, data, length, NULL);
1629
1630 done:
1631         g_free(data);
1632
1633         g_key_file_free(keyfile);
1634
1635         g_free(pathname);
1636
1637         if (device->network != NULL)
1638                 __connman_storage_save_network(device->network);
1639
1640         return 0;
1641 }
1642
1643 static struct connman_storage device_storage = {
1644         .name           = "device",
1645         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1646         .device_load    = device_load,
1647         .device_save    = device_save,
1648 };
1649
1650 int __connman_device_init(void)
1651 {
1652         DBG("");
1653
1654         connection = connman_dbus_get_connection();
1655
1656         if (connman_storage_register(&device_storage) < 0)
1657                 connman_error("Failed to register device storage");
1658
1659         return connman_driver_register(&device_driver);
1660 }
1661
1662 void __connman_device_cleanup(void)
1663 {
1664         DBG("");
1665
1666         connman_driver_unregister(&device_driver);
1667
1668         connman_storage_unregister(&device_storage);
1669
1670         dbus_connection_unref(connection);
1671 }