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