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