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