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