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