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