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