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