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