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