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