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