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