Set correct subtype for transition period
[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         switch (type) {
542         case CONNMAN_DEVICE_TYPE_ETHERNET:
543                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_ETHERNET;
544                 break;
545         default:
546                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
547                 break;
548         }
549
550         device->element.device = device;
551         device->element.destruct = device_destruct;
552
553         device->type = type;
554         device->mode = CONNMAN_DEVICE_MODE_NO_NETWORK;
555         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
556
557         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
558                                                 g_free, unregister_network);
559
560         return device;
561 }
562
563 /**
564  * connman_device_ref:
565  * @device: device structure
566  *
567  * Increase reference counter of device
568  */
569 struct connman_device *connman_device_ref(struct connman_device *device)
570 {
571         if (connman_element_ref(&device->element) == NULL)
572                 return NULL;
573
574         return device;
575 }
576
577 /**
578  * connman_device_unref:
579  * @device: device structure
580  *
581  * Decrease reference counter of device
582  */
583 void connman_device_unref(struct connman_device *device)
584 {
585         connman_element_unref(&device->element);
586 }
587
588 /**
589  * connman_device_set_path:
590  * @device: device structure
591  * @path: path name
592  *
593  * Set path name of device
594  */
595 void connman_device_set_path(struct connman_device *device, const char *path)
596 {
597         g_free(device->element.devpath);
598         device->element.devpath = g_strdup(path);
599
600         g_free(device->path);
601         device->path = g_strdup(path);
602 }
603
604 /**
605  * connman_device_get_path:
606  * @device: device structure
607  *
608  * Get path name of device
609  */
610 const char *connman_device_get_path(struct connman_device *device)
611 {
612         return device->path;
613 }
614
615 /**
616  * connman_device_set_index:
617  * @device: device structure
618  * @index: index number
619  *
620  * Set index number of device
621  */
622 void connman_device_set_index(struct connman_device *device, int index)
623 {
624         device->element.index = index;
625 }
626
627 /**
628  * connman_device_get_index:
629  * @device: device structure
630  *
631  * Get index number of device
632  */
633 int connman_device_get_index(struct connman_device *device)
634 {
635         return device->element.index;
636 }
637
638 /**
639  * connman_device_set_interface:
640  * @device: device structure
641  * @interface: interface name
642  *
643  * Set interface name of device
644  */
645 void connman_device_set_interface(struct connman_device *device,
646                                                         const char *interface)
647 {
648         g_free(device->element.devname);
649         device->element.devname = g_strdup(interface);
650
651         g_free(device->interface);
652         device->interface = g_strdup(interface);
653 }
654
655 /**
656  * connman_device_get_interface:
657  * @device: device structure
658  *
659  * Get interface name of device
660  */
661 const char *connman_device_get_interface(struct connman_device *device)
662 {
663         return device->interface;
664 }
665
666 /**
667  * connman_device_set_policy:
668  * @device: device structure
669  * @policy: power and connection policy
670  *
671  * Change power and connection policy of device
672  */
673 void connman_device_set_policy(struct connman_device *device,
674                                         enum connman_device_policy policy)
675 {
676         device->policy = policy;
677 }
678
679 /**
680  * connman_device_set_mode:
681  * @device: device structure
682  * @mode: network mode
683  *
684  * Change network mode of device
685  */
686 void connman_device_set_mode(struct connman_device *device,
687                                                 enum connman_device_mode mode)
688 {
689         device->mode = mode;
690 }
691
692 /**
693  * connman_device_set_powered:
694  * @device: device structure
695  * @powered: powered state
696  *
697  * Change power state of device
698  */
699 int connman_device_set_powered(struct connman_device *device,
700                                                         gboolean powered)
701 {
702         DBusMessage *signal;
703         DBusMessageIter entry, value;
704         const char *key = "Powered";
705
706         DBG("driver %p powered %d", device, powered);
707
708         if (device->powered == powered)
709                 return -EALREADY;
710
711         device->powered = powered;
712
713         signal = dbus_message_new_signal(device->element.path,
714                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
715         if (signal == NULL)
716                 return 0;
717
718         dbus_message_iter_init_append(signal, &entry);
719
720         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
721
722         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
723                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
724         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
725         dbus_message_iter_close_container(&entry, &value);
726
727         g_dbus_send_message(connection, signal);
728
729         return 0;
730 }
731
732 /**
733  * connman_device_set_carrier:
734  * @device: device structure
735  * @carrier: carrier state
736  *
737  * Change carrier state of device (only for device without scanning)
738  */
739 int connman_device_set_carrier(struct connman_device *device,
740                                                         gboolean carrier)
741 {
742         DBG("driver %p carrier %d", device, carrier);
743
744         if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK)
745                 return -EINVAL;
746
747         if (device->carrier == carrier)
748                 return -EALREADY;
749
750         device->carrier = carrier;
751
752         if (carrier == TRUE) {
753                 struct connman_element *element;
754
755                 element = connman_element_create(NULL);
756                 if (element != NULL) {
757                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
758                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
759                         element->index   = device->element.index;
760
761                         if (connman_element_register(element,
762                                                         &device->element) < 0)
763                                 connman_element_unref(element);
764                 }
765         } else
766                 connman_element_unregister_children(&device->element);
767
768         return 0;
769 }
770
771 /**
772  * connman_device_set_scanning:
773  * @device: device structure
774  * @scanning: scanning state
775  *
776  * Change scanning state of device
777  */
778 int connman_device_set_scanning(struct connman_device *device,
779                                                         gboolean scanning)
780 {
781         DBusMessage *signal;
782         DBusMessageIter entry, value;
783         const char *key = "Scanning";
784
785         DBG("driver %p scanning %d", device, scanning);
786
787         if (!device->driver || !device->driver->scan)
788                 return -EINVAL;
789
790         if (device->scanning == scanning)
791                 return -EALREADY;
792
793         device->scanning = scanning;
794
795         signal = dbus_message_new_signal(device->element.path,
796                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
797         if (signal == NULL)
798                 return 0;
799
800         dbus_message_iter_init_append(signal, &entry);
801
802         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
803
804         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
805                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
806         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
807         dbus_message_iter_close_container(&entry, &value);
808
809         g_dbus_send_message(connection, signal);
810
811         return 0;
812 }
813
814 /**
815  * connman_device_add_network:
816  * @device: device structure
817  * @network: network structure
818  *
819  * Add new network to the device
820  */
821 int connman_device_add_network(struct connman_device *device,
822                                         struct connman_network *network)
823 {
824         const char *identifier = connman_network_get_identifier(network);
825         int err;
826
827         DBG("device %p network %p", device, network);
828
829         if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK)
830                 return -EINVAL;
831
832         err = connman_element_register((struct connman_element *) network,
833                                                         &device->element);
834         if (err < 0)
835                 return err;
836
837         g_hash_table_insert(device->networks, g_strdup(identifier),
838                                                                 network);
839
840         return 0;
841 }
842
843 /**
844  * connman_device_get_network:
845  * @device: device structure
846  * @identifier: network identifier
847  *
848  * Get network for given identifier
849  */
850 struct connman_network *connman_device_get_network(struct connman_device *device,
851                                                         const char *identifier)
852 {
853         DBG("device %p identifier %s", device, identifier);
854
855         return g_hash_table_lookup(device->networks, identifier);
856 }
857
858 /**
859  * connman_device_remove_network:
860  * @device: device structure
861  * @identifier: network identifier
862  *
863  * Remove network for given identifier
864  */
865 int connman_device_remove_network(struct connman_device *device,
866                                                         const char *identifier)
867 {
868         DBG("device %p identifier %s", device, identifier);
869
870         g_hash_table_remove(device->networks, identifier);
871
872         return 0;
873 }
874
875 /**
876  * connman_device_register:
877  * @device: device structure
878  *
879  * Register device with the system
880  */
881 int connman_device_register(struct connman_device *device)
882 {
883         return connman_element_register(&device->element, NULL);
884 }
885
886 /**
887  * connman_device_unregister:
888  * @device: device structure
889  *
890  * Unregister device with the system
891  */
892 void connman_device_unregister(struct connman_device *device)
893 {
894         connman_element_unregister(&device->element);
895 }
896
897 /**
898  * connman_device_get_data:
899  * @device: device structure
900  *
901  * Get private device data pointer
902  */
903 void *connman_device_get_data(struct connman_device *device)
904 {
905         return device->driver_data;
906 }
907
908 /**
909  * connman_device_set_data:
910  * @device: device structure
911  * @data: data pointer
912  *
913  * Set private device data pointer
914  */
915 void connman_device_set_data(struct connman_device *device, void *data)
916 {
917         device->driver_data = data;
918 }
919
920 static void device_enable(struct connman_device *device)
921 {
922         DBG("device %p", device);
923
924         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
925                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
926                 return;
927
928         if (device->powered == TRUE)
929                 return;
930
931         if (device->driver->enable)
932                 device->driver->enable(device);
933 }
934
935 static void device_disable(struct connman_device *device)
936 {
937         DBG("device %p", device);
938
939         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
940                 return;
941
942         if (device->powered == FALSE)
943                 return;
944
945         if (device->driver->disable)
946                 device->driver->disable(device);
947 }
948
949 static gboolean match_driver(struct connman_device *device,
950                                         struct connman_device_driver *driver)
951 {
952         if (device->type == driver->type ||
953                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
954                 return TRUE;
955
956         return FALSE;
957 }
958
959 static int device_probe(struct connman_element *element)
960 {
961         struct connman_device *device = element->device;
962         GSList *list;
963         int err;
964
965         DBG("element %p name %s", element, element->name);
966
967         if (device == NULL)
968                 return -ENODEV;
969
970         for (list = driver_list; list; list = list->next) {
971                 struct connman_device_driver *driver = list->data;
972
973                 if (match_driver(device, driver) == FALSE)
974                         continue;
975
976                 DBG("driver %p name %s", driver, driver->name);
977
978                 if (driver->probe(device) == 0) {
979                         device->driver = driver;
980                         break;
981                 }
982         }
983
984         if (!device->driver)
985                 return -ENODEV;
986
987         err = register_interface(element);
988         if (err < 0) {
989                 if (device->driver->remove)
990                         device->driver->remove(device);
991                 return err;
992         }
993
994         device_enable(device);
995
996         return 0;
997 }
998
999 static void device_remove(struct connman_element *element)
1000 {
1001         struct connman_device *device = element->device;
1002
1003         DBG("element %p name %s", element, element->name);
1004
1005         if (device == NULL)
1006                 return;
1007
1008         if (!device->driver)
1009                 return;
1010
1011         device_disable(device);
1012
1013         unregister_interface(element);
1014
1015         if (device->driver->remove)
1016                 device->driver->remove(device);
1017 }
1018
1019 static struct connman_driver device_driver = {
1020         .name           = "device",
1021         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1022         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1023         .probe          = device_probe,
1024         .remove         = device_remove,
1025 };
1026
1027 int __connman_device_init(void)
1028 {
1029         DBG("");
1030
1031         connection = connman_dbus_get_connection();
1032
1033         return connman_driver_register(&device_driver);
1034 }
1035
1036 void __connman_device_cleanup(void)
1037 {
1038         DBG("");
1039
1040         connman_driver_unregister(&device_driver);
1041
1042         dbus_connection_unref(connection);
1043 }