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