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