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