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