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