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