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