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