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