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