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