Add support for different security privileges
[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         GHashTableIter iter;
980         gpointer key, value;
981         unsigned int count = 0;
982
983         DBG("device %p", device);
984
985         g_hash_table_iter_init(&iter, device->networks);
986
987         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
988                 struct connman_network *network = value;
989                 int err;
990
991                 count++;
992
993                 if (connman_network_get_remember(network) == FALSE)
994                         continue;
995
996                 err = connman_network_connect(network);
997                 if (err == 0 || err == -EINPROGRESS)
998                         return;
999         }
1000
1001         if (count > 0)
1002                 return;
1003
1004         if (device->driver && device->driver->scan)
1005                 device->driver->scan(device);
1006 }
1007
1008 /**
1009  * connman_device_set_scanning:
1010  * @device: device structure
1011  * @scanning: scanning state
1012  *
1013  * Change scanning state of device
1014  */
1015 int connman_device_set_scanning(struct connman_device *device,
1016                                                 connman_bool_t scanning)
1017 {
1018         DBusMessage *signal;
1019         DBusMessageIter entry, value;
1020         const char *key = "Scanning";
1021
1022         DBG("driver %p scanning %d", device, scanning);
1023
1024         if (!device->driver || !device->driver->scan)
1025                 return -EINVAL;
1026
1027         if (device->scanning == scanning)
1028                 return -EALREADY;
1029
1030         device->scanning = scanning;
1031
1032         signal = dbus_message_new_signal(device->element.path,
1033                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1034         if (signal == NULL)
1035                 return 0;
1036
1037         dbus_message_iter_init_append(signal, &entry);
1038
1039         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1040
1041         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1042                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1043         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1044         dbus_message_iter_close_container(&entry, &value);
1045
1046         g_dbus_send_message(connection, signal);
1047
1048         if (scanning == TRUE)
1049                 return 0;
1050
1051         if (device->connections > 0)
1052                 return 0;
1053
1054         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1055                 return 0;
1056
1057         connect_known_network(device);
1058
1059         return 0;
1060 }
1061
1062 /**
1063  * connman_device_set_string:
1064  * @device: device structure
1065  * @key: unique identifier
1066  * @value: string value
1067  *
1068  * Set string value for specific key
1069  */
1070 int connman_device_set_string(struct connman_device *device,
1071                                         const char *key, const char *value)
1072 {
1073         DBG("device %p key %s value %s", device, key, value);
1074
1075         if (g_str_equal(key, "Name") == TRUE) {
1076                 g_free(device->name);
1077                 device->name = g_strdup(value);
1078         } else if (g_str_equal(key, "Node") == TRUE) {
1079                 g_free(device->node);
1080                 device->node = g_strdup(value);
1081         }
1082
1083         return 0;
1084 }
1085
1086 /**
1087  * connman_device_get_string:
1088  * @device: device structure
1089  * @key: unique identifier
1090  *
1091  * Get string value for specific key
1092  */
1093 const char *connman_device_get_string(struct connman_device *device,
1094                                                         const char *key)
1095 {
1096         DBG("device %p key %s", device, key);
1097
1098         if (g_str_equal(key, "Name") == TRUE)
1099                 return device->name;
1100         else if (g_str_equal(key, "Node") == TRUE)
1101                 return device->node;
1102
1103         return NULL;
1104 }
1105
1106 static void set_flightmode(struct connman_element *element, gpointer user_data)
1107 {
1108         struct connman_device *device = element->device;
1109         connman_bool_t flightmode = GPOINTER_TO_UINT(user_data);
1110         connman_bool_t powered;
1111
1112         DBG("element %p name %s", element, element->name);
1113
1114         if (device == NULL)
1115                 return;
1116
1117         powered = (flightmode == TRUE) ? FALSE : TRUE;
1118
1119         if (device->powered == powered)
1120                 return;
1121
1122         set_powered(device, powered);
1123 }
1124
1125 int __connman_device_set_flightmode(connman_bool_t flightmode)
1126 {
1127         DBG("flightmode %d", flightmode);
1128
1129         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1130                                 set_flightmode, GUINT_TO_POINTER(flightmode));
1131
1132         return 0;
1133 }
1134
1135 void __connman_device_increase_connections(struct connman_device *device)
1136 {
1137         device->connections++;
1138 }
1139
1140 void __connman_device_decrease_connections(struct connman_device *device)
1141 {
1142         device->connections--;
1143 }
1144
1145 /**
1146  * connman_device_add_network:
1147  * @device: device structure
1148  * @network: network structure
1149  *
1150  * Add new network to the device
1151  */
1152 int connman_device_add_network(struct connman_device *device,
1153                                         struct connman_network *network)
1154 {
1155         const char *identifier = connman_network_get_identifier(network);
1156         int err;
1157
1158         DBG("device %p network %p", device, network);
1159
1160         switch (device->mode) {
1161         case CONNMAN_DEVICE_MODE_UNKNOWN:
1162         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1163                 return -EINVAL;
1164         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1165         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1166                 break;
1167         }
1168
1169         __connman_network_set_device(network, device);
1170
1171         __connman_storage_load_network(network);
1172
1173         err = connman_element_register((struct connman_element *) network,
1174                                                         &device->element);
1175         if (err < 0) {
1176                 __connman_network_set_device(network, NULL);
1177                 return err;
1178         }
1179
1180         g_hash_table_insert(device->networks, g_strdup(identifier),
1181                                                                 network);
1182
1183         return 0;
1184 }
1185
1186 /**
1187  * connman_device_get_network:
1188  * @device: device structure
1189  * @identifier: network identifier
1190  *
1191  * Get network for given identifier
1192  */
1193 struct connman_network *connman_device_get_network(struct connman_device *device,
1194                                                         const char *identifier)
1195 {
1196         DBG("device %p identifier %s", device, identifier);
1197
1198         return g_hash_table_lookup(device->networks, identifier);
1199 }
1200
1201 /**
1202  * connman_device_remove_network:
1203  * @device: device structure
1204  * @identifier: network identifier
1205  *
1206  * Remove network for given identifier
1207  */
1208 int connman_device_remove_network(struct connman_device *device,
1209                                                         const char *identifier)
1210 {
1211         DBG("device %p identifier %s", device, identifier);
1212
1213         g_hash_table_remove(device->networks, identifier);
1214
1215         return 0;
1216 }
1217
1218 /**
1219  * connman_device_register:
1220  * @device: device structure
1221  *
1222  * Register device with the system
1223  */
1224 int connman_device_register(struct connman_device *device)
1225 {
1226         __connman_storage_load_device(device);
1227
1228         return connman_element_register(&device->element, NULL);
1229 }
1230
1231 /**
1232  * connman_device_unregister:
1233  * @device: device structure
1234  *
1235  * Unregister device with the system
1236  */
1237 void connman_device_unregister(struct connman_device *device)
1238 {
1239         __connman_storage_save_device(device);
1240
1241         connman_element_unregister(&device->element);
1242 }
1243
1244 /**
1245  * connman_device_get_data:
1246  * @device: device structure
1247  *
1248  * Get private device data pointer
1249  */
1250 void *connman_device_get_data(struct connman_device *device)
1251 {
1252         return device->driver_data;
1253 }
1254
1255 /**
1256  * connman_device_set_data:
1257  * @device: device structure
1258  * @data: data pointer
1259  *
1260  * Set private device data pointer
1261  */
1262 void connman_device_set_data(struct connman_device *device, void *data)
1263 {
1264         device->driver_data = data;
1265 }
1266
1267 static gboolean match_driver(struct connman_device *device,
1268                                         struct connman_device_driver *driver)
1269 {
1270         if (device->type == driver->type ||
1271                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1272                 return TRUE;
1273
1274         return FALSE;
1275 }
1276
1277 static int device_probe(struct connman_element *element)
1278 {
1279         struct connman_device *device = element->device;
1280         GSList *list;
1281
1282         DBG("element %p name %s", element, element->name);
1283
1284         if (device == NULL)
1285                 return -ENODEV;
1286
1287         if (device->driver != NULL)
1288                 return -EALREADY;
1289
1290         for (list = driver_list; list; list = list->next) {
1291                 struct connman_device_driver *driver = list->data;
1292
1293                 if (match_driver(device, driver) == FALSE)
1294                         continue;
1295
1296                 DBG("driver %p name %s", driver, driver->name);
1297
1298                 if (driver->probe(device) == 0) {
1299                         device->driver = driver;
1300                         break;
1301                 }
1302         }
1303
1304         if (device->driver == NULL)
1305                 return -ENODEV;
1306
1307         return setup_device(device);
1308 }
1309
1310 static void device_remove(struct connman_element *element)
1311 {
1312         struct connman_device *device = element->device;
1313
1314         DBG("element %p name %s", element, element->name);
1315
1316         if (device == NULL)
1317                 return;
1318
1319         if (device->driver == NULL)
1320                 return;
1321
1322         remove_device(device);
1323 }
1324
1325 static struct connman_driver device_driver = {
1326         .name           = "device",
1327         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1328         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1329         .probe          = device_probe,
1330         .remove         = device_remove,
1331 };
1332
1333 static int device_load(struct connman_device *device)
1334 {
1335         GKeyFile *keyfile;
1336         gchar *pathname, *data = NULL;
1337         gsize length;
1338         char *str;
1339         int val;
1340
1341         DBG("device %p", device);
1342
1343         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1344                                                         device->element.name);
1345         if (pathname == NULL)
1346                 return -ENOMEM;
1347
1348         keyfile = g_key_file_new();
1349
1350         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1351                 g_free(pathname);
1352                 return -ENOENT;
1353         }
1354
1355         g_free(pathname);
1356
1357         if (g_key_file_load_from_data(keyfile, data, length,
1358                                                         0, NULL) == FALSE) {
1359                 g_free(data);
1360                 return -EILSEQ;
1361         }
1362
1363         g_free(data);
1364
1365         str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL);
1366         if (str != NULL) {
1367                 device->policy = string2policy(str);
1368                 g_free(str);
1369         }
1370
1371         val = g_key_file_get_integer(keyfile, "Configuration",
1372                                                         "Priority", NULL);
1373         if (val > 0)
1374                 device->priority = val;
1375
1376         g_key_file_free(keyfile);
1377
1378         return 0;
1379 }
1380
1381 static int device_save(struct connman_device *device)
1382 {
1383         GKeyFile *keyfile;
1384         gchar *pathname, *data = NULL;
1385         gsize length;
1386         const char *str;
1387
1388         DBG("device %p", device);
1389
1390         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1391                                                         device->element.name);
1392         if (pathname == NULL)
1393                 return -ENOMEM;
1394
1395         keyfile = g_key_file_new();
1396
1397         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1398                 goto update;
1399
1400         if (length > 0) {
1401                 if (g_key_file_load_from_data(keyfile, data, length,
1402                                                         0, NULL) == FALSE)
1403                         goto done;
1404         }
1405
1406         g_free(data);
1407
1408 update:
1409         str = policy2string(device->policy);
1410         if (str != NULL)
1411                 g_key_file_set_string(keyfile, "Configuration", "Policy", str);
1412
1413         if (device->priority > 0)
1414                 g_key_file_set_integer(keyfile, "Configuration",
1415                                                 "Priority", device->priority);
1416
1417         data = g_key_file_to_data(keyfile, &length, NULL);
1418
1419         g_file_set_contents(pathname, data, length, NULL);
1420
1421 done:
1422         g_free(data);
1423
1424         g_key_file_free(keyfile);
1425
1426         g_free(pathname);
1427
1428         return 0;
1429 }
1430
1431 static struct connman_storage device_storage = {
1432         .name           = "device",
1433         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1434         .device_load    = device_load,
1435         .device_save    = device_save,
1436 };
1437
1438 int __connman_device_init(void)
1439 {
1440         DBG("");
1441
1442         connection = connman_dbus_get_connection();
1443
1444         if (connman_storage_register(&device_storage) < 0)
1445                 connman_error("Failed to register device storage");
1446
1447         return connman_driver_register(&device_driver);
1448 }
1449
1450 void __connman_device_cleanup(void)
1451 {
1452         DBG("");
1453
1454         connman_driver_unregister(&device_driver);
1455
1456         connman_storage_unregister(&device_storage);
1457
1458         dbus_connection_unref(connection);
1459 }