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