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