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