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