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