Fix rearming the scan trigger if a device got disabled
[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_persistent;
44         connman_bool_t carrier;
45         connman_bool_t scanning;
46         connman_bool_t disconnected;
47         connman_uint16_t scan_interval;
48         char *name;
49         char *node;
50         char *address;
51         char *interface;
52         char *control;
53         char *ident;
54         int phyindex;
55         unsigned int connections;
56         guint scan_timeout;
57         struct connman_ipconfig *ipconfig;
58
59         struct connman_device_driver *driver;
60         void *driver_data;
61
62         connman_bool_t registered;
63
64         char *last_network;
65         struct connman_network *network;
66         GHashTable *networks;
67
68         DBusMessage *pending;
69         guint timeout;
70 };
71
72 static gboolean device_scan_trigger(gpointer user_data)
73 {
74         struct connman_device *device = user_data;
75
76         DBG("device %p", device);
77
78         if (device->driver == NULL) {
79                 device->scan_timeout = 0;
80                 return FALSE;
81         }
82
83         if (device->driver->scan)
84                 device->driver->scan(device);
85
86         return TRUE;
87 }
88
89 static void clear_scan_trigger(struct connman_device *device)
90 {
91         if (device->scan_timeout > 0) {
92                 g_source_remove(device->scan_timeout);
93                 device->scan_timeout = 0;
94         }
95 }
96
97 static void reset_scan_trigger(struct connman_device *device)
98 {
99         clear_scan_trigger(device);
100
101         if (device->scan_interval > 0) {
102                 guint interval = device->scan_interval;
103                 device->scan_timeout = g_timeout_add_seconds(interval,
104                                         device_scan_trigger, device);
105         }
106 }
107
108 static const char *type2description(enum connman_device_type type)
109 {
110         switch (type) {
111         case CONNMAN_DEVICE_TYPE_UNKNOWN:
112         case CONNMAN_DEVICE_TYPE_VENDOR:
113                 break;
114         case CONNMAN_DEVICE_TYPE_ETHERNET:
115                 return "Ethernet";
116         case CONNMAN_DEVICE_TYPE_WIFI:
117                 return "Wireless";
118         case CONNMAN_DEVICE_TYPE_WIMAX:
119                 return "WiMAX";
120         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
121                 return "Bluetooth";
122         case CONNMAN_DEVICE_TYPE_GPS:
123                 return "GPS";
124         case CONNMAN_DEVICE_TYPE_MBM:
125         case CONNMAN_DEVICE_TYPE_HSO:
126         case CONNMAN_DEVICE_TYPE_NOZOMI:
127         case CONNMAN_DEVICE_TYPE_HUAWEI:
128         case CONNMAN_DEVICE_TYPE_NOVATEL:
129                 return "Cellular";
130         }
131
132         return NULL;
133 }
134
135 static const char *type2string(enum connman_device_type type)
136 {
137         switch (type) {
138         case CONNMAN_DEVICE_TYPE_UNKNOWN:
139         case CONNMAN_DEVICE_TYPE_VENDOR:
140                 break;
141         case CONNMAN_DEVICE_TYPE_ETHERNET:
142                 return "ethernet";
143         case CONNMAN_DEVICE_TYPE_WIFI:
144                 return "wifi";
145         case CONNMAN_DEVICE_TYPE_WIMAX:
146                 return "wimax";
147         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
148                 return "bluetooth";
149         case CONNMAN_DEVICE_TYPE_GPS:
150                 return "gps";
151         case CONNMAN_DEVICE_TYPE_MBM:
152         case CONNMAN_DEVICE_TYPE_HSO:
153         case CONNMAN_DEVICE_TYPE_HUAWEI:
154         case CONNMAN_DEVICE_TYPE_NOZOMI:
155         case CONNMAN_DEVICE_TYPE_NOVATEL:
156                 return "cellular";
157         }
158
159         return NULL;
160 }
161
162 enum connman_service_type __connman_device_get_service_type(struct connman_device *device)
163 {
164         enum connman_device_type type = connman_device_get_type(device);
165
166         switch (type) {
167         case CONNMAN_DEVICE_TYPE_UNKNOWN:
168         case CONNMAN_DEVICE_TYPE_VENDOR:
169         case CONNMAN_DEVICE_TYPE_GPS:
170         case CONNMAN_DEVICE_TYPE_NOZOMI:
171         case CONNMAN_DEVICE_TYPE_HUAWEI:
172         case CONNMAN_DEVICE_TYPE_NOVATEL:
173                 break;
174         case CONNMAN_DEVICE_TYPE_ETHERNET:
175                 return CONNMAN_SERVICE_TYPE_ETHERNET;
176         case CONNMAN_DEVICE_TYPE_WIFI:
177                 return CONNMAN_SERVICE_TYPE_WIFI;
178         case CONNMAN_DEVICE_TYPE_WIMAX:
179                 return CONNMAN_SERVICE_TYPE_WIMAX;
180         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
181                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
182         case CONNMAN_DEVICE_TYPE_MBM:
183         case CONNMAN_DEVICE_TYPE_HSO:
184                 return CONNMAN_SERVICE_TYPE_CELLULAR;
185         }
186
187         return CONNMAN_SERVICE_TYPE_UNKNOWN;
188 }
189
190 static int set_connected(struct connman_device *device,
191                                                 connman_bool_t connected)
192 {
193         if (connected == TRUE) {
194                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
195                 struct connman_element *element;
196
197                 device->disconnected = TRUE;
198
199                 switch (device->element.ipv4.method) {
200                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
201                 case CONNMAN_IPCONFIG_METHOD_OFF:
202                         return 0;
203                 case CONNMAN_IPCONFIG_METHOD_STATIC:
204                         type = CONNMAN_ELEMENT_TYPE_IPV4;
205                         break;
206                 case CONNMAN_IPCONFIG_METHOD_DHCP:
207                         type = CONNMAN_ELEMENT_TYPE_DHCP;
208                         break;
209                 }
210
211                 element = connman_element_create(NULL);
212                 if (element != NULL) {
213                         struct connman_service *service;
214
215                         element->type  = type;
216                         element->index = device->element.index;
217
218                         if (connman_element_register(element,
219                                                         &device->element) < 0)
220                                 connman_element_unref(element);
221
222                         device->disconnected = FALSE;
223
224                         service = __connman_service_lookup_from_device(device);
225                         __connman_service_indicate_state(service,
226                                         CONNMAN_SERVICE_STATE_CONFIGURATION);
227                 }
228         } else {
229                 struct connman_service *service;
230
231                 connman_element_unregister_children(&device->element);
232
233                 device->disconnected = TRUE;
234
235                 service = __connman_service_lookup_from_device(device);
236                 __connman_service_indicate_state(service,
237                                         CONNMAN_SERVICE_STATE_IDLE);
238         }
239
240         if (connected == TRUE) {
241                 enum connman_service_type type;
242
243                 type = __connman_device_get_service_type(device);
244                 __connman_notifier_connect(type);
245         } else {
246                 enum connman_service_type type;
247
248                 type = __connman_device_get_service_type(device);
249                 __connman_notifier_disconnect(type);
250         }
251
252         return 0;
253 }
254
255 static int set_carrier(struct connman_device *device, connman_bool_t carrier)
256 {
257         struct connman_service *service;
258
259         if (carrier == TRUE)
260                 __connman_profile_add_device(device);
261         else
262                 __connman_profile_remove_device(device);
263
264         service = __connman_service_lookup_from_device(device);
265         __connman_service_set_carrier(service, carrier);
266
267         return set_connected(device, carrier);
268 }
269
270 static int powered_changed(struct connman_device *device)
271 {
272         DBusMessage *signal;
273         DBusMessageIter entry, value;
274         const char *key = "Powered";
275
276         signal = dbus_message_new_signal(device->element.path,
277                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
278         if (signal == NULL)
279                 return -ENOMEM;
280
281         dbus_message_iter_init_append(signal, &entry);
282
283         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
284
285         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
286                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
287         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
288                                                         &device->powered);
289         dbus_message_iter_close_container(&entry, &value);
290
291         g_dbus_send_message(connection, signal);
292
293         return 0;
294 }
295
296 static int set_powered(struct connman_device *device, connman_bool_t powered)
297 {
298         struct connman_device_driver *driver = device->driver;
299         enum connman_service_type type;
300         int err;
301
302         DBG("device %p powered %d", device, powered);
303
304         if (device->powered == powered)
305                 return -EALREADY;
306
307         if (!driver)
308                 return -EINVAL;
309
310         type = __connman_device_get_service_type(device);
311
312         if (powered == TRUE) {
313                 if (driver->enable) {
314                         err = driver->enable(device);
315                         if (err == 0)
316                                 __connman_notifier_enable(type);
317                 } else
318                         err = -EINVAL;
319         } else {
320                 clear_scan_trigger(device);
321
322                 g_hash_table_remove_all(device->networks);
323
324                 set_carrier(device, FALSE);
325
326                 if (driver->disable) {
327                         err = driver->disable(device);
328                         if (err == 0)
329                                 __connman_notifier_disable(type);
330                 } else
331                         err = -EINVAL;
332         }
333
334         if (err == 0) {
335                 device->powered = powered;
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         int err;
677
678         DBG("device %p", device);
679
680         err = register_interface(&device->element);
681         if (err < 0) {
682                 if (device->driver->remove)
683                         device->driver->remove(device);
684                 device->driver = NULL;
685                 return err;
686         }
687
688         switch (device->mode) {
689         case CONNMAN_DEVICE_MODE_UNKNOWN:
690         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
691         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
692                 break;
693         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
694                 if (device->carrier == TRUE && device->secondary == FALSE)
695                         __connman_profile_add_device(device);
696                 break;
697         }
698
699         if (device->offlinemode == FALSE &&
700                                 device->powered_persistent == TRUE)
701                 __connman_device_enable(device);
702
703         return 0;
704 }
705
706 static void probe_driver(struct connman_element *element, gpointer user_data)
707 {
708         struct connman_device_driver *driver = user_data;
709
710         DBG("element %p name %s", element, element->name);
711
712         if (element->device == NULL)
713                 return;
714
715         if (element->device->driver != NULL)
716                 return;
717
718         if (driver->type != element->device->type)
719                 return;
720
721         if (driver->probe(element->device) < 0)
722                 return;
723
724         element->device->driver = driver;
725
726         setup_device(element->device);
727 }
728
729 static void remove_device(struct connman_device *device)
730 {
731         DBG("device %p", device);
732
733         __connman_device_disable(device);
734
735         switch (device->mode) {
736         case CONNMAN_DEVICE_MODE_UNKNOWN:
737         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
738         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
739                 break;
740         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
741                 if (device->secondary == FALSE)
742                         __connman_profile_remove_device(device);
743                 break;
744         }
745
746         unregister_interface(&device->element);
747
748         if (device->driver->remove)
749                 device->driver->remove(device);
750
751         device->driver = NULL;
752 }
753
754 static void remove_driver(struct connman_element *element, gpointer user_data)
755 {
756         struct connman_device_driver *driver = user_data;
757
758         DBG("element %p name %s", element, element->name);
759
760         if (element->device == NULL)
761                 return;
762
763         if (element->device->driver == driver)
764                 remove_device(element->device);
765 }
766
767 connman_bool_t __connman_device_has_driver(struct connman_device *device)
768 {
769         if (device == NULL || device->driver == NULL)
770                 return FALSE;
771
772         return device->registered;
773 }
774
775 static GSList *driver_list = NULL;
776
777 static gint compare_priority(gconstpointer a, gconstpointer b)
778 {
779         const struct connman_device_driver *driver1 = a;
780         const struct connman_device_driver *driver2 = b;
781
782         return driver2->priority - driver1->priority;
783 }
784
785 /**
786  * connman_device_driver_register:
787  * @driver: device driver definition
788  *
789  * Register a new device driver
790  *
791  * Returns: %0 on success
792  */
793 int connman_device_driver_register(struct connman_device_driver *driver)
794 {
795         DBG("driver %p name %s", driver, driver->name);
796
797         driver_list = g_slist_insert_sorted(driver_list, driver,
798                                                         compare_priority);
799
800         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
801                                                 probe_driver, driver);
802
803         return 0;
804 }
805
806 /**
807  * connman_device_driver_unregister:
808  * @driver: device driver definition
809  *
810  * Remove a previously registered device driver
811  */
812 void connman_device_driver_unregister(struct connman_device_driver *driver)
813 {
814         DBG("driver %p name %s", driver, driver->name);
815
816         driver_list = g_slist_remove(driver_list, driver);
817
818         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
819                                                 remove_driver, driver);
820 }
821
822 static void unregister_network(gpointer data)
823 {
824         struct connman_network *network = data;
825
826         DBG("network %p", network);
827
828         connman_element_unregister((struct connman_element *) network);
829
830         connman_network_unref(network);
831 }
832
833 static void device_destruct(struct connman_element *element)
834 {
835         struct connman_device *device = element->device;
836
837         DBG("element %p name %s", element, element->name);
838
839         if (device->timeout > 0) {
840                 g_source_remove(device->timeout);
841                 device->timeout = 0;
842         }
843
844         if (device->pending != NULL) {
845                 dbus_message_unref(device->pending);
846                 device->pending = NULL;
847         }
848
849         g_free(device->ident);
850         g_free(device->node);
851         g_free(device->name);
852         g_free(device->address);
853         g_free(device->control);
854         g_free(device->interface);
855
856         connman_ipconfig_unref(device->ipconfig);
857
858         g_free(device->last_network);
859
860         g_hash_table_destroy(device->networks);
861         device->networks = NULL;
862 }
863
864 /**
865  * connman_device_create:
866  * @node: device node name (for example an address)
867  * @type: device type
868  *
869  * Allocate a new device of given #type and assign the #node name to it.
870  *
871  * Returns: a newly-allocated #connman_device structure
872  */
873 struct connman_device *connman_device_create(const char *node,
874                                                 enum connman_device_type type)
875 {
876         struct connman_device *device;
877         const char *str;
878
879         DBG("node %s type %d", node, type);
880
881         device = g_try_new0(struct connman_device, 1);
882         if (device == NULL)
883                 return NULL;
884
885         DBG("device %p", device);
886
887         __connman_element_initialize(&device->element);
888
889         device->element.name = g_strdup(node);
890         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
891
892         device->element.device = device;
893         device->element.destruct = device_destruct;
894
895         str = type2string(type);
896         if (str != NULL)
897                 connman_element_set_string(&device->element,
898                                         CONNMAN_PROPERTY_ID_TYPE, str);
899
900         device->element.ipv4.method = CONNMAN_IPCONFIG_METHOD_DHCP;
901
902         device->type      = type;
903         device->name      = g_strdup(type2description(device->type));
904         device->mode      = CONNMAN_DEVICE_MODE_UNKNOWN;
905         device->secondary = FALSE;
906
907         device->powered_persistent = TRUE;
908
909         device->phyindex = -1;
910
911         switch (type) {
912         case CONNMAN_DEVICE_TYPE_UNKNOWN:
913         case CONNMAN_DEVICE_TYPE_VENDOR:
914                 device->scan_interval = 0;
915                 break;
916         case CONNMAN_DEVICE_TYPE_ETHERNET:
917         case CONNMAN_DEVICE_TYPE_WIFI:
918                 device->scan_interval = 300;
919                 break;
920         case CONNMAN_DEVICE_TYPE_WIMAX:
921                 device->scan_interval = 0;
922                 break;
923         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
924                 device->scan_interval = 0;
925                 break;
926         case CONNMAN_DEVICE_TYPE_GPS:
927                 device->scan_interval = 0;
928                 break;
929         case CONNMAN_DEVICE_TYPE_MBM:
930         case CONNMAN_DEVICE_TYPE_HSO:
931         case CONNMAN_DEVICE_TYPE_NOZOMI:
932         case CONNMAN_DEVICE_TYPE_HUAWEI:
933         case CONNMAN_DEVICE_TYPE_NOVATEL:
934                 device->scan_interval = 0;
935                 break;
936         }
937
938         device->ipconfig = connman_ipconfig_create();
939         if (device->ipconfig == NULL) {
940                 connman_device_unref(device);
941                 return NULL;
942         }
943
944         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
945                                                 g_free, unregister_network);
946
947         return device;
948 }
949
950 /**
951  * connman_device_ref:
952  * @device: device structure
953  *
954  * Increase reference counter of device
955  */
956 struct connman_device *connman_device_ref(struct connman_device *device)
957 {
958         if (connman_element_ref(&device->element) == NULL)
959                 return NULL;
960
961         return device;
962 }
963
964 /**
965  * connman_device_unref:
966  * @device: device structure
967  *
968  * Decrease reference counter of device
969  */
970 void connman_device_unref(struct connman_device *device)
971 {
972         connman_element_unref(&device->element);
973 }
974
975 const char *__connman_device_get_type(struct connman_device *device)
976 {
977         return type2string(device->type);
978 }
979
980 /**
981  * connman_device_get_type:
982  * @device: device structure
983  *
984  * Get type of device
985  */
986 enum connman_device_type connman_device_get_type(struct connman_device *device)
987 {
988         return device->type;
989 }
990
991 /**
992  * connman_device_get_name:
993  * @device: device structure
994  *
995  * Get unique name of device
996  */
997 const char *connman_device_get_name(struct connman_device *device)
998 {
999         return device->element.name;
1000 }
1001
1002 /**
1003  * connman_device_get_path:
1004  * @device: device structure
1005  *
1006  * Get path name of device
1007  */
1008 const char *connman_device_get_path(struct connman_device *device)
1009 {
1010         return device->element.path;
1011 }
1012
1013 /**
1014  * connman_device_set_index:
1015  * @device: device structure
1016  * @index: index number
1017  *
1018  * Set index number of device
1019  */
1020 void connman_device_set_index(struct connman_device *device, int index)
1021 {
1022         device->element.index = index;
1023 }
1024
1025 /**
1026  * connman_device_get_index:
1027  * @device: device structure
1028  *
1029  * Get index number of device
1030  */
1031 int connman_device_get_index(struct connman_device *device)
1032 {
1033         return device->element.index;
1034 }
1035
1036 int __connman_device_get_phyindex(struct connman_device *device)
1037 {
1038         return device->phyindex;
1039 }
1040
1041 void __connman_device_set_phyindex(struct connman_device *device,
1042                                                         int phyindex)
1043 {
1044         device->phyindex = phyindex;
1045 }
1046
1047 /**
1048  * connman_device_set_interface:
1049  * @device: device structure
1050  * @interface: interface name
1051  * @control: control interface
1052  *
1053  * Set interface name of device
1054  */
1055 void connman_device_set_interface(struct connman_device *device,
1056                                 const char *interface, const char *control)
1057 {
1058         g_free(device->element.devname);
1059         device->element.devname = g_strdup(interface);
1060
1061         g_free(device->interface);
1062         device->interface = g_strdup(interface);
1063
1064         g_free(device->control);
1065         device->control = g_strdup(control);
1066
1067         if (device->name == NULL) {
1068                 const char *str = type2description(device->type);
1069                 if (str != NULL && device->interface != NULL)
1070                         device->name = g_strdup_printf("%s (%s)", str,
1071                                                         device->interface);
1072         }
1073 }
1074
1075 const char *connman_device_get_control(struct connman_device *device)
1076 {
1077         return device->control;
1078 }
1079
1080 /**
1081  * connman_device_set_ident:
1082  * @device: device structure
1083  * @ident: unique identifier
1084  *
1085  * Set unique identifier of device
1086  */
1087 void connman_device_set_ident(struct connman_device *device,
1088                                                         const char *ident)
1089 {
1090         g_free(device->ident);
1091         device->ident = g_strdup(ident);
1092 }
1093
1094 const char *__connman_device_get_ident(struct connman_device *device)
1095 {
1096         return device->ident;
1097 }
1098
1099 /**
1100  * connman_device_set_mode:
1101  * @device: device structure
1102  * @mode: network mode
1103  *
1104  * Change network mode of device
1105  */
1106 void connman_device_set_mode(struct connman_device *device,
1107                                                 enum connman_device_mode mode)
1108 {
1109         device->mode = mode;
1110 }
1111
1112 /**
1113  * connman_device_get_mode:
1114  * @device: device structure
1115  *
1116  * Get network mode of device
1117  */
1118 enum connman_device_mode connman_device_get_mode(struct connman_device *device)
1119 {
1120         return device->mode;
1121 }
1122
1123 /**
1124  * connman_device_set_secondary:
1125  * @device: device structure
1126  * @secondary: secondary value
1127  *
1128  * Change secondary value of device
1129  */
1130 void connman_device_set_secondary(struct connman_device *device,
1131                                                 connman_bool_t secondary)
1132 {
1133         device->secondary = secondary;
1134 }
1135
1136 /**
1137  * connman_device_get_secondary:
1138  * @device: device structure
1139  *
1140  * Get secondary value of device
1141  */
1142 connman_bool_t connman_device_get_secondary(struct connman_device *device)
1143 {
1144         return device->secondary;
1145 }
1146
1147 /**
1148  * connman_device_set_powered:
1149  * @device: device structure
1150  * @powered: powered state
1151  *
1152  * Change power state of device
1153  */
1154 int connman_device_set_powered(struct connman_device *device,
1155                                                 connman_bool_t powered)
1156 {
1157         enum connman_service_type type;
1158
1159         DBG("driver %p powered %d", device, powered);
1160
1161         if (device->timeout > 0) {
1162                 g_source_remove(device->timeout);
1163                 device->timeout = 0;
1164         }
1165
1166         if (device->pending != NULL) {
1167                 g_dbus_send_reply(connection, device->pending,
1168                                                         DBUS_TYPE_INVALID);
1169
1170                 dbus_message_unref(device->pending);
1171                 device->pending = NULL;
1172         }
1173
1174         if (device->powered == powered)
1175                 return -EALREADY;
1176
1177         device->powered = powered;
1178
1179         type = __connman_device_get_service_type(device);
1180
1181         if (device->powered == TRUE)
1182                 __connman_notifier_enable(type);
1183         else
1184                 __connman_notifier_disable(type);
1185
1186         if (device->registered == FALSE)
1187                 return 0;
1188
1189         powered_changed(device);
1190
1191         if (powered == FALSE)
1192                 return 0;
1193
1194         reset_scan_trigger(device);
1195
1196         if (device->driver->scan)
1197                 device->driver->scan(device);
1198
1199         return 0;
1200 }
1201
1202 int __connman_device_set_blocked(struct connman_device *device,
1203                                                 connman_bool_t blocked)
1204 {
1205         connman_bool_t powered;
1206
1207         DBG("device %p blocked %d", device, blocked);
1208
1209         if (device->blocked == blocked)
1210                 return -EALREADY;
1211
1212         device->blocked = blocked;
1213
1214         if (device->offlinemode == TRUE)
1215                 return 0;
1216
1217         if (blocked == FALSE)
1218                 powered = device->powered_persistent;
1219         else
1220                 powered = FALSE;
1221
1222         return set_powered(device, powered);
1223 }
1224
1225 /**
1226  * connman_device_set_carrier:
1227  * @device: device structure
1228  * @carrier: carrier state
1229  *
1230  * Change carrier state of device (only for device without scanning)
1231  */
1232 int connman_device_set_carrier(struct connman_device *device,
1233                                                 connman_bool_t carrier)
1234 {
1235         DBG("device %p carrier %d", device, carrier);
1236
1237         switch (device->mode) {
1238         case CONNMAN_DEVICE_MODE_UNKNOWN:
1239         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1240         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1241                 return -EINVAL;
1242         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1243                 break;
1244         }
1245
1246         if (device->carrier == carrier)
1247                 return -EALREADY;
1248
1249         device->carrier = carrier;
1250
1251         return set_carrier(device, device->carrier);
1252 }
1253
1254 int __connman_device_scan(struct connman_device *device)
1255 {
1256         if (!device->driver || !device->driver->scan)
1257                 return -EOPNOTSUPP;
1258
1259         if (device->powered == FALSE)
1260                 return -ENOLINK;
1261
1262         return device->driver->scan(device);
1263 }
1264
1265 int __connman_device_enable(struct connman_device *device)
1266 {
1267         enum connman_service_type type;
1268         int err;
1269
1270         DBG("device %p", device);
1271
1272         if (!device->driver || !device->driver->enable)
1273                 return -EOPNOTSUPP;
1274
1275         if (device->powered == TRUE)
1276                 return -EALREADY;
1277
1278         err = device->driver->enable(device);
1279         if (err < 0)
1280                 return err;
1281
1282         device->powered = TRUE;
1283
1284         type = __connman_device_get_service_type(device);
1285         __connman_notifier_enable(type);
1286
1287         return 0;
1288 }
1289
1290 int __connman_device_enable_persistent(struct connman_device *device)
1291 {
1292         DBG("device %p", device);
1293
1294         device->powered_persistent = TRUE;
1295
1296         __connman_storage_save_device(device);
1297
1298         return __connman_device_enable(device);
1299 }
1300
1301 int __connman_device_disable(struct connman_device *device)
1302 {
1303         enum connman_service_type type;
1304         int err;
1305
1306         DBG("device %p", device);
1307
1308         if (!device->driver || !device->driver->disable)
1309                 return -EOPNOTSUPP;
1310
1311         if (device->powered == FALSE)
1312                 return -ENOLINK;
1313
1314         clear_scan_trigger(device);
1315
1316         g_hash_table_remove_all(device->networks);
1317
1318         err = device->driver->disable(device);
1319         if (err < 0)
1320                 return err;
1321
1322         device->powered = FALSE;
1323
1324         type = __connman_device_get_service_type(device);
1325         __connman_notifier_disable(type);
1326
1327         return 0;
1328 }
1329
1330 int __connman_device_disable_persistent(struct connman_device *device)
1331 {
1332         DBG("device %p", device);
1333
1334         device->powered_persistent = FALSE;
1335
1336         __connman_storage_save_device(device);
1337
1338         return __connman_device_disable(device);
1339 }
1340
1341 int __connman_device_connect(struct connman_device *device)
1342 {
1343         DBG("device %p", device);
1344
1345         if (device->disconnected == FALSE)
1346                 return -EINVAL;
1347
1348         if (device->driver && device->driver->connect)
1349                 device->driver->connect(device);
1350
1351         return 0;
1352 }
1353
1354 int __connman_device_disconnect(struct connman_device *device)
1355 {
1356         GHashTableIter iter;
1357         gpointer key, value;
1358
1359         DBG("device %p", device);
1360
1361         connman_device_set_disconnected(device, TRUE);
1362
1363         g_hash_table_iter_init(&iter, device->networks);
1364
1365         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1366                 struct connman_network *network = value;
1367
1368                 __connman_network_disconnect(network);
1369         }
1370
1371         if (device->driver && device->driver->disconnect)
1372                 device->driver->disconnect(device);
1373
1374         return 0;
1375 }
1376
1377 static void mark_network_unavailable(gpointer key, gpointer value,
1378                                                         gpointer user_data)
1379 {
1380         struct connman_network *network = value;
1381
1382         if (connman_network_get_connected(network) == TRUE)
1383                 return;
1384
1385         connman_network_set_available(network, FALSE);
1386 }
1387
1388 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1389                                                         gpointer user_data)
1390 {
1391         struct connman_network *network = value;
1392
1393         if (connman_network_get_connected(network) == TRUE)
1394                 return FALSE;
1395
1396         if (connman_network_get_available(network) == TRUE)
1397                 return FALSE;
1398
1399         return TRUE;
1400 }
1401
1402 void __connman_device_cleanup_networks(struct connman_device *device)
1403 {
1404         g_hash_table_foreach_remove(device->networks,
1405                                         remove_unavailable_network, NULL);
1406 }
1407
1408 /**
1409  * connman_device_set_scanning:
1410  * @device: device structure
1411  * @scanning: scanning state
1412  *
1413  * Change scanning state of device
1414  */
1415 int connman_device_set_scanning(struct connman_device *device,
1416                                                 connman_bool_t scanning)
1417 {
1418         DBusMessage *signal;
1419         DBusMessageIter entry, value;
1420         const char *key = "Scanning";
1421
1422         DBG("device %p scanning %d", device, scanning);
1423
1424         if (!device->driver || !device->driver->scan)
1425                 return -EINVAL;
1426
1427         if (device->scanning == scanning)
1428                 return -EALREADY;
1429
1430         device->scanning = scanning;
1431
1432         signal = dbus_message_new_signal(device->element.path,
1433                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1434         if (signal == NULL)
1435                 return 0;
1436
1437         dbus_message_iter_init_append(signal, &entry);
1438
1439         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1440
1441         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1442                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1443         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1444         dbus_message_iter_close_container(&entry, &value);
1445
1446         g_dbus_send_message(connection, signal);
1447
1448         if (scanning == TRUE) {
1449                 reset_scan_trigger(device);
1450
1451                 g_hash_table_foreach(device->networks,
1452                                         mark_network_unavailable, NULL);
1453
1454                 return 0;
1455         }
1456
1457         __connman_device_cleanup_networks(device);
1458
1459         if (device->connections > 0)
1460                 return 0;
1461
1462         if (device->disconnected == TRUE)
1463                 return 0;
1464
1465         __connman_service_auto_connect();
1466
1467         return 0;
1468 }
1469
1470 /**
1471  * connman_device_set_disconnected:
1472  * @device: device structure
1473  * @disconnected: disconnected state
1474  *
1475  * Change disconnected state of device (only for device with networks)
1476  */
1477 int connman_device_set_disconnected(struct connman_device *device,
1478                                                 connman_bool_t disconnected)
1479 {
1480         DBG("device %p disconnected %d", device, disconnected);
1481
1482         switch (device->mode) {
1483         case CONNMAN_DEVICE_MODE_UNKNOWN:
1484         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1485                 return -EINVAL;
1486         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1487         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1488                 break;
1489         }
1490
1491         if (device->disconnected == disconnected)
1492                 return -EALREADY;
1493
1494         device->disconnected = disconnected;
1495
1496         return 0;
1497 }
1498
1499 /**
1500  * connman_device_get_disconnected:
1501  * @device: device structure
1502  *
1503  * Get device disconnected state
1504  */
1505 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
1506 {
1507         return device->disconnected;
1508 }
1509
1510 /**
1511  * connman_device_set_connected:
1512  * @device: device structure
1513  * @connected: connected state
1514  *
1515  * Change connected state of device (for Ethernet like devices)
1516  */
1517 int connman_device_set_connected(struct connman_device *device,
1518                                                 connman_bool_t connected)
1519 {
1520         DBG("device %p connected %d", device, connected);
1521
1522         switch (device->mode) {
1523         case CONNMAN_DEVICE_MODE_UNKNOWN:
1524         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1525         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1526                 return -EINVAL;
1527         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1528                 break;
1529         }
1530
1531         if (device->carrier == FALSE)
1532                 return -ENOTCONN;
1533
1534         return set_connected(device, connected);
1535 }
1536
1537 /**
1538  * connman_device_set_string:
1539  * @device: device structure
1540  * @key: unique identifier
1541  * @value: string value
1542  *
1543  * Set string value for specific key
1544  */
1545 int connman_device_set_string(struct connman_device *device,
1546                                         const char *key, const char *value)
1547 {
1548         DBG("device %p key %s value %s", device, key, value);
1549
1550         if (g_str_equal(key, "Address") == TRUE) {
1551                 g_free(device->address);
1552                 device->address = g_strdup(value);
1553         } else if (g_str_equal(key, "Name") == TRUE) {
1554                 g_free(device->name);
1555                 device->name = g_strdup(value);
1556         } else if (g_str_equal(key, "Node") == TRUE) {
1557                 g_free(device->node);
1558                 device->node = g_strdup(value);
1559         }
1560
1561         return connman_element_set_string(&device->element, key, value);
1562 }
1563
1564 /**
1565  * connman_device_get_string:
1566  * @device: device structure
1567  * @key: unique identifier
1568  *
1569  * Get string value for specific key
1570  */
1571 const char *connman_device_get_string(struct connman_device *device,
1572                                                         const char *key)
1573 {
1574         DBG("device %p key %s", device, key);
1575
1576         if (g_str_equal(key, "Address") == TRUE)
1577                 return device->address;
1578         else if (g_str_equal(key, "Name") == TRUE)
1579                 return device->name;
1580         else if (g_str_equal(key, "Node") == TRUE)
1581                 return device->node;
1582
1583         return connman_element_get_string(&device->element, key);
1584 }
1585
1586 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1587 {
1588         struct connman_device *device = element->device;
1589         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1590         connman_bool_t powered;
1591
1592         DBG("element %p name %s", element, element->name);
1593
1594         if (device == NULL)
1595                 return;
1596
1597         device->offlinemode = offlinemode;
1598
1599         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1600
1601         if (device->powered == powered)
1602                 return;
1603
1604         if (device->powered_persistent == FALSE)
1605                 powered = FALSE;
1606
1607         set_powered(device, powered);
1608 }
1609
1610 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1611 {
1612         DBG("offlinmode %d", offlinemode);
1613
1614         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1615                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1616
1617         __connman_notifier_offlinemode(offlinemode);
1618
1619         return 0;
1620 }
1621
1622 void __connman_device_increase_connections(struct connman_device *device)
1623 {
1624         enum connman_service_type type;
1625
1626         device->connections++;
1627
1628         type = __connman_device_get_service_type(device);
1629         __connman_notifier_connect(type);
1630 }
1631
1632 void __connman_device_decrease_connections(struct connman_device *device)
1633 {
1634         enum connman_service_type type;
1635
1636         device->connections--;
1637
1638         type = __connman_device_get_service_type(device);
1639         __connman_notifier_disconnect(type);
1640 }
1641
1642 /**
1643  * connman_device_add_network:
1644  * @device: device structure
1645  * @network: network structure
1646  *
1647  * Add new network to the device
1648  */
1649 int connman_device_add_network(struct connman_device *device,
1650                                         struct connman_network *network)
1651 {
1652         const char *identifier = connman_network_get_identifier(network);
1653         int err;
1654
1655         DBG("device %p network %p", device, network);
1656
1657         switch (device->mode) {
1658         case CONNMAN_DEVICE_MODE_UNKNOWN:
1659         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1660                 return -EINVAL;
1661         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1662         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1663                 break;
1664         }
1665
1666         __connman_network_set_device(network, device);
1667
1668         err = connman_element_register((struct connman_element *) network,
1669                                                         &device->element);
1670         if (err < 0) {
1671                 __connman_network_set_device(network, NULL);
1672                 return err;
1673         }
1674
1675         g_hash_table_insert(device->networks, g_strdup(identifier),
1676                                                                 network);
1677
1678         return 0;
1679 }
1680
1681 /**
1682  * connman_device_get_network:
1683  * @device: device structure
1684  * @identifier: network identifier
1685  *
1686  * Get network for given identifier
1687  */
1688 struct connman_network *connman_device_get_network(struct connman_device *device,
1689                                                         const char *identifier)
1690 {
1691         DBG("device %p identifier %s", device, identifier);
1692
1693         return g_hash_table_lookup(device->networks, identifier);
1694 }
1695
1696 /**
1697  * connman_device_remove_network:
1698  * @device: device structure
1699  * @identifier: network identifier
1700  *
1701  * Remove network for given identifier
1702  */
1703 int connman_device_remove_network(struct connman_device *device,
1704                                                         const char *identifier)
1705 {
1706         DBG("device %p identifier %s", device, identifier);
1707
1708         g_hash_table_remove(device->networks, identifier);
1709
1710         return 0;
1711 }
1712
1713 void __connman_device_set_network(struct connman_device *device,
1714                                         struct connman_network *network)
1715 {
1716         const char *name;
1717
1718         if (device->network == network)
1719                 return;
1720
1721         if (device->network != NULL)
1722                 connman_network_unref(device->network);
1723
1724         if (network != NULL) {
1725                 name = connman_network_get_string(network,
1726                                                 CONNMAN_PROPERTY_ID_NAME);
1727                 g_free(device->last_network);
1728                 device->last_network = g_strdup(name);
1729
1730                 device->network = connman_network_ref(network);
1731         } else {
1732                 g_free(device->last_network);
1733                 device->last_network = NULL;
1734
1735                 device->network = NULL;
1736         }
1737 }
1738
1739 /**
1740  * connman_device_register:
1741  * @device: device structure
1742  *
1743  * Register device with the system
1744  */
1745 int connman_device_register(struct connman_device *device)
1746 {
1747         enum connman_service_type type;
1748
1749         __connman_storage_load_device(device);
1750
1751         device->offlinemode = __connman_manager_get_offlinemode();
1752
1753         type = __connman_device_get_service_type(device);
1754         __connman_notifier_register(type);
1755
1756         return connman_element_register(&device->element, NULL);
1757 }
1758
1759 /**
1760  * connman_device_unregister:
1761  * @device: device structure
1762  *
1763  * Unregister device with the system
1764  */
1765 void connman_device_unregister(struct connman_device *device)
1766 {
1767         enum connman_service_type type;
1768
1769         __connman_storage_save_device(device);
1770
1771         type = __connman_device_get_service_type(device);
1772         __connman_notifier_unregister(type);
1773
1774         connman_element_unregister(&device->element);
1775 }
1776
1777 /**
1778  * connman_device_get_data:
1779  * @device: device structure
1780  *
1781  * Get private device data pointer
1782  */
1783 void *connman_device_get_data(struct connman_device *device)
1784 {
1785         return device->driver_data;
1786 }
1787
1788 /**
1789  * connman_device_set_data:
1790  * @device: device structure
1791  * @data: data pointer
1792  *
1793  * Set private device data pointer
1794  */
1795 void connman_device_set_data(struct connman_device *device, void *data)
1796 {
1797         device->driver_data = data;
1798 }
1799
1800 static gboolean match_driver(struct connman_device *device,
1801                                         struct connman_device_driver *driver)
1802 {
1803         if (device->type == driver->type ||
1804                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1805                 return TRUE;
1806
1807         return FALSE;
1808 }
1809
1810 static int device_probe(struct connman_element *element)
1811 {
1812         struct connman_device *device = element->device;
1813         GSList *list;
1814
1815         DBG("element %p name %s", element, element->name);
1816
1817         if (device == NULL)
1818                 return -ENODEV;
1819
1820         if (device->driver != NULL)
1821                 return -EALREADY;
1822
1823         for (list = driver_list; list; list = list->next) {
1824                 struct connman_device_driver *driver = list->data;
1825
1826                 if (match_driver(device, driver) == FALSE)
1827                         continue;
1828
1829                 DBG("driver %p name %s", driver, driver->name);
1830
1831                 if (driver->probe(device) == 0) {
1832                         device->driver = driver;
1833                         break;
1834                 }
1835         }
1836
1837         if (device->driver == NULL)
1838                 return -ENODEV;
1839
1840         return setup_device(device);
1841 }
1842
1843 static void device_remove(struct connman_element *element)
1844 {
1845         struct connman_device *device = element->device;
1846
1847         DBG("element %p name %s", element, element->name);
1848
1849         if (device == NULL)
1850                 return;
1851
1852         if (device->driver == NULL)
1853                 return;
1854
1855         remove_device(device);
1856 }
1857
1858 static struct connman_driver device_driver = {
1859         .name           = "device",
1860         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1861         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1862         .probe          = device_probe,
1863         .remove         = device_remove,
1864 };
1865
1866 static int device_load(struct connman_device *device)
1867 {
1868         GKeyFile *keyfile;
1869         GError *error = NULL;
1870         gchar *identifier;
1871         connman_bool_t powered;
1872         int val;
1873
1874         DBG("device %p", device);
1875
1876         keyfile = __connman_storage_open();
1877         if (keyfile == NULL)
1878                 return 0;
1879
1880         identifier = g_strdup_printf("device_%s", device->element.name);
1881         if (identifier == NULL)
1882                 goto done;
1883
1884         powered = g_key_file_get_boolean(keyfile, identifier,
1885                                                 "Powered", &error);
1886         if (error == NULL)
1887                 device->powered_persistent = powered;
1888         g_clear_error(&error);
1889
1890         switch (device->mode) {
1891         case CONNMAN_DEVICE_MODE_UNKNOWN:
1892         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1893                 break;
1894         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1895         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1896                 val = g_key_file_get_integer(keyfile, identifier,
1897                                                 "ScanInterval", &error);
1898                 if (error == NULL && val > 0)
1899                         device->scan_interval = val;
1900                 g_clear_error(&error);
1901                 break;
1902         }
1903
1904 done:
1905         g_free(identifier);
1906
1907         __connman_storage_close(keyfile, FALSE);
1908
1909         return 0;
1910 }
1911
1912 static int device_save(struct connman_device *device)
1913 {
1914         GKeyFile *keyfile;
1915         gchar *identifier;
1916
1917         DBG("device %p", device);
1918
1919         keyfile = __connman_storage_open();
1920         if (keyfile == NULL)
1921                 return 0;
1922
1923         identifier = g_strdup_printf("device_%s", device->element.name);
1924         if (identifier == NULL)
1925                 goto done;
1926
1927         g_key_file_set_boolean(keyfile, identifier,
1928                                         "Powered", device->powered_persistent);
1929
1930         switch (device->mode) {
1931         case CONNMAN_DEVICE_MODE_UNKNOWN:
1932         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1933                 break;
1934         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1935         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1936                 if (device->scan_interval > 0)
1937                         g_key_file_set_integer(keyfile, identifier,
1938                                         "ScanInterval", device->scan_interval);
1939                 break;
1940         }
1941
1942 done:
1943         g_free(identifier);
1944
1945         __connman_storage_close(keyfile, TRUE);
1946
1947         return 0;
1948 }
1949
1950 static struct connman_storage device_storage = {
1951         .name           = "device",
1952         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1953         .device_load    = device_load,
1954         .device_save    = device_save,
1955 };
1956
1957 int __connman_device_init(void)
1958 {
1959         DBG("");
1960
1961         connection = connman_dbus_get_connection();
1962
1963         if (connman_storage_register(&device_storage) < 0)
1964                 connman_error("Failed to register device storage");
1965
1966         return connman_driver_register(&device_driver);
1967 }
1968
1969 void __connman_device_cleanup(void)
1970 {
1971         DBG("");
1972
1973         connman_driver_unregister(&device_driver);
1974
1975         connman_storage_unregister(&device_storage);
1976
1977         dbus_connection_unref(connection);
1978 }