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