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