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