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