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