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