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