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