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