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