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