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