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