a07726a98b083d70c5f0bf687b07af870851e147
[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 <string.h>
28
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 struct connman_device {
34         struct connman_element element;
35         enum connman_device_type type;
36         enum connman_device_mode mode;
37         enum connman_device_policy policy;
38         connman_bool_t powered;
39         connman_bool_t carrier;
40         connman_bool_t scanning;
41         connman_bool_t disconnected;
42         connman_uint8_t priority;
43         connman_uint16_t scan_interval;
44         char *name;
45         char *node;
46         char *interface;
47         unsigned int connections;
48         guint scan_timeout;
49
50         struct connman_device_driver *driver;
51         void *driver_data;
52
53         connman_bool_t registered;
54
55         char *last_network;
56         struct connman_network *network;
57         GHashTable *networks;
58 };
59
60 static gboolean device_scan_trigger(gpointer user_data)
61 {
62         struct connman_device *device = user_data;
63
64         DBG("device %p", device);
65
66         if (device->driver == NULL) {
67                 device->scan_timeout = 0;
68                 return FALSE;
69         }
70
71         if (device->driver->scan)
72                 device->driver->scan(device);
73
74         return TRUE;
75 }
76
77 static const char *type2description(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 "Wireless";
87         case CONNMAN_DEVICE_TYPE_WIMAX:
88                 return "WiMAX";
89         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
90                 return "Bluetooth";
91         case CONNMAN_DEVICE_TYPE_GPS:
92                 return "GPS";
93         case CONNMAN_DEVICE_TYPE_HSO:
94         case CONNMAN_DEVICE_TYPE_NOZOMI:
95         case CONNMAN_DEVICE_TYPE_HUAWEI:
96         case CONNMAN_DEVICE_TYPE_NOVATEL:
97                 return "Cellular";
98         }
99
100         return NULL;
101 }
102
103 static const char *type2string(enum connman_device_type type)
104 {
105         switch (type) {
106         case CONNMAN_DEVICE_TYPE_UNKNOWN:
107         case CONNMAN_DEVICE_TYPE_VENDOR:
108                 break;
109         case CONNMAN_DEVICE_TYPE_ETHERNET:
110                 return "ethernet";
111         case CONNMAN_DEVICE_TYPE_WIFI:
112                 return "wifi";
113         case CONNMAN_DEVICE_TYPE_WIMAX:
114                 return "wimax";
115         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
116                 return "bluetooth";
117         case CONNMAN_DEVICE_TYPE_GPS:
118                 return "gps";
119         case CONNMAN_DEVICE_TYPE_HSO:
120         case CONNMAN_DEVICE_TYPE_HUAWEI:
121         case CONNMAN_DEVICE_TYPE_NOZOMI:
122         case CONNMAN_DEVICE_TYPE_NOVATEL:
123                 return "cellular";
124         }
125
126         return NULL;
127 }
128
129 static const char *policy2string(enum connman_device_policy policy)
130 {
131         switch (policy) {
132         case CONNMAN_DEVICE_POLICY_UNKNOWN:
133                 break;
134         case CONNMAN_DEVICE_POLICY_IGNORE:
135                 return "ignore";
136         case CONNMAN_DEVICE_POLICY_OFF:
137                 return "off";
138         case CONNMAN_DEVICE_POLICY_AUTO:
139                 return "auto";
140         case CONNMAN_DEVICE_POLICY_MANUAL:
141                 return "manual";
142         }
143
144         return NULL;
145 }
146
147 static enum connman_device_policy string2policy(const char *policy)
148 {
149         if (g_str_equal(policy, "ignore") == TRUE)
150                 return CONNMAN_DEVICE_POLICY_IGNORE;
151         else if (g_str_equal(policy, "off") == TRUE)
152                 return CONNMAN_DEVICE_POLICY_OFF;
153         else if (g_str_equal(policy, "auto") == TRUE)
154                 return CONNMAN_DEVICE_POLICY_AUTO;
155         else if (g_str_equal(policy, "manual") == TRUE)
156                 return CONNMAN_DEVICE_POLICY_MANUAL;
157         else
158                 return CONNMAN_DEVICE_POLICY_UNKNOWN;
159 }
160
161 static int set_powered(struct connman_device *device, connman_bool_t powered)
162 {
163         struct connman_device_driver *driver = device->driver;
164         int err;
165
166         DBG("device %p powered %d", device, powered);
167
168         if (!driver)
169                 return -EINVAL;
170
171         if (powered == TRUE) {
172                 if (driver->enable)
173                         err = driver->enable(device);
174                 else
175                         err = -EINVAL;
176         } else {
177                 g_hash_table_remove_all(device->networks);
178
179                 if (driver->disable)
180                         err = driver->disable(device);
181                 else
182                         err = -EINVAL;
183         }
184
185         return err;
186 }
187
188 static int set_policy(DBusConnection *connection,
189                                 struct connman_device *device,
190                                         enum connman_device_policy policy)
191 {
192         DBusMessage *signal;
193         DBusMessageIter entry, value;
194         const char *str, *key = "Policy";
195         int err = 0;
196
197         DBG("device %p policy %d", device, policy);
198
199         if (device->policy == policy)
200                 return 0;
201
202         switch (policy) {
203         case CONNMAN_DEVICE_POLICY_UNKNOWN:
204                 return -EINVAL;
205         case CONNMAN_DEVICE_POLICY_IGNORE:
206                 break;
207         case CONNMAN_DEVICE_POLICY_OFF:
208                 if (device->powered == TRUE)
209                         err = set_powered(device, FALSE);
210                 break;
211         case CONNMAN_DEVICE_POLICY_AUTO:
212         case CONNMAN_DEVICE_POLICY_MANUAL:
213                 if (device->powered == FALSE)
214                         err = set_powered(device, TRUE);
215                 break;
216         }
217
218         if (err < 0)
219                 return err;
220
221         device->policy = policy;
222
223         signal = dbus_message_new_signal(device->element.path,
224                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
225         if (signal == NULL)
226                 return 0;
227
228         dbus_message_iter_init_append(signal, &entry);
229
230         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
231
232         str = policy2string(policy);
233
234         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
235                                         DBUS_TYPE_STRING_AS_STRING, &value);
236         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
237         dbus_message_iter_close_container(&entry, &value);
238
239         g_dbus_send_message(connection, signal);
240
241         return 0;
242 }
243
244 static void append_path(gpointer key, gpointer value, gpointer user_data)
245 {
246         struct connman_element *element = value;
247         DBusMessageIter *iter = user_data;
248
249         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
250                                                         &element->path);
251 }
252
253 static void append_networks(struct connman_device *device,
254                                                 DBusMessageIter *entry)
255 {
256         DBusMessageIter value, iter;
257         const char *key = "Networks";
258
259         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
260
261         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
262                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
263                                                                 &value);
264
265         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
266                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
267         g_hash_table_foreach(device->networks, append_path, &iter);
268         dbus_message_iter_close_container(&value, &iter);
269
270         dbus_message_iter_close_container(entry, &value);
271 }
272
273 static DBusMessage *get_properties(DBusConnection *conn,
274                                         DBusMessage *msg, void *data)
275 {
276         struct connman_device *device = data;
277         DBusMessage *reply;
278         DBusMessageIter array, dict, entry;
279         const char *str;
280
281         DBG("conn %p", conn);
282
283         if (__connman_security_check_privilege(msg,
284                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
285                 return __connman_error_permission_denied(msg);
286
287         reply = dbus_message_new_method_return(msg);
288         if (reply == NULL)
289                 return NULL;
290
291         dbus_message_iter_init_append(reply, &array);
292
293         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
294                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
295                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
296                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
297
298         str = type2description(device->type);
299         if (str != NULL && device->interface != NULL) {
300                 char *name = g_strdup_printf("%s (%s)", str, device->interface);
301                 if (name != NULL)
302                         connman_dbus_dict_append_variant(&dict, "Name",
303                                                 DBUS_TYPE_STRING, &name);
304                 g_free(name);
305         }
306
307         str = type2string(device->type);
308         if (str != NULL)
309                 connman_dbus_dict_append_variant(&dict, "Type",
310                                                 DBUS_TYPE_STRING, &str);
311
312         if (device->interface != NULL)
313                 connman_dbus_dict_append_variant(&dict, "Interface",
314                                         DBUS_TYPE_STRING, &device->interface);
315
316         str = policy2string(device->policy);
317         if (str != NULL)
318                 connman_dbus_dict_append_variant(&dict, "Policy",
319                                                 DBUS_TYPE_STRING, &str);
320
321         if (device->priority > 0)
322                 connman_dbus_dict_append_variant(&dict, "Priority",
323                                         DBUS_TYPE_BYTE, &device->priority);
324
325         connman_dbus_dict_append_variant(&dict, "Powered",
326                                         DBUS_TYPE_BOOLEAN, &device->powered);
327
328         if (device->driver && device->driver->scan)
329                 connman_dbus_dict_append_variant(&dict, "Scanning",
330                                         DBUS_TYPE_BOOLEAN, &device->scanning);
331
332         switch (device->mode) {
333         case CONNMAN_DEVICE_MODE_UNKNOWN:
334                 break;
335         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
336                 __connman_element_append_ipv4(&device->element, &dict);
337                 break;
338         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
339         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
340                 if (device->scan_interval > 0)
341                         connman_dbus_dict_append_variant(&dict, "ScanInterval",
342                                 DBUS_TYPE_UINT16, &device->scan_interval);
343
344                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
345                                                                 NULL, &entry);
346                 append_networks(device, &entry);
347                 dbus_message_iter_close_container(&dict, &entry);
348                 break;
349         }
350
351         dbus_message_iter_close_container(&array, &dict);
352
353         return reply;
354 }
355
356 static DBusMessage *set_property(DBusConnection *conn,
357                                         DBusMessage *msg, void *data)
358 {
359         struct connman_device *device = data;
360         DBusMessageIter iter, value;
361         const char *name;
362         int type;
363
364         DBG("conn %p", conn);
365
366         if (dbus_message_iter_init(msg, &iter) == FALSE)
367                 return __connman_error_invalid_arguments(msg);
368
369         dbus_message_iter_get_basic(&iter, &name);
370         dbus_message_iter_next(&iter);
371         dbus_message_iter_recurse(&iter, &value);
372
373         if (__connman_security_check_privilege(msg,
374                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
375                 return __connman_error_permission_denied(msg);
376
377         type = dbus_message_iter_get_arg_type(&value);
378
379         if (g_str_equal(name, "Powered") == TRUE) {
380                 connman_bool_t powered;
381                 int err;
382
383                 if (type != DBUS_TYPE_BOOLEAN)
384                         return __connman_error_invalid_arguments(msg);
385
386                 dbus_message_iter_get_basic(&value, &powered);
387
388                 if (device->powered == powered)
389                         return __connman_error_invalid_arguments(msg);
390
391                 err = set_powered(device, powered);
392                 if (err < 0 && err != -EINPROGRESS)
393                         return __connman_error_failed(msg);
394         } else if (g_str_equal(name, "Policy") == TRUE) {
395                 enum connman_device_policy policy;
396                 const char *str;
397                 int err;
398
399                 if (type != DBUS_TYPE_STRING)
400                         return __connman_error_invalid_arguments(msg);
401
402                 dbus_message_iter_get_basic(&value, &str);
403                 policy = string2policy(str);
404                 if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN)
405                         return __connman_error_invalid_arguments(msg);
406
407                 err = set_policy(conn, device, policy);
408                 if (err < 0)
409                         return __connman_error_failed(msg);
410         } else if (g_str_equal(name, "Priority") == TRUE) {
411                 connman_uint8_t priority;
412
413                 if (type != DBUS_TYPE_BYTE)
414                         return __connman_error_invalid_arguments(msg);
415
416                 dbus_message_iter_get_basic(&value, &priority);
417
418                 device->priority = priority;
419         } else if (g_str_equal(name, "ScanInterval") == TRUE) {
420                 connman_uint16_t interval;
421
422                 switch (device->mode) {
423                 case CONNMAN_DEVICE_MODE_UNKNOWN:
424                 case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
425                         return __connman_error_invalid_arguments(msg);
426                 case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
427                 case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
428                         break;
429                 }
430
431                 if (type != DBUS_TYPE_UINT16)
432                         return __connman_error_invalid_arguments(msg);
433
434                 dbus_message_iter_get_basic(&value, &interval);
435
436                 device->scan_interval = interval;
437
438                 if (device->scan_timeout > 0) {
439                         g_source_remove(device->scan_timeout);
440                         device->scan_timeout = 0;
441                 }
442
443                 if (device->scan_interval > 0) {
444                         guint interval = device->scan_interval;
445                         device->scan_timeout = g_timeout_add_seconds(interval,
446                                                 device_scan_trigger, device);
447                 }
448         } else if (g_str_has_prefix(name, "IPv4") == TRUE) {
449                 switch (device->mode) {
450                 case CONNMAN_DEVICE_MODE_UNKNOWN:
451                 case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
452                 case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
453                         return __connman_error_invalid_arguments(msg);
454                 case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
455                         __connman_element_set_ipv4(&device->element,
456                                                                 name, &value);
457                         break;
458                 }
459         }
460
461         __connman_storage_save_device(device);
462
463         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
464 }
465
466 static DBusMessage *create_network(DBusConnection *conn,
467                                         DBusMessage *msg, void *data)
468 {
469         DBG("conn %p", conn);
470
471         if (__connman_security_check_privilege(msg,
472                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
473                 return __connman_error_permission_denied(msg);
474
475         return __connman_error_invalid_arguments(msg);
476 }
477
478 static DBusMessage *remove_network(DBusConnection *conn,
479                                         DBusMessage *msg, void *data)
480 {
481         DBG("conn %p", conn);
482
483         if (__connman_security_check_privilege(msg,
484                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
485                 return __connman_error_permission_denied(msg);
486
487         return __connman_error_invalid_arguments(msg);
488 }
489
490 static DBusMessage *propose_scan(DBusConnection *conn,
491                                         DBusMessage *msg, void *data)
492 {
493         struct connman_device *device = data;
494         int err;
495
496         DBG("conn %p", conn);
497
498         switch (device->mode) {
499         case CONNMAN_DEVICE_MODE_UNKNOWN:
500         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
501                 return __connman_error_not_supported(msg);
502         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
503         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
504                 break;
505         }
506
507         if (!device->driver || !device->driver->scan)
508                 return __connman_error_not_supported(msg);
509
510         if (device->powered == FALSE)
511                 return __connman_error_failed(msg);
512
513         err = device->driver->scan(device);
514         if (err < 0)
515                 return __connman_error_failed(msg);
516
517         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
518 }
519
520 static GDBusMethodTable device_methods[] = {
521         { "GetProperties", "",      "a{sv}", get_properties },
522         { "SetProperty",   "sv",    "",      set_property   },
523         { "CreateNetwork", "a{sv}", "o",     create_network },
524         { "RemoveNetwork", "o",     "",      remove_network },
525         { "ProposeScan",   "",      "",      propose_scan   },
526         { },
527 };
528
529 static GDBusSignalTable device_signals[] = {
530         { "PropertyChanged", "sv" },
531         { },
532 };
533
534 static DBusConnection *connection;
535
536 static void append_devices(DBusMessageIter *entry)
537 {
538         DBusMessageIter value, iter;
539         const char *key = "Devices";
540
541         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
542
543         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
544                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
545                                                                 &value);
546
547         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
548                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
549         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
550         dbus_message_iter_close_container(&value, &iter);
551
552         dbus_message_iter_close_container(entry, &value);
553 }
554
555 static void emit_devices_signal(void)
556 {
557         DBusMessage *signal;
558         DBusMessageIter entry;
559
560         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
561                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
562         if (signal == NULL)
563                 return;
564
565         dbus_message_iter_init_append(signal, &entry);
566
567         append_devices(&entry);
568
569         g_dbus_send_message(connection, signal);
570 }
571
572 static int register_interface(struct connman_element *element)
573 {
574         struct connman_device *device = element->device;
575
576         DBG("element %p name %s", element, element->name);
577
578         if (g_dbus_register_interface(connection, element->path,
579                                         CONNMAN_DEVICE_INTERFACE,
580                                         device_methods, device_signals,
581                                         NULL, device, NULL) == FALSE) {
582                 connman_error("Failed to register %s device", element->path);
583                 return -EIO;
584         }
585
586         device->registered = TRUE;
587
588         emit_devices_signal();
589
590         return 0;
591 }
592
593 static void unregister_interface(struct connman_element *element)
594 {
595         struct connman_device *device = element->device;
596
597         DBG("element %p name %s", element, element->name);
598
599         device->registered = FALSE;
600
601         emit_devices_signal();
602
603         g_dbus_unregister_interface(connection, element->path,
604                                                 CONNMAN_DEVICE_INTERFACE);
605 }
606
607 static void device_enable(struct connman_device *device)
608 {
609         DBG("device %p", device);
610
611         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
612                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
613                 return;
614
615         if (device->powered == TRUE)
616                 return;
617
618         if (device->driver->enable)
619                 device->driver->enable(device);
620 }
621
622 static void device_disable(struct connman_device *device)
623 {
624         DBG("device %p", device);
625
626         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
627                 return;
628
629         if (device->powered == FALSE)
630                 return;
631
632         g_hash_table_remove_all(device->networks);
633
634         if (device->driver->disable)
635                 device->driver->disable(device);
636 }
637
638 static int setup_device(struct connman_device *device)
639 {
640         int err;
641
642         DBG("device %p", device);
643
644         err = register_interface(&device->element);
645         if (err < 0) {
646                 if (device->driver->remove)
647                         device->driver->remove(device);
648                 device->driver = NULL;
649                 return err;
650         }
651
652         switch (device->mode) {
653         case CONNMAN_DEVICE_MODE_UNKNOWN:
654         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
655         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
656                 break;
657         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
658                 __connman_profile_add_device(device);
659                 break;
660         }
661
662         device_enable(device);
663
664         return 0;
665 }
666
667 static void probe_driver(struct connman_element *element, gpointer user_data)
668 {
669         struct connman_device_driver *driver = user_data;
670
671         DBG("element %p name %s", element, element->name);
672
673         if (element->device == NULL)
674                 return;
675
676         if (element->device->driver != NULL)
677                 return;
678
679         if (driver->type != element->device->type)
680                 return;
681
682         if (driver->probe(element->device) < 0)
683                 return;
684
685         element->device->driver = driver;
686
687         setup_device(element->device);
688 }
689
690 static void remove_device(struct connman_device *device)
691 {
692         DBG("device %p", device);
693
694         device_disable(device);
695
696         switch (device->mode) {
697         case CONNMAN_DEVICE_MODE_UNKNOWN:
698         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
699         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
700                 break;
701         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
702                 __connman_profile_remove_device(device);
703                 break;
704         }
705
706         unregister_interface(&device->element);
707
708         if (device->driver->remove)
709                 device->driver->remove(device);
710
711         device->driver = NULL;
712 }
713
714 static void remove_driver(struct connman_element *element, gpointer user_data)
715 {
716         struct connman_device_driver *driver = user_data;
717
718         DBG("element %p name %s", element, element->name);
719
720         if (element->device == NULL)
721                 return;
722
723         if (element->device->driver == driver)
724                 remove_device(element->device);
725 }
726
727 connman_bool_t __connman_device_has_driver(struct connman_device *device)
728 {
729         if (device == NULL || device->driver == NULL)
730                 return FALSE;
731
732         return device->registered;
733 }
734
735 static GSList *driver_list = NULL;
736
737 static gint compare_priority(gconstpointer a, gconstpointer b)
738 {
739         const struct connman_device_driver *driver1 = a;
740         const struct connman_device_driver *driver2 = b;
741
742         return driver2->priority - driver1->priority;
743 }
744
745 /**
746  * connman_device_driver_register:
747  * @driver: device driver definition
748  *
749  * Register a new device driver
750  *
751  * Returns: %0 on success
752  */
753 int connman_device_driver_register(struct connman_device_driver *driver)
754 {
755         DBG("driver %p name %s", driver, driver->name);
756
757         driver_list = g_slist_insert_sorted(driver_list, driver,
758                                                         compare_priority);
759
760         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
761                                                 probe_driver, driver);
762
763         return 0;
764 }
765
766 /**
767  * connman_device_driver_unregister:
768  * @driver: device driver definition
769  *
770  * Remove a previously registered device driver
771  */
772 void connman_device_driver_unregister(struct connman_device_driver *driver)
773 {
774         DBG("driver %p name %s", driver, driver->name);
775
776         driver_list = g_slist_remove(driver_list, driver);
777
778         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
779                                                 remove_driver, driver);
780 }
781
782 static void unregister_network(gpointer data)
783 {
784         struct connman_network *network = data;
785
786         DBG("network %p", network);
787
788         connman_element_unregister((struct connman_element *) network);
789
790         connman_network_unref(network);
791 }
792
793 static void device_destruct(struct connman_element *element)
794 {
795         struct connman_device *device = element->device;
796
797         DBG("element %p name %s", element, element->name);
798
799         g_free(device->node);
800         g_free(device->name);
801         g_free(device->interface);
802
803         g_free(device->last_network);
804
805         g_hash_table_destroy(device->networks);
806         device->networks = NULL;
807 }
808
809 /**
810  * connman_device_create:
811  * @node: device node name (for example an address)
812  * @type: device type
813  *
814  * Allocate a new device of given #type and assign the #node name to it.
815  *
816  * Returns: a newly-allocated #connman_device structure
817  */
818 struct connman_device *connman_device_create(const char *node,
819                                                 enum connman_device_type type)
820 {
821         struct connman_device *device;
822         const char *str;
823
824         DBG("node %s type %d", node, type);
825
826         device = g_try_new0(struct connman_device, 1);
827         if (device == NULL)
828                 return NULL;
829
830         DBG("device %p", device);
831
832         __connman_element_initialize(&device->element);
833
834         device->element.name = g_strdup(node);
835         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
836
837         device->element.device = device;
838         device->element.destruct = device_destruct;
839
840         str = type2string(type);
841         if (str != NULL)
842                 connman_element_set_static_property(&device->element,
843                                         "Type", DBUS_TYPE_STRING, &str);
844
845         device->element.ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
846
847         device->type   = type;
848         device->mode   = CONNMAN_DEVICE_MODE_UNKNOWN;
849         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
850
851         switch (type) {
852         case CONNMAN_DEVICE_TYPE_UNKNOWN:
853         case CONNMAN_DEVICE_TYPE_VENDOR:
854                 device->priority = 0;
855                 device->scan_interval = 0;
856                 break;
857         case CONNMAN_DEVICE_TYPE_ETHERNET:
858         case CONNMAN_DEVICE_TYPE_WIFI:
859                 device->priority = 100;
860                 device->scan_interval = 300;
861                 break;
862         case CONNMAN_DEVICE_TYPE_WIMAX:
863                 device->priority = 20;
864                 device->scan_interval = 0;
865                 break;
866         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
867                 device->priority = 50;
868                 device->scan_interval = 0;
869                 break;
870         case CONNMAN_DEVICE_TYPE_GPS:
871                 device->priority = 0;
872                 device->scan_interval = 0;
873                 break;
874         case CONNMAN_DEVICE_TYPE_HSO:
875         case CONNMAN_DEVICE_TYPE_NOZOMI:
876         case CONNMAN_DEVICE_TYPE_HUAWEI:
877         case CONNMAN_DEVICE_TYPE_NOVATEL:
878                 device->priority = 60;
879                 device->scan_interval = 0;
880                 break;
881         }
882
883         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
884                                                 g_free, unregister_network);
885
886         return device;
887 }
888
889 /**
890  * connman_device_ref:
891  * @device: device structure
892  *
893  * Increase reference counter of device
894  */
895 struct connman_device *connman_device_ref(struct connman_device *device)
896 {
897         if (connman_element_ref(&device->element) == NULL)
898                 return NULL;
899
900         return device;
901 }
902
903 /**
904  * connman_device_unref:
905  * @device: device structure
906  *
907  * Decrease reference counter of device
908  */
909 void connman_device_unref(struct connman_device *device)
910 {
911         connman_element_unref(&device->element);
912 }
913
914 /**
915  * connman_device_get_name:
916  * @device: device structure
917  *
918  * Get unique name of device
919  */
920 const char *connman_device_get_name(struct connman_device *device)
921 {
922         return device->element.name;
923 }
924
925 /**
926  * connman_device_get_path:
927  * @device: device structure
928  *
929  * Get path name of device
930  */
931 const char *connman_device_get_path(struct connman_device *device)
932 {
933         return device->element.path;
934 }
935
936 /**
937  * connman_device_set_index:
938  * @device: device structure
939  * @index: index number
940  *
941  * Set index number of device
942  */
943 void connman_device_set_index(struct connman_device *device, int index)
944 {
945         device->element.index = index;
946 }
947
948 /**
949  * connman_device_get_index:
950  * @device: device structure
951  *
952  * Get index number of device
953  */
954 int connman_device_get_index(struct connman_device *device)
955 {
956         return device->element.index;
957 }
958
959 /**
960  * connman_device_set_interface:
961  * @device: device structure
962  * @interface: interface name
963  *
964  * Set interface name of device
965  */
966 void connman_device_set_interface(struct connman_device *device,
967                                                         const char *interface)
968 {
969         g_free(device->element.devname);
970         device->element.devname = g_strdup(interface);
971
972         g_free(device->interface);
973         device->interface = g_strdup(interface);
974 }
975
976 /**
977  * connman_device_get_interface:
978  * @device: device structure
979  *
980  * Get interface name of device
981  */
982 const char *connman_device_get_interface(struct connman_device *device)
983 {
984         return device->interface;
985 }
986
987 /**
988  * connman_device_set_policy:
989  * @device: device structure
990  * @policy: power and connection policy
991  *
992  * Change power and connection policy of device
993  */
994 void connman_device_set_policy(struct connman_device *device,
995                                         enum connman_device_policy policy)
996 {
997         device->policy = policy;
998 }
999
1000 /**
1001  * connman_device_set_mode:
1002  * @device: device structure
1003  * @mode: network mode
1004  *
1005  * Change network mode of device
1006  */
1007 void connman_device_set_mode(struct connman_device *device,
1008                                                 enum connman_device_mode mode)
1009 {
1010         device->mode = mode;
1011 }
1012
1013 /**
1014  * connman_device_get_mode:
1015  * @device: device structure
1016  *
1017  * Get network mode of device
1018  */
1019 enum connman_device_mode connman_device_get_mode(struct connman_device *device)
1020 {
1021         return device->mode;
1022 }
1023
1024 /**
1025  * connman_device_set_powered:
1026  * @device: device structure
1027  * @powered: powered state
1028  *
1029  * Change power state of device
1030  */
1031 int connman_device_set_powered(struct connman_device *device,
1032                                                 connman_bool_t powered)
1033 {
1034         DBusMessage *signal;
1035         DBusMessageIter entry, value;
1036         const char *key = "Powered";
1037
1038         DBG("driver %p powered %d", device, powered);
1039
1040         if (device->powered == powered)
1041                 return -EALREADY;
1042
1043         device->powered = powered;
1044
1045         if (device->registered == FALSE)
1046                 return 0;
1047
1048         signal = dbus_message_new_signal(device->element.path,
1049                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1050         if (signal == NULL)
1051                 return 0;
1052
1053         dbus_message_iter_init_append(signal, &entry);
1054
1055         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1056
1057         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1058                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1059         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
1060         dbus_message_iter_close_container(&entry, &value);
1061
1062         g_dbus_send_message(connection, signal);
1063
1064         if (powered == FALSE)
1065                 return 0;
1066
1067         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1068                 return 0;
1069
1070         if (device->scan_timeout > 0) {
1071                 g_source_remove(device->scan_timeout);
1072                 device->scan_timeout = 0;
1073         }
1074
1075         if (device->scan_interval > 0) {
1076                 guint interval = device->scan_interval;
1077                 device->scan_timeout = g_timeout_add_seconds(interval,
1078                                         device_scan_trigger, device);
1079         }
1080
1081         if (device->driver->scan)
1082                 device->driver->scan(device);
1083
1084         return 0;
1085 }
1086
1087 /**
1088  * connman_device_set_carrier:
1089  * @device: device structure
1090  * @carrier: carrier state
1091  *
1092  * Change carrier state of device (only for device without scanning)
1093  */
1094 int connman_device_set_carrier(struct connman_device *device,
1095                                                 connman_bool_t carrier)
1096 {
1097         DBG("driver %p carrier %d", device, carrier);
1098
1099         switch (device->mode) {
1100         case CONNMAN_DEVICE_MODE_UNKNOWN:
1101         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1102         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1103                 return -EINVAL;
1104         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1105                 break;
1106         }
1107
1108         if (device->carrier == carrier)
1109                 return -EALREADY;
1110
1111         device->carrier = carrier;
1112
1113         if (carrier == TRUE) {
1114                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
1115                 struct connman_element *element;
1116
1117                 switch (device->element.ipv4.method) {
1118                 case CONNMAN_IPV4_METHOD_UNKNOWN:
1119                 case CONNMAN_IPV4_METHOD_OFF:
1120                         return 0;
1121                 case CONNMAN_IPV4_METHOD_STATIC:
1122                         type = CONNMAN_ELEMENT_TYPE_IPV4;
1123                         break;
1124                 case CONNMAN_IPV4_METHOD_DHCP:
1125                         type = CONNMAN_ELEMENT_TYPE_DHCP;
1126                         break;
1127                 }
1128
1129                 element = connman_element_create(NULL);
1130                 if (element != NULL) {
1131                         element->type  = type;
1132                         element->index = device->element.index;
1133
1134                         if (connman_element_register(element,
1135                                                         &device->element) < 0)
1136                                 connman_element_unref(element);
1137                 }
1138         } else
1139                 connman_element_unregister_children(&device->element);
1140
1141         return 0;
1142 }
1143
1144 void __connman_device_disconnect(struct connman_device *device)
1145 {
1146         GHashTableIter iter;
1147         gpointer key, value;
1148
1149         DBG("device %p", device);
1150
1151         connman_device_set_disconnected(device, TRUE);
1152
1153         g_hash_table_iter_init(&iter, device->networks);
1154
1155         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1156                 struct connman_network *network = value;
1157
1158                 if (connman_network_get_connected(network) == TRUE)
1159                         __connman_network_disconnect(network);
1160         }
1161 }
1162
1163 static void connect_known_network(struct connman_device *device)
1164 {
1165         struct connman_network *network = NULL;
1166         GHashTableIter iter;
1167         gpointer key, value;
1168         unsigned int count = 0;
1169
1170         DBG("device %p", device);
1171
1172         g_hash_table_iter_init(&iter, device->networks);
1173
1174         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1175                 connman_uint8_t old_priority, new_priority;
1176                 connman_uint8_t old_strength, new_strength;
1177                 const char *name;
1178
1179                 count++;
1180
1181                 if (connman_network_get_available(value) == FALSE)
1182                         continue;
1183
1184                 name = connman_network_get_string(value, "Name");
1185                 if (name != NULL && device->last_network != NULL) {
1186                         if (g_str_equal(name, device->last_network) == TRUE) {
1187                                 network = value;
1188                                 break;
1189                         }
1190                 }
1191
1192                 if (connman_network_get_remember(value) == FALSE)
1193                         continue;
1194
1195                 if (network == NULL) {
1196                         network = value;
1197                         continue;
1198                 }
1199
1200                 old_priority = connman_network_get_uint8(network, "Priority");
1201                 new_priority = connman_network_get_uint8(value, "Priority");
1202
1203                 if (new_priority != old_priority) {
1204                         if (new_priority > old_priority)
1205                                 network = value;
1206                         continue;
1207                 }
1208
1209                 old_strength = connman_network_get_uint8(network, "Strength");
1210                 new_strength = connman_network_get_uint8(value, "Strength");
1211
1212                 if (new_strength > old_strength)
1213                         network = value;
1214         }
1215
1216         if (network != NULL) {
1217                 int err;
1218
1219                 err = connman_network_connect(network);
1220                 if (err == 0 || err == -EINPROGRESS)
1221                         return;
1222         }
1223
1224         if (count > 0)
1225                 return;
1226
1227         if (device->driver && device->driver->scan)
1228                 device->driver->scan(device);
1229 }
1230
1231 static void mark_network_unavailable(gpointer key, gpointer value,
1232                                                         gpointer user_data)
1233 {
1234         struct connman_network *network = value;
1235
1236         if (connman_network_get_connected(network) == TRUE)
1237                 return;
1238
1239         connman_network_set_available(network, FALSE);
1240 }
1241
1242 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1243                                                         gpointer user_data)
1244 {
1245         struct connman_network *network = value;
1246
1247         if (connman_network_get_connected(network) == TRUE)
1248                 return FALSE;
1249
1250         if (connman_network_get_remember(network) == TRUE)
1251                 return FALSE;
1252
1253         if (connman_network_get_available(network) == TRUE)
1254                 return FALSE;
1255
1256         return TRUE;
1257 }
1258
1259 /**
1260  * connman_device_set_scanning:
1261  * @device: device structure
1262  * @scanning: scanning state
1263  *
1264  * Change scanning state of device
1265  */
1266 int connman_device_set_scanning(struct connman_device *device,
1267                                                 connman_bool_t scanning)
1268 {
1269         DBusMessage *signal;
1270         DBusMessageIter entry, value;
1271         const char *key = "Scanning";
1272
1273         DBG("driver %p scanning %d", device, scanning);
1274
1275         if (!device->driver || !device->driver->scan)
1276                 return -EINVAL;
1277
1278         if (device->scanning == scanning)
1279                 return -EALREADY;
1280
1281         device->scanning = scanning;
1282
1283         signal = dbus_message_new_signal(device->element.path,
1284                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1285         if (signal == NULL)
1286                 return 0;
1287
1288         dbus_message_iter_init_append(signal, &entry);
1289
1290         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1291
1292         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1293                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1294         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1295         dbus_message_iter_close_container(&entry, &value);
1296
1297         g_dbus_send_message(connection, signal);
1298
1299         if (scanning == TRUE) {
1300                 if (device->scan_timeout > 0) {
1301                         g_source_remove(device->scan_timeout);
1302                         device->scan_timeout = 0;
1303                 }
1304
1305                 if (device->scan_interval > 0) {
1306                         guint interval = device->scan_interval;
1307                         device->scan_timeout = g_timeout_add_seconds(interval,
1308                                                 device_scan_trigger, device);
1309                 }
1310
1311                 g_hash_table_foreach(device->networks,
1312                                         mark_network_unavailable, NULL);
1313                 return 0;
1314         }
1315
1316         g_hash_table_foreach_remove(device->networks,
1317                                         remove_unavailable_network, NULL);
1318
1319         if (device->connections > 0)
1320                 return 0;
1321
1322         if (device->disconnected == TRUE)
1323                 return 0;
1324
1325         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1326                 return 0;
1327
1328         connect_known_network(device);
1329
1330         return 0;
1331 }
1332
1333 /**
1334  * connman_device_set_disconnected:
1335  * @device: device structure
1336  * @disconnected: disconnected state
1337  *
1338  * Change disconnected state of device (only for device with networks)
1339  */
1340 int connman_device_set_disconnected(struct connman_device *device,
1341                                                 connman_bool_t disconnected)
1342 {
1343         DBG("driver %p disconnected %d", device, disconnected);
1344
1345         switch (device->mode) {
1346         case CONNMAN_DEVICE_MODE_UNKNOWN:
1347         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1348                 return -EINVAL;
1349         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1350         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1351                 break;
1352         }
1353
1354         if (device->disconnected == disconnected)
1355                 return -EALREADY;
1356
1357         device->disconnected = disconnected;
1358
1359         return 0;
1360 }
1361
1362 /**
1363  * connman_device_set_string:
1364  * @device: device structure
1365  * @key: unique identifier
1366  * @value: string value
1367  *
1368  * Set string value for specific key
1369  */
1370 int connman_device_set_string(struct connman_device *device,
1371                                         const char *key, const char *value)
1372 {
1373         DBG("device %p key %s value %s", device, key, value);
1374
1375         if (g_str_equal(key, "Name") == TRUE) {
1376                 g_free(device->name);
1377                 device->name = g_strdup(value);
1378         } else if (g_str_equal(key, "Node") == TRUE) {
1379                 g_free(device->node);
1380                 device->node = g_strdup(value);
1381         }
1382
1383         return 0;
1384 }
1385
1386 /**
1387  * connman_device_get_string:
1388  * @device: device structure
1389  * @key: unique identifier
1390  *
1391  * Get string value for specific key
1392  */
1393 const char *connman_device_get_string(struct connman_device *device,
1394                                                         const char *key)
1395 {
1396         DBG("device %p key %s", device, key);
1397
1398         if (g_str_equal(key, "Name") == TRUE)
1399                 return device->name;
1400         else if (g_str_equal(key, "Node") == TRUE)
1401                 return device->node;
1402
1403         return NULL;
1404 }
1405
1406 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1407 {
1408         struct connman_device *device = element->device;
1409         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1410         connman_bool_t powered;
1411
1412         DBG("element %p name %s", element, element->name);
1413
1414         if (device == NULL)
1415                 return;
1416
1417         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1418
1419         if (device->powered == powered)
1420                 return;
1421
1422         set_powered(device, powered);
1423 }
1424
1425 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1426 {
1427         DBG("offlinmode %d", offlinemode);
1428
1429         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1430                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1431
1432         return 0;
1433 }
1434
1435 void __connman_device_increase_connections(struct connman_device *device)
1436 {
1437         device->connections++;
1438 }
1439
1440 void __connman_device_decrease_connections(struct connman_device *device)
1441 {
1442         device->connections--;
1443 }
1444
1445 /**
1446  * connman_device_add_network:
1447  * @device: device structure
1448  * @network: network structure
1449  *
1450  * Add new network to the device
1451  */
1452 int connman_device_add_network(struct connman_device *device,
1453                                         struct connman_network *network)
1454 {
1455         const char *identifier = connman_network_get_identifier(network);
1456         int err;
1457
1458         DBG("device %p network %p", device, network);
1459
1460         switch (device->mode) {
1461         case CONNMAN_DEVICE_MODE_UNKNOWN:
1462         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1463                 return -EINVAL;
1464         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1465         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1466                 break;
1467         }
1468
1469         __connman_network_set_device(network, device);
1470
1471         __connman_storage_load_network(network);
1472
1473         err = connman_element_register((struct connman_element *) network,
1474                                                         &device->element);
1475         if (err < 0) {
1476                 __connman_network_set_device(network, NULL);
1477                 return err;
1478         }
1479
1480         g_hash_table_insert(device->networks, g_strdup(identifier),
1481                                                                 network);
1482
1483         return 0;
1484 }
1485
1486 /**
1487  * connman_device_get_network:
1488  * @device: device structure
1489  * @identifier: network identifier
1490  *
1491  * Get network for given identifier
1492  */
1493 struct connman_network *connman_device_get_network(struct connman_device *device,
1494                                                         const char *identifier)
1495 {
1496         DBG("device %p identifier %s", device, identifier);
1497
1498         return g_hash_table_lookup(device->networks, identifier);
1499 }
1500
1501 /**
1502  * connman_device_remove_network:
1503  * @device: device structure
1504  * @identifier: network identifier
1505  *
1506  * Remove network for given identifier
1507  */
1508 int connman_device_remove_network(struct connman_device *device,
1509                                                         const char *identifier)
1510 {
1511         DBG("device %p identifier %s", device, identifier);
1512
1513         g_hash_table_remove(device->networks, identifier);
1514
1515         return 0;
1516 }
1517
1518 void __connman_device_set_network(struct connman_device *device,
1519                                         struct connman_network *network)
1520 {
1521         const char *name;
1522
1523         if (network != NULL) {
1524                 name = connman_network_get_string(network, "Name");
1525                 device->last_network = g_strdup(name);
1526         }
1527
1528         device->network = network;
1529 }
1530
1531 /**
1532  * connman_device_register:
1533  * @device: device structure
1534  *
1535  * Register device with the system
1536  */
1537 int connman_device_register(struct connman_device *device)
1538 {
1539         __connman_storage_load_device(device);
1540
1541         switch (device->mode) {
1542         case CONNMAN_DEVICE_MODE_UNKNOWN:
1543         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1544                 break;
1545         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1546         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1547                 __connman_storage_init_network(device);
1548                 break;
1549         }
1550
1551         return connman_element_register(&device->element, NULL);
1552 }
1553
1554 /**
1555  * connman_device_unregister:
1556  * @device: device structure
1557  *
1558  * Unregister device with the system
1559  */
1560 void connman_device_unregister(struct connman_device *device)
1561 {
1562         __connman_storage_save_device(device);
1563
1564         connman_element_unregister(&device->element);
1565 }
1566
1567 /**
1568  * connman_device_get_data:
1569  * @device: device structure
1570  *
1571  * Get private device data pointer
1572  */
1573 void *connman_device_get_data(struct connman_device *device)
1574 {
1575         return device->driver_data;
1576 }
1577
1578 /**
1579  * connman_device_set_data:
1580  * @device: device structure
1581  * @data: data pointer
1582  *
1583  * Set private device data pointer
1584  */
1585 void connman_device_set_data(struct connman_device *device, void *data)
1586 {
1587         device->driver_data = data;
1588 }
1589
1590 static gboolean match_driver(struct connman_device *device,
1591                                         struct connman_device_driver *driver)
1592 {
1593         if (device->type == driver->type ||
1594                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1595                 return TRUE;
1596
1597         return FALSE;
1598 }
1599
1600 static int device_probe(struct connman_element *element)
1601 {
1602         struct connman_device *device = element->device;
1603         GSList *list;
1604
1605         DBG("element %p name %s", element, element->name);
1606
1607         if (device == NULL)
1608                 return -ENODEV;
1609
1610         if (device->driver != NULL)
1611                 return -EALREADY;
1612
1613         for (list = driver_list; list; list = list->next) {
1614                 struct connman_device_driver *driver = list->data;
1615
1616                 if (match_driver(device, driver) == FALSE)
1617                         continue;
1618
1619                 DBG("driver %p name %s", driver, driver->name);
1620
1621                 if (driver->probe(device) == 0) {
1622                         device->driver = driver;
1623                         break;
1624                 }
1625         }
1626
1627         if (device->driver == NULL)
1628                 return -ENODEV;
1629
1630         return setup_device(device);
1631 }
1632
1633 static void device_remove(struct connman_element *element)
1634 {
1635         struct connman_device *device = element->device;
1636
1637         DBG("element %p name %s", element, element->name);
1638
1639         if (device == NULL)
1640                 return;
1641
1642         if (device->driver == NULL)
1643                 return;
1644
1645         remove_device(device);
1646 }
1647
1648 static struct connman_driver device_driver = {
1649         .name           = "device",
1650         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1651         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1652         .probe          = device_probe,
1653         .remove         = device_remove,
1654 };
1655
1656 static int device_load(struct connman_device *device)
1657 {
1658         GKeyFile *keyfile;
1659         gchar *pathname, *data = NULL;
1660         gsize length;
1661         char *str;
1662         int val;
1663
1664         DBG("device %p", device);
1665
1666         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1667                                                         device->element.name);
1668         if (pathname == NULL)
1669                 return -ENOMEM;
1670
1671         keyfile = g_key_file_new();
1672
1673         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1674                 g_free(pathname);
1675                 return -ENOENT;
1676         }
1677
1678         g_free(pathname);
1679
1680         if (g_key_file_load_from_data(keyfile, data, length,
1681                                                         0, NULL) == FALSE) {
1682                 g_free(data);
1683                 return -EILSEQ;
1684         }
1685
1686         g_free(data);
1687
1688         str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL);
1689         if (str != NULL) {
1690                 device->policy = string2policy(str);
1691                 g_free(str);
1692         }
1693
1694         val = g_key_file_get_integer(keyfile, "Configuration",
1695                                                         "Priority", NULL);
1696         if (val > 0)
1697                 device->priority = val;
1698
1699         switch (device->mode) {
1700         case CONNMAN_DEVICE_MODE_UNKNOWN:
1701         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1702                 break;
1703         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1704         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1705                 val = g_key_file_get_integer(keyfile, "Configuration",
1706                                                         "ScanInterval", NULL);
1707                 if (val > 0)
1708                         device->scan_interval = val;
1709                 break;
1710         }
1711
1712         str = g_key_file_get_string(keyfile, "Configuration",
1713                                                         "LastNetwork", NULL);
1714         if (str != NULL)
1715                 device->last_network = str;
1716
1717         g_key_file_free(keyfile);
1718
1719         return 0;
1720 }
1721
1722 static int device_save(struct connman_device *device)
1723 {
1724         GKeyFile *keyfile;
1725         gchar *pathname, *data = NULL;
1726         gsize length;
1727         const char *str;
1728
1729         DBG("device %p", device);
1730
1731         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1732                                                         device->element.name);
1733         if (pathname == NULL)
1734                 return -ENOMEM;
1735
1736         keyfile = g_key_file_new();
1737
1738         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1739                 goto update;
1740
1741         if (length > 0) {
1742                 if (g_key_file_load_from_data(keyfile, data, length,
1743                                                         0, NULL) == FALSE)
1744                         goto done;
1745         }
1746
1747         g_free(data);
1748
1749 update:
1750         str = policy2string(device->policy);
1751         if (str != NULL)
1752                 g_key_file_set_string(keyfile, "Configuration", "Policy", str);
1753
1754         if (device->priority > 0)
1755                 g_key_file_set_integer(keyfile, "Configuration",
1756                                                 "Priority", device->priority);
1757
1758         switch (device->mode) {
1759         case CONNMAN_DEVICE_MODE_UNKNOWN:
1760         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1761                 break;
1762         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1763         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1764                 if (device->scan_interval > 0)
1765                         g_key_file_set_integer(keyfile, "Configuration",
1766                                         "ScanInterval", device->scan_interval);
1767                 break;
1768         }
1769
1770         if (device->last_network != NULL)
1771                 g_key_file_set_string(keyfile, "Configuration",
1772                                         "LastNetwork", device->last_network);
1773
1774         data = g_key_file_to_data(keyfile, &length, NULL);
1775
1776         g_file_set_contents(pathname, data, length, NULL);
1777
1778 done:
1779         g_free(data);
1780
1781         g_key_file_free(keyfile);
1782
1783         g_free(pathname);
1784
1785         if (device->network != NULL)
1786                 __connman_storage_save_network(device->network);
1787
1788         return 0;
1789 }
1790
1791 static struct connman_storage device_storage = {
1792         .name           = "device",
1793         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1794         .device_load    = device_load,
1795         .device_save    = device_save,
1796 };
1797
1798 int __connman_device_init(void)
1799 {
1800         DBG("");
1801
1802         connection = connman_dbus_get_connection();
1803
1804         if (connman_storage_register(&device_storage) < 0)
1805                 connman_error("Failed to register device storage");
1806
1807         return connman_driver_register(&device_driver);
1808 }
1809
1810 void __connman_device_cleanup(void)
1811 {
1812         DBG("");
1813
1814         connman_driver_unregister(&device_driver);
1815
1816         connman_storage_unregister(&device_storage);
1817
1818         dbus_connection_unref(connection);
1819 }