Track current network within device framework
[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 <gdbus.h>
28
29 #include "connman.h"
30
31 struct connman_device {
32         struct connman_element element;
33         enum connman_device_type type;
34         enum connman_device_mode mode;
35         enum connman_device_policy policy;
36         connman_bool_t powered;
37         connman_bool_t carrier;
38         connman_bool_t scanning;
39         connman_uint8_t priority;
40         char *name;
41         char *node;
42         char *interface;
43         unsigned int connections;
44
45         struct connman_device_driver *driver;
46         void *driver_data;
47
48         connman_bool_t registered;
49
50         struct connman_network *network;
51         GHashTable *networks;
52 };
53
54 static const char *type2description(enum connman_device_type type)
55 {
56         switch (type) {
57         case CONNMAN_DEVICE_TYPE_UNKNOWN:
58         case CONNMAN_DEVICE_TYPE_VENDOR:
59                 break;
60         case CONNMAN_DEVICE_TYPE_ETHERNET:
61                 return "Ethernet";
62         case CONNMAN_DEVICE_TYPE_WIFI:
63                 return "Wireless";
64         case CONNMAN_DEVICE_TYPE_WIMAX:
65                 return "WiMAX";
66         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
67                 return "Bluetooth";
68         case CONNMAN_DEVICE_TYPE_HSO:
69         case CONNMAN_DEVICE_TYPE_NOZOMI:
70         case CONNMAN_DEVICE_TYPE_HUAWEI:
71         case CONNMAN_DEVICE_TYPE_NOVATEL:
72                 return "Cellular";
73         }
74
75         return NULL;
76 }
77
78 static const char *type2string(enum connman_device_type type)
79 {
80         switch (type) {
81         case CONNMAN_DEVICE_TYPE_UNKNOWN:
82         case CONNMAN_DEVICE_TYPE_VENDOR:
83                 break;
84         case CONNMAN_DEVICE_TYPE_ETHERNET:
85                 return "ethernet";
86         case CONNMAN_DEVICE_TYPE_WIFI:
87                 return "wifi";
88         case CONNMAN_DEVICE_TYPE_WIMAX:
89                 return "wimax";
90         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
91                 return "bluetooth";
92         case CONNMAN_DEVICE_TYPE_HSO:
93         case CONNMAN_DEVICE_TYPE_HUAWEI:
94         case CONNMAN_DEVICE_TYPE_NOZOMI:
95         case CONNMAN_DEVICE_TYPE_NOVATEL:
96                 return "cellular";
97         }
98
99         return NULL;
100 }
101
102 static const char *policy2string(enum connman_device_policy policy)
103 {
104         switch (policy) {
105         case CONNMAN_DEVICE_POLICY_UNKNOWN:
106                 break;
107         case CONNMAN_DEVICE_POLICY_IGNORE:
108                 return "ignore";
109         case CONNMAN_DEVICE_POLICY_OFF:
110                 return "off";
111         case CONNMAN_DEVICE_POLICY_AUTO:
112                 return "auto";
113         case CONNMAN_DEVICE_POLICY_MANUAL:
114                 return "manual";
115         }
116
117         return NULL;
118 }
119
120 static enum connman_device_policy string2policy(const char *policy)
121 {
122         if (g_str_equal(policy, "ignore") == TRUE)
123                 return CONNMAN_DEVICE_POLICY_IGNORE;
124         else if (g_str_equal(policy, "off") == TRUE)
125                 return CONNMAN_DEVICE_POLICY_OFF;
126         else if (g_str_equal(policy, "auto") == TRUE)
127                 return CONNMAN_DEVICE_POLICY_AUTO;
128         else if (g_str_equal(policy, "manual") == TRUE)
129                 return CONNMAN_DEVICE_POLICY_MANUAL;
130         else
131                 return CONNMAN_DEVICE_POLICY_UNKNOWN;
132 }
133
134 static int set_powered(struct connman_device *device, connman_bool_t powered)
135 {
136         struct connman_device_driver *driver = device->driver;
137         int err;
138
139         DBG("device %p powered %d", device, powered);
140
141         if (!driver)
142                 return -EINVAL;
143
144         if (powered == TRUE) {
145                 if (driver->enable)
146                         err = driver->enable(device);
147                 else
148                         err = -EINVAL;
149         } else {
150                 g_hash_table_remove_all(device->networks);
151
152                 if (driver->disable)
153                         err = driver->disable(device);
154                 else
155                         err = -EINVAL;
156         }
157
158         return err;
159 }
160
161 static int set_policy(DBusConnection *connection,
162                                 struct connman_device *device,
163                                         enum connman_device_policy policy)
164 {
165         DBusMessage *signal;
166         DBusMessageIter entry, value;
167         const char *str, *key = "Policy";
168         int err = 0;
169
170         DBG("device %p policy %d", device, policy);
171
172         if (device->policy == policy)
173                 return 0;
174
175         switch (policy) {
176         case CONNMAN_DEVICE_POLICY_UNKNOWN:
177                 return -EINVAL;
178         case CONNMAN_DEVICE_POLICY_IGNORE:
179                 break;
180         case CONNMAN_DEVICE_POLICY_OFF:
181                 if (device->powered == TRUE)
182                         err = set_powered(device, FALSE);
183                 break;
184         case CONNMAN_DEVICE_POLICY_AUTO:
185         case CONNMAN_DEVICE_POLICY_MANUAL:
186                 if (device->powered == FALSE)
187                         err = set_powered(device, TRUE);
188                 break;
189         }
190
191         if (err < 0)
192                 return err;
193
194         device->policy = policy;
195
196         signal = dbus_message_new_signal(device->element.path,
197                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
198         if (signal == NULL)
199                 return 0;
200
201         dbus_message_iter_init_append(signal, &entry);
202
203         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
204
205         str = policy2string(policy);
206
207         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
208                                         DBUS_TYPE_STRING_AS_STRING, &value);
209         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
210         dbus_message_iter_close_container(&entry, &value);
211
212         g_dbus_send_message(connection, signal);
213
214         return 0;
215 }
216
217 static void append_networks(struct connman_device *device,
218                                                 DBusMessageIter *entry)
219 {
220         DBusMessageIter value, iter;
221         const char *key = "Networks";
222
223         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
224
225         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
226                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
227                                                                 &value);
228
229         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
230                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
231         __connman_element_list((struct connman_element *) device,
232                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
233         dbus_message_iter_close_container(&value, &iter);
234
235         dbus_message_iter_close_container(entry, &value);
236 }
237
238 static DBusMessage *get_properties(DBusConnection *conn,
239                                         DBusMessage *msg, void *data)
240 {
241         struct connman_device *device = data;
242         DBusMessage *reply;
243         DBusMessageIter array, dict, entry;
244         const char *str;
245
246         DBG("conn %p", conn);
247
248         if (__connman_security_check_privilege(msg,
249                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
250                 return __connman_error_permission_denied(msg);
251
252         reply = dbus_message_new_method_return(msg);
253         if (reply == NULL)
254                 return NULL;
255
256         dbus_message_iter_init_append(reply, &array);
257
258         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
259                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
260                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
261                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
262
263         str = type2description(device->type);
264         if (str != NULL && device->interface != NULL) {
265                 char *name = g_strdup_printf("%s (%s)", str, device->interface);
266                 if (name != NULL)
267                         connman_dbus_dict_append_variant(&dict, "Name",
268                                                 DBUS_TYPE_STRING, &name);
269                 g_free(name);
270         }
271
272         str = type2string(device->type);
273         if (str != NULL)
274                 connman_dbus_dict_append_variant(&dict, "Type",
275                                                 DBUS_TYPE_STRING, &str);
276
277         if (device->interface != NULL)
278                 connman_dbus_dict_append_variant(&dict, "Interface",
279                                         DBUS_TYPE_STRING, &device->interface);
280
281         str = policy2string(device->policy);
282         if (str != NULL)
283                 connman_dbus_dict_append_variant(&dict, "Policy",
284                                                 DBUS_TYPE_STRING, &str);
285
286         if (device->priority > 0)
287                 connman_dbus_dict_append_variant(&dict, "Priority",
288                                         DBUS_TYPE_BYTE, &device->priority);
289
290         connman_dbus_dict_append_variant(&dict, "Powered",
291                                         DBUS_TYPE_BOOLEAN, &device->powered);
292
293         if (device->driver && device->driver->scan)
294                 connman_dbus_dict_append_variant(&dict, "Scanning",
295                                         DBUS_TYPE_BOOLEAN, &device->scanning);
296
297         switch (device->mode) {
298         case CONNMAN_DEVICE_MODE_UNKNOWN:
299         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
300                 break;
301         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
302         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
303                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
304                                                                 NULL, &entry);
305                 append_networks(device, &entry);
306                 dbus_message_iter_close_container(&dict, &entry);
307                 break;
308         }
309
310         dbus_message_iter_close_container(&array, &dict);
311
312         return reply;
313 }
314
315 static DBusMessage *set_property(DBusConnection *conn,
316                                         DBusMessage *msg, void *data)
317 {
318         struct connman_device *device = data;
319         DBusMessageIter iter, value;
320         const char *name;
321         int type;
322
323         DBG("conn %p", conn);
324
325         if (dbus_message_iter_init(msg, &iter) == FALSE)
326                 return __connman_error_invalid_arguments(msg);
327
328         dbus_message_iter_get_basic(&iter, &name);
329         dbus_message_iter_next(&iter);
330         dbus_message_iter_recurse(&iter, &value);
331
332         if (__connman_security_check_privilege(msg,
333                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
334                 return __connman_error_permission_denied(msg);
335
336         type = dbus_message_iter_get_arg_type(&value);
337
338         if (g_str_equal(name, "Powered") == TRUE) {
339                 connman_bool_t powered;
340                 int err;
341
342                 if (type != DBUS_TYPE_BOOLEAN)
343                         return __connman_error_invalid_arguments(msg);
344
345                 dbus_message_iter_get_basic(&value, &powered);
346
347                 if (device->powered == powered)
348                         return __connman_error_invalid_arguments(msg);
349
350                 err = set_powered(device, powered);
351                 if (err < 0 && err != -EINPROGRESS)
352                         return __connman_error_failed(msg);
353         } else if (g_str_equal(name, "Policy") == TRUE) {
354                 enum connman_device_policy policy;
355                 const char *str;
356                 int err;
357
358                 if (type != DBUS_TYPE_STRING)
359                         return __connman_error_invalid_arguments(msg);
360
361                 dbus_message_iter_get_basic(&value, &str);
362                 policy = string2policy(str);
363                 if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN)
364                         return __connman_error_invalid_arguments(msg);
365
366                 err = set_policy(conn, device, policy);
367                 if (err < 0)
368                         return __connman_error_failed(msg);
369         } else if (g_str_equal(name, "Priority") == TRUE) {
370                 connman_uint8_t priority;
371
372                 if (type != DBUS_TYPE_BYTE)
373                         return __connman_error_invalid_arguments(msg);
374
375                 dbus_message_iter_get_basic(&value, &priority);
376
377                 device->priority = priority;
378         }
379
380         __connman_storage_save_device(device);
381
382         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
383 }
384
385 static DBusMessage *create_network(DBusConnection *conn,
386                                         DBusMessage *msg, void *data)
387 {
388         DBG("conn %p", conn);
389
390         if (__connman_security_check_privilege(msg,
391                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
392                 return __connman_error_permission_denied(msg);
393
394         return __connman_error_invalid_arguments(msg);
395 }
396
397 static DBusMessage *remove_network(DBusConnection *conn,
398                                         DBusMessage *msg, void *data)
399 {
400         DBG("conn %p", conn);
401
402         if (__connman_security_check_privilege(msg,
403                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
404                 return __connman_error_permission_denied(msg);
405
406         return __connman_error_invalid_arguments(msg);
407 }
408
409 static DBusMessage *propose_scan(DBusConnection *conn,
410                                         DBusMessage *msg, void *data)
411 {
412         struct connman_device *device = data;
413         int err;
414
415         DBG("conn %p", conn);
416
417         switch (device->mode) {
418         case CONNMAN_DEVICE_MODE_UNKNOWN:
419         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
420                 return __connman_error_not_supported(msg);
421         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
422         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
423                 break;
424         }
425
426         if (!device->driver || !device->driver->scan)
427                 return __connman_error_not_supported(msg);
428
429         if (device->powered == FALSE)
430                 return __connman_error_failed(msg);
431
432         err = device->driver->scan(device);
433         if (err < 0)
434                 return __connman_error_failed(msg);
435
436         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
437 }
438
439 static GDBusMethodTable device_methods[] = {
440         { "GetProperties", "",      "a{sv}", get_properties },
441         { "SetProperty",   "sv",    "",      set_property   },
442         { "CreateNetwork", "a{sv}", "o",     create_network },
443         { "RemoveNetwork", "o",     "",      remove_network },
444         { "ProposeScan",   "",      "",      propose_scan   },
445         { },
446 };
447
448 static GDBusSignalTable device_signals[] = {
449         { "PropertyChanged", "sv" },
450         { },
451 };
452
453 static DBusConnection *connection;
454
455 static void append_devices(DBusMessageIter *entry)
456 {
457         DBusMessageIter value, iter;
458         const char *key = "Devices";
459
460         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
461
462         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
463                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
464                                                                 &value);
465
466         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
467                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
468         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
469         dbus_message_iter_close_container(&value, &iter);
470
471         dbus_message_iter_close_container(entry, &value);
472 }
473
474 static void emit_devices_signal(void)
475 {
476         DBusMessage *signal;
477         DBusMessageIter entry;
478
479         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
480                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
481         if (signal == NULL)
482                 return;
483
484         dbus_message_iter_init_append(signal, &entry);
485
486         append_devices(&entry);
487
488         g_dbus_send_message(connection, signal);
489 }
490
491 static int register_interface(struct connman_element *element)
492 {
493         struct connman_device *device = element->device;
494
495         DBG("element %p name %s", element, element->name);
496
497         if (g_dbus_register_interface(connection, element->path,
498                                         CONNMAN_DEVICE_INTERFACE,
499                                         device_methods, device_signals,
500                                         NULL, device, NULL) == FALSE) {
501                 connman_error("Failed to register %s device", element->path);
502                 return -EIO;
503         }
504
505         device->registered = TRUE;
506
507         emit_devices_signal();
508
509         return 0;
510 }
511
512 static void unregister_interface(struct connman_element *element)
513 {
514         struct connman_device *device = element->device;
515
516         DBG("element %p name %s", element, element->name);
517
518         device->registered = FALSE;
519
520         emit_devices_signal();
521
522         g_dbus_unregister_interface(connection, element->path,
523                                                 CONNMAN_DEVICE_INTERFACE);
524 }
525
526 static void device_enable(struct connman_device *device)
527 {
528         DBG("device %p", device);
529
530         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
531                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
532                 return;
533
534         if (device->powered == TRUE)
535                 return;
536
537         if (device->driver->enable)
538                 device->driver->enable(device);
539 }
540
541 static void device_disable(struct connman_device *device)
542 {
543         DBG("device %p", device);
544
545         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
546                 return;
547
548         if (device->powered == FALSE)
549                 return;
550
551         g_hash_table_remove_all(device->networks);
552
553         if (device->driver->disable)
554                 device->driver->disable(device);
555 }
556
557 static int setup_device(struct connman_device *device)
558 {
559         int err;
560
561         DBG("device %p", device);
562
563         err = register_interface(&device->element);
564         if (err < 0) {
565                 if (device->driver->remove)
566                         device->driver->remove(device);
567                 device->driver = NULL;
568                 return err;
569         }
570
571         device_enable(device);
572
573         return 0;
574 }
575
576 static void probe_driver(struct connman_element *element, gpointer user_data)
577 {
578         struct connman_device_driver *driver = user_data;
579
580         DBG("element %p name %s", element, element->name);
581
582         if (element->device == NULL)
583                 return;
584
585         if (element->device->driver != NULL)
586                 return;
587
588         if (driver->probe(element->device) < 0)
589                 return;
590
591         element->device->driver = driver;
592
593         setup_device(element->device);
594 }
595
596 static void remove_device(struct connman_device *device)
597 {
598         DBG("device %p", device);
599
600         device_disable(device);
601
602         unregister_interface(&device->element);
603
604         if (device->driver->remove)
605                 device->driver->remove(device);
606
607         device->driver = NULL;
608 }
609
610 static void remove_driver(struct connman_element *element, gpointer user_data)
611 {
612         struct connman_device_driver *driver = user_data;
613
614         DBG("element %p name %s", element, element->name);
615
616         if (element->device == NULL)
617                 return;
618
619         if (element->device->driver == driver)
620                 remove_device(element->device);
621 }
622
623 connman_bool_t __connman_device_has_driver(struct connman_device *device)
624 {
625         if (device == NULL || device->driver == NULL)
626                 return FALSE;
627
628         return device->registered;
629 }
630
631 static GSList *driver_list = NULL;
632
633 static gint compare_priority(gconstpointer a, gconstpointer b)
634 {
635         const struct connman_device_driver *driver1 = a;
636         const struct connman_device_driver *driver2 = b;
637
638         return driver2->priority - driver1->priority;
639 }
640
641 /**
642  * connman_device_driver_register:
643  * @driver: device driver definition
644  *
645  * Register a new device driver
646  *
647  * Returns: %0 on success
648  */
649 int connman_device_driver_register(struct connman_device_driver *driver)
650 {
651         DBG("driver %p name %s", driver, driver->name);
652
653         driver_list = g_slist_insert_sorted(driver_list, driver,
654                                                         compare_priority);
655
656         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
657                                                 probe_driver, driver);
658
659         return 0;
660 }
661
662 /**
663  * connman_device_driver_unregister:
664  * @driver: device driver definition
665  *
666  * Remove a previously registered device driver
667  */
668 void connman_device_driver_unregister(struct connman_device_driver *driver)
669 {
670         DBG("driver %p name %s", driver, driver->name);
671
672         driver_list = g_slist_remove(driver_list, driver);
673
674         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
675                                                 remove_driver, driver);
676 }
677
678 static void unregister_network(gpointer data)
679 {
680         struct connman_network *network = data;
681
682         DBG("network %p", network);
683
684         connman_element_unregister((struct connman_element *) network);
685
686         connman_network_unref(network);
687 }
688
689 static void device_destruct(struct connman_element *element)
690 {
691         struct connman_device *device = element->device;
692
693         DBG("element %p name %s", element, element->name);
694
695         g_free(device->node);
696         g_free(device->name);
697         g_free(device->interface);
698
699         g_hash_table_destroy(device->networks);
700         device->networks = NULL;
701 }
702
703 /**
704  * connman_device_create:
705  * @node: device node name (for example an address)
706  * @type: device type
707  *
708  * Allocate a new device of given #type and assign the #node name to it.
709  *
710  * Returns: a newly-allocated #connman_device structure
711  */
712 struct connman_device *connman_device_create(const char *node,
713                                                 enum connman_device_type type)
714 {
715         struct connman_device *device;
716         const char *str;
717
718         DBG("node %s type %d", node, type);
719
720         device = g_try_new0(struct connman_device, 1);
721         if (device == NULL)
722                 return NULL;
723
724         DBG("device %p", device);
725
726         __connman_element_initialize(&device->element);
727
728         device->element.name = g_strdup(node);
729         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
730
731         device->element.device = device;
732         device->element.destruct = device_destruct;
733
734         str = type2string(type);
735         if (str != NULL)
736                 connman_element_add_static_property(&device->element,
737                                         "Type", DBUS_TYPE_STRING, &str);
738
739         device->type   = type;
740         device->mode   = CONNMAN_DEVICE_MODE_UNKNOWN;
741         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
742
743         switch (type) {
744         case CONNMAN_DEVICE_TYPE_UNKNOWN:
745         case CONNMAN_DEVICE_TYPE_VENDOR:
746                 device->priority = 0;
747                 break;
748         case CONNMAN_DEVICE_TYPE_ETHERNET:
749         case CONNMAN_DEVICE_TYPE_WIFI:
750                 device->priority = 100;
751                 break;
752         case CONNMAN_DEVICE_TYPE_WIMAX:
753                 device->priority = 20;
754                 break;
755         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
756                 device->priority = 50;
757                 break;
758         case CONNMAN_DEVICE_TYPE_HSO:
759         case CONNMAN_DEVICE_TYPE_NOZOMI:
760         case CONNMAN_DEVICE_TYPE_HUAWEI:
761         case CONNMAN_DEVICE_TYPE_NOVATEL:
762                 device->priority = 60;
763                 break;
764         }
765
766         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
767                                                 g_free, unregister_network);
768
769         return device;
770 }
771
772 /**
773  * connman_device_ref:
774  * @device: device structure
775  *
776  * Increase reference counter of device
777  */
778 struct connman_device *connman_device_ref(struct connman_device *device)
779 {
780         if (connman_element_ref(&device->element) == NULL)
781                 return NULL;
782
783         return device;
784 }
785
786 /**
787  * connman_device_unref:
788  * @device: device structure
789  *
790  * Decrease reference counter of device
791  */
792 void connman_device_unref(struct connman_device *device)
793 {
794         connman_element_unref(&device->element);
795 }
796
797 /**
798  * connman_device_get_name:
799  * @device: device structure
800  *
801  * Get unique name of device
802  */
803 const char *connman_device_get_name(struct connman_device *device)
804 {
805         return device->element.name;
806 }
807
808 /**
809  * connman_device_get_path:
810  * @device: device structure
811  *
812  * Get path name of device
813  */
814 const char *connman_device_get_path(struct connman_device *device)
815 {
816         return device->element.path;
817 }
818
819 /**
820  * connman_device_set_index:
821  * @device: device structure
822  * @index: index number
823  *
824  * Set index number of device
825  */
826 void connman_device_set_index(struct connman_device *device, int index)
827 {
828         device->element.index = index;
829 }
830
831 /**
832  * connman_device_get_index:
833  * @device: device structure
834  *
835  * Get index number of device
836  */
837 int connman_device_get_index(struct connman_device *device)
838 {
839         return device->element.index;
840 }
841
842 /**
843  * connman_device_set_interface:
844  * @device: device structure
845  * @interface: interface name
846  *
847  * Set interface name of device
848  */
849 void connman_device_set_interface(struct connman_device *device,
850                                                         const char *interface)
851 {
852         g_free(device->element.devname);
853         device->element.devname = g_strdup(interface);
854
855         g_free(device->interface);
856         device->interface = g_strdup(interface);
857 }
858
859 /**
860  * connman_device_get_interface:
861  * @device: device structure
862  *
863  * Get interface name of device
864  */
865 const char *connman_device_get_interface(struct connman_device *device)
866 {
867         return device->interface;
868 }
869
870 /**
871  * connman_device_set_policy:
872  * @device: device structure
873  * @policy: power and connection policy
874  *
875  * Change power and connection policy of device
876  */
877 void connman_device_set_policy(struct connman_device *device,
878                                         enum connman_device_policy policy)
879 {
880         device->policy = policy;
881 }
882
883 /**
884  * connman_device_set_mode:
885  * @device: device structure
886  * @mode: network mode
887  *
888  * Change network mode of device
889  */
890 void connman_device_set_mode(struct connman_device *device,
891                                                 enum connman_device_mode mode)
892 {
893         device->mode = mode;
894 }
895
896 /**
897  * connman_device_get_mode:
898  * @device: device structure
899  *
900  * Get network mode of device
901  */
902 enum connman_device_mode connman_device_get_mode(struct connman_device *device)
903 {
904         return device->mode;
905 }
906
907 /**
908  * connman_device_set_powered:
909  * @device: device structure
910  * @powered: powered state
911  *
912  * Change power state of device
913  */
914 int connman_device_set_powered(struct connman_device *device,
915                                                 connman_bool_t powered)
916 {
917         DBusMessage *signal;
918         DBusMessageIter entry, value;
919         const char *key = "Powered";
920
921         DBG("driver %p powered %d", device, powered);
922
923         if (device->powered == powered)
924                 return -EALREADY;
925
926         device->powered = powered;
927
928         signal = dbus_message_new_signal(device->element.path,
929                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
930         if (signal == NULL)
931                 return 0;
932
933         dbus_message_iter_init_append(signal, &entry);
934
935         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
936
937         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
938                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
939         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
940         dbus_message_iter_close_container(&entry, &value);
941
942         g_dbus_send_message(connection, signal);
943
944         if (powered == FALSE)
945                 return 0;
946
947         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
948                 return 0;
949
950         if (device->driver->scan)
951                 device->driver->scan(device);
952
953         return 0;
954 }
955
956 /**
957  * connman_device_set_carrier:
958  * @device: device structure
959  * @carrier: carrier state
960  *
961  * Change carrier state of device (only for device without scanning)
962  */
963 int connman_device_set_carrier(struct connman_device *device,
964                                                 connman_bool_t carrier)
965 {
966         DBG("driver %p carrier %d", device, carrier);
967
968         switch (device->mode) {
969         case CONNMAN_DEVICE_MODE_UNKNOWN:
970         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
971         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
972                 return -EINVAL;
973         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
974                 break;
975         }
976
977         if (device->carrier == carrier)
978                 return -EALREADY;
979
980         device->carrier = carrier;
981
982         if (carrier == TRUE) {
983                 struct connman_element *element;
984
985                 element = connman_element_create(NULL);
986                 if (element != NULL) {
987                         element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
988                         element->index = device->element.index;
989
990                         if (connman_element_register(element,
991                                                         &device->element) < 0)
992                                 connman_element_unref(element);
993                 }
994         } else
995                 connman_element_unregister_children(&device->element);
996
997         return 0;
998 }
999
1000 void __connman_device_disconnect(struct connman_device *device)
1001 {
1002         GHashTableIter iter;
1003         gpointer key, value;
1004
1005         DBG("device %p", device);
1006
1007         g_hash_table_iter_init(&iter, device->networks);
1008
1009         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1010                 struct connman_network *network = value;
1011
1012                 if (connman_network_get_connected(network) == TRUE)
1013                         __connman_network_disconnect(network);
1014         }
1015 }
1016
1017 static void connect_known_network(struct connman_device *device)
1018 {
1019         struct connman_network *network = NULL;
1020         GHashTableIter iter;
1021         gpointer key, value;
1022         unsigned int count = 0;
1023
1024         DBG("device %p", device);
1025
1026         g_hash_table_iter_init(&iter, device->networks);
1027
1028         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1029                 connman_uint8_t old_priority, new_priority;
1030                 connman_uint8_t old_strength, new_strength;
1031
1032                 count++;
1033
1034                 if (connman_network_get_remember(value) == FALSE)
1035                         continue;
1036
1037                 if (network == NULL) {
1038                         network = value;
1039                         continue;
1040                 }
1041
1042                 old_priority = connman_network_get_uint8(network, "Priority");
1043                 new_priority = connman_network_get_uint8(value, "Priority");
1044
1045                 if (new_priority != old_priority) {
1046                         if (new_priority > old_priority)
1047                                 network = value;
1048                         continue;
1049                 }
1050
1051                 old_strength = connman_network_get_uint8(network, "Strength");
1052                 new_strength = connman_network_get_uint8(value, "Strength");
1053
1054                 if (new_strength > old_strength)
1055                         network = value;
1056         }
1057
1058         if (network != NULL) {
1059                 int err;
1060
1061                 err = connman_network_connect(network);
1062                 if (err == 0 || err == -EINPROGRESS)
1063                         return;
1064         }
1065
1066         if (count > 0)
1067                 return;
1068
1069         if (device->driver && device->driver->scan)
1070                 device->driver->scan(device);
1071 }
1072
1073 static void mark_network_unavailable(gpointer key, gpointer value,
1074                                                         gpointer user_data)
1075 {
1076         struct connman_network *network = value;
1077
1078         if (connman_network_get_remember(network) == TRUE)
1079                 return;
1080
1081         connman_network_set_available(network, FALSE);
1082 }
1083
1084 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1085                                                         gpointer user_data)
1086 {
1087         struct connman_network *network = value;
1088
1089         if (connman_network_get_remember(network) == TRUE)
1090                 return FALSE;
1091
1092         if (connman_network_get_available(network) == TRUE)
1093                 return FALSE;
1094
1095         return TRUE;
1096 }
1097
1098 /**
1099  * connman_device_set_scanning:
1100  * @device: device structure
1101  * @scanning: scanning state
1102  *
1103  * Change scanning state of device
1104  */
1105 int connman_device_set_scanning(struct connman_device *device,
1106                                                 connman_bool_t scanning)
1107 {
1108         DBusMessage *signal;
1109         DBusMessageIter entry, value;
1110         const char *key = "Scanning";
1111
1112         DBG("driver %p scanning %d", device, scanning);
1113
1114         if (!device->driver || !device->driver->scan)
1115                 return -EINVAL;
1116
1117         if (device->scanning == scanning)
1118                 return -EALREADY;
1119
1120         device->scanning = scanning;
1121
1122         signal = dbus_message_new_signal(device->element.path,
1123                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1124         if (signal == NULL)
1125                 return 0;
1126
1127         dbus_message_iter_init_append(signal, &entry);
1128
1129         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1130
1131         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1132                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1133         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1134         dbus_message_iter_close_container(&entry, &value);
1135
1136         g_dbus_send_message(connection, signal);
1137
1138         if (scanning == TRUE) {
1139                 g_hash_table_foreach(device->networks,
1140                                         mark_network_unavailable, NULL);
1141                 return 0;
1142         }
1143
1144         g_hash_table_foreach_remove(device->networks,
1145                                         remove_unavailable_network, NULL);
1146
1147         if (device->connections > 0)
1148                 return 0;
1149
1150         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1151                 return 0;
1152
1153         connect_known_network(device);
1154
1155         return 0;
1156 }
1157
1158 /**
1159  * connman_device_set_string:
1160  * @device: device structure
1161  * @key: unique identifier
1162  * @value: string value
1163  *
1164  * Set string value for specific key
1165  */
1166 int connman_device_set_string(struct connman_device *device,
1167                                         const char *key, const char *value)
1168 {
1169         DBG("device %p key %s value %s", device, key, value);
1170
1171         if (g_str_equal(key, "Name") == TRUE) {
1172                 g_free(device->name);
1173                 device->name = g_strdup(value);
1174         } else if (g_str_equal(key, "Node") == TRUE) {
1175                 g_free(device->node);
1176                 device->node = g_strdup(value);
1177         }
1178
1179         return 0;
1180 }
1181
1182 /**
1183  * connman_device_get_string:
1184  * @device: device structure
1185  * @key: unique identifier
1186  *
1187  * Get string value for specific key
1188  */
1189 const char *connman_device_get_string(struct connman_device *device,
1190                                                         const char *key)
1191 {
1192         DBG("device %p key %s", device, key);
1193
1194         if (g_str_equal(key, "Name") == TRUE)
1195                 return device->name;
1196         else if (g_str_equal(key, "Node") == TRUE)
1197                 return device->node;
1198
1199         return NULL;
1200 }
1201
1202 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1203 {
1204         struct connman_device *device = element->device;
1205         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1206         connman_bool_t powered;
1207
1208         DBG("element %p name %s", element, element->name);
1209
1210         if (device == NULL)
1211                 return;
1212
1213         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1214
1215         if (device->powered == powered)
1216                 return;
1217
1218         set_powered(device, powered);
1219 }
1220
1221 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1222 {
1223         DBG("offlinmode %d", offlinemode);
1224
1225         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1226                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1227
1228         return 0;
1229 }
1230
1231 void __connman_device_increase_connections(struct connman_device *device)
1232 {
1233         device->connections++;
1234 }
1235
1236 void __connman_device_decrease_connections(struct connman_device *device)
1237 {
1238         device->connections--;
1239 }
1240
1241 /**
1242  * connman_device_add_network:
1243  * @device: device structure
1244  * @network: network structure
1245  *
1246  * Add new network to the device
1247  */
1248 int connman_device_add_network(struct connman_device *device,
1249                                         struct connman_network *network)
1250 {
1251         const char *identifier = connman_network_get_identifier(network);
1252         int err;
1253
1254         DBG("device %p network %p", device, network);
1255
1256         switch (device->mode) {
1257         case CONNMAN_DEVICE_MODE_UNKNOWN:
1258         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1259                 return -EINVAL;
1260         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1261         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1262                 break;
1263         }
1264
1265         __connman_network_set_device(network, device);
1266
1267         __connman_storage_load_network(network);
1268
1269         err = connman_element_register((struct connman_element *) network,
1270                                                         &device->element);
1271         if (err < 0) {
1272                 __connman_network_set_device(network, NULL);
1273                 return err;
1274         }
1275
1276         g_hash_table_insert(device->networks, g_strdup(identifier),
1277                                                                 network);
1278
1279         return 0;
1280 }
1281
1282 /**
1283  * connman_device_get_network:
1284  * @device: device structure
1285  * @identifier: network identifier
1286  *
1287  * Get network for given identifier
1288  */
1289 struct connman_network *connman_device_get_network(struct connman_device *device,
1290                                                         const char *identifier)
1291 {
1292         DBG("device %p identifier %s", device, identifier);
1293
1294         return g_hash_table_lookup(device->networks, identifier);
1295 }
1296
1297 /**
1298  * connman_device_remove_network:
1299  * @device: device structure
1300  * @identifier: network identifier
1301  *
1302  * Remove network for given identifier
1303  */
1304 int connman_device_remove_network(struct connman_device *device,
1305                                                         const char *identifier)
1306 {
1307         DBG("device %p identifier %s", device, identifier);
1308
1309         g_hash_table_remove(device->networks, identifier);
1310
1311         return 0;
1312 }
1313
1314 void __connman_device_set_network(struct connman_device *device,
1315                                         struct connman_network *network)
1316 {
1317         device->network = network;
1318 }
1319
1320 /**
1321  * connman_device_register:
1322  * @device: device structure
1323  *
1324  * Register device with the system
1325  */
1326 int connman_device_register(struct connman_device *device)
1327 {
1328         __connman_storage_load_device(device);
1329
1330         switch (device->mode) {
1331         case CONNMAN_DEVICE_MODE_UNKNOWN:
1332         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1333                 break;
1334         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1335         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1336                 __connman_storage_init_network(device);
1337                 break;
1338         }
1339
1340         return connman_element_register(&device->element, NULL);
1341 }
1342
1343 /**
1344  * connman_device_unregister:
1345  * @device: device structure
1346  *
1347  * Unregister device with the system
1348  */
1349 void connman_device_unregister(struct connman_device *device)
1350 {
1351         __connman_storage_save_device(device);
1352
1353         connman_element_unregister(&device->element);
1354 }
1355
1356 /**
1357  * connman_device_get_data:
1358  * @device: device structure
1359  *
1360  * Get private device data pointer
1361  */
1362 void *connman_device_get_data(struct connman_device *device)
1363 {
1364         return device->driver_data;
1365 }
1366
1367 /**
1368  * connman_device_set_data:
1369  * @device: device structure
1370  * @data: data pointer
1371  *
1372  * Set private device data pointer
1373  */
1374 void connman_device_set_data(struct connman_device *device, void *data)
1375 {
1376         device->driver_data = data;
1377 }
1378
1379 static gboolean match_driver(struct connman_device *device,
1380                                         struct connman_device_driver *driver)
1381 {
1382         if (device->type == driver->type ||
1383                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1384                 return TRUE;
1385
1386         return FALSE;
1387 }
1388
1389 static int device_probe(struct connman_element *element)
1390 {
1391         struct connman_device *device = element->device;
1392         GSList *list;
1393
1394         DBG("element %p name %s", element, element->name);
1395
1396         if (device == NULL)
1397                 return -ENODEV;
1398
1399         if (device->driver != NULL)
1400                 return -EALREADY;
1401
1402         for (list = driver_list; list; list = list->next) {
1403                 struct connman_device_driver *driver = list->data;
1404
1405                 if (match_driver(device, driver) == FALSE)
1406                         continue;
1407
1408                 DBG("driver %p name %s", driver, driver->name);
1409
1410                 if (driver->probe(device) == 0) {
1411                         device->driver = driver;
1412                         break;
1413                 }
1414         }
1415
1416         if (device->driver == NULL)
1417                 return -ENODEV;
1418
1419         return setup_device(device);
1420 }
1421
1422 static void device_remove(struct connman_element *element)
1423 {
1424         struct connman_device *device = element->device;
1425
1426         DBG("element %p name %s", element, element->name);
1427
1428         if (device == NULL)
1429                 return;
1430
1431         if (device->driver == NULL)
1432                 return;
1433
1434         remove_device(device);
1435 }
1436
1437 static struct connman_driver device_driver = {
1438         .name           = "device",
1439         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1440         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1441         .probe          = device_probe,
1442         .remove         = device_remove,
1443 };
1444
1445 static int device_load(struct connman_device *device)
1446 {
1447         GKeyFile *keyfile;
1448         gchar *pathname, *data = NULL;
1449         gsize length;
1450         char *str;
1451         int val;
1452
1453         DBG("device %p", device);
1454
1455         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1456                                                         device->element.name);
1457         if (pathname == NULL)
1458                 return -ENOMEM;
1459
1460         keyfile = g_key_file_new();
1461
1462         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1463                 g_free(pathname);
1464                 return -ENOENT;
1465         }
1466
1467         g_free(pathname);
1468
1469         if (g_key_file_load_from_data(keyfile, data, length,
1470                                                         0, NULL) == FALSE) {
1471                 g_free(data);
1472                 return -EILSEQ;
1473         }
1474
1475         g_free(data);
1476
1477         str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL);
1478         if (str != NULL) {
1479                 device->policy = string2policy(str);
1480                 g_free(str);
1481         }
1482
1483         val = g_key_file_get_integer(keyfile, "Configuration",
1484                                                         "Priority", NULL);
1485         if (val > 0)
1486                 device->priority = val;
1487
1488         g_key_file_free(keyfile);
1489
1490         return 0;
1491 }
1492
1493 static int device_save(struct connman_device *device)
1494 {
1495         GKeyFile *keyfile;
1496         gchar *pathname, *data = NULL;
1497         gsize length;
1498         const char *str;
1499
1500         DBG("device %p", device);
1501
1502         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1503                                                         device->element.name);
1504         if (pathname == NULL)
1505                 return -ENOMEM;
1506
1507         keyfile = g_key_file_new();
1508
1509         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1510                 goto update;
1511
1512         if (length > 0) {
1513                 if (g_key_file_load_from_data(keyfile, data, length,
1514                                                         0, NULL) == FALSE)
1515                         goto done;
1516         }
1517
1518         g_free(data);
1519
1520 update:
1521         str = policy2string(device->policy);
1522         if (str != NULL)
1523                 g_key_file_set_string(keyfile, "Configuration", "Policy", str);
1524
1525         if (device->priority > 0)
1526                 g_key_file_set_integer(keyfile, "Configuration",
1527                                                 "Priority", device->priority);
1528
1529         data = g_key_file_to_data(keyfile, &length, NULL);
1530
1531         g_file_set_contents(pathname, data, length, NULL);
1532
1533 done:
1534         g_free(data);
1535
1536         g_key_file_free(keyfile);
1537
1538         g_free(pathname);
1539
1540         return 0;
1541 }
1542
1543 static struct connman_storage device_storage = {
1544         .name           = "device",
1545         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1546         .device_load    = device_load,
1547         .device_save    = device_save,
1548 };
1549
1550 int __connman_device_init(void)
1551 {
1552         DBG("");
1553
1554         connection = connman_dbus_get_connection();
1555
1556         if (connman_storage_register(&device_storage) < 0)
1557                 connman_error("Failed to register device storage");
1558
1559         return connman_driver_register(&device_driver);
1560 }
1561
1562 void __connman_device_cleanup(void)
1563 {
1564         DBG("");
1565
1566         connman_driver_unregister(&device_driver);
1567
1568         connman_storage_unregister(&device_storage);
1569
1570         dbus_connection_unref(connection);
1571 }