element: Remove network code
[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_enable(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         g_hash_table_remove_all(device->networks);
275
276         err = device->driver->disable(device);
277         if (err < 0 && err != -EALREADY) {
278                 if (err == -EINPROGRESS)
279                         device->powered_pending = FALSE;
280                 return err;
281         }
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_disable(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 unregister_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_unregister(network);
430         connman_network_unref(network);
431 }
432
433 static void device_destruct(struct connman_device *device)
434 {
435         DBG("device %p name %s", device, device->name);
436
437         clear_scan_trigger(device);
438
439         g_free(device->ident);
440         g_free(device->node);
441         g_free(device->name);
442         g_free(device->address);
443         g_free(device->interface);
444         g_free(device->path);
445         g_free(device->devname);
446
447         g_free(device->last_network);
448
449         g_hash_table_destroy(device->networks);
450         device->networks = NULL;
451
452         g_free(device);
453 }
454
455 /**
456  * connman_device_create:
457  * @node: device node name (for example an address)
458  * @type: device type
459  *
460  * Allocate a new device of given #type and assign the #node name to it.
461  *
462  * Returns: a newly-allocated #connman_device structure
463  */
464 struct connman_device *connman_device_create(const char *node,
465                                                 enum connman_device_type type)
466 {
467         struct connman_device *device;
468         enum connman_service_type service_type;
469         connman_bool_t bg_scan;
470
471         DBG("node %s type %d", node, type);
472
473         device = g_try_new0(struct connman_device, 1);
474         if (device == NULL)
475                 return NULL;
476
477         DBG("device %p", device);
478
479         device->refcount = 1;
480
481         bg_scan = connman_setting_get_bool("BackgroundScanning");
482
483         device->type = type;
484         device->name = g_strdup(type2description(device->type));
485
486         device->powered_persistent = TRUE;
487
488         device->phyindex = -1;
489
490         service_type = __connman_device_get_service_type(device);
491         device->blocked = __connman_technology_get_blocked(service_type);
492         device->backoff_interval = SCAN_INITIAL_DELAY;
493
494         switch (type) {
495         case CONNMAN_DEVICE_TYPE_UNKNOWN:
496         case CONNMAN_DEVICE_TYPE_ETHERNET:
497         case CONNMAN_DEVICE_TYPE_WIMAX:
498         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
499         case CONNMAN_DEVICE_TYPE_CELLULAR:
500         case CONNMAN_DEVICE_TYPE_GPS:
501         case CONNMAN_DEVICE_TYPE_GADGET:
502         case CONNMAN_DEVICE_TYPE_VENDOR:
503                 device->scan_interval = 0;
504                 break;
505         case CONNMAN_DEVICE_TYPE_WIFI:
506                 if (bg_scan == TRUE)
507                         device->scan_interval = 300;
508                 else
509                         device->scan_interval = 0;
510                 break;
511         }
512
513         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
514                                                 g_free, unregister_network);
515
516         device_list = g_slist_append(device_list, device);
517
518         return device;
519 }
520
521 /**
522  * connman_device_ref:
523  * @device: device structure
524  *
525  * Increase reference counter of device
526  */
527 struct connman_device *connman_device_ref(struct connman_device *device)
528 {
529         DBG("%p", device);
530
531         g_atomic_int_inc(&device->refcount);
532
533         return device;
534 }
535
536 /**
537  * connman_device_unref:
538  * @device: device structure
539  *
540  * Decrease reference counter of device
541  */
542 void connman_device_unref(struct connman_device *device)
543 {
544         if (g_atomic_int_dec_and_test(&device->refcount) == FALSE)
545                 return;
546
547         if (device->driver) {
548                 device->driver->remove(device);
549                 device->driver = NULL;
550         }
551
552         device_list = g_slist_remove(device_list, device);
553
554         device_destruct(device);
555 }
556
557 const char *__connman_device_get_type(struct connman_device *device)
558 {
559         return type2string(device->type);
560 }
561
562 /**
563  * connman_device_get_type:
564  * @device: device structure
565  *
566  * Get type of device
567  */
568 enum connman_device_type connman_device_get_type(struct connman_device *device)
569 {
570         return device->type;
571 }
572
573 /**
574  * connman_device_set_index:
575  * @device: device structure
576  * @index: index number
577  *
578  * Set index number of device
579  */
580 void connman_device_set_index(struct connman_device *device, int index)
581 {
582         device->index = index;
583 }
584
585 /**
586  * connman_device_get_index:
587  * @device: device structure
588  *
589  * Get index number of device
590  */
591 int connman_device_get_index(struct connman_device *device)
592 {
593         return device->index;
594 }
595
596 int __connman_device_get_phyindex(struct connman_device *device)
597 {
598         return device->phyindex;
599 }
600
601 void __connman_device_set_phyindex(struct connman_device *device,
602                                                         int phyindex)
603 {
604         device->phyindex = phyindex;
605 }
606
607 /**
608  * connman_device_set_interface:
609  * @device: device structure
610  * @interface: interface name
611  *
612  * Set interface name of device
613  */
614 void connman_device_set_interface(struct connman_device *device,
615                                                 const char *interface)
616 {
617         g_free(device->devname);
618         device->devname = g_strdup(interface);
619
620         g_free(device->interface);
621         device->interface = g_strdup(interface);
622
623         if (device->name == NULL) {
624                 const char *str = type2description(device->type);
625                 if (str != NULL && device->interface != NULL)
626                         device->name = g_strdup_printf("%s (%s)", str,
627                                                         device->interface);
628         }
629 }
630
631 /**
632  * connman_device_set_ident:
633  * @device: device structure
634  * @ident: unique identifier
635  *
636  * Set unique identifier of device
637  */
638 void connman_device_set_ident(struct connman_device *device,
639                                                         const char *ident)
640 {
641         g_free(device->ident);
642         device->ident = g_strdup(ident);
643 }
644
645 const char *connman_device_get_ident(struct connman_device *device)
646 {
647         return device->ident;
648 }
649
650 /**
651  * connman_device_set_powered:
652  * @device: device structure
653  * @powered: powered state
654  *
655  * Change power state of device
656  */
657 int connman_device_set_powered(struct connman_device *device,
658                                                 connman_bool_t powered)
659 {
660         int err;
661         enum connman_service_type type;
662
663         DBG("driver %p powered %d", device, powered);
664
665         if (device->powered == powered) {
666                 device->powered_pending = powered;
667                 return -EALREADY;
668         }
669
670         if (powered == TRUE)
671                 err = __connman_device_enable(device);
672         else
673                 err = __connman_device_disable(device);
674
675         if (err < 0 && err != -EINPROGRESS && err != -EALREADY)
676                 return err;
677
678         device->powered = powered;
679         device->powered_pending = powered;
680
681         type = __connman_device_get_service_type(device);
682
683         if (device->powered == TRUE)
684                 __connman_technology_enable(type);
685         else
686                 __connman_technology_disable(type);
687
688         if (device->offlinemode == TRUE && powered == TRUE)
689                 return connman_device_set_powered(device, FALSE);
690
691         if (powered == FALSE)
692                 return 0;
693
694         reset_scan_trigger(device);
695
696         if (device->driver && device->driver->scan)
697                 device->driver->scan(device);
698
699         return 0;
700 }
701
702 int __connman_device_set_blocked(struct connman_device *device,
703                                                 connman_bool_t blocked)
704 {
705         connman_bool_t powered;
706
707         DBG("device %p blocked %d", device, blocked);
708
709         device->blocked = blocked;
710
711         if (device->offlinemode == TRUE)
712                 return 0;
713
714         connman_info("%s {rfkill} blocked %d", device->interface, blocked);
715
716         if (blocked == FALSE)
717                 powered = device->powered_persistent;
718         else
719                 powered = FALSE;
720
721         return set_powered(device, powered);
722 }
723
724 connman_bool_t __connman_device_get_blocked(struct connman_device *device)
725 {
726         return device->blocked;
727 }
728
729 int __connman_device_scan(struct connman_device *device)
730 {
731         if (!device->driver || !device->driver->scan)
732                 return -EOPNOTSUPP;
733
734         if (device->powered == FALSE)
735                 return -ENOLINK;
736
737         reset_scan_trigger(device);
738
739         return device->driver->scan(device);
740 }
741
742 int __connman_device_enable_persistent(struct connman_device *device)
743 {
744         int err;
745
746         DBG("device %p", device);
747
748         device->powered_persistent = TRUE;
749
750         __connman_storage_save_device(device);
751
752         err = __connman_device_enable(device);
753         if (err == 0 || err == -EINPROGRESS) {
754                 device->offlinemode = FALSE;
755                 if (__connman_profile_get_offlinemode() == TRUE) {
756                         __connman_profile_set_offlinemode(FALSE, FALSE);
757
758                         __connman_profile_save_default();
759                 }
760         }
761
762         return err;
763 }
764
765 int __connman_device_disable_persistent(struct connman_device *device)
766 {
767         DBG("device %p", device);
768
769         device->powered_persistent = FALSE;
770
771         __connman_storage_save_device(device);
772
773         return __connman_device_disable(device);
774 }
775
776 int __connman_device_disconnect(struct connman_device *device)
777 {
778         GHashTableIter iter;
779         gpointer key, value;
780
781         DBG("device %p", device);
782
783         connman_device_set_disconnected(device, TRUE);
784
785         g_hash_table_iter_init(&iter, device->networks);
786
787         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
788                 struct connman_network *network = value;
789
790                 if (connman_network_get_connecting(network) == TRUE) {
791                         /*
792                          * Skip network in the process of connecting.
793                          * This is a workaround for WiFi networks serviced
794                          * by the supplicant plugin that hold a reference
795                          * to the network.  If we disconnect the network
796                          * here then the referenced object will not be
797                          * registered and usage (like launching DHCP client)
798                          * will fail.  There is nothing to be gained by
799                          * removing the network here anyway.
800                          */
801                         connman_warn("Skipping disconnect of %s, network is connecting.",
802                                 connman_network_get_identifier(network));
803                         continue;
804                 }
805
806                 __connman_network_disconnect(network);
807         }
808
809         return 0;
810 }
811
812 static void mark_network_available(gpointer key, gpointer value,
813                                                         gpointer user_data)
814 {
815         struct connman_network *network = value;
816
817         connman_network_set_available(network, TRUE);
818 }
819
820 static void mark_network_unavailable(gpointer key, gpointer value,
821                                                         gpointer user_data)
822 {
823         struct connman_network *network = value;
824
825         if (connman_network_get_connected(network) == TRUE)
826                 return;
827
828         connman_network_set_available(network, FALSE);
829 }
830
831 static gboolean remove_unavailable_network(gpointer key, gpointer value,
832                                                         gpointer user_data)
833 {
834         struct connman_network *network = value;
835
836         if (connman_network_get_connected(network) == TRUE)
837                 return FALSE;
838
839         if (connman_network_get_available(network) == TRUE)
840                 return FALSE;
841
842         return TRUE;
843 }
844
845 void __connman_device_cleanup_networks(struct connman_device *device)
846 {
847         g_hash_table_foreach_remove(device->networks,
848                                         remove_unavailable_network, NULL);
849 }
850
851 connman_bool_t __connman_device_scanning(struct connman_device *device)
852 {
853         return device->scanning;
854 }
855
856 void connman_device_reset_scanning(struct connman_device *device)
857 {
858         device->scanning = FALSE;
859
860         g_hash_table_foreach(device->networks,
861                                 mark_network_available, NULL);
862
863 }
864
865 /**
866  * connman_device_set_scanning:
867  * @device: device structure
868  * @scanning: scanning state
869  *
870  * Change scanning state of device
871  */
872 int connman_device_set_scanning(struct connman_device *device,
873                                                 connman_bool_t scanning)
874 {
875         DBG("device %p scanning %d", device, scanning);
876
877         if (!device->driver || !device->driver->scan)
878                 return -EINVAL;
879
880         if (device->scanning == scanning)
881                 return -EALREADY;
882
883         device->scanning = scanning;
884
885         if (scanning == TRUE) {
886                 reset_scan_trigger(device);
887
888                 g_hash_table_foreach(device->networks,
889                                         mark_network_unavailable, NULL);
890
891                 return 0;
892         }
893
894         __connman_device_cleanup_networks(device);
895
896         if (device->connections > 0)
897                 return 0;
898
899         __connman_service_auto_connect();
900
901         return 0;
902 }
903
904 /**
905  * connman_device_set_disconnected:
906  * @device: device structure
907  * @disconnected: disconnected state
908  *
909  * Change disconnected state of device (only for device with networks)
910  */
911 int connman_device_set_disconnected(struct connman_device *device,
912                                                 connman_bool_t disconnected)
913 {
914         DBG("device %p disconnected %d", device, disconnected);
915
916         if (device->disconnected == disconnected)
917                 return -EALREADY;
918
919         device->disconnected = disconnected;
920
921         if (disconnected == TRUE)
922                 force_scan_trigger(device);
923
924         return 0;
925 }
926
927 /**
928  * connman_device_get_disconnected:
929  * @device: device structure
930  *
931  * Get device disconnected state
932  */
933 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
934 {
935         return device->disconnected;
936 }
937
938 /**
939  * connman_device_set_string:
940  * @device: device structure
941  * @key: unique identifier
942  * @value: string value
943  *
944  * Set string value for specific key
945  */
946 int connman_device_set_string(struct connman_device *device,
947                                         const char *key, const char *value)
948 {
949         DBG("device %p key %s value %s", device, key, value);
950
951         if (g_str_equal(key, "Address") == TRUE) {
952                 g_free(device->address);
953                 device->address = g_strdup(value);
954         } else if (g_str_equal(key, "Name") == TRUE) {
955                 g_free(device->name);
956                 device->name = g_strdup(value);
957         } else if (g_str_equal(key, "Node") == TRUE) {
958                 g_free(device->node);
959                 device->node = g_strdup(value);
960         } else if (g_str_equal(key, "Path") == TRUE) {
961                 g_free(device->path);
962                 device->path = g_strdup(value);
963         } else {
964                 return -EINVAL;
965         }
966
967         return 0;
968 }
969
970 /**
971  * connman_device_get_string:
972  * @device: device structure
973  * @key: unique identifier
974  *
975  * Get string value for specific key
976  */
977 const char *connman_device_get_string(struct connman_device *device,
978                                                         const char *key)
979 {
980         DBG("device %p key %s", device, key);
981
982         if (g_str_equal(key, "Address") == TRUE)
983                 return device->address;
984         else if (g_str_equal(key, "Name") == TRUE)
985                 return device->name;
986         else if (g_str_equal(key, "Node") == TRUE)
987                 return device->node;
988         else if (g_str_equal(key, "Interface") == TRUE)
989                 return device->interface;
990         else if (g_str_equal(key, "Path") == TRUE)
991                 return device->path;
992
993         return NULL;
994 }
995
996 static void set_offlinemode(struct connman_device *device,
997                                 connman_bool_t offlinemode)
998 {
999         connman_bool_t powered;
1000
1001         DBG("device %p name %s", device, device->name);
1002
1003         if (device == NULL)
1004                 return;
1005
1006         device->offlinemode = offlinemode;
1007
1008         if (device->blocked == TRUE)
1009                 return;
1010
1011         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1012
1013         if (device->powered == powered)
1014                 return;
1015
1016         if (device->powered_persistent == FALSE)
1017                 powered = FALSE;
1018
1019         set_powered(device, powered);
1020 }
1021
1022 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1023 {
1024         GSList *list;
1025
1026         DBG("offlinmode %d", offlinemode);
1027
1028         for (list = device_list; list != NULL; list = list->next) {
1029                 struct connman_device *device = list->data;
1030
1031                 set_offlinemode(device, offlinemode);
1032         }
1033
1034         __connman_notifier_offlinemode(offlinemode);
1035
1036         return 0;
1037 }
1038
1039 void __connman_device_increase_connections(struct connman_device *device)
1040 {
1041         if (device == NULL)
1042                 return;
1043
1044         device->connections++;
1045 }
1046
1047 void __connman_device_decrease_connections(struct connman_device *device)
1048 {
1049         if (device == NULL)
1050                 return;
1051
1052         device->connections--;
1053
1054         if (device->connections == 0)
1055                 device->backoff_interval = SCAN_INITIAL_DELAY;
1056 }
1057
1058 /**
1059  * connman_device_add_network:
1060  * @device: device structure
1061  * @network: network structure
1062  *
1063  * Add new network to the device
1064  */
1065 int connman_device_add_network(struct connman_device *device,
1066                                         struct connman_network *network)
1067 {
1068         const char *identifier = connman_network_get_identifier(network);
1069
1070         DBG("device %p network %p", device, network);
1071
1072         if (identifier == NULL)
1073                 return -EINVAL;
1074
1075         __connman_network_set_device(network, device);
1076
1077         g_hash_table_insert(device->networks, g_strdup(identifier),
1078                                                                 network);
1079
1080         return 0;
1081 }
1082
1083 /**
1084  * connman_device_get_network:
1085  * @device: device structure
1086  * @identifier: network identifier
1087  *
1088  * Get network for given identifier
1089  */
1090 struct connman_network *connman_device_get_network(struct connman_device *device,
1091                                                         const char *identifier)
1092 {
1093         DBG("device %p identifier %s", device, identifier);
1094
1095         return g_hash_table_lookup(device->networks, identifier);
1096 }
1097
1098 /**
1099  * connman_device_remove_network:
1100  * @device: device structure
1101  * @identifier: network identifier
1102  *
1103  * Remove network for given identifier
1104  */
1105 int connman_device_remove_network(struct connman_device *device,
1106                                                         const char *identifier)
1107 {
1108         struct connman_network *network;
1109
1110         DBG("device %p identifier %s", device, identifier);
1111
1112         network = connman_device_get_network(device, identifier);
1113         if (network == NULL)
1114                 return 0;
1115
1116         __connman_network_set_device(network, NULL);
1117
1118         g_hash_table_remove(device->networks, identifier);
1119
1120         return 0;
1121 }
1122
1123 void connman_device_remove_all_networks(struct connman_device *device)
1124 {
1125         g_hash_table_remove_all(device->networks);
1126 }
1127
1128 void __connman_device_set_network(struct connman_device *device,
1129                                         struct connman_network *network)
1130 {
1131         const char *name;
1132
1133         if (device == NULL)
1134                 return;
1135
1136         if (device->network == network)
1137                 return;
1138
1139         if (device->network != NULL)
1140                 connman_network_unref(device->network);
1141
1142         if (network != NULL) {
1143                 name = connman_network_get_string(network,
1144                                                 CONNMAN_PROPERTY_ID_NAME);
1145                 g_free(device->last_network);
1146                 device->last_network = g_strdup(name);
1147
1148                 device->network = connman_network_ref(network);
1149         } else {
1150                 g_free(device->last_network);
1151                 device->last_network = NULL;
1152
1153                 device->network = NULL;
1154         }
1155 }
1156
1157 void __connman_device_set_reconnect(struct connman_device *device,
1158                                                 connman_bool_t reconnect)
1159 {
1160         device->reconnect = reconnect;
1161 }
1162
1163 connman_bool_t  __connman_device_get_reconnect(
1164                                 struct connman_device *device)
1165 {
1166         return device->reconnect;
1167 }
1168
1169 static gboolean match_driver(struct connman_device *device,
1170                                         struct connman_device_driver *driver)
1171 {
1172         if (device->type == driver->type ||
1173                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1174                 return TRUE;
1175
1176         return FALSE;
1177 }
1178
1179 static int device_probe(struct connman_device *device)
1180 {
1181         GSList *list;
1182
1183         DBG("device %p name %s", device, device->name);
1184
1185         if (device->driver != NULL)
1186                 return -EALREADY;
1187
1188         for (list = driver_list; list; list = list->next) {
1189                 struct connman_device_driver *driver = list->data;
1190
1191                 if (match_driver(device, driver) == FALSE)
1192                         continue;
1193
1194                 DBG("driver %p name %s", driver, driver->name);
1195
1196                 if (driver->probe(device) == 0) {
1197                         device->driver = driver;
1198                         break;
1199                 }
1200         }
1201
1202         if (device->driver == NULL)
1203                 return -ENODEV;
1204
1205         return setup_device(device);
1206 }
1207
1208 static void device_remove(struct connman_device *device)
1209 {
1210         DBG("device %p name %s", device, device->name);
1211
1212         if (device->driver == NULL)
1213                 return;
1214
1215         remove_device(device);
1216 }
1217
1218 /**
1219  * connman_device_register:
1220  * @device: device structure
1221  *
1222  * Register device with the system
1223  */
1224 int connman_device_register(struct connman_device *device)
1225 {
1226         __connman_storage_load_device(device);
1227
1228         device->offlinemode = __connman_profile_get_offlinemode();
1229
1230         return device_probe(device);
1231 }
1232
1233 /**
1234  * connman_device_unregister:
1235  * @device: device structure
1236  *
1237  * Unregister device with the system
1238  */
1239 void connman_device_unregister(struct connman_device *device)
1240 {
1241         __connman_storage_save_device(device);
1242
1243         device_remove(device);
1244 }
1245
1246 /**
1247  * connman_device_get_data:
1248  * @device: device structure
1249  *
1250  * Get private device data pointer
1251  */
1252 void *connman_device_get_data(struct connman_device *device)
1253 {
1254         return device->driver_data;
1255 }
1256
1257 /**
1258  * connman_device_set_data:
1259  * @device: device structure
1260  * @data: data pointer
1261  *
1262  * Set private device data pointer
1263  */
1264 void connman_device_set_data(struct connman_device *device, void *data)
1265 {
1266         device->driver_data = data;
1267 }
1268
1269 struct connman_device *__connman_device_find_device(
1270                                 enum connman_service_type type)
1271 {
1272         GSList *list;
1273
1274         for (list = device_list; list != NULL; list = list->next) {
1275                 struct connman_device *device = list->data;
1276                 enum connman_service_type service_type =
1277                         connman_device_get_type(device);
1278
1279                 if (service_type != type)
1280                         continue;
1281
1282                 return device;
1283         }
1284
1285         return NULL;
1286 }
1287
1288 int __connman_device_request_scan(enum connman_service_type type)
1289 {
1290         GSList *list;
1291         int err;
1292
1293         switch (type) {
1294         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1295         case CONNMAN_SERVICE_TYPE_SYSTEM:
1296         case CONNMAN_SERVICE_TYPE_ETHERNET:
1297         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1298         case CONNMAN_SERVICE_TYPE_CELLULAR:
1299         case CONNMAN_SERVICE_TYPE_GPS:
1300         case CONNMAN_SERVICE_TYPE_VPN:
1301         case CONNMAN_SERVICE_TYPE_GADGET:
1302                 return 0;
1303         case CONNMAN_SERVICE_TYPE_WIFI:
1304         case CONNMAN_SERVICE_TYPE_WIMAX:
1305                 break;
1306         }
1307
1308         for (list = device_list; list != NULL; list = list->next) {
1309                 struct connman_device *device = list->data;
1310                 enum connman_service_type service_type =
1311                         __connman_device_get_service_type(device);
1312
1313                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
1314                                 service_type != type) {
1315                         continue;
1316                 }
1317
1318                 err = __connman_device_scan(device);
1319                 if (err < 0 && err != -EINPROGRESS) {
1320                         DBG("err %d", err);
1321                         /* XXX maybe only a continue? */
1322                         return err;
1323                 }
1324         }
1325
1326         return 0;
1327 }
1328
1329 static int set_technology(enum connman_service_type type, connman_bool_t enable)
1330 {
1331         GSList *list;
1332         int err;
1333
1334         DBG("type %d enable %d", type, enable);
1335
1336         switch (type) {
1337         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1338         case CONNMAN_SERVICE_TYPE_SYSTEM:
1339         case CONNMAN_SERVICE_TYPE_GPS:
1340         case CONNMAN_SERVICE_TYPE_VPN:
1341         case CONNMAN_SERVICE_TYPE_GADGET:
1342                 return 0;
1343         case CONNMAN_SERVICE_TYPE_ETHERNET:
1344         case CONNMAN_SERVICE_TYPE_WIFI:
1345         case CONNMAN_SERVICE_TYPE_WIMAX:
1346         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1347         case CONNMAN_SERVICE_TYPE_CELLULAR:
1348                 break;
1349         }
1350
1351         for (list = device_list; list != NULL; list = list->next) {
1352                 struct connman_device *device = list->data;
1353                 enum connman_service_type service_type =
1354                         __connman_device_get_service_type(device);
1355
1356                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
1357                                 service_type != type) {
1358                         continue;
1359                 }
1360
1361                 if (enable == TRUE)
1362                         err = __connman_device_enable_persistent(device);
1363                 else
1364                         err = __connman_device_disable_persistent(device);
1365
1366                 if (err < 0 && err != -EINPROGRESS) {
1367                         DBG("err %d", err);
1368                         /* XXX maybe only a continue? */
1369                         return err;
1370                 }
1371         }
1372
1373         return 0;
1374 }
1375
1376 int __connman_device_enable_technology(enum connman_service_type type)
1377 {
1378         return set_technology(type, TRUE);
1379 }
1380
1381 int __connman_device_disable_technology(enum connman_service_type type)
1382 {
1383         return set_technology(type, FALSE);
1384 }
1385
1386 connman_bool_t __connman_device_isfiltered(const char *devname)
1387 {
1388         char **pattern;
1389
1390         if (device_filter == NULL)
1391                 goto nodevice;
1392
1393         for (pattern = device_filter; *pattern; pattern++) {
1394                 if (g_pattern_match_simple(*pattern, devname) == FALSE) {
1395                         DBG("ignoring device %s (match)", devname);
1396                         return TRUE;
1397                 }
1398         }
1399
1400 nodevice:
1401         if (nodevice_filter == NULL)
1402                 return FALSE;
1403
1404         for (pattern = nodevice_filter; *pattern; pattern++) {
1405                 if (g_pattern_match_simple(*pattern, devname) == TRUE) {
1406                         DBG("ignoring device %s (no match)", devname);
1407                         return TRUE;
1408                 }
1409         }
1410
1411         return FALSE;
1412 }
1413
1414 static int device_load(struct connman_device *device)
1415 {
1416         const char *ident = __connman_profile_active_ident();
1417         GKeyFile *keyfile;
1418         GError *error = NULL;
1419         gchar *identifier;
1420         connman_bool_t powered;
1421
1422         DBG("device %p", device);
1423
1424         keyfile = __connman_storage_open_profile(ident);
1425         if (keyfile == NULL)
1426                 return 0;
1427
1428         identifier = g_strdup_printf("device_%s", device->name);
1429         if (identifier == NULL)
1430                 goto done;
1431
1432         powered = g_key_file_get_boolean(keyfile, identifier,
1433                                                 "Powered", &error);
1434         if (error == NULL)
1435                 device->powered_persistent = powered;
1436         g_clear_error(&error);
1437
1438 done:
1439         g_free(identifier);
1440
1441         __connman_storage_close_profile(ident, keyfile, FALSE);
1442
1443         return 0;
1444 }
1445
1446 static int device_save(struct connman_device *device)
1447 {
1448         const char *ident = __connman_profile_active_ident();
1449         GKeyFile *keyfile;
1450         gchar *identifier;
1451
1452         DBG("device %p", device);
1453
1454         keyfile = __connman_storage_open_profile(ident);
1455         if (keyfile == NULL)
1456                 return 0;
1457
1458         identifier = g_strdup_printf("device_%s", device->name);
1459         if (identifier == NULL)
1460                 goto done;
1461
1462         g_key_file_set_boolean(keyfile, identifier,
1463                                         "Powered", device->powered_persistent);
1464
1465 done:
1466         g_free(identifier);
1467
1468         __connman_storage_close_profile(ident, keyfile, TRUE);
1469
1470         return 0;
1471 }
1472
1473 static struct connman_storage device_storage = {
1474         .name           = "device",
1475         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1476         .device_load    = device_load,
1477         .device_save    = device_save,
1478 };
1479
1480 int __connman_device_init(const char *device, const char *nodevice)
1481 {
1482         DBG("");
1483
1484         if (device != NULL)
1485                 device_filter = g_strsplit(device, ",", -1);
1486
1487         if (nodevice != NULL)
1488                 nodevice_filter = g_strsplit(nodevice, ",", -1);
1489
1490         return connman_storage_register(&device_storage);
1491 }
1492
1493 void __connman_device_cleanup(void)
1494 {
1495         DBG("");
1496
1497         g_strfreev(nodevice_filter);
1498         g_strfreev(device_filter);
1499
1500         connman_storage_unregister(&device_storage);
1501 }