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