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