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