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