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