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