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