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