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