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