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