Call into device specific connect and disconnect callbacks
[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 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 DBusMessage *join_network(DBusConnection *conn,
530                                         DBusMessage *msg, void *data)
531 {
532         struct connman_device *device = data;
533         struct connman_network *network;
534         enum connman_network_type type;
535         DBusMessageIter iter, array;
536         int err, index;
537
538         DBG("conn %p", conn);
539
540         if (__connman_security_check_privilege(msg,
541                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
542                 return __connman_error_permission_denied(msg);
543
544         if (!device->driver || !device->driver->join)
545                 return __connman_error_not_supported(msg);
546
547         dbus_message_iter_init(msg, &iter);
548         dbus_message_iter_recurse(&iter, &array);
549
550         switch (device->type) {
551         case CONNMAN_DEVICE_TYPE_WIFI:
552                 type = CONNMAN_NETWORK_TYPE_WIFI;
553                 break;
554         default:
555                 return __connman_error_not_supported(msg);
556         }
557
558         network = connman_network_create("00_00_00_00_00_00", type);
559         if (network == NULL)
560                 return __connman_error_failed(msg, ENOMEM);
561
562         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
563                 DBusMessageIter entry, value;
564                 const char *key, *str;
565
566                 dbus_message_iter_recurse(&array, &entry);
567                 dbus_message_iter_get_basic(&entry, &key);
568
569                 dbus_message_iter_next(&entry);
570                 dbus_message_iter_recurse(&entry, &value);
571
572                 switch (dbus_message_iter_get_arg_type(&value)) {
573                 case DBUS_TYPE_STRING:
574                         dbus_message_iter_get_basic(&value, &str);
575                         if (g_str_equal(key, "WiFi.SSID") == TRUE)
576                                 connman_network_set_blob(network, key,
577                                                         str, strlen(str));
578                         else
579                                 connman_network_set_string(network, key, str);
580                         break;
581                 }
582
583                 dbus_message_iter_next(&array);
584         }
585
586         index = connman_device_get_index(device);
587         connman_network_set_index(network, index);
588
589         connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
590
591         err = device->driver->join(device, network);
592
593         connman_network_unref(network);
594
595         if (err < 0)
596                 return __connman_error_failed(msg, -err);
597
598         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
599 }
600
601 static DBusMessage *create_network(DBusConnection *conn,
602                                         DBusMessage *msg, void *data)
603 {
604         DBG("conn %p", conn);
605
606         if (__connman_security_check_privilege(msg,
607                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
608                 return __connman_error_permission_denied(msg);
609
610         return __connman_error_invalid_arguments(msg);
611 }
612
613 static DBusMessage *remove_network(DBusConnection *conn,
614                                         DBusMessage *msg, void *data)
615 {
616         DBG("conn %p", conn);
617
618         if (__connman_security_check_privilege(msg,
619                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
620                 return __connman_error_permission_denied(msg);
621
622         return __connman_error_invalid_arguments(msg);
623 }
624
625 static DBusMessage *propose_scan(DBusConnection *conn,
626                                         DBusMessage *msg, void *data)
627 {
628         struct connman_device *device = data;
629         int err;
630
631         DBG("conn %p", conn);
632
633         switch (device->mode) {
634         case CONNMAN_DEVICE_MODE_UNKNOWN:
635         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
636                 return __connman_error_not_supported(msg);
637         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
638         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
639                 break;
640         }
641
642         if (!device->driver || !device->driver->scan)
643                 return __connman_error_not_supported(msg);
644
645         if (device->powered == FALSE)
646                 return __connman_error_failed(msg, EINVAL);
647
648         err = device->driver->scan(device);
649         if (err < 0)
650                 return __connman_error_failed(msg, -err);
651
652         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
653 }
654
655 static GDBusMethodTable device_methods[] = {
656         { "GetProperties", "",      "a{sv}", get_properties },
657         { "SetProperty",   "sv",    "",      set_property   },
658         { "JoinNetwork",   "a{sv}", "",      join_network   },
659         { "CreateNetwork", "a{sv}", "o",     create_network },
660         { "RemoveNetwork", "o",     "",      remove_network },
661         { "ProposeScan",   "",      "",      propose_scan   },
662         { },
663 };
664
665 static GDBusSignalTable device_signals[] = {
666         { "PropertyChanged", "sv" },
667         { },
668 };
669
670 static DBusConnection *connection;
671
672 static void append_devices(DBusMessageIter *entry)
673 {
674         DBusMessageIter value, iter;
675         const char *key = "Devices";
676
677         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
678
679         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
680                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
681                                                                 &value);
682
683         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
684                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
685         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
686         dbus_message_iter_close_container(&value, &iter);
687
688         dbus_message_iter_close_container(entry, &value);
689 }
690
691 static void emit_devices_signal(void)
692 {
693         DBusMessage *signal;
694         DBusMessageIter entry;
695
696         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
697                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
698         if (signal == NULL)
699                 return;
700
701         dbus_message_iter_init_append(signal, &entry);
702
703         append_devices(&entry);
704
705         g_dbus_send_message(connection, signal);
706 }
707
708 static int register_interface(struct connman_element *element)
709 {
710         struct connman_device *device = element->device;
711
712         DBG("element %p name %s", element, element->name);
713
714         if (g_dbus_register_interface(connection, element->path,
715                                         CONNMAN_DEVICE_INTERFACE,
716                                         device_methods, device_signals,
717                                         NULL, device, NULL) == FALSE) {
718                 connman_error("Failed to register %s device", element->path);
719                 return -EIO;
720         }
721
722         device->registered = TRUE;
723
724         emit_devices_signal();
725
726         return 0;
727 }
728
729 static void unregister_interface(struct connman_element *element)
730 {
731         struct connman_device *device = element->device;
732
733         DBG("element %p name %s", element, element->name);
734
735         device->registered = FALSE;
736
737         emit_devices_signal();
738
739         g_dbus_unregister_interface(connection, element->path,
740                                                 CONNMAN_DEVICE_INTERFACE);
741 }
742
743 static void device_enable(struct connman_device *device)
744 {
745         DBG("device %p", device);
746
747         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
748                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
749                 return;
750
751         if (device->powered == TRUE)
752                 return;
753
754         if (device->driver->enable) {
755                 device->driver->enable(device);
756                 __connman_notifier_device_type_increase(device->type);
757         }
758 }
759
760 static void device_disable(struct connman_device *device)
761 {
762         DBG("device %p", device);
763
764         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
765                 return;
766
767         if (device->powered == FALSE)
768                 return;
769
770         g_hash_table_remove_all(device->networks);
771
772         if (device->driver->disable) {
773                 device->driver->disable(device);
774                 __connman_notifier_device_type_decrease(device->type);
775         }
776 }
777
778 static int setup_device(struct connman_device *device)
779 {
780         int err;
781
782         DBG("device %p", device);
783
784         err = register_interface(&device->element);
785         if (err < 0) {
786                 if (device->driver->remove)
787                         device->driver->remove(device);
788                 device->driver = NULL;
789                 return err;
790         }
791
792         switch (device->mode) {
793         case CONNMAN_DEVICE_MODE_UNKNOWN:
794         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
795         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
796                 break;
797         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
798                 if (device->secondary == FALSE)
799                         __connman_profile_add_device(device);
800                 break;
801         }
802
803         device_enable(device);
804
805         return 0;
806 }
807
808 static void probe_driver(struct connman_element *element, gpointer user_data)
809 {
810         struct connman_device_driver *driver = user_data;
811
812         DBG("element %p name %s", element, element->name);
813
814         if (element->device == NULL)
815                 return;
816
817         if (element->device->driver != NULL)
818                 return;
819
820         if (driver->type != element->device->type)
821                 return;
822
823         if (driver->probe(element->device) < 0)
824                 return;
825
826         element->device->driver = driver;
827
828         setup_device(element->device);
829 }
830
831 static void remove_device(struct connman_device *device)
832 {
833         DBG("device %p", device);
834
835         device_disable(device);
836
837         switch (device->mode) {
838         case CONNMAN_DEVICE_MODE_UNKNOWN:
839         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
840         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
841                 break;
842         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
843                 if (device->secondary == FALSE)
844                         __connman_profile_remove_device(device);
845                 break;
846         }
847
848         unregister_interface(&device->element);
849
850         if (device->driver->remove)
851                 device->driver->remove(device);
852
853         device->driver = NULL;
854 }
855
856 static void remove_driver(struct connman_element *element, gpointer user_data)
857 {
858         struct connman_device_driver *driver = user_data;
859
860         DBG("element %p name %s", element, element->name);
861
862         if (element->device == NULL)
863                 return;
864
865         if (element->device->driver == driver)
866                 remove_device(element->device);
867 }
868
869 connman_bool_t __connman_device_has_driver(struct connman_device *device)
870 {
871         if (device == NULL || device->driver == NULL)
872                 return FALSE;
873
874         return device->registered;
875 }
876
877 static GSList *driver_list = NULL;
878
879 static gint compare_priority(gconstpointer a, gconstpointer b)
880 {
881         const struct connman_device_driver *driver1 = a;
882         const struct connman_device_driver *driver2 = b;
883
884         return driver2->priority - driver1->priority;
885 }
886
887 /**
888  * connman_device_driver_register:
889  * @driver: device driver definition
890  *
891  * Register a new device driver
892  *
893  * Returns: %0 on success
894  */
895 int connman_device_driver_register(struct connman_device_driver *driver)
896 {
897         DBG("driver %p name %s", driver, driver->name);
898
899         driver_list = g_slist_insert_sorted(driver_list, driver,
900                                                         compare_priority);
901
902         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
903                                                 probe_driver, driver);
904
905         return 0;
906 }
907
908 /**
909  * connman_device_driver_unregister:
910  * @driver: device driver definition
911  *
912  * Remove a previously registered device driver
913  */
914 void connman_device_driver_unregister(struct connman_device_driver *driver)
915 {
916         DBG("driver %p name %s", driver, driver->name);
917
918         driver_list = g_slist_remove(driver_list, driver);
919
920         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
921                                                 remove_driver, driver);
922 }
923
924 static void unregister_network(gpointer data)
925 {
926         struct connman_network *network = data;
927
928         DBG("network %p", network);
929
930         connman_element_unregister((struct connman_element *) network);
931
932         connman_network_unref(network);
933 }
934
935 static void device_destruct(struct connman_element *element)
936 {
937         struct connman_device *device = element->device;
938
939         DBG("element %p name %s", element, element->name);
940
941         g_free(device->ident);
942         g_free(device->node);
943         g_free(device->name);
944         g_free(device->address);
945         g_free(device->interface);
946
947         g_free(device->last_network);
948
949         g_hash_table_destroy(device->networks);
950         device->networks = NULL;
951 }
952
953 /**
954  * connman_device_create:
955  * @node: device node name (for example an address)
956  * @type: device type
957  *
958  * Allocate a new device of given #type and assign the #node name to it.
959  *
960  * Returns: a newly-allocated #connman_device structure
961  */
962 struct connman_device *connman_device_create(const char *node,
963                                                 enum connman_device_type type)
964 {
965         struct connman_device *device;
966         const char *str;
967
968         DBG("node %s type %d", node, type);
969
970         device = g_try_new0(struct connman_device, 1);
971         if (device == NULL)
972                 return NULL;
973
974         DBG("device %p", device);
975
976         __connman_element_initialize(&device->element);
977
978         device->element.name = g_strdup(node);
979         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
980
981         device->element.device = device;
982         device->element.destruct = device_destruct;
983
984         str = type2string(type);
985         if (str != NULL)
986                 connman_element_set_string(&device->element,
987                                         CONNMAN_PROPERTY_ID_TYPE, str);
988
989         device->element.ipv4.method = CONNMAN_IPV4_METHOD_DHCP;
990
991         device->type      = type;
992         device->name      = g_strdup(type2description(device->type));
993         device->mode      = CONNMAN_DEVICE_MODE_UNKNOWN;
994         device->policy    = CONNMAN_DEVICE_POLICY_AUTO;
995         device->secondary = FALSE;
996
997         switch (type) {
998         case CONNMAN_DEVICE_TYPE_UNKNOWN:
999         case CONNMAN_DEVICE_TYPE_VENDOR:
1000                 device->priority = 0;
1001                 device->scan_interval = 0;
1002                 break;
1003         case CONNMAN_DEVICE_TYPE_ETHERNET:
1004         case CONNMAN_DEVICE_TYPE_WIFI:
1005                 device->priority = 100;
1006                 device->scan_interval = 300;
1007                 break;
1008         case CONNMAN_DEVICE_TYPE_WIMAX:
1009                 device->priority = 20;
1010                 device->scan_interval = 0;
1011                 break;
1012         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
1013                 device->priority = 50;
1014                 device->scan_interval = 0;
1015                 break;
1016         case CONNMAN_DEVICE_TYPE_GPS:
1017                 device->priority = 0;
1018                 device->scan_interval = 0;
1019                 break;
1020         case CONNMAN_DEVICE_TYPE_HSO:
1021         case CONNMAN_DEVICE_TYPE_NOZOMI:
1022         case CONNMAN_DEVICE_TYPE_HUAWEI:
1023         case CONNMAN_DEVICE_TYPE_NOVATEL:
1024                 device->priority = 60;
1025                 device->scan_interval = 0;
1026                 break;
1027         }
1028
1029         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
1030                                                 g_free, unregister_network);
1031
1032         return device;
1033 }
1034
1035 /**
1036  * connman_device_ref:
1037  * @device: device structure
1038  *
1039  * Increase reference counter of device
1040  */
1041 struct connman_device *connman_device_ref(struct connman_device *device)
1042 {
1043         if (connman_element_ref(&device->element) == NULL)
1044                 return NULL;
1045
1046         return device;
1047 }
1048
1049 /**
1050  * connman_device_unref:
1051  * @device: device structure
1052  *
1053  * Decrease reference counter of device
1054  */
1055 void connman_device_unref(struct connman_device *device)
1056 {
1057         connman_element_unref(&device->element);
1058 }
1059
1060 const char *__connman_device_get_type(struct connman_device *device)
1061 {
1062         return type2string(device->type);
1063 }
1064
1065 /**
1066  * connman_device_get_type:
1067  * @device: device structure
1068  *
1069  * Get type of device
1070  */
1071 enum connman_device_type connman_device_get_type(struct connman_device *device)
1072 {
1073         return device->type;
1074 }
1075
1076 /**
1077  * connman_device_get_name:
1078  * @device: device structure
1079  *
1080  * Get unique name of device
1081  */
1082 const char *connman_device_get_name(struct connman_device *device)
1083 {
1084         return device->element.name;
1085 }
1086
1087 /**
1088  * connman_device_get_path:
1089  * @device: device structure
1090  *
1091  * Get path name of device
1092  */
1093 const char *connman_device_get_path(struct connman_device *device)
1094 {
1095         return device->element.path;
1096 }
1097
1098 /**
1099  * connman_device_set_index:
1100  * @device: device structure
1101  * @index: index number
1102  *
1103  * Set index number of device
1104  */
1105 void connman_device_set_index(struct connman_device *device, int index)
1106 {
1107         device->element.index = index;
1108 }
1109
1110 /**
1111  * connman_device_get_index:
1112  * @device: device structure
1113  *
1114  * Get index number of device
1115  */
1116 int connman_device_get_index(struct connman_device *device)
1117 {
1118         return device->element.index;
1119 }
1120
1121 /**
1122  * connman_device_set_interface:
1123  * @device: device structure
1124  * @interface: interface name
1125  *
1126  * Set interface name of device
1127  */
1128 void connman_device_set_interface(struct connman_device *device,
1129                                                         const char *interface)
1130 {
1131         g_free(device->element.devname);
1132         device->element.devname = g_strdup(interface);
1133
1134         g_free(device->interface);
1135         device->interface = g_strdup(interface);
1136
1137         if (device->name == NULL) {
1138                 const char *str = type2description(device->type);
1139                 if (str != NULL && device->interface != NULL)
1140                         device->name = g_strdup_printf("%s (%s)", str,
1141                                                         device->interface);
1142         }
1143 }
1144
1145 /**
1146  * connman_device_get_interface:
1147  * @device: device structure
1148  *
1149  * Get interface name of device
1150  */
1151 const char *connman_device_get_interface(struct connman_device *device)
1152 {
1153         return device->interface;
1154 }
1155
1156 /**
1157  * connman_device_set_ident:
1158  * @device: device structure
1159  * @ident: unique identifier
1160  *
1161  * Set unique identifier of device
1162  */
1163 void connman_device_set_ident(struct connman_device *device,
1164                                                         const char *ident)
1165 {
1166         g_free(device->ident);
1167         device->ident = g_strdup(ident);
1168 }
1169
1170 const char *__connman_device_get_ident(struct connman_device *device)
1171 {
1172         return device->ident;
1173 }
1174
1175 /**
1176  * connman_device_set_policy:
1177  * @device: device structure
1178  * @policy: power and connection policy
1179  *
1180  * Change power and connection policy of device
1181  */
1182 void connman_device_set_policy(struct connman_device *device,
1183                                         enum connman_device_policy policy)
1184 {
1185         device->policy = policy;
1186 }
1187
1188 /**
1189  * connman_device_set_mode:
1190  * @device: device structure
1191  * @mode: network mode
1192  *
1193  * Change network mode of device
1194  */
1195 void connman_device_set_mode(struct connman_device *device,
1196                                                 enum connman_device_mode mode)
1197 {
1198         device->mode = mode;
1199 }
1200
1201 /**
1202  * connman_device_get_mode:
1203  * @device: device structure
1204  *
1205  * Get network mode of device
1206  */
1207 enum connman_device_mode connman_device_get_mode(struct connman_device *device)
1208 {
1209         return device->mode;
1210 }
1211
1212 /**
1213  * connman_device_set_secondary:
1214  * @device: device structure
1215  * @secondary: secondary value
1216  *
1217  * Change secondary value of device
1218  */
1219 void connman_device_set_secondary(struct connman_device *device,
1220                                                 connman_bool_t secondary)
1221 {
1222         device->secondary = secondary;
1223 }
1224
1225 /**
1226  * connman_device_get_secondary:
1227  * @device: device structure
1228  *
1229  * Get secondary value of device
1230  */
1231 connman_bool_t connman_device_get_secondary(struct connman_device *device)
1232 {
1233         return device->secondary;
1234 }
1235
1236 /**
1237  * connman_device_set_powered:
1238  * @device: device structure
1239  * @powered: powered state
1240  *
1241  * Change power state of device
1242  */
1243 int connman_device_set_powered(struct connman_device *device,
1244                                                 connman_bool_t powered)
1245 {
1246         DBusMessage *signal;
1247         DBusMessageIter entry, value;
1248         const char *key = "Powered";
1249
1250         DBG("driver %p powered %d", device, powered);
1251
1252         if (device->powered == powered)
1253                 return -EALREADY;
1254
1255         device->powered = powered;
1256
1257         if (device->registered == FALSE)
1258                 return 0;
1259
1260         signal = dbus_message_new_signal(device->element.path,
1261                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1262         if (signal == NULL)
1263                 return 0;
1264
1265         dbus_message_iter_init_append(signal, &entry);
1266
1267         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1268
1269         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1270                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1271         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
1272         dbus_message_iter_close_container(&entry, &value);
1273
1274         g_dbus_send_message(connection, signal);
1275
1276         if (powered == FALSE)
1277                 return 0;
1278
1279         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1280                 return 0;
1281
1282         if (device->scan_timeout > 0) {
1283                 g_source_remove(device->scan_timeout);
1284                 device->scan_timeout = 0;
1285         }
1286
1287         if (device->scan_interval > 0) {
1288                 guint interval = device->scan_interval;
1289                 device->scan_timeout = g_timeout_add_seconds(interval,
1290                                         device_scan_trigger, device);
1291         }
1292
1293         if (device->driver->scan)
1294                 device->driver->scan(device);
1295
1296         return 0;
1297 }
1298
1299 /**
1300  * connman_device_set_carrier:
1301  * @device: device structure
1302  * @carrier: carrier state
1303  *
1304  * Change carrier state of device (only for device without scanning)
1305  */
1306 int connman_device_set_carrier(struct connman_device *device,
1307                                                 connman_bool_t carrier)
1308 {
1309         DBG("driver %p carrier %d", device, carrier);
1310
1311         switch (device->mode) {
1312         case CONNMAN_DEVICE_MODE_UNKNOWN:
1313         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1314         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1315                 return -EINVAL;
1316         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1317                 break;
1318         }
1319
1320         if (device->carrier == carrier)
1321                 return -EALREADY;
1322
1323         device->carrier = carrier;
1324
1325         return set_carrier(device, device->carrier);
1326 }
1327
1328 int __connman_device_connect(struct connman_device *device)
1329 {
1330         DBG("device %p", device);
1331
1332         if (device->disconnected == FALSE)
1333                 return -EINVAL;
1334
1335         if (device->driver && device->driver->connect)
1336                 device->driver->connect(device);
1337
1338         return 0;
1339 }
1340
1341 int __connman_device_disconnect(struct connman_device *device)
1342 {
1343         GHashTableIter iter;
1344         gpointer key, value;
1345
1346         DBG("device %p", device);
1347
1348         connman_device_set_disconnected(device, TRUE);
1349
1350         g_hash_table_iter_init(&iter, device->networks);
1351
1352         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1353                 struct connman_network *network = value;
1354
1355                 if (connman_network_get_connected(network) == TRUE)
1356                         __connman_network_disconnect(network);
1357         }
1358
1359         if (device->driver && device->driver->disconnect)
1360                 device->driver->disconnect(device);
1361
1362         return 0;
1363 }
1364
1365 static void connect_known_network(struct connman_device *device)
1366 {
1367         struct connman_network *network = NULL;
1368         GHashTableIter iter;
1369         gpointer key, value;
1370         const char *name;
1371         unsigned int count = 0;
1372
1373         DBG("device %p", device);
1374
1375         g_hash_table_iter_init(&iter, device->networks);
1376
1377         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1378                 connman_uint8_t old_strength, new_strength;
1379
1380                 count++;
1381
1382                 if (connman_network_get_available(value) == FALSE)
1383                         continue;
1384
1385                 name = connman_network_get_string(value,
1386                                                 CONNMAN_PROPERTY_ID_NAME);
1387                 if (name != NULL && device->last_network != NULL) {
1388                         if (g_str_equal(name, device->last_network) == TRUE) {
1389                                 network = value;
1390                                 break;
1391                         }
1392                 }
1393
1394                 if (network == NULL) {
1395                         network = value;
1396                         continue;
1397                 }
1398
1399                 old_strength = connman_network_get_uint8(network,
1400                                                 CONNMAN_PROPERTY_ID_STRENGTH);
1401                 new_strength = connman_network_get_uint8(value,
1402                                                 CONNMAN_PROPERTY_ID_STRENGTH);
1403
1404                 if (new_strength > old_strength)
1405                         network = value;
1406         }
1407
1408         if (network != NULL) {
1409                 int err;
1410
1411                 name = connman_network_get_string(value,
1412                                                 CONNMAN_PROPERTY_ID_NAME);
1413                 if (name != NULL) {
1414                         err = __connman_network_connect(network);
1415                         if (err == 0 || err == -EINPROGRESS)
1416                                 return;
1417                 }
1418         }
1419
1420         if (count > 0)
1421                 return;
1422
1423         if (device->driver && device->driver->scan)
1424                 device->driver->scan(device);
1425 }
1426
1427 static void mark_network_unavailable(gpointer key, gpointer value,
1428                                                         gpointer user_data)
1429 {
1430         struct connman_network *network = value;
1431
1432         if (connman_network_get_connected(network) == TRUE)
1433                 return;
1434
1435         connman_network_set_available(network, FALSE);
1436 }
1437
1438 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1439                                                         gpointer user_data)
1440 {
1441         struct connman_network *network = value;
1442
1443         if (connman_network_get_connected(network) == TRUE)
1444                 return FALSE;
1445
1446         if (connman_network_get_available(network) == TRUE)
1447                 return FALSE;
1448
1449         return TRUE;
1450 }
1451
1452 /**
1453  * connman_device_set_scanning:
1454  * @device: device structure
1455  * @scanning: scanning state
1456  *
1457  * Change scanning state of device
1458  */
1459 int connman_device_set_scanning(struct connman_device *device,
1460                                                 connman_bool_t scanning)
1461 {
1462         DBusMessage *signal;
1463         DBusMessageIter entry, value;
1464         const char *key = "Scanning";
1465
1466         DBG("driver %p scanning %d", device, scanning);
1467
1468         if (!device->driver || !device->driver->scan)
1469                 return -EINVAL;
1470
1471         if (device->scanning == scanning)
1472                 return -EALREADY;
1473
1474         device->scanning = scanning;
1475
1476         signal = dbus_message_new_signal(device->element.path,
1477                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1478         if (signal == NULL)
1479                 return 0;
1480
1481         dbus_message_iter_init_append(signal, &entry);
1482
1483         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1484
1485         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1486                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1487         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1488         dbus_message_iter_close_container(&entry, &value);
1489
1490         g_dbus_send_message(connection, signal);
1491
1492         if (scanning == TRUE) {
1493                 if (device->scan_timeout > 0) {
1494                         g_source_remove(device->scan_timeout);
1495                         device->scan_timeout = 0;
1496                 }
1497
1498                 if (device->scan_interval > 0) {
1499                         guint interval = device->scan_interval;
1500                         device->scan_timeout = g_timeout_add_seconds(interval,
1501                                                 device_scan_trigger, device);
1502                 }
1503
1504                 g_hash_table_foreach(device->networks,
1505                                         mark_network_unavailable, NULL);
1506                 return 0;
1507         }
1508
1509         g_hash_table_foreach_remove(device->networks,
1510                                         remove_unavailable_network, NULL);
1511
1512         if (device->connections > 0)
1513                 return 0;
1514
1515         if (device->disconnected == TRUE)
1516                 return 0;
1517
1518         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1519                 return 0;
1520
1521         connect_known_network(device);
1522
1523         return 0;
1524 }
1525
1526 /**
1527  * connman_device_set_disconnected:
1528  * @device: device structure
1529  * @disconnected: disconnected state
1530  *
1531  * Change disconnected state of device (only for device with networks)
1532  */
1533 int connman_device_set_disconnected(struct connman_device *device,
1534                                                 connman_bool_t disconnected)
1535 {
1536         DBG("driver %p disconnected %d", device, disconnected);
1537
1538         switch (device->mode) {
1539         case CONNMAN_DEVICE_MODE_UNKNOWN:
1540         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1541                 return -EINVAL;
1542         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1543         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1544                 break;
1545         }
1546
1547         if (device->disconnected == disconnected)
1548                 return -EALREADY;
1549
1550         device->disconnected = disconnected;
1551
1552         return 0;
1553 }
1554
1555 /**
1556  * connman_device_set_string:
1557  * @device: device structure
1558  * @key: unique identifier
1559  * @value: string value
1560  *
1561  * Set string value for specific key
1562  */
1563 int connman_device_set_string(struct connman_device *device,
1564                                         const char *key, const char *value)
1565 {
1566         DBG("device %p key %s value %s", device, key, value);
1567
1568         if (g_str_equal(key, "Address") == TRUE) {
1569                 g_free(device->address);
1570                 device->address = g_strdup(value);
1571         } else if (g_str_equal(key, "Name") == TRUE) {
1572                 g_free(device->name);
1573                 device->name = g_strdup(value);
1574         } else if (g_str_equal(key, "Node") == TRUE) {
1575                 g_free(device->node);
1576                 device->node = g_strdup(value);
1577         }
1578
1579         return connman_element_set_string(&device->element, key, value);
1580 }
1581
1582 /**
1583  * connman_device_get_string:
1584  * @device: device structure
1585  * @key: unique identifier
1586  *
1587  * Get string value for specific key
1588  */
1589 const char *connman_device_get_string(struct connman_device *device,
1590                                                         const char *key)
1591 {
1592         DBG("device %p key %s", device, key);
1593
1594         if (g_str_equal(key, "Address") == TRUE)
1595                 return device->address;
1596         else if (g_str_equal(key, "Name") == TRUE)
1597                 return device->name;
1598         else if (g_str_equal(key, "Node") == TRUE)
1599                 return device->node;
1600
1601         return connman_element_get_string(&device->element, key);
1602 }
1603
1604 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1605 {
1606         struct connman_device *device = element->device;
1607         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1608         connman_bool_t powered;
1609
1610         DBG("element %p name %s", element, element->name);
1611
1612         if (device == NULL)
1613                 return;
1614
1615         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1616
1617         if (device->powered == powered)
1618                 return;
1619
1620         set_powered(device, powered);
1621 }
1622
1623 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1624 {
1625         DBG("offlinmode %d", offlinemode);
1626
1627         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1628                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1629
1630         __connman_notifier_offline_mode(offlinemode);
1631
1632         return 0;
1633 }
1634
1635 void __connman_device_increase_connections(struct connman_device *device)
1636 {
1637         device->connections++;
1638 }
1639
1640 void __connman_device_decrease_connections(struct connman_device *device)
1641 {
1642         device->connections--;
1643 }
1644
1645 /**
1646  * connman_device_add_network:
1647  * @device: device structure
1648  * @network: network structure
1649  *
1650  * Add new network to the device
1651  */
1652 int connman_device_add_network(struct connman_device *device,
1653                                         struct connman_network *network)
1654 {
1655         const char *identifier = connman_network_get_identifier(network);
1656         int err;
1657
1658         DBG("device %p network %p", device, network);
1659
1660         switch (device->mode) {
1661         case CONNMAN_DEVICE_MODE_UNKNOWN:
1662         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1663                 return -EINVAL;
1664         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1665         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1666                 break;
1667         }
1668
1669         __connman_network_set_device(network, device);
1670
1671         __connman_storage_load_network(network);
1672
1673         err = connman_element_register((struct connman_element *) network,
1674                                                         &device->element);
1675         if (err < 0) {
1676                 __connman_network_set_device(network, NULL);
1677                 return err;
1678         }
1679
1680         g_hash_table_insert(device->networks, g_strdup(identifier),
1681                                                                 network);
1682
1683         return 0;
1684 }
1685
1686 /**
1687  * connman_device_get_network:
1688  * @device: device structure
1689  * @identifier: network identifier
1690  *
1691  * Get network for given identifier
1692  */
1693 struct connman_network *connman_device_get_network(struct connman_device *device,
1694                                                         const char *identifier)
1695 {
1696         DBG("device %p identifier %s", device, identifier);
1697
1698         return g_hash_table_lookup(device->networks, identifier);
1699 }
1700
1701 /**
1702  * connman_device_remove_network:
1703  * @device: device structure
1704  * @identifier: network identifier
1705  *
1706  * Remove network for given identifier
1707  */
1708 int connman_device_remove_network(struct connman_device *device,
1709                                                         const char *identifier)
1710 {
1711         DBG("device %p identifier %s", device, identifier);
1712
1713         g_hash_table_remove(device->networks, identifier);
1714
1715         return 0;
1716 }
1717
1718 void __connman_device_set_network(struct connman_device *device,
1719                                         struct connman_network *network)
1720 {
1721         const char *name;
1722
1723         if (device->network == network)
1724                 return;
1725
1726         if (device->network != NULL)
1727                 connman_network_unref(device->network);
1728
1729         if (network != NULL) {
1730                 name = connman_network_get_string(network,
1731                                                 CONNMAN_PROPERTY_ID_NAME);
1732                 g_free(device->last_network);
1733                 device->last_network = g_strdup(name);
1734
1735                 device->network = connman_network_ref(network);
1736         } else {
1737                 g_free(device->last_network);
1738                 device->last_network = NULL;
1739
1740                 device->network = NULL;
1741         }
1742 }
1743
1744 /**
1745  * connman_device_register:
1746  * @device: device structure
1747  *
1748  * Register device with the system
1749  */
1750 int connman_device_register(struct connman_device *device)
1751 {
1752         __connman_storage_load_device(device);
1753
1754         switch (device->mode) {
1755         case CONNMAN_DEVICE_MODE_UNKNOWN:
1756         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1757                 break;
1758         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1759         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1760                 __connman_storage_init_network(device);
1761                 break;
1762         }
1763
1764         return connman_element_register(&device->element, NULL);
1765 }
1766
1767 /**
1768  * connman_device_unregister:
1769  * @device: device structure
1770  *
1771  * Unregister device with the system
1772  */
1773 void connman_device_unregister(struct connman_device *device)
1774 {
1775         __connman_storage_save_device(device);
1776
1777         connman_element_unregister(&device->element);
1778 }
1779
1780 /**
1781  * connman_device_get_data:
1782  * @device: device structure
1783  *
1784  * Get private device data pointer
1785  */
1786 void *connman_device_get_data(struct connman_device *device)
1787 {
1788         return device->driver_data;
1789 }
1790
1791 /**
1792  * connman_device_set_data:
1793  * @device: device structure
1794  * @data: data pointer
1795  *
1796  * Set private device data pointer
1797  */
1798 void connman_device_set_data(struct connman_device *device, void *data)
1799 {
1800         device->driver_data = data;
1801 }
1802
1803 static gboolean match_driver(struct connman_device *device,
1804                                         struct connman_device_driver *driver)
1805 {
1806         if (device->type == driver->type ||
1807                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1808                 return TRUE;
1809
1810         return FALSE;
1811 }
1812
1813 static int device_probe(struct connman_element *element)
1814 {
1815         struct connman_device *device = element->device;
1816         GSList *list;
1817
1818         DBG("element %p name %s", element, element->name);
1819
1820         if (device == NULL)
1821                 return -ENODEV;
1822
1823         if (device->driver != NULL)
1824                 return -EALREADY;
1825
1826         for (list = driver_list; list; list = list->next) {
1827                 struct connman_device_driver *driver = list->data;
1828
1829                 if (match_driver(device, driver) == FALSE)
1830                         continue;
1831
1832                 DBG("driver %p name %s", driver, driver->name);
1833
1834                 if (driver->probe(device) == 0) {
1835                         device->driver = driver;
1836                         break;
1837                 }
1838         }
1839
1840         if (device->driver == NULL)
1841                 return -ENODEV;
1842
1843         return setup_device(device);
1844 }
1845
1846 static void device_remove(struct connman_element *element)
1847 {
1848         struct connman_device *device = element->device;
1849
1850         DBG("element %p name %s", element, element->name);
1851
1852         if (device == NULL)
1853                 return;
1854
1855         if (device->driver == NULL)
1856                 return;
1857
1858         remove_device(device);
1859 }
1860
1861 static struct connman_driver device_driver = {
1862         .name           = "device",
1863         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1864         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1865         .probe          = device_probe,
1866         .remove         = device_remove,
1867 };
1868
1869 static int device_load(struct connman_device *device)
1870 {
1871         GKeyFile *keyfile;
1872         gchar *pathname, *identifier, *data = NULL;
1873         gsize length;
1874         char *str;
1875         int val;
1876
1877         DBG("device %p", device);
1878
1879         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1880                                         __connman_profile_active_ident());
1881         if (pathname == NULL)
1882                 return -ENOMEM;
1883
1884         keyfile = g_key_file_new();
1885
1886         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1887                 g_free(pathname);
1888                 return -ENOENT;
1889         }
1890
1891         g_free(pathname);
1892
1893         if (g_key_file_load_from_data(keyfile, data, length,
1894                                                         0, NULL) == FALSE) {
1895                 g_free(data);
1896                 return -EILSEQ;
1897         }
1898
1899         g_free(data);
1900
1901         identifier = g_strdup_printf("device_%s", device->element.name);
1902         if (identifier == NULL)
1903                 goto done;
1904
1905         str = g_key_file_get_string(keyfile, identifier, "Policy", NULL);
1906         if (str != NULL) {
1907                 device->policy = string2policy(str);
1908                 g_free(str);
1909         }
1910
1911         switch (device->mode) {
1912         case CONNMAN_DEVICE_MODE_UNKNOWN:
1913         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1914                 break;
1915         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1916         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1917                 val = g_key_file_get_integer(keyfile, identifier,
1918                                                         "ScanInterval", NULL);
1919                 if (val > 0)
1920                         device->scan_interval = val;
1921                 break;
1922         }
1923
1924 done:
1925         g_key_file_free(keyfile);
1926
1927         g_free(identifier);
1928
1929         return 0;
1930 }
1931
1932 static int device_save(struct connman_device *device)
1933 {
1934         GKeyFile *keyfile;
1935         gchar *pathname, *identifier = NULL, *data = NULL;
1936         gsize length;
1937         const char *str;
1938
1939         DBG("device %p", device);
1940
1941         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1942                                         __connman_profile_active_ident());
1943         if (pathname == NULL)
1944                 return -ENOMEM;
1945
1946         keyfile = g_key_file_new();
1947
1948         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1949                 goto update;
1950
1951         if (length > 0) {
1952                 if (g_key_file_load_from_data(keyfile, data, length,
1953                                                         0, NULL) == FALSE)
1954                         goto done;
1955         }
1956
1957         g_free(data);
1958
1959 update:
1960         identifier = g_strdup_printf("device_%s", device->element.name);
1961         if (identifier == NULL)
1962                 goto done;
1963
1964         str = policy2string(device->policy);
1965         if (str != NULL)
1966                 g_key_file_set_string(keyfile, identifier, "Policy", str);
1967
1968         switch (device->mode) {
1969         case CONNMAN_DEVICE_MODE_UNKNOWN:
1970         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1971                 break;
1972         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1973         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1974                 if (device->scan_interval > 0)
1975                         g_key_file_set_integer(keyfile, identifier,
1976                                         "ScanInterval", device->scan_interval);
1977                 break;
1978         }
1979
1980         data = g_key_file_to_data(keyfile, &length, NULL);
1981
1982         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
1983                 connman_error("Failed to store device information");
1984
1985 done:
1986         g_free(data);
1987
1988         g_key_file_free(keyfile);
1989
1990         g_free(identifier);
1991         g_free(pathname);
1992
1993         return 0;
1994 }
1995
1996 static struct connman_storage device_storage = {
1997         .name           = "device",
1998         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1999         .device_load    = device_load,
2000         .device_save    = device_save,
2001 };
2002
2003 int __connman_device_init(void)
2004 {
2005         DBG("");
2006
2007         connection = connman_dbus_get_connection();
2008
2009         if (connman_storage_register(&device_storage) < 0)
2010                 connman_error("Failed to register device storage");
2011
2012         return connman_driver_register(&device_driver);
2013 }
2014
2015 void __connman_device_cleanup(void)
2016 {
2017         DBG("");
2018
2019         connman_driver_unregister(&device_driver);
2020
2021         connman_storage_unregister(&device_storage);
2022
2023         dbus_connection_unref(connection);
2024 }