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