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