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