Fix broken handling of last network when disconnectiong manually
[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         unsigned int count = 0;
1365
1366         DBG("device %p", device);
1367
1368         g_hash_table_iter_init(&iter, device->networks);
1369
1370         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
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 (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                 err = connman_network_connect(network);
1406                 if (err == 0 || err == -EINPROGRESS)
1407                         return;
1408         }
1409
1410         if (count > 0)
1411                 return;
1412
1413         if (device->driver && device->driver->scan)
1414                 device->driver->scan(device);
1415 }
1416
1417 static void mark_network_unavailable(gpointer key, gpointer value,
1418                                                         gpointer user_data)
1419 {
1420         struct connman_network *network = value;
1421
1422         if (connman_network_get_connected(network) == TRUE)
1423                 return;
1424
1425         connman_network_set_available(network, FALSE);
1426 }
1427
1428 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1429                                                         gpointer user_data)
1430 {
1431         struct connman_network *network = value;
1432
1433         if (connman_network_get_connected(network) == TRUE)
1434                 return FALSE;
1435
1436         if (connman_network_get_available(network) == TRUE)
1437                 return FALSE;
1438
1439         return TRUE;
1440 }
1441
1442 /**
1443  * connman_device_set_scanning:
1444  * @device: device structure
1445  * @scanning: scanning state
1446  *
1447  * Change scanning state of device
1448  */
1449 int connman_device_set_scanning(struct connman_device *device,
1450                                                 connman_bool_t scanning)
1451 {
1452         DBusMessage *signal;
1453         DBusMessageIter entry, value;
1454         const char *key = "Scanning";
1455
1456         DBG("driver %p scanning %d", device, scanning);
1457
1458         if (!device->driver || !device->driver->scan)
1459                 return -EINVAL;
1460
1461         if (device->scanning == scanning)
1462                 return -EALREADY;
1463
1464         device->scanning = scanning;
1465
1466         signal = dbus_message_new_signal(device->element.path,
1467                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1468         if (signal == NULL)
1469                 return 0;
1470
1471         dbus_message_iter_init_append(signal, &entry);
1472
1473         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1474
1475         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1476                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1477         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1478         dbus_message_iter_close_container(&entry, &value);
1479
1480         g_dbus_send_message(connection, signal);
1481
1482         if (scanning == TRUE) {
1483                 if (device->scan_timeout > 0) {
1484                         g_source_remove(device->scan_timeout);
1485                         device->scan_timeout = 0;
1486                 }
1487
1488                 if (device->scan_interval > 0) {
1489                         guint interval = device->scan_interval;
1490                         device->scan_timeout = g_timeout_add_seconds(interval,
1491                                                 device_scan_trigger, device);
1492                 }
1493
1494                 g_hash_table_foreach(device->networks,
1495                                         mark_network_unavailable, NULL);
1496                 return 0;
1497         }
1498
1499         g_hash_table_foreach_remove(device->networks,
1500                                         remove_unavailable_network, NULL);
1501
1502         if (device->connections > 0)
1503                 return 0;
1504
1505         if (device->disconnected == TRUE)
1506                 return 0;
1507
1508         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1509                 return 0;
1510
1511         connect_known_network(device);
1512
1513         return 0;
1514 }
1515
1516 /**
1517  * connman_device_set_disconnected:
1518  * @device: device structure
1519  * @disconnected: disconnected state
1520  *
1521  * Change disconnected state of device (only for device with networks)
1522  */
1523 int connman_device_set_disconnected(struct connman_device *device,
1524                                                 connman_bool_t disconnected)
1525 {
1526         DBG("driver %p disconnected %d", device, disconnected);
1527
1528         switch (device->mode) {
1529         case CONNMAN_DEVICE_MODE_UNKNOWN:
1530         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1531                 return -EINVAL;
1532         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1533         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1534                 break;
1535         }
1536
1537         if (device->disconnected == disconnected)
1538                 return -EALREADY;
1539
1540         device->disconnected = disconnected;
1541
1542         return 0;
1543 }
1544
1545 /**
1546  * connman_device_set_string:
1547  * @device: device structure
1548  * @key: unique identifier
1549  * @value: string value
1550  *
1551  * Set string value for specific key
1552  */
1553 int connman_device_set_string(struct connman_device *device,
1554                                         const char *key, const char *value)
1555 {
1556         DBG("device %p key %s value %s", device, key, value);
1557
1558         if (g_str_equal(key, "Address") == TRUE) {
1559                 g_free(device->address);
1560                 device->address = g_strdup(value);
1561         } else if (g_str_equal(key, "Name") == TRUE) {
1562                 g_free(device->name);
1563                 device->name = g_strdup(value);
1564         } else if (g_str_equal(key, "Node") == TRUE) {
1565                 g_free(device->node);
1566                 device->node = g_strdup(value);
1567         }
1568
1569         return connman_element_set_string(&device->element, key, value);
1570 }
1571
1572 /**
1573  * connman_device_get_string:
1574  * @device: device structure
1575  * @key: unique identifier
1576  *
1577  * Get string value for specific key
1578  */
1579 const char *connman_device_get_string(struct connman_device *device,
1580                                                         const char *key)
1581 {
1582         DBG("device %p key %s", device, key);
1583
1584         if (g_str_equal(key, "Address") == TRUE)
1585                 return device->address;
1586         else if (g_str_equal(key, "Name") == TRUE)
1587                 return device->name;
1588         else if (g_str_equal(key, "Node") == TRUE)
1589                 return device->node;
1590
1591         return connman_element_get_string(&device->element, key);
1592 }
1593
1594 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1595 {
1596         struct connman_device *device = element->device;
1597         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1598         connman_bool_t powered;
1599
1600         DBG("element %p name %s", element, element->name);
1601
1602         if (device == NULL)
1603                 return;
1604
1605         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1606
1607         if (device->powered == powered)
1608                 return;
1609
1610         set_powered(device, powered);
1611 }
1612
1613 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1614 {
1615         DBG("offlinmode %d", offlinemode);
1616
1617         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1618                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1619
1620         __connman_notifier_offline_mode(offlinemode);
1621
1622         return 0;
1623 }
1624
1625 void __connman_device_increase_connections(struct connman_device *device)
1626 {
1627         device->connections++;
1628 }
1629
1630 void __connman_device_decrease_connections(struct connman_device *device)
1631 {
1632         device->connections--;
1633 }
1634
1635 /**
1636  * connman_device_add_network:
1637  * @device: device structure
1638  * @network: network structure
1639  *
1640  * Add new network to the device
1641  */
1642 int connman_device_add_network(struct connman_device *device,
1643                                         struct connman_network *network)
1644 {
1645         const char *identifier = connman_network_get_identifier(network);
1646         int err;
1647
1648         DBG("device %p network %p", device, network);
1649
1650         switch (device->mode) {
1651         case CONNMAN_DEVICE_MODE_UNKNOWN:
1652         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1653                 return -EINVAL;
1654         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1655         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1656                 break;
1657         }
1658
1659         __connman_network_set_device(network, device);
1660
1661         __connman_storage_load_network(network);
1662
1663         err = connman_element_register((struct connman_element *) network,
1664                                                         &device->element);
1665         if (err < 0) {
1666                 __connman_network_set_device(network, NULL);
1667                 return err;
1668         }
1669
1670         g_hash_table_insert(device->networks, g_strdup(identifier),
1671                                                                 network);
1672
1673         return 0;
1674 }
1675
1676 /**
1677  * connman_device_get_network:
1678  * @device: device structure
1679  * @identifier: network identifier
1680  *
1681  * Get network for given identifier
1682  */
1683 struct connman_network *connman_device_get_network(struct connman_device *device,
1684                                                         const char *identifier)
1685 {
1686         DBG("device %p identifier %s", device, identifier);
1687
1688         return g_hash_table_lookup(device->networks, identifier);
1689 }
1690
1691 /**
1692  * connman_device_remove_network:
1693  * @device: device structure
1694  * @identifier: network identifier
1695  *
1696  * Remove network for given identifier
1697  */
1698 int connman_device_remove_network(struct connman_device *device,
1699                                                         const char *identifier)
1700 {
1701         DBG("device %p identifier %s", device, identifier);
1702
1703         g_hash_table_remove(device->networks, identifier);
1704
1705         return 0;
1706 }
1707
1708 void __connman_device_set_network(struct connman_device *device,
1709                                         struct connman_network *network)
1710 {
1711         const char *name;
1712
1713         if (network != NULL) {
1714                 name = connman_network_get_string(network,
1715                                                 CONNMAN_PROPERTY_ID_NAME);
1716                 g_free(device->last_network);
1717                 device->last_network = g_strdup(name);
1718         } else {
1719                 g_free(device->last_network);
1720                 device->last_network = NULL;
1721         }
1722
1723         device->network = network;
1724 }
1725
1726 /**
1727  * connman_device_register:
1728  * @device: device structure
1729  *
1730  * Register device with the system
1731  */
1732 int connman_device_register(struct connman_device *device)
1733 {
1734         __connman_storage_load_device(device);
1735
1736         switch (device->mode) {
1737         case CONNMAN_DEVICE_MODE_UNKNOWN:
1738         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1739                 break;
1740         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1741         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1742                 __connman_storage_init_network(device);
1743                 break;
1744         }
1745
1746         return connman_element_register(&device->element, NULL);
1747 }
1748
1749 /**
1750  * connman_device_unregister:
1751  * @device: device structure
1752  *
1753  * Unregister device with the system
1754  */
1755 void connman_device_unregister(struct connman_device *device)
1756 {
1757         __connman_storage_save_device(device);
1758
1759         connman_element_unregister(&device->element);
1760 }
1761
1762 /**
1763  * connman_device_get_data:
1764  * @device: device structure
1765  *
1766  * Get private device data pointer
1767  */
1768 void *connman_device_get_data(struct connman_device *device)
1769 {
1770         return device->driver_data;
1771 }
1772
1773 /**
1774  * connman_device_set_data:
1775  * @device: device structure
1776  * @data: data pointer
1777  *
1778  * Set private device data pointer
1779  */
1780 void connman_device_set_data(struct connman_device *device, void *data)
1781 {
1782         device->driver_data = data;
1783 }
1784
1785 static gboolean match_driver(struct connman_device *device,
1786                                         struct connman_device_driver *driver)
1787 {
1788         if (device->type == driver->type ||
1789                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1790                 return TRUE;
1791
1792         return FALSE;
1793 }
1794
1795 static int device_probe(struct connman_element *element)
1796 {
1797         struct connman_device *device = element->device;
1798         GSList *list;
1799
1800         DBG("element %p name %s", element, element->name);
1801
1802         if (device == NULL)
1803                 return -ENODEV;
1804
1805         if (device->driver != NULL)
1806                 return -EALREADY;
1807
1808         for (list = driver_list; list; list = list->next) {
1809                 struct connman_device_driver *driver = list->data;
1810
1811                 if (match_driver(device, driver) == FALSE)
1812                         continue;
1813
1814                 DBG("driver %p name %s", driver, driver->name);
1815
1816                 if (driver->probe(device) == 0) {
1817                         device->driver = driver;
1818                         break;
1819                 }
1820         }
1821
1822         if (device->driver == NULL)
1823                 return -ENODEV;
1824
1825         return setup_device(device);
1826 }
1827
1828 static void device_remove(struct connman_element *element)
1829 {
1830         struct connman_device *device = element->device;
1831
1832         DBG("element %p name %s", element, element->name);
1833
1834         if (device == NULL)
1835                 return;
1836
1837         if (device->driver == NULL)
1838                 return;
1839
1840         remove_device(device);
1841 }
1842
1843 static struct connman_driver device_driver = {
1844         .name           = "device",
1845         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1846         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1847         .probe          = device_probe,
1848         .remove         = device_remove,
1849 };
1850
1851 static int device_load(struct connman_device *device)
1852 {
1853         GKeyFile *keyfile;
1854         gchar *pathname, *identifier, *data = NULL;
1855         gsize length;
1856         char *str;
1857         int val;
1858
1859         DBG("device %p", device);
1860
1861         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1862                                         __connman_profile_active_ident());
1863         if (pathname == NULL)
1864                 return -ENOMEM;
1865
1866         keyfile = g_key_file_new();
1867
1868         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1869                 g_free(pathname);
1870                 return -ENOENT;
1871         }
1872
1873         g_free(pathname);
1874
1875         if (g_key_file_load_from_data(keyfile, data, length,
1876                                                         0, NULL) == FALSE) {
1877                 g_free(data);
1878                 return -EILSEQ;
1879         }
1880
1881         g_free(data);
1882
1883         identifier = g_strdup_printf("device_%s", device->element.name);
1884         if (identifier == NULL)
1885                 goto done;
1886
1887         str = g_key_file_get_string(keyfile, identifier, "Policy", NULL);
1888         if (str != NULL) {
1889                 device->policy = string2policy(str);
1890                 g_free(str);
1891         }
1892
1893         switch (device->mode) {
1894         case CONNMAN_DEVICE_MODE_UNKNOWN:
1895         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1896                 break;
1897         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1898         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1899                 val = g_key_file_get_integer(keyfile, identifier,
1900                                                         "ScanInterval", NULL);
1901                 if (val > 0)
1902                         device->scan_interval = val;
1903                 break;
1904         }
1905
1906 done:
1907         g_key_file_free(keyfile);
1908
1909         g_free(identifier);
1910
1911         return 0;
1912 }
1913
1914 static int device_save(struct connman_device *device)
1915 {
1916         GKeyFile *keyfile;
1917         gchar *pathname, *identifier = NULL, *data = NULL;
1918         gsize length;
1919         const char *str;
1920
1921         DBG("device %p", device);
1922
1923         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1924                                         __connman_profile_active_ident());
1925         if (pathname == NULL)
1926                 return -ENOMEM;
1927
1928         keyfile = g_key_file_new();
1929
1930         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1931                 goto update;
1932
1933         if (length > 0) {
1934                 if (g_key_file_load_from_data(keyfile, data, length,
1935                                                         0, NULL) == FALSE)
1936                         goto done;
1937         }
1938
1939         g_free(data);
1940
1941 update:
1942         identifier = g_strdup_printf("device_%s", device->element.name);
1943         if (identifier == NULL)
1944                 goto done;
1945
1946         str = policy2string(device->policy);
1947         if (str != NULL)
1948                 g_key_file_set_string(keyfile, identifier, "Policy", str);
1949
1950         switch (device->mode) {
1951         case CONNMAN_DEVICE_MODE_UNKNOWN:
1952         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1953                 break;
1954         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1955         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1956                 if (device->scan_interval > 0)
1957                         g_key_file_set_integer(keyfile, identifier,
1958                                         "ScanInterval", device->scan_interval);
1959                 break;
1960         }
1961
1962         data = g_key_file_to_data(keyfile, &length, NULL);
1963
1964         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
1965                 connman_error("Failed to store device information");
1966
1967 done:
1968         g_free(data);
1969
1970         g_key_file_free(keyfile);
1971
1972         g_free(identifier);
1973         g_free(pathname);
1974
1975         return 0;
1976 }
1977
1978 static struct connman_storage device_storage = {
1979         .name           = "device",
1980         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1981         .device_load    = device_load,
1982         .device_save    = device_save,
1983 };
1984
1985 int __connman_device_init(void)
1986 {
1987         DBG("");
1988
1989         connection = connman_dbus_get_connection();
1990
1991         if (connman_storage_register(&device_storage) < 0)
1992                 connman_error("Failed to register device storage");
1993
1994         return connman_driver_register(&device_driver);
1995 }
1996
1997 void __connman_device_cleanup(void)
1998 {
1999         DBG("");
2000
2001         connman_driver_unregister(&device_driver);
2002
2003         connman_storage_unregister(&device_storage);
2004
2005         dbus_connection_unref(connection);
2006 }