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