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