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