Add function to change initial policy setting
[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_policy:
580  * @device: device structure
581  * @policy: power and connection policy
582  *
583  * Change power and connection policy of device
584  */
585 void connman_device_set_policy(struct connman_device *device,
586                                         enum connman_device_policy policy)
587 {
588         device->policy = policy;
589 }
590
591 /**
592  * connman_device_set_mode:
593  * @device: device structure
594  * @mode: network mode
595  *
596  * Change network mode of device
597  */
598 void connman_device_set_mode(struct connman_device *device,
599                                                 enum connman_device_mode mode)
600 {
601         device->mode = mode;
602 }
603
604 /**
605  * connman_device_set_powered:
606  * @device: device structure
607  * @powered: powered state
608  *
609  * Change power state of device
610  */
611 int connman_device_set_powered(struct connman_device *device,
612                                                         gboolean powered)
613 {
614         DBusMessage *signal;
615         DBusMessageIter entry, value;
616         const char *key = "Powered";
617
618         DBG("driver %p powered %d", device, powered);
619
620         if (device->powered == powered)
621                 return -EALREADY;
622
623         device->powered = powered;
624
625         signal = dbus_message_new_signal(device->element.path,
626                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
627         if (signal == NULL)
628                 return 0;
629
630         dbus_message_iter_init_append(signal, &entry);
631
632         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
633
634         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
635                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
636         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
637         dbus_message_iter_close_container(&entry, &value);
638
639         g_dbus_send_message(connection, signal);
640
641         return 0;
642 }
643
644 /**
645  * connman_device_set_carrier:
646  * @device: device structure
647  * @carrier: carrier state
648  *
649  * Change carrier state of device (only for device without scanning)
650  */
651 int connman_device_set_carrier(struct connman_device *device,
652                                                         gboolean carrier)
653 {
654         DBG("driver %p carrier %d", device, carrier);
655
656         if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK)
657                 return -EINVAL;
658
659         if (device->carrier == carrier)
660                 return -EALREADY;
661
662         device->carrier = carrier;
663
664         if (carrier == TRUE) {
665                 struct connman_element *element;
666
667                 element = connman_element_create(NULL);
668                 if (element != NULL) {
669                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
670                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
671                         element->index   = device->element.index;
672
673                         if (connman_element_register(element,
674                                                         &device->element) < 0)
675                                 connman_element_unref(element);
676                 }
677         } else
678                 connman_element_unregister_children(&device->element);
679
680         return 0;
681 }
682
683 /**
684  * connman_device_set_scanning:
685  * @device: device structure
686  * @scanning: scanning state
687  *
688  * Change scanning state of device
689  */
690 int connman_device_set_scanning(struct connman_device *device,
691                                                         gboolean scanning)
692 {
693         DBusMessage *signal;
694         DBusMessageIter entry, value;
695         const char *key = "Scanning";
696
697         DBG("driver %p scanning %d", device, scanning);
698
699         if (!device->driver || !device->driver->scan)
700                 return -EINVAL;
701
702         if (device->scanning == scanning)
703                 return -EALREADY;
704
705         device->scanning = scanning;
706
707         signal = dbus_message_new_signal(device->element.path,
708                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
709         if (signal == NULL)
710                 return 0;
711
712         dbus_message_iter_init_append(signal, &entry);
713
714         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
715
716         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
717                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
718         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
719         dbus_message_iter_close_container(&entry, &value);
720
721         g_dbus_send_message(connection, signal);
722
723         return 0;
724 }
725
726 /**
727  * connman_device_add_network:
728  * @device: device structure
729  * @network: network structure
730  *
731  * Add new network to the device
732  */
733 int connman_device_add_network(struct connman_device *device,
734                                         struct connman_network *network)
735 {
736         const char *identifier = connman_network_get_identifier(network);
737         int err;
738
739         DBG("device %p network %p", device, network);
740
741         if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK)
742                 return -EINVAL;
743
744         err = connman_element_register((struct connman_element *) network,
745                                                         &device->element);
746         if (err < 0)
747                 return err;
748
749         g_hash_table_insert(device->networks, g_strdup(identifier),
750                                                                 network);
751
752         return 0;
753 }
754
755 /**
756  * connman_device_get_network:
757  * @device: device structure
758  * @identifier: network identifier
759  *
760  * Get network for given identifier
761  */
762 struct connman_network *connman_device_get_network(struct connman_device *device,
763                                                         const char *identifier)
764 {
765         DBG("device %p identifier %s", device, identifier);
766
767         return g_hash_table_lookup(device->networks, identifier);
768 }
769
770 /**
771  * connman_device_remove_network:
772  * @device: device structure
773  * @identifier: network identifier
774  *
775  * Remove network for given identifier
776  */
777 int connman_device_remove_network(struct connman_device *device,
778                                                         const char *identifier)
779 {
780         DBG("device %p identifier %s", device, identifier);
781
782         g_hash_table_remove(device->networks, identifier);
783
784         return 0;
785 }
786
787 /**
788  * connman_device_register:
789  * @device: device structure
790  *
791  * Register device with the system
792  */
793 int connman_device_register(struct connman_device *device)
794 {
795         return connman_element_register(&device->element, NULL);
796 }
797
798 /**
799  * connman_device_unregister:
800  * @device: device structure
801  *
802  * Unregister device with the system
803  */
804 void connman_device_unregister(struct connman_device *device)
805 {
806         connman_element_unregister(&device->element);
807 }
808
809 /**
810  * connman_device_get_data:
811  * @device: device structure
812  *
813  * Get private device data pointer
814  */
815 void *connman_device_get_data(struct connman_device *device)
816 {
817         return device->driver_data;
818 }
819
820 /**
821  * connman_device_set_data:
822  * @device: device structure
823  * @data: data pointer
824  *
825  * Set private device data pointer
826  */
827 void connman_device_set_data(struct connman_device *device, void *data)
828 {
829         device->driver_data = data;
830 }
831
832 static void device_enable(struct connman_device *device)
833 {
834         DBG("device %p", device);
835
836         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
837                 return;
838
839         if (device->powered == TRUE)
840                 return;
841
842         if (device->driver->enable)
843                 device->driver->enable(device);
844 }
845
846 static void device_disable(struct connman_device *device)
847 {
848         DBG("device %p", device);
849
850         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
851                 return;
852
853         if (device->powered == FALSE)
854                 return;
855
856         if (device->driver->disable)
857                 device->driver->disable(device);
858 }
859
860 static gboolean match_driver(struct connman_device *device,
861                                         struct connman_device_driver *driver)
862 {
863         if (device->type == driver->type ||
864                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
865                 return TRUE;
866
867         return FALSE;
868 }
869
870 static int device_probe(struct connman_element *element)
871 {
872         struct connman_device *device = element->device;
873         GSList *list;
874         int err;
875
876         DBG("element %p name %s", element, element->name);
877
878         if (device == NULL)
879                 return -ENODEV;
880
881         for (list = driver_list; list; list = list->next) {
882                 struct connman_device_driver *driver = list->data;
883
884                 if (match_driver(device, driver) == FALSE)
885                         continue;
886
887                 DBG("driver %p name %s", driver, driver->name);
888
889                 if (driver->probe(device) == 0) {
890                         device->driver = driver;
891                         break;
892                 }
893         }
894
895         if (!device->driver)
896                 return -ENODEV;
897
898         err = register_interface(element);
899         if (err < 0) {
900                 if (device->driver->remove)
901                         device->driver->remove(device);
902                 return err;
903         }
904
905         device_enable(device);
906
907         return 0;
908 }
909
910 static void device_remove(struct connman_element *element)
911 {
912         struct connman_device *device = element->device;
913
914         DBG("element %p name %s", element, element->name);
915
916         if (device == NULL)
917                 return;
918
919         if (!device->driver)
920                 return;
921
922         device_disable(device);
923
924         unregister_interface(element);
925
926         if (device->driver->remove)
927                 device->driver->remove(device);
928 }
929
930 static struct connman_driver device_driver = {
931         .name           = "device",
932         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
933         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
934         .probe          = device_probe,
935         .remove         = device_remove,
936 };
937
938 int __connman_device_init(void)
939 {
940         DBG("");
941
942         connection = connman_dbus_get_connection();
943
944         return connman_driver_register(&device_driver);
945 }
946
947 void __connman_device_cleanup(void)
948 {
949         DBG("");
950
951         connman_driver_unregister(&device_driver);
952
953         dbus_connection_unref(connection);
954 }