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