Fix documentation typos
[connman] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  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 <gdbus.h>
28
29 #include "connman.h"
30
31 struct connman_device {
32         struct connman_element element;
33         enum connman_device_type type;
34         enum connman_device_mode mode;
35         enum connman_device_policy policy;
36         gboolean powered;
37         gboolean carrier;
38         gboolean scanning;
39         char *path;
40         char *interface;
41
42         struct connman_device_driver *driver;
43         void *driver_data;
44
45         GHashTable *networks;
46 };
47
48 static const char *type2description(enum connman_device_type type)
49 {
50         switch (type) {
51         case CONNMAN_DEVICE_TYPE_ETHERNET:
52                 return "Ethernet";
53         case CONNMAN_DEVICE_TYPE_WIFI:
54                 return "Wireless";
55         case CONNMAN_DEVICE_TYPE_WIMAX:
56                 return "WiMAX";
57         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
58                 return "Bluetooth";
59         default:
60                 return NULL;
61         }
62 }
63
64 static const char *type2string(enum connman_device_type type)
65 {
66         switch (type) {
67         case CONNMAN_DEVICE_TYPE_ETHERNET:
68                 return "ethernet";
69         case CONNMAN_DEVICE_TYPE_WIFI:
70                 return "wifi";
71         case CONNMAN_DEVICE_TYPE_WIMAX:
72                 return "wimax";
73         case CONNMAN_DEVICE_TYPE_MODEM:
74                 return "modem";
75         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
76                 return "bluetooth";
77         default:
78                 return NULL;
79         }
80 }
81
82 static const char *policy2string(enum connman_device_policy policy)
83 {
84         switch (policy) {
85         case CONNMAN_DEVICE_POLICY_IGNORE:
86                 return "ignore";
87         case CONNMAN_DEVICE_POLICY_AUTO:
88                 return "auto";
89         case CONNMAN_DEVICE_POLICY_OFF:
90                 return "off";
91         default:
92                 return NULL;
93         }
94 }
95
96 static int set_powered(struct connman_device *device, gboolean powered)
97 {
98         struct connman_device_driver *driver = device->driver;
99         int err;
100
101         DBG("device %p powered %d", device, powered);
102
103         if (!driver)
104                 return -EINVAL;
105
106         if (powered == TRUE) {
107                 if (driver->enable)
108                         err = driver->enable(device);
109                 else
110                         err = -EINVAL;
111         } else {
112                 if (driver->disable)
113                         err = driver->disable(device);
114                 else
115                         err = -EINVAL;
116         }
117
118         return err;
119 }
120
121 static void append_networks(struct connman_device *device,
122                                                 DBusMessageIter *entry)
123 {
124         DBusMessageIter value, iter;
125         const char *key = "Networks";
126
127         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
128
129         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
130                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
131                                                                 &value);
132
133         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
134                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
135         /* FIXME append networks */
136         dbus_message_iter_close_container(&value, &iter);
137
138         dbus_message_iter_close_container(entry, &value);
139 }
140
141 static DBusMessage *get_properties(DBusConnection *conn,
142                                         DBusMessage *msg, void *data)
143 {
144         struct connman_device *device = data;
145         DBusMessage *reply;
146         DBusMessageIter array, dict, entry;
147         const char *str;
148
149         DBG("conn %p", conn);
150
151         reply = dbus_message_new_method_return(msg);
152         if (reply == NULL)
153                 return NULL;
154
155         dbus_message_iter_init_append(reply, &array);
156
157         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
158                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
159                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
160                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
161
162         str = type2description(device->type);
163         if (str != NULL && device->interface != NULL) {
164                 char *name = g_strdup_printf("%s (%s)", str, device->interface);
165                 if (name != NULL)
166                         connman_dbus_dict_append_variant(&dict, "Name",
167                                                 DBUS_TYPE_STRING, &name);
168                 g_free(name);
169         }
170
171         str = type2string(device->type);
172         if (str != NULL)
173                 connman_dbus_dict_append_variant(&dict, "Type",
174                                                 DBUS_TYPE_STRING, &str);
175
176         if (device->interface != NULL)
177                 connman_dbus_dict_append_variant(&dict, "Interface",
178                                         DBUS_TYPE_STRING, &device->interface);
179
180         str = policy2string(device->policy);
181         if (str != NULL)
182                 connman_dbus_dict_append_variant(&dict, "Policy",
183                                                 DBUS_TYPE_STRING, &str);
184
185         connman_dbus_dict_append_variant(&dict, "Powered",
186                                         DBUS_TYPE_BOOLEAN, &device->powered);
187
188         if (device->driver && device->driver->scan)
189                 connman_dbus_dict_append_variant(&dict, "Scanning",
190                                         DBUS_TYPE_BOOLEAN, &device->scanning);
191
192         if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK) {
193                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
194                                                                 NULL, &entry);
195                 append_networks(device, &entry);
196                 dbus_message_iter_close_container(&dict, &entry);
197         }
198
199         dbus_message_iter_close_container(&array, &dict);
200
201         return reply;
202 }
203
204 static DBusMessage *set_property(DBusConnection *conn,
205                                         DBusMessage *msg, void *data)
206 {
207         struct connman_device *device = data;
208         DBusMessageIter iter, value;
209         const char *name;
210
211         DBG("conn %p", conn);
212
213         if (dbus_message_iter_init(msg, &iter) == FALSE)
214                 return __connman_error_invalid_arguments(msg);
215
216         dbus_message_iter_get_basic(&iter, &name);
217         dbus_message_iter_next(&iter);
218         dbus_message_iter_recurse(&iter, &value);
219
220         if (__connman_security_check_privileges(msg) < 0)
221                 return __connman_error_permission_denied(msg);
222
223         if (g_str_equal(name, "Powered") == TRUE) {
224                 gboolean powered;
225                 int err;
226
227                 dbus_message_iter_get_basic(&value, &powered);
228
229                 if (device->powered == powered)
230                         return __connman_error_invalid_arguments(msg);
231
232                 err = set_powered(device, powered);
233                 if (err < 0 && err != -EINPROGRESS)
234                         return __connman_error_failed(msg);
235         }
236
237         __connman_element_store(&device->element);
238
239         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
240 }
241
242 static DBusMessage *create_network(DBusConnection *conn,
243                                         DBusMessage *msg, void *data)
244 {
245         DBG("conn %p", conn);
246
247         if (__connman_security_check_privileges(msg) < 0)
248                 return __connman_error_permission_denied(msg);
249
250         return __connman_error_invalid_arguments(msg);
251 }
252
253 static DBusMessage *remove_network(DBusConnection *conn,
254                                         DBusMessage *msg, void *data)
255 {
256         DBG("conn %p", conn);
257
258         if (__connman_security_check_privileges(msg) < 0)
259                 return __connman_error_permission_denied(msg);
260
261         return __connman_error_invalid_arguments(msg);
262 }
263
264 static DBusMessage *propose_scan(DBusConnection *conn,
265                                         DBusMessage *msg, void *data)
266 {
267         struct connman_device *device = data;
268         int err;
269
270         DBG("conn %p", conn);
271
272         if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK)
273                 return __connman_error_not_supported(msg);
274
275         if (!device->driver || !device->driver->scan)
276                 return __connman_error_not_supported(msg);
277
278         err = device->driver->scan(device);
279         if (err < 0)
280                 return __connman_error_failed(msg);
281
282         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
283 }
284
285 static GDBusMethodTable device_methods[] = {
286         { "GetProperties", "",      "a{sv}", get_properties },
287         { "SetProperty",   "sv",    "",      set_property   },
288         { "CreateNetwork", "a{sv}", "o",     create_network },
289         { "RemoveNetwork", "o",     "",      remove_network },
290         { "ProposeScan",   "",      "",      propose_scan   },
291         { },
292 };
293
294 static GDBusSignalTable device_signals[] = {
295         { "PropertyChanged", "sv" },
296         { },
297 };
298
299 static DBusConnection *connection;
300
301 static int register_interface(struct connman_element *element)
302 {
303         struct connman_device *device = element->device;
304
305         g_dbus_unregister_interface(connection, element->path,
306                                                 CONNMAN_DEVICE_INTERFACE);
307
308         if (g_dbus_register_interface(connection, element->path,
309                                         CONNMAN_DEVICE_INTERFACE,
310                                         device_methods, device_signals,
311                                         NULL, device, NULL) == FALSE) {
312                 connman_error("Failed to register %s device", element->path);
313                 return -EIO;
314         }
315
316         return 0;
317 }
318
319 static void unregister_interface(struct connman_element *element)
320 {
321         g_dbus_unregister_interface(connection, element->path,
322                                                 CONNMAN_DEVICE_INTERFACE);
323 }
324
325 static GSList *driver_list = NULL;
326
327 static gint compare_priority(gconstpointer a, gconstpointer b)
328 {
329         const struct connman_device_driver *driver1 = a;
330         const struct connman_device_driver *driver2 = b;
331
332         return driver2->priority - driver1->priority;
333 }
334
335 /**
336  * connman_device_driver_register:
337  * @driver: device driver definition
338  *
339  * Register a new device driver
340  *
341  * Returns: %0 on success
342  */
343 int connman_device_driver_register(struct connman_device_driver *driver)
344 {
345         DBG("driver %p name %s", driver, driver->name);
346
347         driver_list = g_slist_insert_sorted(driver_list, driver,
348                                                         compare_priority);
349
350         //__connman_driver_rescan(&device_driver);
351
352         return 0;
353 }
354
355 /**
356  * connman_device_driver_unregister:
357  * @driver: device driver definition
358  *
359  * Remove a previously registered device driver
360  */
361 void connman_device_driver_unregister(struct connman_device_driver *driver)
362 {
363         DBG("driver %p name %s", driver, driver->name);
364
365         driver_list = g_slist_remove(driver_list, driver);
366 }
367
368 static void unregister_network(gpointer data)
369 {
370         struct connman_network *network = data;
371
372         DBG("network %p", network);
373
374         connman_element_unregister((struct connman_element *) network);
375
376         connman_network_unref(network);
377 }
378
379 static void device_destruct(struct connman_element *element)
380 {
381         struct connman_device *device = element->device;
382
383         DBG("element %p name %s", element, element->name);
384
385         g_free(device->interface);
386
387         g_hash_table_destroy(device->networks);
388 }
389
390 /**
391  * connman_device_create:
392  * @node: device node name (for example an address)
393  * @type: device type
394  *
395  * Allocate a new device of given #type and assign the #node name to it.
396  *
397  * Returns: a newly-allocated #connman_device structure
398  */
399 struct connman_device *connman_device_create(const char *node,
400                                                 enum connman_device_type type)
401 {
402         struct connman_device *device;
403
404         DBG("node %s type %d", node, type);
405
406         device = g_try_new0(struct connman_device, 1);
407         if (device == NULL)
408                 return NULL;
409
410         DBG("device %p", device);
411
412         device->element.refcount = 1;
413
414         device->element.name = g_strdup(node);
415         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
416         device->element.index = -1;
417
418         device->element.device = device;
419         device->element.destruct = device_destruct;
420
421         device->type = type;
422         device->mode = CONNMAN_DEVICE_MODE_NO_NETWORK;
423         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
424
425         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
426                                                 g_free, unregister_network);
427
428         return device;
429 }
430
431 /**
432  * connman_device_ref:
433  * @device: device structure
434  *
435  * Increase reference counter of device
436  */
437 struct connman_device *connman_device_ref(struct connman_device *device)
438 {
439         if (connman_element_ref(&device->element) == NULL)
440                 return NULL;
441
442         return device;
443 }
444
445 /**
446  * connman_device_unref:
447  * @device: device structure
448  *
449  * Decrease reference counter of device
450  */
451 void connman_device_unref(struct connman_device *device)
452 {
453         connman_element_unref(&device->element);
454 }
455
456 /**
457  * connman_device_set_path:
458  * @device: device structure
459  * @path: path name
460  *
461  * Set path name of device
462  */
463 void connman_device_set_path(struct connman_device *device, const char *path)
464 {
465         g_free(device->element.devpath);
466         device->element.devpath = g_strdup(path);
467
468         g_free(device->path);
469         device->path = g_strdup(path);
470 }
471
472 /**
473  * connman_device_get_path:
474  * @device: device structure
475  *
476  * Get path name of device
477  */
478 const char *connman_device_get_path(struct connman_device *device)
479 {
480         return device->path;
481 }
482
483 /**
484  * connman_device_set_index:
485  * @device: device structure
486  * @index: index number
487  *
488  * Set index number of device
489  */
490 void connman_device_set_index(struct connman_device *device, int index)
491 {
492         device->element.index = index;
493 }
494
495 /**
496  * connman_device_get_index:
497  * @device: device structure
498  *
499  * Get index number of device
500  */
501 int connman_device_get_index(struct connman_device *device)
502 {
503         return device->element.index;
504 }
505
506 /**
507  * connman_device_set_interface:
508  * @device: device structure
509  * @interface: interface name
510  *
511  * Set interface name of device
512  */
513 void connman_device_set_interface(struct connman_device *device,
514                                                         const char *interface)
515 {
516         g_free(device->element.devname);
517         device->element.devname = g_strdup(interface);
518
519         g_free(device->interface);
520         device->interface = g_strdup(interface);
521 }
522
523 /**
524  * connman_device_get_interface:
525  * @device: device structure
526  *
527  * Get interface name of device
528  */
529 const char *connman_device_get_interface(struct connman_device *device)
530 {
531         return device->interface;
532 }
533
534 /**
535  * connman_device_set_mode:
536  * @device: device structure
537  * @mode: network mode
538  *
539  * Change network mode of device
540  */
541 void connman_device_set_mode(struct connman_device *device,
542                                                 enum connman_device_mode mode)
543 {
544         device->mode = mode;
545 }
546
547 /**
548  * connman_device_set_powered:
549  * @device: device structure
550  * @powered: powered state
551  *
552  * Change power state of device
553  */
554 int connman_device_set_powered(struct connman_device *device,
555                                                         gboolean powered)
556 {
557         DBusMessage *signal;
558         DBusMessageIter entry, value;
559         const char *key = "Powered";
560
561         DBG("driver %p powered %d", device, powered);
562
563         if (device->powered == powered)
564                 return -EALREADY;
565
566         device->powered = powered;
567
568         signal = dbus_message_new_signal(device->element.path,
569                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
570         if (signal == NULL)
571                 return 0;
572
573         dbus_message_iter_init_append(signal, &entry);
574
575         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
576
577         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
578                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
579         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
580         dbus_message_iter_close_container(&entry, &value);
581
582         g_dbus_send_message(connection, signal);
583
584         return 0;
585 }
586
587 /**
588  * connman_device_set_carrier:
589  * @device: device structure
590  * @carrier: carrier state
591  *
592  * Change carrier state of device (only for device without scanning)
593  */
594 int connman_device_set_carrier(struct connman_device *device,
595                                                         gboolean carrier)
596 {
597         DBG("driver %p carrier %d", device, carrier);
598
599         if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK)
600                 return -EINVAL;
601
602         if (device->carrier == carrier)
603                 return -EALREADY;
604
605         device->carrier = carrier;
606
607         if (carrier == TRUE) {
608                 struct connman_element *element;
609
610                 element = connman_element_create(NULL);
611                 if (element != NULL) {
612                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
613                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
614                         element->index   = device->element.index;
615
616                         if (connman_element_register(element,
617                                                         &device->element) < 0)
618                                 connman_element_unref(element);
619                 }
620         } else
621                 connman_element_unregister_children(&device->element);
622
623         return 0;
624 }
625
626 /**
627  * connman_device_set_scanning:
628  * @device: device structure
629  * @scanning: scanning state
630  *
631  * Change scanning state of device
632  */
633 int connman_device_set_scanning(struct connman_device *device,
634                                                         gboolean scanning)
635 {
636         DBusMessage *signal;
637         DBusMessageIter entry, value;
638         const char *key = "Scanning";
639
640         DBG("driver %p scanning %d", device, scanning);
641
642         if (!device->driver || !device->driver->scan)
643                 return -EINVAL;
644
645         if (device->scanning == scanning)
646                 return -EALREADY;
647
648         device->scanning = scanning;
649
650         signal = dbus_message_new_signal(device->element.path,
651                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
652         if (signal == NULL)
653                 return 0;
654
655         dbus_message_iter_init_append(signal, &entry);
656
657         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
658
659         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
660                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
661         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
662         dbus_message_iter_close_container(&entry, &value);
663
664         g_dbus_send_message(connection, signal);
665
666         return 0;
667 }
668
669 /**
670  * connman_device_add_network:
671  * @device: device structure
672  * @network: network structure
673  *
674  * Add new network to the device
675  */
676 int connman_device_add_network(struct connman_device *device,
677                                         struct connman_network *network)
678 {
679         const char *identifier = connman_network_get_identifier(network);
680         int err;
681
682         DBG("device %p network %p", device, network);
683
684         if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK)
685                 return -EINVAL;
686
687         err = connman_element_register(&device->element,
688                                         (struct connman_element *) network);
689         if (err < 0)
690                 return err;
691
692         g_hash_table_insert(device->networks, g_strdup(identifier),
693                                                                 network);
694
695         return 0;
696 }
697
698 /**
699  * connman_device_get_network:
700  * @device: device structure
701  * @identifier: network identifier
702  *
703  * Get network for given identifier
704  */
705 struct connman_network *connman_device_get_network(struct connman_device *device,
706                                                         const char *identifier)
707 {
708         DBG("device %p identifier %s", device, identifier);
709
710         return g_hash_table_lookup(device->networks, identifier);
711 }
712
713 /**
714  * connman_device_remove_network:
715  * @device: device structure
716  * @identifier: network identifier
717  *
718  * Remove network for given identifier
719  */
720 int connman_device_remove_network(struct connman_device *device,
721                                                         const char *identifier)
722 {
723         DBG("device %p identifier %s", device, identifier);
724
725         g_hash_table_remove(device->networks, identifier);
726
727         return 0;
728 }
729
730 /**
731  * connman_device_register:
732  * @device: device structure
733  *
734  * Register device with the system
735  */
736 int connman_device_register(struct connman_device *device)
737 {
738         return connman_element_register(&device->element, NULL);
739 }
740
741 /**
742  * connman_device_unregister:
743  * @device: device structure
744  *
745  * Unregister device with the system
746  */
747 void connman_device_unregister(struct connman_device *device)
748 {
749         connman_element_unregister(&device->element);
750 }
751
752 /**
753  * connman_device_get_data:
754  * @device: device structure
755  *
756  * Get private device data pointer
757  */
758 void *connman_device_get_data(struct connman_device *device)
759 {
760         return device->driver_data;
761 }
762
763 /**
764  * connman_device_set_data:
765  * @device: device structure
766  * @data: data pointer
767  *
768  * Set private device data pointer
769  */
770 void connman_device_set_data(struct connman_device *device, void *data)
771 {
772         device->driver_data = data;
773 }
774
775 static void device_enable(struct connman_device *device)
776 {
777         DBG("device %p", device);
778
779         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
780                 return;
781
782         if (device->powered == TRUE)
783                 return;
784
785         if (device->driver->enable)
786                 device->driver->enable(device);
787 }
788
789 static void device_disable(struct connman_device *device)
790 {
791         DBG("device %p", device);
792
793         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
794                 return;
795
796         if (device->powered == FALSE)
797                 return;
798
799         if (device->driver->disable)
800                 device->driver->disable(device);
801 }
802
803 static gboolean match_driver(struct connman_device *device,
804                                         struct connman_device_driver *driver)
805 {
806         if (device->type == driver->type ||
807                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
808                 return TRUE;
809
810         return FALSE;
811 }
812
813 static int device_probe(struct connman_element *element)
814 {
815         struct connman_device *device = element->device;
816         GSList *list;
817         int err;
818
819         DBG("element %p name %s", element, element->name);
820
821         if (device == NULL)
822                 return -ENODEV;
823
824         err = register_interface(element);
825         if (err < 0)
826                 return err;
827
828         for (list = driver_list; list; list = list->next) {
829                 struct connman_device_driver *driver = list->data;
830
831                 if (match_driver(device, driver) == FALSE)
832                         continue;
833
834                 DBG("driver %p name %s", driver, driver->name);
835
836                 if (driver->probe(device) == 0) {
837                         device->driver = driver;
838                         device_enable(device);
839                         break;
840                 }
841         }
842
843         return 0;
844 }
845
846 static void device_remove(struct connman_element *element)
847 {
848         struct connman_device *device = element->device;
849
850         DBG("element %p name %s", element, element->name);
851
852         if (device == NULL)
853                 return;
854
855         unregister_interface(element);
856
857         if (device->driver) {
858                 device_disable(device);
859
860                 if (device->driver->remove)
861                         device->driver->remove(device);
862         }
863 }
864
865 static struct connman_driver device_driver = {
866         .name           = "device",
867         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
868         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
869         .probe          = device_probe,
870         .remove         = device_remove,
871 };
872
873 int __connman_device_init(void)
874 {
875         DBG("");
876
877         connection = connman_dbus_get_connection();
878
879         return connman_driver_register(&device_driver);
880 }
881
882 void __connman_device_cleanup(void)
883 {
884         DBG("");
885
886         connman_driver_unregister(&device_driver);
887
888         dbus_connection_unref(connection);
889 }