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