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