device: Do not use connman_element_set/get_string()
[framework/connectivity/connman.git] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 "connman.h"
30
31 struct connman_device {
32         struct connman_element element;
33         enum connman_device_type type;
34         connman_bool_t offlinemode;
35         connman_bool_t blocked;
36         connman_bool_t powered;
37         connman_bool_t powered_pending;
38         connman_bool_t powered_persistent;
39         connman_bool_t scanning;
40         connman_bool_t disconnected;
41         connman_bool_t reconnect;
42         connman_uint16_t scan_interval;
43         connman_uint16_t backoff_interval;
44         char *name;
45         char *node;
46         char *address;
47         char *interface;
48         char *ident;
49         char *path;
50         int phyindex;
51         unsigned int connections;
52         guint scan_timeout;
53
54         struct connman_device_driver *driver;
55         void *driver_data;
56
57         char *last_network;
58         struct connman_network *network;
59         GHashTable *networks;
60 };
61
62 #define SCAN_INITIAL_DELAY 10
63
64 static gboolean device_scan_trigger(gpointer user_data)
65 {
66         struct connman_device *device = user_data;
67
68         DBG("device %p", device);
69
70         if (device->driver == NULL) {
71                 device->scan_timeout = 0;
72                 return FALSE;
73         }
74
75         if (device->driver->scan)
76                 device->driver->scan(device);
77
78         return TRUE;
79 }
80
81 static void clear_scan_trigger(struct connman_device *device)
82 {
83         if (device->scan_timeout > 0) {
84                 g_source_remove(device->scan_timeout);
85                 device->scan_timeout = 0;
86         }
87 }
88
89 static void reset_scan_trigger(struct connman_device *device)
90 {
91         clear_scan_trigger(device);
92
93         if (device->scan_interval > 0) {
94                 guint interval;
95
96                 if (g_hash_table_size(device->networks) == 0) {
97                         if (device->backoff_interval >= device->scan_interval)
98                                 device->backoff_interval = SCAN_INITIAL_DELAY;
99                         interval = device->backoff_interval;
100                 } else
101                         interval = device->scan_interval;
102
103                 DBG("interval %d", interval);
104
105                 device->scan_timeout = g_timeout_add_seconds(interval,
106                                         device_scan_trigger, device);
107
108                 device->backoff_interval *= 2;
109                 if (device->backoff_interval > device->scan_interval)
110                         device->backoff_interval = device->scan_interval;
111         }
112 }
113
114 static void force_scan_trigger(struct connman_device *device)
115 {
116         clear_scan_trigger(device);
117
118         device->scan_timeout = g_timeout_add_seconds(5,
119                                         device_scan_trigger, device);
120 }
121
122 void connman_device_schedule_scan(struct connman_device *device)
123 {
124         reset_scan_trigger(device);
125 }
126
127 static const char *type2description(enum connman_device_type type)
128 {
129         switch (type) {
130         case CONNMAN_DEVICE_TYPE_UNKNOWN:
131         case CONNMAN_DEVICE_TYPE_VENDOR:
132                 break;
133         case CONNMAN_DEVICE_TYPE_ETHERNET:
134                 return "Ethernet";
135         case CONNMAN_DEVICE_TYPE_WIFI:
136                 return "Wireless";
137         case CONNMAN_DEVICE_TYPE_WIMAX:
138                 return "WiMAX";
139         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
140                 return "Bluetooth";
141         case CONNMAN_DEVICE_TYPE_GPS:
142                 return "GPS";
143         case CONNMAN_DEVICE_TYPE_CELLULAR:
144                 return "Cellular";
145         case CONNMAN_DEVICE_TYPE_GADGET:
146                 return "Gadget";
147
148         }
149
150         return NULL;
151 }
152
153 static const char *type2string(enum connman_device_type type)
154 {
155         switch (type) {
156         case CONNMAN_DEVICE_TYPE_UNKNOWN:
157         case CONNMAN_DEVICE_TYPE_VENDOR:
158                 break;
159         case CONNMAN_DEVICE_TYPE_ETHERNET:
160                 return "ethernet";
161         case CONNMAN_DEVICE_TYPE_WIFI:
162                 return "wifi";
163         case CONNMAN_DEVICE_TYPE_WIMAX:
164                 return "wimax";
165         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
166                 return "bluetooth";
167         case CONNMAN_DEVICE_TYPE_GPS:
168                 return "gps";
169         case CONNMAN_DEVICE_TYPE_CELLULAR:
170                 return "cellular";
171         case CONNMAN_DEVICE_TYPE_GADGET:
172                 return "gadget";
173
174         }
175
176         return NULL;
177 }
178
179 enum connman_service_type __connman_device_get_service_type(struct connman_device *device)
180 {
181         enum connman_device_type type = connman_device_get_type(device);
182
183         switch (type) {
184         case CONNMAN_DEVICE_TYPE_UNKNOWN:
185         case CONNMAN_DEVICE_TYPE_VENDOR:
186         case CONNMAN_DEVICE_TYPE_GPS:
187                 break;
188         case CONNMAN_DEVICE_TYPE_ETHERNET:
189                 return CONNMAN_SERVICE_TYPE_ETHERNET;
190         case CONNMAN_DEVICE_TYPE_WIFI:
191                 return CONNMAN_SERVICE_TYPE_WIFI;
192         case CONNMAN_DEVICE_TYPE_WIMAX:
193                 return CONNMAN_SERVICE_TYPE_WIMAX;
194         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
195                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
196         case CONNMAN_DEVICE_TYPE_CELLULAR:
197                 return CONNMAN_SERVICE_TYPE_CELLULAR;
198         case CONNMAN_DEVICE_TYPE_GADGET:
199                 return CONNMAN_SERVICE_TYPE_GADGET;
200
201         }
202
203         return CONNMAN_SERVICE_TYPE_UNKNOWN;
204 }
205
206 int __connman_device_enable(struct connman_device *device)
207 {
208         int err;
209         enum connman_service_type type;
210
211         DBG("device %p %d", device, device->blocked);
212
213         if (!device->driver || !device->driver->enable)
214                 return -EOPNOTSUPP;
215
216         if (device->powered_pending == TRUE)
217                 return -EALREADY;
218
219         if (device->blocked == TRUE)
220                 return -ENOLINK;
221
222         connman_device_set_disconnected(device, FALSE);
223         device->scanning = FALSE;
224
225         err = device->driver->enable(device);
226         if (err < 0 && err != -EALREADY) {
227                 if (err == -EINPROGRESS) {
228                         device->powered_pending = TRUE;
229                         device->offlinemode = FALSE;
230                         if (__connman_profile_get_offlinemode() == TRUE)
231                                 __connman_profile_set_offlinemode(FALSE, FALSE);
232                 }
233                 return err;
234         }
235
236         device->powered_pending = TRUE;
237         device->powered = TRUE;
238         device->offlinemode = FALSE;
239         if (__connman_profile_get_offlinemode() == TRUE)
240                 __connman_profile_set_offlinemode(FALSE, FALSE);
241
242         type = __connman_device_get_service_type(device);
243         __connman_technology_enable(type);
244
245         return 0;
246 }
247
248 int __connman_device_disable(struct connman_device *device)
249 {
250         int err;
251         enum connman_service_type type;
252
253         DBG("device %p", device);
254
255         if (!device->driver || !device->driver->disable)
256                 return -EOPNOTSUPP;
257
258         if (device->powered == FALSE)
259                 return -ENOLINK;
260
261         if (device->powered_pending == FALSE)
262                 return -EALREADY;
263
264         device->reconnect = FALSE;
265
266         clear_scan_trigger(device);
267
268         g_hash_table_remove_all(device->networks);
269
270         err = device->driver->disable(device);
271         if (err < 0 && err != -EALREADY) {
272                 if (err == -EINPROGRESS)
273                         device->powered_pending = FALSE;
274                 return err;
275         }
276
277         device->connections = 0;
278
279         device->powered_pending = FALSE;
280         device->powered = FALSE;
281
282         type = __connman_device_get_service_type(device);
283         __connman_technology_disable(type);
284
285         return 0;
286 }
287
288 static int set_powered(struct connman_device *device, connman_bool_t powered)
289 {
290         DBG("device %p powered %d", device, powered);
291
292         if (powered == TRUE)
293                 return __connman_device_enable(device);
294         else
295                 return __connman_device_disable(device);
296 }
297
298 static int setup_device(struct connman_device *device)
299 {
300         DBG("device %p", device);
301
302         __connman_technology_add_device(device);
303
304         if (device->offlinemode == FALSE &&
305                                 device->powered_persistent == TRUE)
306                 __connman_device_enable(device);
307
308         return 0;
309 }
310
311 static void probe_driver(struct connman_element *element, gpointer user_data)
312 {
313         struct connman_device_driver *driver = user_data;
314
315         DBG("element %p name %s", element, element->name);
316
317         if (element->device == NULL)
318                 return;
319
320         if (element->device->driver != NULL)
321                 return;
322
323         if (driver->type != element->device->type)
324                 return;
325
326         if (driver->probe(element->device) < 0)
327                 return;
328
329         element->device->driver = driver;
330
331         __connman_element_set_driver(element);
332
333         setup_device(element->device);
334 }
335
336 static void remove_device(struct connman_device *device)
337 {
338         DBG("device %p", device);
339
340         __connman_device_disable(device);
341
342         __connman_technology_remove_device(device);
343
344         if (device->driver->remove)
345                 device->driver->remove(device);
346
347         device->driver = NULL;
348 }
349
350 static void remove_driver(struct connman_element *element, gpointer user_data)
351 {
352         struct connman_device_driver *driver = user_data;
353
354         DBG("element %p name %s", element, element->name);
355
356         if (element->device == NULL)
357                 return;
358
359         if (element->device->driver == driver)
360                 remove_device(element->device);
361 }
362
363 connman_bool_t __connman_device_has_driver(struct connman_device *device)
364 {
365         if (device == NULL || device->driver == NULL)
366                 return FALSE;
367
368         return TRUE;
369 }
370
371 static GSList *driver_list = NULL;
372
373 static gint compare_priority(gconstpointer a, gconstpointer b)
374 {
375         const struct connman_device_driver *driver1 = a;
376         const struct connman_device_driver *driver2 = b;
377
378         return driver2->priority - driver1->priority;
379 }
380
381 /**
382  * connman_device_driver_register:
383  * @driver: device driver definition
384  *
385  * Register a new device driver
386  *
387  * Returns: %0 on success
388  */
389 int connman_device_driver_register(struct connman_device_driver *driver)
390 {
391         DBG("driver %p name %s", driver, driver->name);
392
393         driver_list = g_slist_insert_sorted(driver_list, driver,
394                                                         compare_priority);
395
396         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
397                                                 probe_driver, driver);
398
399         return 0;
400 }
401
402 /**
403  * connman_device_driver_unregister:
404  * @driver: device driver definition
405  *
406  * Remove a previously registered device driver
407  */
408 void connman_device_driver_unregister(struct connman_device_driver *driver)
409 {
410         DBG("driver %p name %s", driver, driver->name);
411
412         driver_list = g_slist_remove(driver_list, driver);
413
414         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
415                                                 remove_driver, driver);
416 }
417
418 static void unregister_network(gpointer data)
419 {
420         struct connman_network *network = data;
421
422         DBG("network %p", network);
423
424         connman_element_unregister((struct connman_element *) network);
425
426         __connman_network_set_device(network, NULL);
427
428         connman_network_unref(network);
429 }
430
431 static void device_destruct(struct connman_element *element)
432 {
433         struct connman_device *device = element->device;
434
435         DBG("element %p name %s", element, element->name);
436
437         clear_scan_trigger(device);
438
439         g_free(device->ident);
440         g_free(device->node);
441         g_free(device->name);
442         g_free(device->address);
443         g_free(device->interface);
444         g_free(device->path);
445
446         g_free(device->last_network);
447
448         g_hash_table_destroy(device->networks);
449         device->networks = NULL;
450 }
451
452 /**
453  * connman_device_create:
454  * @node: device node name (for example an address)
455  * @type: device type
456  *
457  * Allocate a new device of given #type and assign the #node name to it.
458  *
459  * Returns: a newly-allocated #connman_device structure
460  */
461 struct connman_device *connman_device_create(const char *node,
462                                                 enum connman_device_type type)
463 {
464         struct connman_device *device;
465         const char *str;
466         enum connman_service_type service_type;
467         connman_bool_t bg_scan;
468
469         DBG("node %s type %d", node, type);
470
471         device = g_try_new0(struct connman_device, 1);
472         if (device == NULL)
473                 return NULL;
474
475         DBG("device %p", device);
476
477         bg_scan = connman_setting_get_bool("BackgroundScanning");
478
479         __connman_element_initialize(&device->element);
480
481         device->element.name = g_strdup(node);
482         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
483
484         device->element.device = device;
485         device->element.destruct = device_destruct;
486
487         str = type2string(type);
488         if (str != NULL)
489                 connman_element_set_string(&device->element,
490                                         CONNMAN_PROPERTY_ID_TYPE, str);
491
492         device->type = type;
493         device->name = g_strdup(type2description(device->type));
494
495         device->powered_persistent = TRUE;
496
497         device->phyindex = -1;
498
499         service_type = __connman_device_get_service_type(device);
500         device->blocked = __connman_technology_get_blocked(service_type);
501         device->backoff_interval = SCAN_INITIAL_DELAY;
502
503         switch (type) {
504         case CONNMAN_DEVICE_TYPE_UNKNOWN:
505         case CONNMAN_DEVICE_TYPE_ETHERNET:
506         case CONNMAN_DEVICE_TYPE_WIMAX:
507         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
508         case CONNMAN_DEVICE_TYPE_CELLULAR:
509         case CONNMAN_DEVICE_TYPE_GPS:
510         case CONNMAN_DEVICE_TYPE_GADGET:
511         case CONNMAN_DEVICE_TYPE_VENDOR:
512                 device->scan_interval = 0;
513                 break;
514         case CONNMAN_DEVICE_TYPE_WIFI:
515                 if (bg_scan == TRUE)
516                         device->scan_interval = 300;
517                 else
518                         device->scan_interval = 0;
519                 break;
520         }
521
522         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
523                                                 g_free, unregister_network);
524
525         return device;
526 }
527
528 /**
529  * connman_device_ref:
530  * @device: device structure
531  *
532  * Increase reference counter of device
533  */
534 struct connman_device *connman_device_ref(struct connman_device *device)
535 {
536         if (connman_element_ref(&device->element) == NULL)
537                 return NULL;
538
539         return device;
540 }
541
542 /**
543  * connman_device_unref:
544  * @device: device structure
545  *
546  * Decrease reference counter of device
547  */
548 void connman_device_unref(struct connman_device *device)
549 {
550         connman_element_unref(&device->element);
551 }
552
553 const char *__connman_device_get_type(struct connman_device *device)
554 {
555         return type2string(device->type);
556 }
557
558 /**
559  * connman_device_get_type:
560  * @device: device structure
561  *
562  * Get type of device
563  */
564 enum connman_device_type connman_device_get_type(struct connman_device *device)
565 {
566         return device->type;
567 }
568
569 /**
570  * connman_device_set_index:
571  * @device: device structure
572  * @index: index number
573  *
574  * Set index number of device
575  */
576 void connman_device_set_index(struct connman_device *device, int index)
577 {
578         device->element.index = index;
579 }
580
581 /**
582  * connman_device_get_index:
583  * @device: device structure
584  *
585  * Get index number of device
586  */
587 int connman_device_get_index(struct connman_device *device)
588 {
589         return device->element.index;
590 }
591
592 int __connman_device_get_phyindex(struct connman_device *device)
593 {
594         return device->phyindex;
595 }
596
597 void __connman_device_set_phyindex(struct connman_device *device,
598                                                         int phyindex)
599 {
600         device->phyindex = phyindex;
601 }
602
603 /**
604  * connman_device_set_interface:
605  * @device: device structure
606  * @interface: interface name
607  *
608  * Set interface name of device
609  */
610 void connman_device_set_interface(struct connman_device *device,
611                                                 const char *interface)
612 {
613         g_free(device->element.devname);
614         device->element.devname = g_strdup(interface);
615
616         g_free(device->interface);
617         device->interface = g_strdup(interface);
618
619         if (device->name == NULL) {
620                 const char *str = type2description(device->type);
621                 if (str != NULL && device->interface != NULL)
622                         device->name = g_strdup_printf("%s (%s)", str,
623                                                         device->interface);
624         }
625 }
626
627 /**
628  * connman_device_set_ident:
629  * @device: device structure
630  * @ident: unique identifier
631  *
632  * Set unique identifier of device
633  */
634 void connman_device_set_ident(struct connman_device *device,
635                                                         const char *ident)
636 {
637         g_free(device->ident);
638         device->ident = g_strdup(ident);
639 }
640
641 const char *connman_device_get_ident(struct connman_device *device)
642 {
643         return device->ident;
644 }
645
646 /**
647  * connman_device_set_powered:
648  * @device: device structure
649  * @powered: powered state
650  *
651  * Change power state of device
652  */
653 int connman_device_set_powered(struct connman_device *device,
654                                                 connman_bool_t powered)
655 {
656         int err;
657         enum connman_service_type type;
658
659         DBG("driver %p powered %d", device, powered);
660
661         if (device->powered == powered) {
662                 device->powered_pending = powered;
663                 return -EALREADY;
664         }
665
666         if (powered == TRUE)
667                 err = __connman_device_enable(device);
668         else
669                 err = __connman_device_disable(device);
670
671         if (err < 0 && err != -EINPROGRESS && err != -EALREADY)
672                 return err;
673
674         device->powered = powered;
675         device->powered_pending = powered;
676
677         type = __connman_device_get_service_type(device);
678
679         if (device->powered == TRUE)
680                 __connman_technology_enable(type);
681         else
682                 __connman_technology_disable(type);
683
684         if (device->offlinemode == TRUE && powered == TRUE)
685                 return connman_device_set_powered(device, FALSE);
686
687         if (powered == FALSE)
688                 return 0;
689
690         reset_scan_trigger(device);
691
692         if (device->driver && device->driver->scan)
693                 device->driver->scan(device);
694
695         return 0;
696 }
697
698 int __connman_device_set_blocked(struct connman_device *device,
699                                                 connman_bool_t blocked)
700 {
701         connman_bool_t powered;
702
703         DBG("device %p blocked %d", device, blocked);
704
705         device->blocked = blocked;
706
707         if (device->offlinemode == TRUE)
708                 return 0;
709
710         connman_info("%s {rfkill} blocked %d", device->interface, blocked);
711
712         if (blocked == FALSE)
713                 powered = device->powered_persistent;
714         else
715                 powered = FALSE;
716
717         return set_powered(device, powered);
718 }
719
720 connman_bool_t __connman_device_get_blocked(struct connman_device *device)
721 {
722         return device->blocked;
723 }
724
725 int __connman_device_scan(struct connman_device *device)
726 {
727         if (!device->driver || !device->driver->scan)
728                 return -EOPNOTSUPP;
729
730         if (device->powered == FALSE)
731                 return -ENOLINK;
732
733         reset_scan_trigger(device);
734
735         return device->driver->scan(device);
736 }
737
738 int __connman_device_enable_persistent(struct connman_device *device)
739 {
740         int err;
741
742         DBG("device %p", device);
743
744         device->powered_persistent = TRUE;
745
746         __connman_storage_save_device(device);
747
748         err = __connman_device_enable(device);
749         if (err == 0 || err == -EINPROGRESS) {
750                 device->offlinemode = FALSE;
751                 if (__connman_profile_get_offlinemode() == TRUE) {
752                         __connman_profile_set_offlinemode(FALSE, FALSE);
753
754                         __connman_profile_save_default();
755                 }
756         }
757
758         return err;
759 }
760
761 int __connman_device_disable_persistent(struct connman_device *device)
762 {
763         DBG("device %p", device);
764
765         device->powered_persistent = FALSE;
766
767         __connman_storage_save_device(device);
768
769         return __connman_device_disable(device);
770 }
771
772 int __connman_device_disconnect(struct connman_device *device)
773 {
774         GHashTableIter iter;
775         gpointer key, value;
776
777         DBG("device %p", device);
778
779         connman_device_set_disconnected(device, TRUE);
780
781         g_hash_table_iter_init(&iter, device->networks);
782
783         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
784                 struct connman_network *network = value;
785
786                 if (connman_network_get_connecting(network) == TRUE) {
787                         /*
788                          * Skip network in the process of connecting.
789                          * This is a workaround for WiFi networks serviced
790                          * by the supplicant plugin that hold a reference
791                          * to the network.  If we disconnect the network
792                          * here then the referenced object will not be
793                          * registered and usage (like launching DHCP client)
794                          * will fail.  There is nothing to be gained by
795                          * removing the network here anyway.
796                          */
797                         connman_warn("Skipping disconnect of %s",
798                                 connman_network_get_identifier(network));
799                         continue;
800                 }
801
802                 __connman_network_disconnect(network);
803         }
804
805         return 0;
806 }
807
808 static void mark_network_available(gpointer key, gpointer value,
809                                                         gpointer user_data)
810 {
811         struct connman_network *network = value;
812
813         connman_network_set_available(network, TRUE);
814 }
815
816 static void mark_network_unavailable(gpointer key, gpointer value,
817                                                         gpointer user_data)
818 {
819         struct connman_network *network = value;
820
821         if (connman_network_get_connected(network) == TRUE)
822                 return;
823
824         connman_network_set_available(network, FALSE);
825 }
826
827 static gboolean remove_unavailable_network(gpointer key, gpointer value,
828                                                         gpointer user_data)
829 {
830         struct connman_network *network = value;
831
832         if (connman_network_get_connected(network) == TRUE)
833                 return FALSE;
834
835         if (connman_network_get_available(network) == TRUE)
836                 return FALSE;
837
838         return TRUE;
839 }
840
841 void __connman_device_cleanup_networks(struct connman_device *device)
842 {
843         g_hash_table_foreach_remove(device->networks,
844                                         remove_unavailable_network, NULL);
845 }
846
847 connman_bool_t __connman_device_scanning(struct connman_device *device)
848 {
849         return device->scanning;
850 }
851
852 void connman_device_reset_scanning(struct connman_device *device)
853 {
854         device->scanning = FALSE;
855
856         g_hash_table_foreach(device->networks,
857                                 mark_network_available, NULL);
858
859 }
860
861 /**
862  * connman_device_set_scanning:
863  * @device: device structure
864  * @scanning: scanning state
865  *
866  * Change scanning state of device
867  */
868 int connman_device_set_scanning(struct connman_device *device,
869                                                 connman_bool_t scanning)
870 {
871         DBG("device %p scanning %d", device, scanning);
872
873         if (!device->driver || !device->driver->scan)
874                 return -EINVAL;
875
876         if (device->scanning == scanning)
877                 return -EALREADY;
878
879         device->scanning = scanning;
880
881         if (scanning == TRUE) {
882                 reset_scan_trigger(device);
883
884                 g_hash_table_foreach(device->networks,
885                                         mark_network_unavailable, NULL);
886
887                 return 0;
888         }
889
890         __connman_device_cleanup_networks(device);
891
892         if (device->connections > 0)
893                 return 0;
894
895         __connman_service_auto_connect();
896
897         return 0;
898 }
899
900 /**
901  * connman_device_set_disconnected:
902  * @device: device structure
903  * @disconnected: disconnected state
904  *
905  * Change disconnected state of device (only for device with networks)
906  */
907 int connman_device_set_disconnected(struct connman_device *device,
908                                                 connman_bool_t disconnected)
909 {
910         DBG("device %p disconnected %d", device, disconnected);
911
912         if (device->disconnected == disconnected)
913                 return -EALREADY;
914
915         device->disconnected = disconnected;
916
917         if (disconnected == TRUE)
918                 force_scan_trigger(device);
919
920         return 0;
921 }
922
923 /**
924  * connman_device_get_disconnected:
925  * @device: device structure
926  *
927  * Get device disconnected state
928  */
929 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
930 {
931         return device->disconnected;
932 }
933
934 /**
935  * connman_device_set_string:
936  * @device: device structure
937  * @key: unique identifier
938  * @value: string value
939  *
940  * Set string value for specific key
941  */
942 int connman_device_set_string(struct connman_device *device,
943                                         const char *key, const char *value)
944 {
945         DBG("device %p key %s value %s", device, key, value);
946
947         if (g_str_equal(key, "Address") == TRUE) {
948                 g_free(device->address);
949                 device->address = g_strdup(value);
950         } else if (g_str_equal(key, "Name") == TRUE) {
951                 g_free(device->name);
952                 device->name = g_strdup(value);
953         } else if (g_str_equal(key, "Node") == TRUE) {
954                 g_free(device->node);
955                 device->node = g_strdup(value);
956         } else if (g_str_equal(key, "Path") == TRUE) {
957                 g_free(device->path);
958                 device->path = g_strdup(value);
959         } else {
960                 return -EINVAL;
961         }
962
963         return 0;
964 }
965
966 /**
967  * connman_device_get_string:
968  * @device: device structure
969  * @key: unique identifier
970  *
971  * Get string value for specific key
972  */
973 const char *connman_device_get_string(struct connman_device *device,
974                                                         const char *key)
975 {
976         DBG("device %p key %s", device, key);
977
978         if (g_str_equal(key, "Address") == TRUE)
979                 return device->address;
980         else if (g_str_equal(key, "Name") == TRUE)
981                 return device->name;
982         else if (g_str_equal(key, "Node") == TRUE)
983                 return device->node;
984         else if (g_str_equal(key, "Interface") == TRUE)
985                 return device->interface;
986         else if (g_str_equal(key, "Path") == TRUE)
987                 return device->path;
988
989         return NULL;
990 }
991
992 static void set_offlinemode(struct connman_element *element, gpointer user_data)
993 {
994         struct connman_device *device = element->device;
995         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
996         connman_bool_t powered;
997
998         DBG("element %p name %s", element, element->name);
999
1000         if (device == NULL)
1001                 return;
1002
1003         device->offlinemode = offlinemode;
1004
1005         if (device->blocked == TRUE)
1006                 return;
1007
1008         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1009
1010         if (device->powered == powered)
1011                 return;
1012
1013         if (device->powered_persistent == FALSE)
1014                 powered = FALSE;
1015
1016         set_powered(device, powered);
1017 }
1018
1019 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1020 {
1021         DBG("offlinmode %d", offlinemode);
1022
1023         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1024                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1025
1026         __connman_notifier_offlinemode(offlinemode);
1027
1028         return 0;
1029 }
1030
1031 void __connman_device_increase_connections(struct connman_device *device)
1032 {
1033         if (device == NULL)
1034                 return;
1035
1036         device->connections++;
1037 }
1038
1039 void __connman_device_decrease_connections(struct connman_device *device)
1040 {
1041         if (device == NULL)
1042                 return;
1043
1044         device->connections--;
1045
1046         if (device->connections == 0)
1047                 device->backoff_interval = SCAN_INITIAL_DELAY;
1048 }
1049
1050 /**
1051  * connman_device_add_network:
1052  * @device: device structure
1053  * @network: network structure
1054  *
1055  * Add new network to the device
1056  */
1057 int connman_device_add_network(struct connman_device *device,
1058                                         struct connman_network *network)
1059 {
1060         const char *identifier = connman_network_get_identifier(network);
1061         int err;
1062
1063         DBG("device %p network %p", device, network);
1064
1065         if (identifier == NULL)
1066                 return -EINVAL;
1067
1068         __connman_network_set_device(network, device);
1069
1070         err = connman_element_register((struct connman_element *) network,
1071                                                         &device->element);
1072         if (err < 0) {
1073                 __connman_network_set_device(network, NULL);
1074                 return err;
1075         }
1076
1077         g_hash_table_insert(device->networks, g_strdup(identifier),
1078                                                                 network);
1079
1080         return 0;
1081 }
1082
1083 /**
1084  * connman_device_get_network:
1085  * @device: device structure
1086  * @identifier: network identifier
1087  *
1088  * Get network for given identifier
1089  */
1090 struct connman_network *connman_device_get_network(struct connman_device *device,
1091                                                         const char *identifier)
1092 {
1093         DBG("device %p identifier %s", device, identifier);
1094
1095         return g_hash_table_lookup(device->networks, identifier);
1096 }
1097
1098 /**
1099  * connman_device_remove_network:
1100  * @device: device structure
1101  * @identifier: network identifier
1102  *
1103  * Remove network for given identifier
1104  */
1105 int connman_device_remove_network(struct connman_device *device,
1106                                                         const char *identifier)
1107 {
1108         DBG("device %p identifier %s", device, identifier);
1109
1110         g_hash_table_remove(device->networks, identifier);
1111
1112         return 0;
1113 }
1114
1115 void connman_device_remove_all_networks(struct connman_device *device)
1116 {
1117         g_hash_table_remove_all(device->networks);
1118 }
1119
1120 void __connman_device_set_network(struct connman_device *device,
1121                                         struct connman_network *network)
1122 {
1123         const char *name;
1124
1125         if (device == NULL)
1126                 return;
1127
1128         if (device->network == network)
1129                 return;
1130
1131         if (device->network != NULL)
1132                 connman_network_unref(device->network);
1133
1134         if (network != NULL) {
1135                 name = connman_network_get_string(network,
1136                                                 CONNMAN_PROPERTY_ID_NAME);
1137                 g_free(device->last_network);
1138                 device->last_network = g_strdup(name);
1139
1140                 device->network = connman_network_ref(network);
1141         } else {
1142                 g_free(device->last_network);
1143                 device->last_network = NULL;
1144
1145                 device->network = NULL;
1146         }
1147 }
1148
1149 void __connman_device_set_reconnect(struct connman_device *device,
1150                                                 connman_bool_t reconnect)
1151 {
1152         device->reconnect = reconnect;
1153 }
1154
1155 connman_bool_t  __connman_device_get_reconnect(
1156                                 struct connman_device *device)
1157 {
1158         return device->reconnect;
1159 }
1160
1161 /**
1162  * connman_device_register:
1163  * @device: device structure
1164  *
1165  * Register device with the system
1166  */
1167 int connman_device_register(struct connman_device *device)
1168 {
1169         __connman_storage_load_device(device);
1170
1171         device->offlinemode = __connman_profile_get_offlinemode();
1172
1173         return connman_element_register(&device->element, NULL);
1174 }
1175
1176 /**
1177  * connman_device_unregister:
1178  * @device: device structure
1179  *
1180  * Unregister device with the system
1181  */
1182 void connman_device_unregister(struct connman_device *device)
1183 {
1184         __connman_storage_save_device(device);
1185
1186         connman_element_unregister(&device->element);
1187 }
1188
1189 /**
1190  * connman_device_get_data:
1191  * @device: device structure
1192  *
1193  * Get private device data pointer
1194  */
1195 void *connman_device_get_data(struct connman_device *device)
1196 {
1197         return device->driver_data;
1198 }
1199
1200 /**
1201  * connman_device_set_data:
1202  * @device: device structure
1203  * @data: data pointer
1204  *
1205  * Set private device data pointer
1206  */
1207 void connman_device_set_data(struct connman_device *device, void *data)
1208 {
1209         device->driver_data = data;
1210 }
1211
1212 static gboolean match_driver(struct connman_device *device,
1213                                         struct connman_device_driver *driver)
1214 {
1215         if (device->type == driver->type ||
1216                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1217                 return TRUE;
1218
1219         return FALSE;
1220 }
1221
1222 static int device_probe(struct connman_element *element)
1223 {
1224         struct connman_device *device = element->device;
1225         GSList *list;
1226
1227         DBG("element %p name %s", element, element->name);
1228
1229         if (device == NULL)
1230                 return -ENODEV;
1231
1232         if (device->driver != NULL)
1233                 return -EALREADY;
1234
1235         for (list = driver_list; list; list = list->next) {
1236                 struct connman_device_driver *driver = list->data;
1237
1238                 if (match_driver(device, driver) == FALSE)
1239                         continue;
1240
1241                 DBG("driver %p name %s", driver, driver->name);
1242
1243                 if (driver->probe(device) == 0) {
1244                         device->driver = driver;
1245                         break;
1246                 }
1247         }
1248
1249         if (device->driver == NULL)
1250                 return -ENODEV;
1251
1252         return setup_device(device);
1253 }
1254
1255 static void device_remove(struct connman_element *element)
1256 {
1257         struct connman_device *device = element->device;
1258
1259         DBG("element %p name %s", element, element->name);
1260
1261         if (device == NULL)
1262                 return;
1263
1264         if (device->driver == NULL)
1265                 return;
1266
1267         remove_device(device);
1268 }
1269
1270 static struct connman_driver device_driver = {
1271         .name           = "device",
1272         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1273         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1274         .probe          = device_probe,
1275         .remove         = device_remove,
1276 };
1277
1278 static int device_load(struct connman_device *device)
1279 {
1280         const char *ident = __connman_profile_active_ident();
1281         GKeyFile *keyfile;
1282         GError *error = NULL;
1283         gchar *identifier;
1284         connman_bool_t powered;
1285
1286         DBG("device %p", device);
1287
1288         keyfile = __connman_storage_open_profile(ident);
1289         if (keyfile == NULL)
1290                 return 0;
1291
1292         identifier = g_strdup_printf("device_%s", device->element.name);
1293         if (identifier == NULL)
1294                 goto done;
1295
1296         powered = g_key_file_get_boolean(keyfile, identifier,
1297                                                 "Powered", &error);
1298         if (error == NULL)
1299                 device->powered_persistent = powered;
1300         g_clear_error(&error);
1301
1302 done:
1303         g_free(identifier);
1304
1305         __connman_storage_close_profile(ident, keyfile, FALSE);
1306
1307         return 0;
1308 }
1309
1310 static int device_save(struct connman_device *device)
1311 {
1312         const char *ident = __connman_profile_active_ident();
1313         GKeyFile *keyfile;
1314         gchar *identifier;
1315
1316         DBG("device %p", device);
1317
1318         keyfile = __connman_storage_open_profile(ident);
1319         if (keyfile == NULL)
1320                 return 0;
1321
1322         identifier = g_strdup_printf("device_%s", device->element.name);
1323         if (identifier == NULL)
1324                 goto done;
1325
1326         g_key_file_set_boolean(keyfile, identifier,
1327                                         "Powered", device->powered_persistent);
1328
1329 done:
1330         g_free(identifier);
1331
1332         __connman_storage_close_profile(ident, keyfile, TRUE);
1333
1334         return 0;
1335 }
1336
1337 static struct connman_storage device_storage = {
1338         .name           = "device",
1339         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1340         .device_load    = device_load,
1341         .device_save    = device_save,
1342 };
1343
1344 int __connman_device_init(void)
1345 {
1346         DBG("");
1347
1348         if (connman_storage_register(&device_storage) < 0)
1349                 connman_error("Failed to register device storage");
1350
1351         return connman_driver_register(&device_driver);
1352 }
1353
1354 void __connman_device_cleanup(void)
1355 {
1356         DBG("");
1357
1358         connman_driver_unregister(&device_driver);
1359
1360         connman_storage_unregister(&device_storage);
1361 }