Remove unused connman_device_get_control function
[framework/connectivity/connman.git] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28
29 #include "connman.h"
30
31 struct connman_device {
32         struct connman_element element;
33         enum connman_device_type type;
34         connman_bool_t offlinemode;
35         connman_bool_t blocked;
36         connman_bool_t powered;
37         connman_bool_t powered_pending;
38         connman_bool_t powered_persistent;
39         connman_bool_t scanning;
40         connman_bool_t disconnected;
41         connman_bool_t reconnect;
42         connman_uint16_t scan_interval;
43         char *name;
44         char *node;
45         char *address;
46         char *interface;
47         char *control;
48         char *ident;
49         int phyindex;
50         unsigned int connections;
51         guint scan_timeout;
52
53         struct connman_device_driver *driver;
54         void *driver_data;
55
56         char *last_network;
57         struct connman_network *network;
58         GHashTable *networks;
59 };
60
61 static gboolean device_scan_trigger(gpointer user_data)
62 {
63         struct connman_device *device = user_data;
64
65         DBG("device %p", device);
66
67         if (device->driver == NULL) {
68                 device->scan_timeout = 0;
69                 return FALSE;
70         }
71
72         if (device->driver->scan)
73                 device->driver->scan(device);
74
75         return TRUE;
76 }
77
78 static void clear_scan_trigger(struct connman_device *device)
79 {
80         if (device->scan_timeout > 0) {
81                 g_source_remove(device->scan_timeout);
82                 device->scan_timeout = 0;
83         }
84 }
85
86 static void reset_scan_trigger(struct connman_device *device)
87 {
88         clear_scan_trigger(device);
89
90         if (device->scan_interval > 0) {
91                 guint interval = device->scan_interval;
92                 device->scan_timeout = g_timeout_add_seconds(interval,
93                                         device_scan_trigger, device);
94         }
95 }
96
97 static void force_scan_trigger(struct connman_device *device)
98 {
99         clear_scan_trigger(device);
100
101         device->scan_timeout = g_timeout_add_seconds(5,
102                                         device_scan_trigger, device);
103 }
104
105 void connman_device_schedule_scan(struct connman_device *device)
106 {
107         reset_scan_trigger(device);
108 }
109
110 static const char *type2description(enum connman_device_type type)
111 {
112         switch (type) {
113         case CONNMAN_DEVICE_TYPE_UNKNOWN:
114         case CONNMAN_DEVICE_TYPE_VENDOR:
115                 break;
116         case CONNMAN_DEVICE_TYPE_ETHERNET:
117                 return "Ethernet";
118         case CONNMAN_DEVICE_TYPE_WIFI:
119                 return "Wireless";
120         case CONNMAN_DEVICE_TYPE_WIMAX:
121                 return "WiMAX";
122         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
123                 return "Bluetooth";
124         case CONNMAN_DEVICE_TYPE_GPS:
125                 return "GPS";
126         case CONNMAN_DEVICE_TYPE_CELLULAR:
127                 return "Cellular";
128         }
129
130         return NULL;
131 }
132
133 static const char *type2string(enum connman_device_type type)
134 {
135         switch (type) {
136         case CONNMAN_DEVICE_TYPE_UNKNOWN:
137         case CONNMAN_DEVICE_TYPE_VENDOR:
138                 break;
139         case CONNMAN_DEVICE_TYPE_ETHERNET:
140                 return "ethernet";
141         case CONNMAN_DEVICE_TYPE_WIFI:
142                 return "wifi";
143         case CONNMAN_DEVICE_TYPE_WIMAX:
144                 return "wimax";
145         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
146                 return "bluetooth";
147         case CONNMAN_DEVICE_TYPE_GPS:
148                 return "gps";
149         case CONNMAN_DEVICE_TYPE_CELLULAR:
150                 return "cellular";
151         }
152
153         return NULL;
154 }
155
156 enum connman_service_type __connman_device_get_service_type(struct connman_device *device)
157 {
158         enum connman_device_type type = connman_device_get_type(device);
159
160         switch (type) {
161         case CONNMAN_DEVICE_TYPE_UNKNOWN:
162         case CONNMAN_DEVICE_TYPE_VENDOR:
163         case CONNMAN_DEVICE_TYPE_GPS:
164                 break;
165         case CONNMAN_DEVICE_TYPE_ETHERNET:
166                 return CONNMAN_SERVICE_TYPE_ETHERNET;
167         case CONNMAN_DEVICE_TYPE_WIFI:
168                 return CONNMAN_SERVICE_TYPE_WIFI;
169         case CONNMAN_DEVICE_TYPE_WIMAX:
170                 return CONNMAN_SERVICE_TYPE_WIMAX;
171         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
172                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
173         case CONNMAN_DEVICE_TYPE_CELLULAR:
174                 return CONNMAN_SERVICE_TYPE_CELLULAR;
175         }
176
177         return CONNMAN_SERVICE_TYPE_UNKNOWN;
178 }
179
180 int __connman_device_enable(struct connman_device *device)
181 {
182         int err;
183
184         DBG("device %p %d", device, device->blocked);
185
186         if (!device->driver || !device->driver->enable)
187                 return -EOPNOTSUPP;
188
189         if (device->powered_pending == TRUE)
190                 return -EALREADY;
191
192         if (device->blocked == TRUE)
193                 return -ENOLINK;
194
195         err = device->driver->enable(device);
196         if (err < 0) {
197                 if (err == -EINPROGRESS) {
198                         device->powered_pending = TRUE;
199                         device->offlinemode = FALSE;
200                         if (__connman_profile_get_offlinemode() == TRUE)
201                                 __connman_profile_set_offlinemode(FALSE, FALSE);
202                 }
203                 return err;
204         }
205
206         device->powered_pending = TRUE;
207         device->powered = TRUE;
208         device->offlinemode = FALSE;
209         if (__connman_profile_get_offlinemode() == TRUE)
210                 __connman_profile_set_offlinemode(FALSE, FALSE);
211
212         __connman_technology_enable_device(device);
213
214         return 0;
215 }
216
217 int __connman_device_disable(struct connman_device *device)
218 {
219         int err;
220
221         DBG("device %p", device);
222
223         if (!device->driver || !device->driver->disable)
224                 return -EOPNOTSUPP;
225
226         if (device->powered == FALSE)
227                 return -ENOLINK;
228
229         if (device->powered_pending == FALSE)
230                 return -EALREADY;
231
232         device->reconnect = FALSE;
233
234         clear_scan_trigger(device);
235
236         g_hash_table_remove_all(device->networks);
237
238         err = device->driver->disable(device);
239         if (err < 0) {
240                 if (err == -EINPROGRESS)
241                         device->powered_pending = FALSE;
242                 return err;
243         }
244
245         device->powered_pending = FALSE;
246         device->powered = FALSE;
247
248         __connman_technology_disable_device(device);
249
250         return 0;
251 }
252
253 static int set_powered(struct connman_device *device, connman_bool_t powered)
254 {
255         DBG("device %p powered %d", device, powered);
256
257         if (powered == TRUE)
258                 return __connman_device_enable(device);
259         else
260                 return __connman_device_disable(device);
261 }
262
263 static int setup_device(struct connman_device *device)
264 {
265         DBG("device %p", device);
266
267         __connman_technology_add_device(device);
268
269         if (device->offlinemode == FALSE &&
270                                 device->powered_persistent == TRUE)
271                 __connman_device_enable(device);
272
273         return 0;
274 }
275
276 static void probe_driver(struct connman_element *element, gpointer user_data)
277 {
278         struct connman_device_driver *driver = user_data;
279
280         DBG("element %p name %s", element, element->name);
281
282         if (element->device == NULL)
283                 return;
284
285         if (element->device->driver != NULL)
286                 return;
287
288         if (driver->type != element->device->type)
289                 return;
290
291         if (driver->probe(element->device) < 0)
292                 return;
293
294         element->device->driver = driver;
295
296         __connman_element_set_driver(element);
297
298         setup_device(element->device);
299 }
300
301 static void remove_device(struct connman_device *device)
302 {
303         int err;
304
305         DBG("device %p", device);
306
307         err = __connman_device_disable(device);
308         if (err < 0 && err == -EINPROGRESS)
309                 __connman_technology_disable_device(device);
310
311         __connman_technology_remove_device(device);
312
313         if (device->driver->remove)
314                 device->driver->remove(device);
315
316         device->driver = NULL;
317 }
318
319 static void remove_driver(struct connman_element *element, gpointer user_data)
320 {
321         struct connman_device_driver *driver = user_data;
322
323         DBG("element %p name %s", element, element->name);
324
325         if (element->device == NULL)
326                 return;
327
328         if (element->device->driver == driver)
329                 remove_device(element->device);
330 }
331
332 connman_bool_t __connman_device_has_driver(struct connman_device *device)
333 {
334         if (device == NULL || device->driver == NULL)
335                 return FALSE;
336
337         return TRUE;
338 }
339
340 static GSList *driver_list = NULL;
341
342 static gint compare_priority(gconstpointer a, gconstpointer b)
343 {
344         const struct connman_device_driver *driver1 = a;
345         const struct connman_device_driver *driver2 = b;
346
347         return driver2->priority - driver1->priority;
348 }
349
350 /**
351  * connman_device_driver_register:
352  * @driver: device driver definition
353  *
354  * Register a new device driver
355  *
356  * Returns: %0 on success
357  */
358 int connman_device_driver_register(struct connman_device_driver *driver)
359 {
360         DBG("driver %p name %s", driver, driver->name);
361
362         driver_list = g_slist_insert_sorted(driver_list, driver,
363                                                         compare_priority);
364
365         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
366                                                 probe_driver, driver);
367
368         return 0;
369 }
370
371 /**
372  * connman_device_driver_unregister:
373  * @driver: device driver definition
374  *
375  * Remove a previously registered device driver
376  */
377 void connman_device_driver_unregister(struct connman_device_driver *driver)
378 {
379         DBG("driver %p name %s", driver, driver->name);
380
381         driver_list = g_slist_remove(driver_list, driver);
382
383         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
384                                                 remove_driver, driver);
385 }
386
387 static void unregister_network(gpointer data)
388 {
389         struct connman_network *network = data;
390
391         DBG("network %p", network);
392
393         connman_element_unregister((struct connman_element *) network);
394
395         __connman_network_set_device(network, NULL);
396
397         connman_network_unref(network);
398 }
399
400 static void device_destruct(struct connman_element *element)
401 {
402         struct connman_device *device = element->device;
403
404         DBG("element %p name %s", element, element->name);
405
406         clear_scan_trigger(device);
407
408         g_free(device->ident);
409         g_free(device->node);
410         g_free(device->name);
411         g_free(device->address);
412         g_free(device->control);
413         g_free(device->interface);
414
415         g_free(device->last_network);
416
417         g_hash_table_destroy(device->networks);
418         device->networks = NULL;
419 }
420
421 /**
422  * connman_device_create:
423  * @node: device node name (for example an address)
424  * @type: device type
425  *
426  * Allocate a new device of given #type and assign the #node name to it.
427  *
428  * Returns: a newly-allocated #connman_device structure
429  */
430 struct connman_device *connman_device_create(const char *node,
431                                                 enum connman_device_type type)
432 {
433         struct connman_device *device;
434         const char *str;
435         enum connman_service_type service_type;
436
437         DBG("node %s type %d", node, type);
438
439         device = g_try_new0(struct connman_device, 1);
440         if (device == NULL)
441                 return NULL;
442
443         DBG("device %p", device);
444
445         __connman_element_initialize(&device->element);
446
447         device->element.name = g_strdup(node);
448         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
449
450         device->element.device = device;
451         device->element.destruct = device_destruct;
452
453         str = type2string(type);
454         if (str != NULL)
455                 connman_element_set_string(&device->element,
456                                         CONNMAN_PROPERTY_ID_TYPE, str);
457
458         device->element.ipv4.method = CONNMAN_IPCONFIG_METHOD_DHCP;
459
460         device->type = type;
461         device->name = g_strdup(type2description(device->type));
462
463         device->powered_persistent = TRUE;
464
465         device->phyindex = -1;
466
467         service_type = __connman_device_get_service_type(device);
468         device->blocked = __connman_technology_get_blocked(service_type);
469
470         switch (type) {
471         case CONNMAN_DEVICE_TYPE_UNKNOWN:
472         case CONNMAN_DEVICE_TYPE_VENDOR:
473                 device->scan_interval = 0;
474                 break;
475         case CONNMAN_DEVICE_TYPE_ETHERNET:
476         case CONNMAN_DEVICE_TYPE_WIFI:
477                 device->scan_interval = 300;
478                 break;
479         case CONNMAN_DEVICE_TYPE_WIMAX:
480                 device->scan_interval = 0;
481                 break;
482         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
483                 device->scan_interval = 0;
484                 break;
485         case CONNMAN_DEVICE_TYPE_GPS:
486                 device->scan_interval = 0;
487                 break;
488         case CONNMAN_DEVICE_TYPE_CELLULAR:
489                 device->scan_interval = 0;
490                 break;
491         }
492
493         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
494                                                 g_free, unregister_network);
495
496         return device;
497 }
498
499 /**
500  * connman_device_ref:
501  * @device: device structure
502  *
503  * Increase reference counter of device
504  */
505 struct connman_device *connman_device_ref(struct connman_device *device)
506 {
507         if (connman_element_ref(&device->element) == NULL)
508                 return NULL;
509
510         return device;
511 }
512
513 /**
514  * connman_device_unref:
515  * @device: device structure
516  *
517  * Decrease reference counter of device
518  */
519 void connman_device_unref(struct connman_device *device)
520 {
521         connman_element_unref(&device->element);
522 }
523
524 const char *__connman_device_get_type(struct connman_device *device)
525 {
526         return type2string(device->type);
527 }
528
529 /**
530  * connman_device_get_type:
531  * @device: device structure
532  *
533  * Get type of device
534  */
535 enum connman_device_type connman_device_get_type(struct connman_device *device)
536 {
537         return device->type;
538 }
539
540 /**
541  * connman_device_set_index:
542  * @device: device structure
543  * @index: index number
544  *
545  * Set index number of device
546  */
547 void connman_device_set_index(struct connman_device *device, int index)
548 {
549         device->element.index = index;
550 }
551
552 /**
553  * connman_device_get_index:
554  * @device: device structure
555  *
556  * Get index number of device
557  */
558 int connman_device_get_index(struct connman_device *device)
559 {
560         return device->element.index;
561 }
562
563 int __connman_device_get_phyindex(struct connman_device *device)
564 {
565         return device->phyindex;
566 }
567
568 void __connman_device_set_phyindex(struct connman_device *device,
569                                                         int phyindex)
570 {
571         device->phyindex = phyindex;
572 }
573
574 /**
575  * connman_device_set_interface:
576  * @device: device structure
577  * @interface: interface name
578  * @control: control interface
579  *
580  * Set interface name of device
581  */
582 void connman_device_set_interface(struct connman_device *device,
583                                 const char *interface, const char *control)
584 {
585         g_free(device->element.devname);
586         device->element.devname = g_strdup(interface);
587
588         g_free(device->interface);
589         device->interface = g_strdup(interface);
590
591         g_free(device->control);
592         device->control = g_strdup(control);
593
594         if (device->name == NULL) {
595                 const char *str = type2description(device->type);
596                 if (str != NULL && device->interface != NULL)
597                         device->name = g_strdup_printf("%s (%s)", str,
598                                                         device->interface);
599         }
600 }
601
602 /**
603  * connman_device_set_ident:
604  * @device: device structure
605  * @ident: unique identifier
606  *
607  * Set unique identifier of device
608  */
609 void connman_device_set_ident(struct connman_device *device,
610                                                         const char *ident)
611 {
612         g_free(device->ident);
613         device->ident = g_strdup(ident);
614 }
615
616 const char *connman_device_get_ident(struct connman_device *device)
617 {
618         return device->ident;
619 }
620
621 /**
622  * connman_device_set_powered:
623  * @device: device structure
624  * @powered: powered state
625  *
626  * Change power state of device
627  */
628 int connman_device_set_powered(struct connman_device *device,
629                                                 connman_bool_t powered)
630 {
631         DBG("driver %p powered %d", device, powered);
632
633         if (device->powered == powered) {
634                 device->powered_pending = powered;
635                 return -EALREADY;
636         }
637
638         if (powered == TRUE)
639                 __connman_device_enable(device);
640         else
641                 __connman_device_disable(device);
642
643         device->powered = powered;
644         device->powered_pending = powered;
645
646         if (device->powered == TRUE)
647                 __connman_technology_enable_device(device);
648         else
649                 __connman_technology_disable_device(device);
650
651         if (device->offlinemode == TRUE && powered == TRUE)
652                 return connman_device_set_powered(device, FALSE);
653
654         if (powered == FALSE)
655                 return 0;
656
657         reset_scan_trigger(device);
658
659         if (device->driver->scan)
660                 device->driver->scan(device);
661
662         return 0;
663 }
664
665 int __connman_device_set_blocked(struct connman_device *device,
666                                                 connman_bool_t blocked)
667 {
668         connman_bool_t powered;
669
670         DBG("device %p blocked %d", device, blocked);
671
672         device->blocked = blocked;
673
674         if (device->offlinemode == TRUE)
675                 return 0;
676
677         connman_info("%s {rfkill} blocked %d", device->interface, blocked);
678
679         if (blocked == FALSE)
680                 powered = device->powered_persistent;
681         else
682                 powered = FALSE;
683
684         return set_powered(device, powered);
685 }
686
687 connman_bool_t __connman_device_get_blocked(struct connman_device *device)
688 {
689         return device->blocked;
690 }
691
692 int __connman_device_scan(struct connman_device *device)
693 {
694         if (!device->driver || !device->driver->scan)
695                 return -EOPNOTSUPP;
696
697         if (device->powered == FALSE)
698                 return -ENOLINK;
699
700         reset_scan_trigger(device);
701
702         return device->driver->scan(device);
703 }
704
705 int __connman_device_enable_persistent(struct connman_device *device)
706 {
707         int err;
708
709         DBG("device %p", device);
710
711         device->powered_persistent = TRUE;
712
713         __connman_storage_save_device(device);
714
715         err = __connman_device_enable(device);
716         if (err == 0 || err == -EINPROGRESS) {
717                 device->offlinemode = FALSE;
718                 if (__connman_profile_get_offlinemode() == TRUE) {
719                         __connman_profile_set_offlinemode(FALSE, FALSE);
720
721                         __connman_profile_save_default();
722                 }
723         }
724
725         return err;
726 }
727
728 int __connman_device_disable_persistent(struct connman_device *device)
729 {
730         DBG("device %p", device);
731
732         device->powered_persistent = FALSE;
733
734         __connman_storage_save_device(device);
735
736         return __connman_device_disable(device);
737 }
738
739 int __connman_device_disconnect(struct connman_device *device)
740 {
741         GHashTableIter iter;
742         gpointer key, value;
743
744         DBG("device %p", device);
745
746         connman_device_set_disconnected(device, TRUE);
747
748         g_hash_table_iter_init(&iter, device->networks);
749
750         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
751                 struct connman_network *network = value;
752
753                 if (__connman_network_get_connecting(network) == TRUE) {
754                         /*
755                          * Skip network in the process of connecting.
756                          * This is a workaround for WiFi networks serviced
757                          * by the supplicant plugin that hold a reference
758                          * to the network.  If we disconnect the network
759                          * here then the referenced object will not be
760                          * registered and usage (like launching DHCP client)
761                          * will fail.  There is nothing to be gained by
762                          * removing the network here anyway.
763                          */
764                         connman_warn("Skipping disconnect of %s",
765                                 connman_network_get_identifier(network));
766                         continue;
767                 }
768
769                 __connman_network_disconnect(network);
770         }
771
772         return 0;
773 }
774
775 static void mark_network_unavailable(gpointer key, gpointer value,
776                                                         gpointer user_data)
777 {
778         struct connman_network *network = value;
779
780         if (connman_network_get_connected(network) == TRUE)
781                 return;
782
783         connman_network_set_available(network, FALSE);
784 }
785
786 static gboolean remove_unavailable_network(gpointer key, gpointer value,
787                                                         gpointer user_data)
788 {
789         struct connman_network *network = value;
790
791         if (connman_network_get_connected(network) == TRUE)
792                 return FALSE;
793
794         if (connman_network_get_available(network) == TRUE)
795                 return FALSE;
796
797         return TRUE;
798 }
799
800 void __connman_device_cleanup_networks(struct connman_device *device)
801 {
802         g_hash_table_foreach_remove(device->networks,
803                                         remove_unavailable_network, NULL);
804 }
805
806 /**
807  * connman_device_set_scanning:
808  * @device: device structure
809  * @scanning: scanning state
810  *
811  * Change scanning state of device
812  */
813 int connman_device_set_scanning(struct connman_device *device,
814                                                 connman_bool_t scanning)
815 {
816         DBG("device %p scanning %d", device, scanning);
817
818         if (!device->driver || !device->driver->scan)
819                 return -EINVAL;
820
821         if (device->scanning == scanning)
822                 return -EALREADY;
823
824         device->scanning = scanning;
825
826         if (scanning == TRUE) {
827                 reset_scan_trigger(device);
828
829                 g_hash_table_foreach(device->networks,
830                                         mark_network_unavailable, NULL);
831
832                 return 0;
833         }
834
835         __connman_device_cleanup_networks(device);
836
837         if (device->connections > 0)
838                 return 0;
839
840         if (device->disconnected == TRUE)
841                 return 0;
842
843         __connman_service_auto_connect();
844
845         return 0;
846 }
847
848 /**
849  * connman_device_set_disconnected:
850  * @device: device structure
851  * @disconnected: disconnected state
852  *
853  * Change disconnected state of device (only for device with networks)
854  */
855 int connman_device_set_disconnected(struct connman_device *device,
856                                                 connman_bool_t disconnected)
857 {
858         DBG("device %p disconnected %d", device, disconnected);
859
860         if (device->disconnected == disconnected)
861                 return -EALREADY;
862
863         device->disconnected = disconnected;
864
865         if (disconnected == TRUE)
866                 force_scan_trigger(device);
867
868         return 0;
869 }
870
871 /**
872  * connman_device_get_disconnected:
873  * @device: device structure
874  *
875  * Get device disconnected state
876  */
877 connman_bool_t connman_device_get_disconnected(struct connman_device *device)
878 {
879         return device->disconnected;
880 }
881
882 /**
883  * connman_device_set_string:
884  * @device: device structure
885  * @key: unique identifier
886  * @value: string value
887  *
888  * Set string value for specific key
889  */
890 int connman_device_set_string(struct connman_device *device,
891                                         const char *key, const char *value)
892 {
893         DBG("device %p key %s value %s", device, key, value);
894
895         if (g_str_equal(key, "Address") == TRUE) {
896                 g_free(device->address);
897                 device->address = g_strdup(value);
898         } else if (g_str_equal(key, "Name") == TRUE) {
899                 g_free(device->name);
900                 device->name = g_strdup(value);
901         } else if (g_str_equal(key, "Node") == TRUE) {
902                 g_free(device->node);
903                 device->node = g_strdup(value);
904         }
905
906         return connman_element_set_string(&device->element, key, value);
907 }
908
909 /**
910  * connman_device_get_string:
911  * @device: device structure
912  * @key: unique identifier
913  *
914  * Get string value for specific key
915  */
916 const char *connman_device_get_string(struct connman_device *device,
917                                                         const char *key)
918 {
919         DBG("device %p key %s", device, key);
920
921         if (g_str_equal(key, "Address") == TRUE)
922                 return device->address;
923         else if (g_str_equal(key, "Name") == TRUE)
924                 return device->name;
925         else if (g_str_equal(key, "Node") == TRUE)
926                 return device->node;
927         else if (g_str_equal(key, "Interface") == TRUE)
928                 return device->interface;
929
930         return connman_element_get_string(&device->element, key);
931 }
932
933 static void set_offlinemode(struct connman_element *element, gpointer user_data)
934 {
935         struct connman_device *device = element->device;
936         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
937         connman_bool_t powered;
938
939         DBG("element %p name %s", element, element->name);
940
941         if (device == NULL)
942                 return;
943
944         device->offlinemode = offlinemode;
945
946         if (device->blocked == TRUE)
947                 return;
948
949         powered = (offlinemode == TRUE) ? FALSE : TRUE;
950
951         if (device->powered == powered)
952                 return;
953
954         if (device->powered_persistent == FALSE)
955                 powered = FALSE;
956
957         set_powered(device, powered);
958 }
959
960 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
961 {
962         DBG("offlinmode %d", offlinemode);
963
964         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
965                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
966
967         __connman_notifier_offlinemode(offlinemode);
968
969         return 0;
970 }
971
972 void __connman_device_increase_connections(struct connman_device *device)
973 {
974         if (device == NULL)
975                 return;
976
977         device->connections++;
978 }
979
980 void __connman_device_decrease_connections(struct connman_device *device)
981 {
982         if (device == NULL)
983                 return;
984
985         device->connections--;
986 }
987
988 /**
989  * connman_device_add_network:
990  * @device: device structure
991  * @network: network structure
992  *
993  * Add new network to the device
994  */
995 int connman_device_add_network(struct connman_device *device,
996                                         struct connman_network *network)
997 {
998         const char *identifier = connman_network_get_identifier(network);
999         int err;
1000
1001         DBG("device %p network %p", device, network);
1002
1003         if (identifier == NULL)
1004                 return -EINVAL;
1005
1006         __connman_network_set_device(network, device);
1007
1008         err = connman_element_register((struct connman_element *) network,
1009                                                         &device->element);
1010         if (err < 0) {
1011                 __connman_network_set_device(network, NULL);
1012                 return err;
1013         }
1014
1015         g_hash_table_insert(device->networks, g_strdup(identifier),
1016                                                                 network);
1017
1018         return 0;
1019 }
1020
1021 /**
1022  * connman_device_get_network:
1023  * @device: device structure
1024  * @identifier: network identifier
1025  *
1026  * Get network for given identifier
1027  */
1028 struct connman_network *connman_device_get_network(struct connman_device *device,
1029                                                         const char *identifier)
1030 {
1031         DBG("device %p identifier %s", device, identifier);
1032
1033         return g_hash_table_lookup(device->networks, identifier);
1034 }
1035
1036 /**
1037  * connman_device_remove_network:
1038  * @device: device structure
1039  * @identifier: network identifier
1040  *
1041  * Remove network for given identifier
1042  */
1043 int connman_device_remove_network(struct connman_device *device,
1044                                                         const char *identifier)
1045 {
1046         DBG("device %p identifier %s", device, identifier);
1047
1048         g_hash_table_remove(device->networks, identifier);
1049
1050         return 0;
1051 }
1052
1053 void connman_device_remove_all_networks(struct connman_device *device)
1054 {
1055         g_hash_table_remove_all(device->networks);
1056 }
1057
1058 void __connman_device_set_network(struct connman_device *device,
1059                                         struct connman_network *network)
1060 {
1061         const char *name;
1062
1063         if (device == NULL)
1064                 return;
1065
1066         if (device->network == network)
1067                 return;
1068
1069         if (device->network != NULL)
1070                 connman_network_unref(device->network);
1071
1072         if (network != NULL) {
1073                 name = connman_network_get_string(network,
1074                                                 CONNMAN_PROPERTY_ID_NAME);
1075                 g_free(device->last_network);
1076                 device->last_network = g_strdup(name);
1077
1078                 device->network = connman_network_ref(network);
1079         } else {
1080                 g_free(device->last_network);
1081                 device->last_network = NULL;
1082
1083                 device->network = NULL;
1084         }
1085 }
1086
1087 void __connman_device_set_reconnect(struct connman_device *device,
1088                                                 connman_bool_t reconnect)
1089 {
1090         device->reconnect = reconnect;
1091 }
1092
1093 connman_bool_t  __connman_device_get_reconnect(
1094                                 struct connman_device *device)
1095 {
1096         return device->reconnect;
1097 }
1098
1099 /**
1100  * connman_device_register:
1101  * @device: device structure
1102  *
1103  * Register device with the system
1104  */
1105 int connman_device_register(struct connman_device *device)
1106 {
1107         __connman_storage_load_device(device);
1108
1109         device->offlinemode = __connman_profile_get_offlinemode();
1110
1111         return connman_element_register(&device->element, NULL);
1112 }
1113
1114 /**
1115  * connman_device_unregister:
1116  * @device: device structure
1117  *
1118  * Unregister device with the system
1119  */
1120 void connman_device_unregister(struct connman_device *device)
1121 {
1122         __connman_storage_save_device(device);
1123
1124         connman_element_unregister(&device->element);
1125 }
1126
1127 /**
1128  * connman_device_get_data:
1129  * @device: device structure
1130  *
1131  * Get private device data pointer
1132  */
1133 void *connman_device_get_data(struct connman_device *device)
1134 {
1135         return device->driver_data;
1136 }
1137
1138 /**
1139  * connman_device_set_data:
1140  * @device: device structure
1141  * @data: data pointer
1142  *
1143  * Set private device data pointer
1144  */
1145 void connman_device_set_data(struct connman_device *device, void *data)
1146 {
1147         device->driver_data = data;
1148 }
1149
1150 static gboolean match_driver(struct connman_device *device,
1151                                         struct connman_device_driver *driver)
1152 {
1153         if (device->type == driver->type ||
1154                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1155                 return TRUE;
1156
1157         return FALSE;
1158 }
1159
1160 static int device_probe(struct connman_element *element)
1161 {
1162         struct connman_device *device = element->device;
1163         GSList *list;
1164
1165         DBG("element %p name %s", element, element->name);
1166
1167         if (device == NULL)
1168                 return -ENODEV;
1169
1170         if (device->driver != NULL)
1171                 return -EALREADY;
1172
1173         for (list = driver_list; list; list = list->next) {
1174                 struct connman_device_driver *driver = list->data;
1175
1176                 if (match_driver(device, driver) == FALSE)
1177                         continue;
1178
1179                 DBG("driver %p name %s", driver, driver->name);
1180
1181                 if (driver->probe(device) == 0) {
1182                         device->driver = driver;
1183                         break;
1184                 }
1185         }
1186
1187         if (device->driver == NULL)
1188                 return -ENODEV;
1189
1190         return setup_device(device);
1191 }
1192
1193 static void device_remove(struct connman_element *element)
1194 {
1195         struct connman_device *device = element->device;
1196
1197         DBG("element %p name %s", element, element->name);
1198
1199         if (device == NULL)
1200                 return;
1201
1202         if (device->driver == NULL)
1203                 return;
1204
1205         remove_device(device);
1206 }
1207
1208 static struct connman_driver device_driver = {
1209         .name           = "device",
1210         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1211         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1212         .probe          = device_probe,
1213         .remove         = device_remove,
1214 };
1215
1216 static int device_load(struct connman_device *device)
1217 {
1218         const char *ident = __connman_profile_active_ident();
1219         GKeyFile *keyfile;
1220         GError *error = NULL;
1221         gchar *identifier;
1222         connman_bool_t powered;
1223         int val;
1224
1225         DBG("device %p", device);
1226
1227         keyfile = __connman_storage_open_profile(ident);
1228         if (keyfile == NULL)
1229                 return 0;
1230
1231         identifier = g_strdup_printf("device_%s", device->element.name);
1232         if (identifier == NULL)
1233                 goto done;
1234
1235         powered = g_key_file_get_boolean(keyfile, identifier,
1236                                                 "Powered", &error);
1237         if (error == NULL)
1238                 device->powered_persistent = powered;
1239         g_clear_error(&error);
1240
1241         val = g_key_file_get_integer(keyfile, identifier,
1242                                                 "ScanInterval", &error);
1243         if (error == NULL)
1244                 device->scan_interval = val;
1245         g_clear_error(&error);
1246
1247 done:
1248         g_free(identifier);
1249
1250         __connman_storage_close_profile(ident, keyfile, FALSE);
1251
1252         return 0;
1253 }
1254
1255 static int device_save(struct connman_device *device)
1256 {
1257         const char *ident = __connman_profile_active_ident();
1258         GKeyFile *keyfile;
1259         gchar *identifier;
1260
1261         DBG("device %p", device);
1262
1263         keyfile = __connman_storage_open_profile(ident);
1264         if (keyfile == NULL)
1265                 return 0;
1266
1267         identifier = g_strdup_printf("device_%s", device->element.name);
1268         if (identifier == NULL)
1269                 goto done;
1270
1271         g_key_file_set_boolean(keyfile, identifier,
1272                                         "Powered", device->powered_persistent);
1273
1274         g_key_file_set_integer(keyfile, identifier,
1275                                         "ScanInterval", device->scan_interval);
1276
1277 done:
1278         g_free(identifier);
1279
1280         __connman_storage_close_profile(ident, keyfile, TRUE);
1281
1282         return 0;
1283 }
1284
1285 static struct connman_storage device_storage = {
1286         .name           = "device",
1287         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1288         .device_load    = device_load,
1289         .device_save    = device_save,
1290 };
1291
1292 int __connman_device_init(void)
1293 {
1294         DBG("");
1295
1296         if (connman_storage_register(&device_storage) < 0)
1297                 connman_error("Failed to register device storage");
1298
1299         return connman_driver_register(&device_driver);
1300 }
1301
1302 void __connman_device_cleanup(void)
1303 {
1304         DBG("");
1305
1306         connman_driver_unregister(&device_driver);
1307
1308         connman_storage_unregister(&device_storage);
1309 }