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