Remove DBusConnection reference from device/network interfaces
[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_get_name:
542  * @device: device structure
543  *
544  * Get unique name of device
545  */
546 const char *connman_device_get_name(struct connman_device *device)
547 {
548         return device->element.name;
549 }
550
551 /**
552  * connman_device_get_path:
553  * @device: device structure
554  *
555  * Get path name of device
556  */
557 const char *connman_device_get_path(struct connman_device *device)
558 {
559         return device->element.path;
560 }
561
562 /**
563  * connman_device_set_index:
564  * @device: device structure
565  * @index: index number
566  *
567  * Set index number of device
568  */
569 void connman_device_set_index(struct connman_device *device, int index)
570 {
571         device->element.index = index;
572 }
573
574 /**
575  * connman_device_get_index:
576  * @device: device structure
577  *
578  * Get index number of device
579  */
580 int connman_device_get_index(struct connman_device *device)
581 {
582         return device->element.index;
583 }
584
585 int __connman_device_get_phyindex(struct connman_device *device)
586 {
587         return device->phyindex;
588 }
589
590 void __connman_device_set_phyindex(struct connman_device *device,
591                                                         int phyindex)
592 {
593         device->phyindex = phyindex;
594 }
595
596 /**
597  * connman_device_set_interface:
598  * @device: device structure
599  * @interface: interface name
600  * @control: control interface
601  *
602  * Set interface name of device
603  */
604 void connman_device_set_interface(struct connman_device *device,
605                                 const char *interface, const char *control)
606 {
607         g_free(device->element.devname);
608         device->element.devname = g_strdup(interface);
609
610         g_free(device->interface);
611         device->interface = g_strdup(interface);
612
613         g_free(device->control);
614         device->control = g_strdup(control);
615
616         if (device->name == NULL) {
617                 const char *str = type2description(device->type);
618                 if (str != NULL && device->interface != NULL)
619                         device->name = g_strdup_printf("%s (%s)", str,
620                                                         device->interface);
621         }
622 }
623
624 const char *connman_device_get_control(struct connman_device *device)
625 {
626         return device->control;
627 }
628
629 /**
630  * connman_device_set_ident:
631  * @device: device structure
632  * @ident: unique identifier
633  *
634  * Set unique identifier of device
635  */
636 void connman_device_set_ident(struct connman_device *device,
637                                                         const char *ident)
638 {
639         g_free(device->ident);
640         device->ident = g_strdup(ident);
641 }
642
643 const char *connman_device_get_ident(struct connman_device *device)
644 {
645         return device->ident;
646 }
647
648 /**
649  * connman_device_set_powered:
650  * @device: device structure
651  * @powered: powered state
652  *
653  * Change power state of device
654  */
655 int connman_device_set_powered(struct connman_device *device,
656                                                 connman_bool_t powered)
657 {
658         DBG("driver %p powered %d", device, powered);
659
660         if (device->powered == powered) {
661                 device->powered_pending = powered;
662                 return -EALREADY;
663         }
664
665         if (powered == TRUE)
666                 __connman_device_enable(device);
667         else
668                 __connman_device_disable(device);
669
670         device->powered = powered;
671         device->powered_pending = powered;
672
673         if (device->powered == TRUE)
674                 __connman_technology_enable_device(device);
675         else
676                 __connman_technology_disable_device(device);
677
678         if (device->offlinemode == TRUE && powered == TRUE)
679                 return connman_device_set_powered(device, FALSE);
680
681         if (powered == FALSE)
682                 return 0;
683
684         reset_scan_trigger(device);
685
686         if (device->driver->scan)
687                 device->driver->scan(device);
688
689         return 0;
690 }
691
692 int __connman_device_set_blocked(struct connman_device *device,
693                                                 connman_bool_t blocked)
694 {
695         connman_bool_t powered;
696
697         DBG("device %p blocked %d", device, blocked);
698
699         device->blocked = blocked;
700
701         if (device->offlinemode == TRUE)
702                 return 0;
703
704         connman_info("%s {rfkill} blocked %d", device->interface, blocked);
705
706         if (blocked == FALSE)
707                 powered = device->powered_persistent;
708         else
709                 powered = FALSE;
710
711         return set_powered(device, powered);
712 }
713
714 connman_bool_t __connman_device_get_blocked(struct connman_device *device)
715 {
716         return device->blocked;
717 }
718
719 int __connman_device_scan(struct connman_device *device)
720 {
721         if (!device->driver || !device->driver->scan)
722                 return -EOPNOTSUPP;
723
724         if (device->powered == FALSE)
725                 return -ENOLINK;
726
727         reset_scan_trigger(device);
728
729         return device->driver->scan(device);
730 }
731
732 int __connman_device_enable_persistent(struct connman_device *device)
733 {
734         int err;
735
736         DBG("device %p", device);
737
738         device->powered_persistent = TRUE;
739
740         __connman_storage_save_device(device);
741
742         err = __connman_device_enable(device);
743         if (err == 0 || err == -EINPROGRESS) {
744                 device->offlinemode = FALSE;
745                 if (__connman_profile_get_offlinemode() == TRUE) {
746                         __connman_profile_set_offlinemode(FALSE, FALSE);
747
748                         __connman_profile_save_default();
749                 }
750         }
751
752         return err;
753 }
754
755 int __connman_device_disable_persistent(struct connman_device *device)
756 {
757         DBG("device %p", device);
758
759         device->powered_persistent = FALSE;
760
761         __connman_storage_save_device(device);
762
763         return __connman_device_disable(device);
764 }
765
766 int __connman_device_disconnect(struct connman_device *device)
767 {
768         GHashTableIter iter;
769         gpointer key, value;
770
771         DBG("device %p", device);
772
773         connman_device_set_disconnected(device, TRUE);
774
775         g_hash_table_iter_init(&iter, device->networks);
776
777         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
778                 struct connman_network *network = value;
779
780                 if (__connman_network_get_connecting(network) == TRUE) {
781                         /*
782                          * Skip network in the process of connecting.
783                          * This is a workaround for WiFi networks serviced
784                          * by the supplicant plugin that hold a reference
785                          * to the network.  If we disconnect the network
786                          * here then the referenced object will not be
787                          * registered and usage (like launching DHCP client)
788                          * will fail.  There is nothing to be gained by
789                          * removing the network here anyway.
790                          */
791                         connman_warn("Skipping disconnect of %s",
792                                 connman_network_get_identifier(network));
793                         continue;
794                 }
795
796                 __connman_network_disconnect(network);
797         }
798
799         return 0;
800 }
801
802 static void mark_network_unavailable(gpointer key, gpointer value,
803                                                         gpointer user_data)
804 {
805         struct connman_network *network = value;
806
807         if (connman_network_get_connected(network) == TRUE)
808                 return;
809
810         connman_network_set_available(network, FALSE);
811 }
812
813 static gboolean remove_unavailable_network(gpointer key, gpointer value,
814                                                         gpointer user_data)
815 {
816         struct connman_network *network = value;
817
818         if (connman_network_get_connected(network) == TRUE)
819                 return FALSE;
820
821         if (connman_network_get_available(network) == TRUE)
822                 return FALSE;
823
824         return TRUE;
825 }
826
827 void __connman_device_cleanup_networks(struct connman_device *device)
828 {
829         g_hash_table_foreach_remove(device->networks,
830                                         remove_unavailable_network, NULL);
831 }
832
833 /**
834  * connman_device_set_scanning:
835  * @device: device structure
836  * @scanning: scanning state
837  *
838  * Change scanning state of device
839  */
840 int connman_device_set_scanning(struct connman_device *device,
841                                                 connman_bool_t scanning)
842 {
843         DBG("device %p scanning %d", device, scanning);
844
845         if (!device->driver || !device->driver->scan)
846                 return -EINVAL;
847
848         if (device->scanning == scanning)
849                 return -EALREADY;
850
851         device->scanning = scanning;
852
853         if (scanning == TRUE) {
854                 reset_scan_trigger(device);
855
856                 g_hash_table_foreach(device->networks,
857                                         mark_network_unavailable, NULL);
858
859                 return 0;
860         }
861
862         __connman_device_cleanup_networks(device);
863
864         if (device->connections > 0)
865                 return 0;
866
867         if (device->disconnected == TRUE)
868                 return 0;
869
870         __connman_service_auto_connect();
871
872         return 0;
873 }
874
875 /**
876  * connman_device_set_disconnected:
877  * @device: device structure
878  * @disconnected: disconnected state
879  *
880  * Change disconnected state of device (only for device with networks)
881  */
882 int connman_device_set_disconnected(struct connman_device *device,
883                                                 connman_bool_t disconnected)
884 {
885         DBG("device %p disconnected %d", device, disconnected);
886
887         if (device->disconnected == disconnected)
888                 return -EALREADY;
889
890         device->disconnected = disconnected;
891
892         if (disconnected == TRUE)
893                 force_scan_trigger(device);
894
895         return 0;
896 }
897
898 /**
899  * connman_device_get_disconnected:
900  * @device: device structure
901  *
902  * Get device disconnected state
903  */
904 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
905 {
906         return device->disconnected;
907 }
908
909 /**
910  * connman_device_set_string:
911  * @device: device structure
912  * @key: unique identifier
913  * @value: string value
914  *
915  * Set string value for specific key
916  */
917 int connman_device_set_string(struct connman_device *device,
918                                         const char *key, const char *value)
919 {
920         DBG("device %p key %s value %s", device, key, value);
921
922         if (g_str_equal(key, "Address") == TRUE) {
923                 g_free(device->address);
924                 device->address = g_strdup(value);
925         } else if (g_str_equal(key, "Name") == TRUE) {
926                 g_free(device->name);
927                 device->name = g_strdup(value);
928         } else if (g_str_equal(key, "Node") == TRUE) {
929                 g_free(device->node);
930                 device->node = g_strdup(value);
931         }
932
933         return connman_element_set_string(&device->element, key, value);
934 }
935
936 /**
937  * connman_device_get_string:
938  * @device: device structure
939  * @key: unique identifier
940  *
941  * Get string value for specific key
942  */
943 const char *connman_device_get_string(struct connman_device *device,
944                                                         const char *key)
945 {
946         DBG("device %p key %s", device, key);
947
948         if (g_str_equal(key, "Address") == TRUE)
949                 return device->address;
950         else if (g_str_equal(key, "Name") == TRUE)
951                 return device->name;
952         else if (g_str_equal(key, "Node") == TRUE)
953                 return device->node;
954         else if (g_str_equal(key, "Interface") == TRUE)
955                 return device->interface;
956
957         return connman_element_get_string(&device->element, key);
958 }
959
960 static void set_offlinemode(struct connman_element *element, gpointer user_data)
961 {
962         struct connman_device *device = element->device;
963         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
964         connman_bool_t powered;
965
966         DBG("element %p name %s", element, element->name);
967
968         if (device == NULL)
969                 return;
970
971         device->offlinemode = offlinemode;
972
973         if (device->blocked == TRUE)
974                 return;
975
976         powered = (offlinemode == TRUE) ? FALSE : TRUE;
977
978         if (device->powered == powered)
979                 return;
980
981         if (device->powered_persistent == FALSE)
982                 powered = FALSE;
983
984         set_powered(device, powered);
985 }
986
987 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
988 {
989         DBG("offlinmode %d", offlinemode);
990
991         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
992                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
993
994         __connman_notifier_offlinemode(offlinemode);
995
996         return 0;
997 }
998
999 void __connman_device_increase_connections(struct connman_device *device)
1000 {
1001         if (device == NULL)
1002                 return;
1003
1004         device->connections++;
1005 }
1006
1007 void __connman_device_decrease_connections(struct connman_device *device)
1008 {
1009         if (device == NULL)
1010                 return;
1011
1012         device->connections--;
1013 }
1014
1015 /**
1016  * connman_device_add_network:
1017  * @device: device structure
1018  * @network: network structure
1019  *
1020  * Add new network to the device
1021  */
1022 int connman_device_add_network(struct connman_device *device,
1023                                         struct connman_network *network)
1024 {
1025         const char *identifier = connman_network_get_identifier(network);
1026         int err;
1027
1028         DBG("device %p network %p", device, network);
1029
1030         if (identifier == NULL)
1031                 return -EINVAL;
1032
1033         __connman_network_set_device(network, device);
1034
1035         err = connman_element_register((struct connman_element *) network,
1036                                                         &device->element);
1037         if (err < 0) {
1038                 __connman_network_set_device(network, NULL);
1039                 return err;
1040         }
1041
1042         g_hash_table_insert(device->networks, g_strdup(identifier),
1043                                                                 network);
1044
1045         return 0;
1046 }
1047
1048 /**
1049  * connman_device_get_network:
1050  * @device: device structure
1051  * @identifier: network identifier
1052  *
1053  * Get network for given identifier
1054  */
1055 struct connman_network *connman_device_get_network(struct connman_device *device,
1056                                                         const char *identifier)
1057 {
1058         DBG("device %p identifier %s", device, identifier);
1059
1060         return g_hash_table_lookup(device->networks, identifier);
1061 }
1062
1063 /**
1064  * connman_device_remove_network:
1065  * @device: device structure
1066  * @identifier: network identifier
1067  *
1068  * Remove network for given identifier
1069  */
1070 int connman_device_remove_network(struct connman_device *device,
1071                                                         const char *identifier)
1072 {
1073         DBG("device %p identifier %s", device, identifier);
1074
1075         g_hash_table_remove(device->networks, identifier);
1076
1077         return 0;
1078 }
1079
1080 void connman_device_remove_all_networks(struct connman_device *device)
1081 {
1082         g_hash_table_remove_all(device->networks);
1083 }
1084
1085 void __connman_device_set_network(struct connman_device *device,
1086                                         struct connman_network *network)
1087 {
1088         const char *name;
1089
1090         if (device == NULL)
1091                 return;
1092
1093         if (device->network == network)
1094                 return;
1095
1096         if (device->network != NULL)
1097                 connman_network_unref(device->network);
1098
1099         if (network != NULL) {
1100                 name = connman_network_get_string(network,
1101                                                 CONNMAN_PROPERTY_ID_NAME);
1102                 g_free(device->last_network);
1103                 device->last_network = g_strdup(name);
1104
1105                 device->network = connman_network_ref(network);
1106         } else {
1107                 g_free(device->last_network);
1108                 device->last_network = NULL;
1109
1110                 device->network = NULL;
1111         }
1112 }
1113
1114 void __connman_device_set_reconnect(struct connman_device *device,
1115                                                 connman_bool_t reconnect)
1116 {
1117         device->reconnect = reconnect;
1118 }
1119
1120 connman_bool_t  __connman_device_get_reconnect(
1121                                 struct connman_device *device)
1122 {
1123         return device->reconnect;
1124 }
1125
1126 /**
1127  * connman_device_register:
1128  * @device: device structure
1129  *
1130  * Register device with the system
1131  */
1132 int connman_device_register(struct connman_device *device)
1133 {
1134         __connman_storage_load_device(device);
1135
1136         device->offlinemode = __connman_profile_get_offlinemode();
1137
1138         return connman_element_register(&device->element, NULL);
1139 }
1140
1141 /**
1142  * connman_device_unregister:
1143  * @device: device structure
1144  *
1145  * Unregister device with the system
1146  */
1147 void connman_device_unregister(struct connman_device *device)
1148 {
1149         __connman_storage_save_device(device);
1150
1151         connman_element_unregister(&device->element);
1152 }
1153
1154 /**
1155  * connman_device_get_data:
1156  * @device: device structure
1157  *
1158  * Get private device data pointer
1159  */
1160 void *connman_device_get_data(struct connman_device *device)
1161 {
1162         return device->driver_data;
1163 }
1164
1165 /**
1166  * connman_device_set_data:
1167  * @device: device structure
1168  * @data: data pointer
1169  *
1170  * Set private device data pointer
1171  */
1172 void connman_device_set_data(struct connman_device *device, void *data)
1173 {
1174         device->driver_data = data;
1175 }
1176
1177 static gboolean match_driver(struct connman_device *device,
1178                                         struct connman_device_driver *driver)
1179 {
1180         if (device->type == driver->type ||
1181                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1182                 return TRUE;
1183
1184         return FALSE;
1185 }
1186
1187 static int device_probe(struct connman_element *element)
1188 {
1189         struct connman_device *device = element->device;
1190         GSList *list;
1191
1192         DBG("element %p name %s", element, element->name);
1193
1194         if (device == NULL)
1195                 return -ENODEV;
1196
1197         if (device->driver != NULL)
1198                 return -EALREADY;
1199
1200         for (list = driver_list; list; list = list->next) {
1201                 struct connman_device_driver *driver = list->data;
1202
1203                 if (match_driver(device, driver) == FALSE)
1204                         continue;
1205
1206                 DBG("driver %p name %s", driver, driver->name);
1207
1208                 if (driver->probe(device) == 0) {
1209                         device->driver = driver;
1210                         break;
1211                 }
1212         }
1213
1214         if (device->driver == NULL)
1215                 return -ENODEV;
1216
1217         return setup_device(device);
1218 }
1219
1220 static void device_remove(struct connman_element *element)
1221 {
1222         struct connman_device *device = element->device;
1223
1224         DBG("element %p name %s", element, element->name);
1225
1226         if (device == NULL)
1227                 return;
1228
1229         if (device->driver == NULL)
1230                 return;
1231
1232         remove_device(device);
1233 }
1234
1235 static struct connman_driver device_driver = {
1236         .name           = "device",
1237         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1238         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1239         .probe          = device_probe,
1240         .remove         = device_remove,
1241 };
1242
1243 static int device_load(struct connman_device *device)
1244 {
1245         const char *ident = __connman_profile_active_ident();
1246         GKeyFile *keyfile;
1247         GError *error = NULL;
1248         gchar *identifier;
1249         connman_bool_t powered;
1250         int val;
1251
1252         DBG("device %p", device);
1253
1254         keyfile = __connman_storage_open_profile(ident);
1255         if (keyfile == NULL)
1256                 return 0;
1257
1258         identifier = g_strdup_printf("device_%s", device->element.name);
1259         if (identifier == NULL)
1260                 goto done;
1261
1262         powered = g_key_file_get_boolean(keyfile, identifier,
1263                                                 "Powered", &error);
1264         if (error == NULL)
1265                 device->powered_persistent = powered;
1266         g_clear_error(&error);
1267
1268         val = g_key_file_get_integer(keyfile, identifier,
1269                                                 "ScanInterval", &error);
1270         if (error == NULL)
1271                 device->scan_interval = val;
1272         g_clear_error(&error);
1273
1274 done:
1275         g_free(identifier);
1276
1277         __connman_storage_close_profile(ident, keyfile, FALSE);
1278
1279         return 0;
1280 }
1281
1282 static int device_save(struct connman_device *device)
1283 {
1284         const char *ident = __connman_profile_active_ident();
1285         GKeyFile *keyfile;
1286         gchar *identifier;
1287
1288         DBG("device %p", device);
1289
1290         keyfile = __connman_storage_open_profile(ident);
1291         if (keyfile == NULL)
1292                 return 0;
1293
1294         identifier = g_strdup_printf("device_%s", device->element.name);
1295         if (identifier == NULL)
1296                 goto done;
1297
1298         g_key_file_set_boolean(keyfile, identifier,
1299                                         "Powered", device->powered_persistent);
1300
1301         g_key_file_set_integer(keyfile, identifier,
1302                                         "ScanInterval", device->scan_interval);
1303
1304 done:
1305         g_free(identifier);
1306
1307         __connman_storage_close_profile(ident, keyfile, TRUE);
1308
1309         return 0;
1310 }
1311
1312 static struct connman_storage device_storage = {
1313         .name           = "device",
1314         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1315         .device_load    = device_load,
1316         .device_save    = device_save,
1317 };
1318
1319 int __connman_device_init(void)
1320 {
1321         DBG("");
1322
1323         if (connman_storage_register(&device_storage) < 0)
1324                 connman_error("Failed to register device storage");
1325
1326         return connman_driver_register(&device_driver);
1327 }
1328
1329 void __connman_device_cleanup(void)
1330 {
1331         DBG("");
1332
1333         connman_driver_unregister(&device_driver);
1334
1335         connman_storage_unregister(&device_storage);
1336 }