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