device: Add function for requesting a hidden scan
[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         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                 connman_network_set_connected(device->network, FALSE);
311
312         err = device->driver->disable(device);
313         if (err == 0) {
314                 connman_device_set_powered(device, FALSE);
315                 goto done;
316         }
317
318         if (err == -EALREADY) {
319                 connman_device_set_powered(device, FALSE);
320                 goto done;
321         }
322
323         if (err == -EINPROGRESS)
324                 device->pending_timeout = g_timeout_add_seconds(4,
325                                         device_pending_reset, device);
326 done:
327         return err;
328 }
329
330 static void probe_driver(struct connman_device_driver *driver)
331 {
332         GSList *list;
333
334         DBG("driver %p name %s", driver, driver->name);
335
336         for (list = device_list; list != NULL; list = list->next) {
337                 struct connman_device *device = list->data;
338
339                 if (device->driver != NULL)
340                         continue;
341
342                 if (driver->type != device->type)
343                         continue;
344
345                 if (driver->probe(device) < 0)
346                         continue;
347
348                 device->driver = driver;
349
350                 __connman_technology_add_device(device);
351         }
352 }
353
354 static void remove_device(struct connman_device *device)
355 {
356         DBG("device %p", device);
357
358         __connman_device_disable(device);
359
360         __connman_technology_remove_device(device);
361
362         if (device->driver->remove)
363                 device->driver->remove(device);
364
365         device->driver = NULL;
366 }
367
368 static void remove_driver(struct connman_device_driver *driver)
369 {
370         GSList *list;
371
372         DBG("driver %p name %s", driver, driver->name);
373
374         for (list = device_list; list != NULL; list = list->next) {
375                 struct connman_device *device = list->data;
376
377                 if (device->driver == driver)
378                         remove_device(device);
379         }
380 }
381
382 connman_bool_t __connman_device_has_driver(struct connman_device *device)
383 {
384         if (device == NULL || device->driver == NULL)
385                 return FALSE;
386
387         return TRUE;
388 }
389
390 static GSList *driver_list = NULL;
391
392 static gint compare_priority(gconstpointer a, gconstpointer b)
393 {
394         const struct connman_device_driver *driver1 = a;
395         const struct connman_device_driver *driver2 = b;
396
397         return driver2->priority - driver1->priority;
398 }
399
400 /**
401  * connman_device_driver_register:
402  * @driver: device driver definition
403  *
404  * Register a new device driver
405  *
406  * Returns: %0 on success
407  */
408 int connman_device_driver_register(struct connman_device_driver *driver)
409 {
410         DBG("driver %p name %s", driver, driver->name);
411
412         driver_list = g_slist_insert_sorted(driver_list, driver,
413                                                         compare_priority);
414         probe_driver(driver);
415
416         return 0;
417 }
418
419 /**
420  * connman_device_driver_unregister:
421  * @driver: device driver definition
422  *
423  * Remove a previously registered device driver
424  */
425 void connman_device_driver_unregister(struct connman_device_driver *driver)
426 {
427         DBG("driver %p name %s", driver, driver->name);
428
429         driver_list = g_slist_remove(driver_list, driver);
430
431         remove_driver(driver);
432 }
433
434 static void free_network(gpointer data)
435 {
436         struct connman_network *network = data;
437
438         DBG("network %p", network);
439
440         __connman_network_set_device(network, NULL);
441
442         connman_network_unref(network);
443 }
444
445 static void device_destruct(struct connman_device *device)
446 {
447         DBG("device %p name %s", device, device->name);
448
449         clear_pending_trigger(device);
450         clear_scan_trigger(device);
451
452         g_free(device->ident);
453         g_free(device->node);
454         g_free(device->name);
455         g_free(device->address);
456         g_free(device->interface);
457         g_free(device->path);
458         g_free(device->devname);
459
460         g_free(device->last_network);
461
462         g_hash_table_destroy(device->networks);
463         device->networks = NULL;
464
465         g_free(device);
466 }
467
468 /**
469  * connman_device_create:
470  * @node: device node name (for example an address)
471  * @type: device type
472  *
473  * Allocate a new device of given #type and assign the #node name to it.
474  *
475  * Returns: a newly-allocated #connman_device structure
476  */
477 struct connman_device *connman_device_create(const char *node,
478                                                 enum connman_device_type type)
479 {
480         struct connman_device *device;
481         connman_bool_t bg_scan;
482
483         DBG("node %s type %d", node, type);
484
485         device = g_try_new0(struct connman_device, 1);
486         if (device == NULL)
487                 return NULL;
488
489         DBG("device %p", device);
490
491         device->refcount = 1;
492
493         bg_scan = connman_setting_get_bool("BackgroundScanning");
494
495         device->type = type;
496         device->name = g_strdup(type2description(device->type));
497
498         device->phyindex = -1;
499
500         device->backoff_interval = SCAN_INITIAL_DELAY;
501
502         switch (type) {
503         case CONNMAN_DEVICE_TYPE_UNKNOWN:
504         case CONNMAN_DEVICE_TYPE_ETHERNET:
505         case CONNMAN_DEVICE_TYPE_WIMAX:
506         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
507         case CONNMAN_DEVICE_TYPE_CELLULAR:
508         case CONNMAN_DEVICE_TYPE_GPS:
509         case CONNMAN_DEVICE_TYPE_GADGET:
510         case CONNMAN_DEVICE_TYPE_VENDOR:
511                 device->scan_interval = 0;
512                 break;
513         case CONNMAN_DEVICE_TYPE_WIFI:
514                 if (bg_scan == TRUE)
515                         device->scan_interval = 300;
516                 else
517                         device->scan_interval = 0;
518                 break;
519         }
520
521         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
522                                                 g_free, free_network);
523
524         device_list = g_slist_append(device_list, device);
525
526         return device;
527 }
528
529 /**
530  * connman_device_ref:
531  * @device: device structure
532  *
533  * Increase reference counter of device
534  */
535 struct connman_device *connman_device_ref(struct connman_device *device)
536 {
537         DBG("%p", device);
538
539         __sync_fetch_and_add(&device->refcount, 1);
540
541         return device;
542 }
543
544 /**
545  * connman_device_unref:
546  * @device: device structure
547  *
548  * Decrease reference counter of device
549  */
550 void connman_device_unref(struct connman_device *device)
551 {
552         if (__sync_fetch_and_sub(&device->refcount, 1) != 1)
553                 return;
554
555         if (device->driver) {
556                 device->driver->remove(device);
557                 device->driver = NULL;
558         }
559
560         device_list = g_slist_remove(device_list, device);
561
562         device_destruct(device);
563 }
564
565 const char *__connman_device_get_type(struct connman_device *device)
566 {
567         return type2string(device->type);
568 }
569
570 /**
571  * connman_device_get_type:
572  * @device: device structure
573  *
574  * Get type of device
575  */
576 enum connman_device_type connman_device_get_type(struct connman_device *device)
577 {
578         return device->type;
579 }
580
581 /**
582  * connman_device_set_index:
583  * @device: device structure
584  * @index: index number
585  *
586  * Set index number of device
587  */
588 void connman_device_set_index(struct connman_device *device, int index)
589 {
590         device->index = index;
591 }
592
593 /**
594  * connman_device_get_index:
595  * @device: device structure
596  *
597  * Get index number of device
598  */
599 int connman_device_get_index(struct connman_device *device)
600 {
601         return device->index;
602 }
603
604 int __connman_device_get_phyindex(struct connman_device *device)
605 {
606         return device->phyindex;
607 }
608
609 void __connman_device_set_phyindex(struct connman_device *device,
610                                                         int phyindex)
611 {
612         device->phyindex = phyindex;
613 }
614
615 /**
616  * connman_device_set_interface:
617  * @device: device structure
618  * @interface: interface name
619  *
620  * Set interface name of device
621  */
622 void connman_device_set_interface(struct connman_device *device,
623                                                 const char *interface)
624 {
625         g_free(device->devname);
626         device->devname = g_strdup(interface);
627
628         g_free(device->interface);
629         device->interface = g_strdup(interface);
630
631         if (device->name == NULL) {
632                 const char *str = type2description(device->type);
633                 if (str != NULL && device->interface != NULL)
634                         device->name = g_strdup_printf("%s (%s)", str,
635                                                         device->interface);
636         }
637 }
638
639 /**
640  * connman_device_set_ident:
641  * @device: device structure
642  * @ident: unique identifier
643  *
644  * Set unique identifier of device
645  */
646 void connman_device_set_ident(struct connman_device *device,
647                                                         const char *ident)
648 {
649         g_free(device->ident);
650         device->ident = g_strdup(ident);
651 }
652
653 const char *connman_device_get_ident(struct connman_device *device)
654 {
655         return device->ident;
656 }
657
658 /**
659  * connman_device_set_powered:
660  * @device: device structure
661  * @powered: powered state
662  *
663  * Change power state of device
664  */
665 int connman_device_set_powered(struct connman_device *device,
666                                                 connman_bool_t powered)
667 {
668         enum connman_service_type type;
669
670         DBG("driver %p powered %d", device, powered);
671
672         if (device->powered == powered)
673                 return -EALREADY;
674
675         clear_pending_trigger(device);
676
677         device->powered_pending = PENDING_NONE;
678
679         device->powered = powered;
680
681         type = __connman_device_get_service_type(device);
682
683         if (device->powered == TRUE)
684                 __connman_technology_enabled(type);
685         else
686                 __connman_technology_disabled(type);
687
688         if (powered == FALSE)
689                 return 0;
690
691         connman_device_set_disconnected(device, FALSE);
692         device->scanning = FALSE;
693
694         reset_scan_trigger(device);
695
696         if (device->driver && device->driver->scan_fast)
697                 device->driver->scan_fast(device);
698         else if (device->driver && device->driver->scan)
699                 device->driver->scan(device);
700
701         return 0;
702 }
703
704 static int device_scan(struct connman_device *device)
705 {
706         if (!device->driver || !device->driver->scan)
707                 return -EOPNOTSUPP;
708
709         if (device->powered == FALSE)
710                 return -ENOLINK;
711
712         reset_scan_trigger(device);
713
714         return device->driver->scan(device);
715 }
716
717 int __connman_device_disconnect(struct connman_device *device)
718 {
719         GHashTableIter iter;
720         gpointer key, value;
721
722         DBG("device %p", device);
723
724         connman_device_set_disconnected(device, TRUE);
725
726         g_hash_table_iter_init(&iter, device->networks);
727
728         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
729                 struct connman_network *network = value;
730
731                 if (connman_network_get_connecting(network) == TRUE) {
732                         /*
733                          * Skip network in the process of connecting.
734                          * This is a workaround for WiFi networks serviced
735                          * by the supplicant plugin that hold a reference
736                          * to the network.  If we disconnect the network
737                          * here then the referenced object will not be
738                          * registered and usage (like launching DHCP client)
739                          * will fail.  There is nothing to be gained by
740                          * removing the network here anyway.
741                          */
742                         connman_warn("Skipping disconnect of %s, network is connecting.",
743                                 connman_network_get_identifier(network));
744                         continue;
745                 }
746
747                 __connman_network_disconnect(network);
748         }
749
750         return 0;
751 }
752
753 static void mark_network_available(gpointer key, gpointer value,
754                                                         gpointer user_data)
755 {
756         struct connman_network *network = value;
757
758         connman_network_set_available(network, TRUE);
759 }
760
761 static void mark_network_unavailable(gpointer key, gpointer value,
762                                                         gpointer user_data)
763 {
764         struct connman_network *network = value;
765
766         if (connman_network_get_connected(network) == TRUE)
767                 return;
768
769         connman_network_set_available(network, FALSE);
770 }
771
772 static gboolean remove_unavailable_network(gpointer key, gpointer value,
773                                                         gpointer user_data)
774 {
775         struct connman_network *network = value;
776
777         if (connman_network_get_connected(network) == TRUE)
778                 return FALSE;
779
780         if (connman_network_get_available(network) == TRUE)
781                 return FALSE;
782
783         return TRUE;
784 }
785
786 void __connman_device_cleanup_networks(struct connman_device *device)
787 {
788         g_hash_table_foreach_remove(device->networks,
789                                         remove_unavailable_network, NULL);
790 }
791
792 connman_bool_t __connman_device_scanning(struct connman_device *device)
793 {
794         return device->scanning;
795 }
796
797 void connman_device_reset_scanning(struct connman_device *device)
798 {
799         device->scanning = FALSE;
800
801         g_hash_table_foreach(device->networks,
802                                 mark_network_available, NULL);
803
804 }
805
806 /**
807  * connman_device_set_scanning:
808  * @device: device structure
809  * @scanning: scanning state
810  *
811  * Change scanning state of device
812  */
813 int connman_device_set_scanning(struct connman_device *device,
814                                                 connman_bool_t scanning)
815 {
816         DBG("device %p scanning %d", device, scanning);
817
818         if (!device->driver || !device->driver->scan)
819                 return -EINVAL;
820
821         if (device->scanning == scanning)
822                 return -EALREADY;
823
824         device->scanning = scanning;
825
826         if (scanning == TRUE) {
827                 reset_scan_trigger(device);
828
829                 g_hash_table_foreach(device->networks,
830                                         mark_network_unavailable, NULL);
831
832                 return 0;
833         }
834
835         __connman_device_cleanup_networks(device);
836
837         __connman_service_auto_connect();
838
839         return 0;
840 }
841
842 /**
843  * connman_device_set_disconnected:
844  * @device: device structure
845  * @disconnected: disconnected state
846  *
847  * Change disconnected state of device (only for device with networks)
848  */
849 int connman_device_set_disconnected(struct connman_device *device,
850                                                 connman_bool_t disconnected)
851 {
852         DBG("device %p disconnected %d", device, disconnected);
853
854         if (device->disconnected == disconnected)
855                 return -EALREADY;
856
857         device->disconnected = disconnected;
858
859         if (disconnected == TRUE)
860         {
861                 force_scan_trigger(device);
862                 device->backoff_interval = SCAN_INITIAL_DELAY;
863         }
864
865         return 0;
866 }
867
868 /**
869  * connman_device_get_disconnected:
870  * @device: device structure
871  *
872  * Get device disconnected state
873  */
874 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
875 {
876         return device->disconnected;
877 }
878
879 /**
880  * connman_device_set_string:
881  * @device: device structure
882  * @key: unique identifier
883  * @value: string value
884  *
885  * Set string value for specific key
886  */
887 int connman_device_set_string(struct connman_device *device,
888                                         const char *key, const char *value)
889 {
890         DBG("device %p key %s value %s", device, key, value);
891
892         if (g_str_equal(key, "Address") == TRUE) {
893                 g_free(device->address);
894                 device->address = g_strdup(value);
895         } else if (g_str_equal(key, "Name") == TRUE) {
896                 g_free(device->name);
897                 device->name = g_strdup(value);
898         } else if (g_str_equal(key, "Node") == TRUE) {
899                 g_free(device->node);
900                 device->node = g_strdup(value);
901         } else if (g_str_equal(key, "Path") == TRUE) {
902                 g_free(device->path);
903                 device->path = g_strdup(value);
904         } else {
905                 return -EINVAL;
906         }
907
908         return 0;
909 }
910
911 /**
912  * connman_device_get_string:
913  * @device: device structure
914  * @key: unique identifier
915  *
916  * Get string value for specific key
917  */
918 const char *connman_device_get_string(struct connman_device *device,
919                                                         const char *key)
920 {
921         DBG("device %p key %s", device, key);
922
923         if (g_str_equal(key, "Address") == TRUE)
924                 return device->address;
925         else if (g_str_equal(key, "Name") == TRUE)
926                 return device->name;
927         else if (g_str_equal(key, "Node") == TRUE)
928                 return device->node;
929         else if (g_str_equal(key, "Interface") == TRUE)
930                 return device->interface;
931         else if (g_str_equal(key, "Path") == TRUE)
932                 return device->path;
933
934         return NULL;
935 }
936
937 /**
938  * connman_device_add_network:
939  * @device: device structure
940  * @network: network structure
941  *
942  * Add new network to the device
943  */
944 int connman_device_add_network(struct connman_device *device,
945                                         struct connman_network *network)
946 {
947         const char *identifier = connman_network_get_identifier(network);
948
949         DBG("device %p network %p", device, network);
950
951         if (identifier == NULL)
952                 return -EINVAL;
953
954         connman_network_ref(network);
955
956         __connman_network_set_device(network, device);
957
958         g_hash_table_insert(device->networks, g_strdup(identifier),
959                                                                 network);
960
961         return 0;
962 }
963
964 /**
965  * connman_device_get_network:
966  * @device: device structure
967  * @identifier: network identifier
968  *
969  * Get network for given identifier
970  */
971 struct connman_network *connman_device_get_network(struct connman_device *device,
972                                                         const char *identifier)
973 {
974         DBG("device %p identifier %s", device, identifier);
975
976         return g_hash_table_lookup(device->networks, identifier);
977 }
978
979 /**
980  * connman_device_remove_network:
981  * @device: device structure
982  * @identifier: network identifier
983  *
984  * Remove network for given identifier
985  */
986 int connman_device_remove_network(struct connman_device *device,
987                                                 struct connman_network *network)
988 {
989         const char *identifier;
990
991         DBG("device %p network %p", device, network);
992
993         if (network == NULL)
994                 return 0;
995
996         identifier = connman_network_get_identifier(network);
997         g_hash_table_remove(device->networks, identifier);
998
999         return 0;
1000 }
1001
1002 void connman_device_remove_all_networks(struct connman_device *device)
1003 {
1004         g_hash_table_remove_all(device->networks);
1005 }
1006
1007 void __connman_device_set_network(struct connman_device *device,
1008                                         struct connman_network *network)
1009 {
1010         const char *name;
1011
1012         if (device == NULL)
1013                 return;
1014
1015         if (device->network == network)
1016                 return;
1017
1018         if (network != NULL) {
1019                 name = connman_network_get_string(network, "Name");
1020                 g_free(device->last_network);
1021                 device->last_network = g_strdup(name);
1022
1023                 device->network = network;
1024         } else {
1025                 g_free(device->last_network);
1026                 device->last_network = NULL;
1027
1028                 device->network = NULL;
1029         }
1030 }
1031
1032 void __connman_device_set_reconnect(struct connman_device *device,
1033                                                 connman_bool_t reconnect)
1034 {
1035         device->reconnect = reconnect;
1036 }
1037
1038 connman_bool_t  __connman_device_get_reconnect(
1039                                 struct connman_device *device)
1040 {
1041         return device->reconnect;
1042 }
1043
1044 static gboolean match_driver(struct connman_device *device,
1045                                         struct connman_device_driver *driver)
1046 {
1047         if (device->type == driver->type ||
1048                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1049                 return TRUE;
1050
1051         return FALSE;
1052 }
1053
1054 /**
1055  * connman_device_register:
1056  * @device: device structure
1057  *
1058  * Register device with the system
1059  */
1060 int connman_device_register(struct connman_device *device)
1061 {
1062         GSList *list;
1063
1064         DBG("device %p name %s", device, device->name);
1065
1066         if (device->driver != NULL)
1067                 return -EALREADY;
1068
1069         for (list = driver_list; list; list = list->next) {
1070                 struct connman_device_driver *driver = list->data;
1071
1072                 if (match_driver(device, driver) == FALSE)
1073                         continue;
1074
1075                 DBG("driver %p name %s", driver, driver->name);
1076
1077                 if (driver->probe(device) == 0) {
1078                         device->driver = driver;
1079                         break;
1080                 }
1081         }
1082
1083         if (device->driver == NULL)
1084                 return 0;
1085
1086         return __connman_technology_add_device(device);
1087 }
1088
1089 /**
1090  * connman_device_unregister:
1091  * @device: device structure
1092  *
1093  * Unregister device with the system
1094  */
1095 void connman_device_unregister(struct connman_device *device)
1096 {
1097         DBG("device %p name %s", device, device->name);
1098
1099         if (device->driver == NULL)
1100                 return;
1101
1102         remove_device(device);
1103 }
1104
1105 /**
1106  * connman_device_get_data:
1107  * @device: device structure
1108  *
1109  * Get private device data pointer
1110  */
1111 void *connman_device_get_data(struct connman_device *device)
1112 {
1113         return device->driver_data;
1114 }
1115
1116 /**
1117  * connman_device_set_data:
1118  * @device: device structure
1119  * @data: data pointer
1120  *
1121  * Set private device data pointer
1122  */
1123 void connman_device_set_data(struct connman_device *device, void *data)
1124 {
1125         device->driver_data = data;
1126 }
1127
1128 struct connman_device *__connman_device_find_device(
1129                                 enum connman_service_type type)
1130 {
1131         GSList *list;
1132
1133         for (list = device_list; list != NULL; list = list->next) {
1134                 struct connman_device *device = list->data;
1135                 enum connman_service_type service_type =
1136                         __connman_device_get_service_type(device);
1137
1138                 if (service_type != type)
1139                         continue;
1140
1141                 return device;
1142         }
1143
1144         return NULL;
1145 }
1146
1147 int __connman_device_request_scan(enum connman_service_type type)
1148 {
1149         GSList *list;
1150         int err;
1151
1152         switch (type) {
1153         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1154         case CONNMAN_SERVICE_TYPE_SYSTEM:
1155         case CONNMAN_SERVICE_TYPE_ETHERNET:
1156         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1157         case CONNMAN_SERVICE_TYPE_CELLULAR:
1158         case CONNMAN_SERVICE_TYPE_GPS:
1159         case CONNMAN_SERVICE_TYPE_VPN:
1160         case CONNMAN_SERVICE_TYPE_GADGET:
1161                 return 0;
1162         case CONNMAN_SERVICE_TYPE_WIFI:
1163         case CONNMAN_SERVICE_TYPE_WIMAX:
1164                 break;
1165         }
1166
1167         for (list = device_list; list != NULL; list = list->next) {
1168                 struct connman_device *device = list->data;
1169                 enum connman_service_type service_type =
1170                         __connman_device_get_service_type(device);
1171
1172                 if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
1173                                 service_type != type) {
1174                         continue;
1175                 }
1176
1177                 err = device_scan(device);
1178                 if (err < 0 && err != -EINPROGRESS) {
1179                         DBG("err %d", err);
1180                         /* XXX maybe only a continue? */
1181                         return err;
1182                 }
1183         }
1184
1185         return 0;
1186 }
1187
1188 int __connman_device_request_hidden_scan(struct connman_device *device,
1189                                 const char *ssid, unsigned int ssid_len,
1190                                 const char *identity, const char *passphrase)
1191 {
1192         DBG("device %p", device);
1193
1194         if (device == NULL || device->driver == NULL ||
1195                         device->driver->scan_hidden == NULL)
1196                 return -EINVAL;
1197
1198         if (device->scanning == TRUE)
1199                 return -EALREADY;
1200
1201         return device->driver->scan_hidden(device, ssid, ssid_len,
1202                                         identity, passphrase);
1203 }
1204
1205 connman_bool_t __connman_device_isfiltered(const char *devname)
1206 {
1207         char **pattern;
1208
1209         if (device_filter == NULL)
1210                 goto nodevice;
1211
1212         for (pattern = device_filter; *pattern; pattern++) {
1213                 if (g_pattern_match_simple(*pattern, devname) == FALSE) {
1214                         DBG("ignoring device %s (match)", devname);
1215                         return TRUE;
1216                 }
1217         }
1218
1219 nodevice:
1220         if (g_pattern_match_simple("dummy*", devname) == TRUE) {
1221                 DBG("ignoring dummy networking devices");
1222                 return TRUE;
1223         }
1224
1225         if (nodevice_filter == NULL)
1226                 return FALSE;
1227
1228         for (pattern = nodevice_filter; *pattern; pattern++) {
1229                 if (g_pattern_match_simple(*pattern, devname) == TRUE) {
1230                         DBG("ignoring device %s (no match)", devname);
1231                         return TRUE;
1232                 }
1233         }
1234
1235         return FALSE;
1236 }
1237
1238 int __connman_device_init(const char *device, const char *nodevice)
1239 {
1240         DBG("");
1241
1242         if (device != NULL)
1243                 device_filter = g_strsplit(device, ",", -1);
1244
1245         if (nodevice != NULL)
1246                 nodevice_filter = g_strsplit(nodevice, ",", -1);
1247
1248         return 0;
1249 }
1250
1251 void __connman_device_cleanup(void)
1252 {
1253         DBG("");
1254
1255         g_strfreev(nodevice_filter);
1256         g_strfreev(device_filter);
1257 }