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