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