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