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