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