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