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