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