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