Remove old property system
[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         __connman_element_initialize(&device->element);
714
715         device->element.name = g_strdup(node);
716         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
717
718         device->element.device = device;
719         device->element.destruct = device_destruct;
720
721         str = type2string(type);
722         if (str != NULL)
723                 connman_element_add_static_property(&device->element,
724                                         "Type", DBUS_TYPE_STRING, &str);
725
726         device->type   = type;
727         device->mode   = CONNMAN_DEVICE_MODE_UNKNOWN;
728         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
729
730         switch (type) {
731         case CONNMAN_DEVICE_TYPE_UNKNOWN:
732         case CONNMAN_DEVICE_TYPE_VENDOR:
733                 device->priority = 0;
734                 break;
735         case CONNMAN_DEVICE_TYPE_ETHERNET:
736         case CONNMAN_DEVICE_TYPE_WIFI:
737                 device->priority = 100;
738                 break;
739         case CONNMAN_DEVICE_TYPE_WIMAX:
740                 device->priority = 20;
741                 break;
742         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
743                 device->priority = 50;
744                 break;
745         case CONNMAN_DEVICE_TYPE_HSO:
746         case CONNMAN_DEVICE_TYPE_NOZOMI:
747         case CONNMAN_DEVICE_TYPE_HUAWEI:
748         case CONNMAN_DEVICE_TYPE_NOVATEL:
749                 device->priority = 60;
750                 break;
751         }
752
753         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
754                                                 g_free, unregister_network);
755
756         return device;
757 }
758
759 /**
760  * connman_device_ref:
761  * @device: device structure
762  *
763  * Increase reference counter of device
764  */
765 struct connman_device *connman_device_ref(struct connman_device *device)
766 {
767         if (connman_element_ref(&device->element) == NULL)
768                 return NULL;
769
770         return device;
771 }
772
773 /**
774  * connman_device_unref:
775  * @device: device structure
776  *
777  * Decrease reference counter of device
778  */
779 void connman_device_unref(struct connman_device *device)
780 {
781         connman_element_unref(&device->element);
782 }
783
784 /**
785  * connman_device_get_name:
786  * @device: device structure
787  *
788  * Get unique name of device
789  */
790 const char *connman_device_get_name(struct connman_device *device)
791 {
792         return device->element.name;
793 }
794
795 /**
796  * connman_device_get_path:
797  * @device: device structure
798  *
799  * Get path name of device
800  */
801 const char *connman_device_get_path(struct connman_device *device)
802 {
803         return device->element.path;
804 }
805
806 /**
807  * connman_device_set_index:
808  * @device: device structure
809  * @index: index number
810  *
811  * Set index number of device
812  */
813 void connman_device_set_index(struct connman_device *device, int index)
814 {
815         device->element.index = index;
816 }
817
818 /**
819  * connman_device_get_index:
820  * @device: device structure
821  *
822  * Get index number of device
823  */
824 int connman_device_get_index(struct connman_device *device)
825 {
826         return device->element.index;
827 }
828
829 /**
830  * connman_device_set_interface:
831  * @device: device structure
832  * @interface: interface name
833  *
834  * Set interface name of device
835  */
836 void connman_device_set_interface(struct connman_device *device,
837                                                         const char *interface)
838 {
839         g_free(device->element.devname);
840         device->element.devname = g_strdup(interface);
841
842         g_free(device->interface);
843         device->interface = g_strdup(interface);
844 }
845
846 /**
847  * connman_device_get_interface:
848  * @device: device structure
849  *
850  * Get interface name of device
851  */
852 const char *connman_device_get_interface(struct connman_device *device)
853 {
854         return device->interface;
855 }
856
857 /**
858  * connman_device_set_policy:
859  * @device: device structure
860  * @policy: power and connection policy
861  *
862  * Change power and connection policy of device
863  */
864 void connman_device_set_policy(struct connman_device *device,
865                                         enum connman_device_policy policy)
866 {
867         device->policy = policy;
868 }
869
870 /**
871  * connman_device_set_mode:
872  * @device: device structure
873  * @mode: network mode
874  *
875  * Change network mode of device
876  */
877 void connman_device_set_mode(struct connman_device *device,
878                                                 enum connman_device_mode mode)
879 {
880         device->mode = mode;
881 }
882
883 /**
884  * connman_device_set_powered:
885  * @device: device structure
886  * @powered: powered state
887  *
888  * Change power state of device
889  */
890 int connman_device_set_powered(struct connman_device *device,
891                                                 connman_bool_t powered)
892 {
893         DBusMessage *signal;
894         DBusMessageIter entry, value;
895         const char *key = "Powered";
896
897         DBG("driver %p powered %d", device, powered);
898
899         if (device->powered == powered)
900                 return -EALREADY;
901
902         device->powered = powered;
903
904         signal = dbus_message_new_signal(device->element.path,
905                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
906         if (signal == NULL)
907                 return 0;
908
909         dbus_message_iter_init_append(signal, &entry);
910
911         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
912
913         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
914                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
915         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
916         dbus_message_iter_close_container(&entry, &value);
917
918         g_dbus_send_message(connection, signal);
919
920         if (powered == FALSE)
921                 return 0;
922
923         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
924                 return 0;
925
926         if (device->driver->scan)
927                 device->driver->scan(device);
928
929         return 0;
930 }
931
932 /**
933  * connman_device_set_carrier:
934  * @device: device structure
935  * @carrier: carrier state
936  *
937  * Change carrier state of device (only for device without scanning)
938  */
939 int connman_device_set_carrier(struct connman_device *device,
940                                                 connman_bool_t carrier)
941 {
942         DBG("driver %p carrier %d", device, carrier);
943
944         switch (device->mode) {
945         case CONNMAN_DEVICE_MODE_UNKNOWN:
946         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
947         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
948                 return -EINVAL;
949         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
950                 break;
951         }
952
953         if (device->carrier == carrier)
954                 return -EALREADY;
955
956         device->carrier = carrier;
957
958         if (carrier == TRUE) {
959                 struct connman_element *element;
960
961                 element = connman_element_create(NULL);
962                 if (element != NULL) {
963                         element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
964                         element->index = device->element.index;
965
966                         if (connman_element_register(element,
967                                                         &device->element) < 0)
968                                 connman_element_unref(element);
969                 }
970         } else
971                 connman_element_unregister_children(&device->element);
972
973         return 0;
974 }
975
976 static void connect_known_network(struct connman_device *device)
977 {
978         struct connman_network *network = NULL;
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                 connman_uint8_t old_priority, new_priority;
989                 connman_uint8_t old_strength, new_strength;
990
991                 count++;
992
993                 if (connman_network_get_remember(value) == FALSE)
994                         continue;
995
996                 if (network == NULL) {
997                         network = value;
998                         continue;
999                 }
1000
1001                 old_priority = connman_network_get_uint8(network, "Priority");
1002                 new_priority = connman_network_get_uint8(value, "Priority");
1003
1004                 if (new_priority != old_priority) {
1005                         if (new_priority > old_priority)
1006                                 network = value;
1007                         continue;
1008                 }
1009
1010                 old_strength = connman_network_get_uint8(network, "Strength");
1011                 new_strength = connman_network_get_uint8(value, "Strength");
1012
1013                 if (new_strength > old_strength)
1014                         network = value;
1015         }
1016
1017         if (network != NULL) {
1018                 int err;
1019
1020                 err = connman_network_connect(network);
1021                 if (err == 0 || err == -EINPROGRESS)
1022                         return;
1023         }
1024
1025         if (count > 0)
1026                 return;
1027
1028         if (device->driver && device->driver->scan)
1029                 device->driver->scan(device);
1030 }
1031
1032 static void mark_network_unavailable(gpointer key, gpointer value,
1033                                                         gpointer user_data)
1034 {
1035         struct connman_network *network = value;
1036
1037         if (connman_network_get_remember(network) == TRUE)
1038                 return;
1039
1040         connman_network_set_available(network, FALSE);
1041 }
1042
1043 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1044                                                         gpointer user_data)
1045 {
1046         struct connman_network *network = value;
1047
1048         if (connman_network_get_remember(network) == TRUE)
1049                 return FALSE;
1050
1051         if (connman_network_get_available(network) == TRUE)
1052                 return FALSE;
1053
1054         return TRUE;
1055 }
1056
1057 /**
1058  * connman_device_set_scanning:
1059  * @device: device structure
1060  * @scanning: scanning state
1061  *
1062  * Change scanning state of device
1063  */
1064 int connman_device_set_scanning(struct connman_device *device,
1065                                                 connman_bool_t scanning)
1066 {
1067         DBusMessage *signal;
1068         DBusMessageIter entry, value;
1069         const char *key = "Scanning";
1070
1071         DBG("driver %p scanning %d", device, scanning);
1072
1073         if (!device->driver || !device->driver->scan)
1074                 return -EINVAL;
1075
1076         if (device->scanning == scanning)
1077                 return -EALREADY;
1078
1079         device->scanning = scanning;
1080
1081         signal = dbus_message_new_signal(device->element.path,
1082                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1083         if (signal == NULL)
1084                 return 0;
1085
1086         dbus_message_iter_init_append(signal, &entry);
1087
1088         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1089
1090         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1091                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1092         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1093         dbus_message_iter_close_container(&entry, &value);
1094
1095         g_dbus_send_message(connection, signal);
1096
1097         if (scanning == TRUE) {
1098                 g_hash_table_foreach(device->networks,
1099                                         mark_network_unavailable, NULL);
1100                 return 0;
1101         }
1102
1103         g_hash_table_foreach_remove(device->networks,
1104                                         remove_unavailable_network, NULL);
1105
1106         if (device->connections > 0)
1107                 return 0;
1108
1109         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1110                 return 0;
1111
1112         connect_known_network(device);
1113
1114         return 0;
1115 }
1116
1117 /**
1118  * connman_device_set_string:
1119  * @device: device structure
1120  * @key: unique identifier
1121  * @value: string value
1122  *
1123  * Set string value for specific key
1124  */
1125 int connman_device_set_string(struct connman_device *device,
1126                                         const char *key, const char *value)
1127 {
1128         DBG("device %p key %s value %s", device, key, value);
1129
1130         if (g_str_equal(key, "Name") == TRUE) {
1131                 g_free(device->name);
1132                 device->name = g_strdup(value);
1133         } else if (g_str_equal(key, "Node") == TRUE) {
1134                 g_free(device->node);
1135                 device->node = g_strdup(value);
1136         }
1137
1138         return 0;
1139 }
1140
1141 /**
1142  * connman_device_get_string:
1143  * @device: device structure
1144  * @key: unique identifier
1145  *
1146  * Get string value for specific key
1147  */
1148 const char *connman_device_get_string(struct connman_device *device,
1149                                                         const char *key)
1150 {
1151         DBG("device %p key %s", device, key);
1152
1153         if (g_str_equal(key, "Name") == TRUE)
1154                 return device->name;
1155         else if (g_str_equal(key, "Node") == TRUE)
1156                 return device->node;
1157
1158         return NULL;
1159 }
1160
1161 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1162 {
1163         struct connman_device *device = element->device;
1164         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1165         connman_bool_t powered;
1166
1167         DBG("element %p name %s", element, element->name);
1168
1169         if (device == NULL)
1170                 return;
1171
1172         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1173
1174         if (device->powered == powered)
1175                 return;
1176
1177         set_powered(device, powered);
1178 }
1179
1180 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1181 {
1182         DBG("offlinmode %d", offlinemode);
1183
1184         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1185                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1186
1187         return 0;
1188 }
1189
1190 void __connman_device_increase_connections(struct connman_device *device)
1191 {
1192         device->connections++;
1193 }
1194
1195 void __connman_device_decrease_connections(struct connman_device *device)
1196 {
1197         device->connections--;
1198 }
1199
1200 /**
1201  * connman_device_add_network:
1202  * @device: device structure
1203  * @network: network structure
1204  *
1205  * Add new network to the device
1206  */
1207 int connman_device_add_network(struct connman_device *device,
1208                                         struct connman_network *network)
1209 {
1210         const char *identifier = connman_network_get_identifier(network);
1211         int err;
1212
1213         DBG("device %p network %p", device, network);
1214
1215         switch (device->mode) {
1216         case CONNMAN_DEVICE_MODE_UNKNOWN:
1217         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1218                 return -EINVAL;
1219         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1220         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1221                 break;
1222         }
1223
1224         __connman_network_set_device(network, device);
1225
1226         __connman_storage_load_network(network);
1227
1228         err = connman_element_register((struct connman_element *) network,
1229                                                         &device->element);
1230         if (err < 0) {
1231                 __connman_network_set_device(network, NULL);
1232                 return err;
1233         }
1234
1235         g_hash_table_insert(device->networks, g_strdup(identifier),
1236                                                                 network);
1237
1238         return 0;
1239 }
1240
1241 /**
1242  * connman_device_get_network:
1243  * @device: device structure
1244  * @identifier: network identifier
1245  *
1246  * Get network for given identifier
1247  */
1248 struct connman_network *connman_device_get_network(struct connman_device *device,
1249                                                         const char *identifier)
1250 {
1251         DBG("device %p identifier %s", device, identifier);
1252
1253         return g_hash_table_lookup(device->networks, identifier);
1254 }
1255
1256 /**
1257  * connman_device_remove_network:
1258  * @device: device structure
1259  * @identifier: network identifier
1260  *
1261  * Remove network for given identifier
1262  */
1263 int connman_device_remove_network(struct connman_device *device,
1264                                                         const char *identifier)
1265 {
1266         DBG("device %p identifier %s", device, identifier);
1267
1268         g_hash_table_remove(device->networks, identifier);
1269
1270         return 0;
1271 }
1272
1273 /**
1274  * connman_device_register:
1275  * @device: device structure
1276  *
1277  * Register device with the system
1278  */
1279 int connman_device_register(struct connman_device *device)
1280 {
1281         __connman_storage_load_device(device);
1282
1283         switch (device->mode) {
1284         case CONNMAN_DEVICE_MODE_UNKNOWN:
1285         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1286                 break;
1287         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1288         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1289                 __connman_storage_init_network(device);
1290                 break;
1291         }
1292
1293         return connman_element_register(&device->element, NULL);
1294 }
1295
1296 /**
1297  * connman_device_unregister:
1298  * @device: device structure
1299  *
1300  * Unregister device with the system
1301  */
1302 void connman_device_unregister(struct connman_device *device)
1303 {
1304         __connman_storage_save_device(device);
1305
1306         connman_element_unregister(&device->element);
1307 }
1308
1309 /**
1310  * connman_device_get_data:
1311  * @device: device structure
1312  *
1313  * Get private device data pointer
1314  */
1315 void *connman_device_get_data(struct connman_device *device)
1316 {
1317         return device->driver_data;
1318 }
1319
1320 /**
1321  * connman_device_set_data:
1322  * @device: device structure
1323  * @data: data pointer
1324  *
1325  * Set private device data pointer
1326  */
1327 void connman_device_set_data(struct connman_device *device, void *data)
1328 {
1329         device->driver_data = data;
1330 }
1331
1332 static gboolean match_driver(struct connman_device *device,
1333                                         struct connman_device_driver *driver)
1334 {
1335         if (device->type == driver->type ||
1336                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1337                 return TRUE;
1338
1339         return FALSE;
1340 }
1341
1342 static int device_probe(struct connman_element *element)
1343 {
1344         struct connman_device *device = element->device;
1345         GSList *list;
1346
1347         DBG("element %p name %s", element, element->name);
1348
1349         if (device == NULL)
1350                 return -ENODEV;
1351
1352         if (device->driver != NULL)
1353                 return -EALREADY;
1354
1355         for (list = driver_list; list; list = list->next) {
1356                 struct connman_device_driver *driver = list->data;
1357
1358                 if (match_driver(device, driver) == FALSE)
1359                         continue;
1360
1361                 DBG("driver %p name %s", driver, driver->name);
1362
1363                 if (driver->probe(device) == 0) {
1364                         device->driver = driver;
1365                         break;
1366                 }
1367         }
1368
1369         if (device->driver == NULL)
1370                 return -ENODEV;
1371
1372         return setup_device(device);
1373 }
1374
1375 static void device_remove(struct connman_element *element)
1376 {
1377         struct connman_device *device = element->device;
1378
1379         DBG("element %p name %s", element, element->name);
1380
1381         if (device == NULL)
1382                 return;
1383
1384         if (device->driver == NULL)
1385                 return;
1386
1387         remove_device(device);
1388 }
1389
1390 static struct connman_driver device_driver = {
1391         .name           = "device",
1392         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1393         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1394         .probe          = device_probe,
1395         .remove         = device_remove,
1396 };
1397
1398 static int device_load(struct connman_device *device)
1399 {
1400         GKeyFile *keyfile;
1401         gchar *pathname, *data = NULL;
1402         gsize length;
1403         char *str;
1404         int val;
1405
1406         DBG("device %p", device);
1407
1408         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1409                                                         device->element.name);
1410         if (pathname == NULL)
1411                 return -ENOMEM;
1412
1413         keyfile = g_key_file_new();
1414
1415         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1416                 g_free(pathname);
1417                 return -ENOENT;
1418         }
1419
1420         g_free(pathname);
1421
1422         if (g_key_file_load_from_data(keyfile, data, length,
1423                                                         0, NULL) == FALSE) {
1424                 g_free(data);
1425                 return -EILSEQ;
1426         }
1427
1428         g_free(data);
1429
1430         str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL);
1431         if (str != NULL) {
1432                 device->policy = string2policy(str);
1433                 g_free(str);
1434         }
1435
1436         val = g_key_file_get_integer(keyfile, "Configuration",
1437                                                         "Priority", NULL);
1438         if (val > 0)
1439                 device->priority = val;
1440
1441         g_key_file_free(keyfile);
1442
1443         return 0;
1444 }
1445
1446 static int device_save(struct connman_device *device)
1447 {
1448         GKeyFile *keyfile;
1449         gchar *pathname, *data = NULL;
1450         gsize length;
1451         const char *str;
1452
1453         DBG("device %p", device);
1454
1455         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1456                                                         device->element.name);
1457         if (pathname == NULL)
1458                 return -ENOMEM;
1459
1460         keyfile = g_key_file_new();
1461
1462         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1463                 goto update;
1464
1465         if (length > 0) {
1466                 if (g_key_file_load_from_data(keyfile, data, length,
1467                                                         0, NULL) == FALSE)
1468                         goto done;
1469         }
1470
1471         g_free(data);
1472
1473 update:
1474         str = policy2string(device->policy);
1475         if (str != NULL)
1476                 g_key_file_set_string(keyfile, "Configuration", "Policy", str);
1477
1478         if (device->priority > 0)
1479                 g_key_file_set_integer(keyfile, "Configuration",
1480                                                 "Priority", device->priority);
1481
1482         data = g_key_file_to_data(keyfile, &length, NULL);
1483
1484         g_file_set_contents(pathname, data, length, NULL);
1485
1486 done:
1487         g_free(data);
1488
1489         g_key_file_free(keyfile);
1490
1491         g_free(pathname);
1492
1493         return 0;
1494 }
1495
1496 static struct connman_storage device_storage = {
1497         .name           = "device",
1498         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1499         .device_load    = device_load,
1500         .device_save    = device_save,
1501 };
1502
1503 int __connman_device_init(void)
1504 {
1505         DBG("");
1506
1507         connection = connman_dbus_get_connection();
1508
1509         if (connman_storage_register(&device_storage) < 0)
1510                 connman_error("Failed to register device storage");
1511
1512         return connman_driver_register(&device_driver);
1513 }
1514
1515 void __connman_device_cleanup(void)
1516 {
1517         DBG("");
1518
1519         connman_driver_unregister(&device_driver);
1520
1521         connman_storage_unregister(&device_storage);
1522
1523         dbus_connection_unref(connection);
1524 }