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