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