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