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