X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fdevice.c;h=b4a4b0fd37f81787e92dc1ff808c2adea0555a6b;hb=9b05cebe93ad885ee2a2156f6310eb7da365e581;hp=cd49b293f6b11ba659118a09430ba08df608ac96;hpb=48551ded08069a2d39d701bc78bab33a52ea96e0;p=connman diff --git a/src/device.c b/src/device.c index cd49b29..b4a4b0f 100644 --- a/src/device.c +++ b/src/device.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -31,51 +31,105 @@ struct connman_device { struct connman_element element; enum connman_device_type type; + enum connman_device_mode mode; enum connman_device_policy policy; - gboolean powered; - gboolean carrier; - gboolean scanning; + connman_bool_t powered; + connman_bool_t carrier; + connman_bool_t scanning; + char *name; + char *node; char *interface; + unsigned int connections; struct connman_device_driver *driver; void *driver_data; - GSList *networks; + connman_bool_t registered; + + GHashTable *networks; }; +static const char *type2description(enum connman_device_type type) +{ + switch (type) { + case CONNMAN_DEVICE_TYPE_UNKNOWN: + case CONNMAN_DEVICE_TYPE_VENDOR: + break; + case CONNMAN_DEVICE_TYPE_ETHERNET: + return "Ethernet"; + case CONNMAN_DEVICE_TYPE_WIFI: + return "Wireless"; + case CONNMAN_DEVICE_TYPE_WIMAX: + return "WiMAX"; + case CONNMAN_DEVICE_TYPE_BLUETOOTH: + return "Bluetooth"; + case CONNMAN_DEVICE_TYPE_HSO: + case CONNMAN_DEVICE_TYPE_NOZOMI: + case CONNMAN_DEVICE_TYPE_HUAWEI: + case CONNMAN_DEVICE_TYPE_NOVATEL: + return "Cellular"; + } + + return NULL; +} + static const char *type2string(enum connman_device_type type) { switch (type) { + case CONNMAN_DEVICE_TYPE_UNKNOWN: + case CONNMAN_DEVICE_TYPE_VENDOR: + break; case CONNMAN_DEVICE_TYPE_ETHERNET: return "ethernet"; case CONNMAN_DEVICE_TYPE_WIFI: return "wifi"; case CONNMAN_DEVICE_TYPE_WIMAX: return "wimax"; - case CONNMAN_DEVICE_TYPE_MODEM: - return "modem"; case CONNMAN_DEVICE_TYPE_BLUETOOTH: return "bluetooth"; - default: - return NULL; + case CONNMAN_DEVICE_TYPE_HSO: + case CONNMAN_DEVICE_TYPE_HUAWEI: + case CONNMAN_DEVICE_TYPE_NOZOMI: + case CONNMAN_DEVICE_TYPE_NOVATEL: + return "cellular"; } + + return NULL; } static const char *policy2string(enum connman_device_policy policy) { switch (policy) { + case CONNMAN_DEVICE_POLICY_UNKNOWN: + break; case CONNMAN_DEVICE_POLICY_IGNORE: return "ignore"; - case CONNMAN_DEVICE_POLICY_AUTO: - return "auto"; case CONNMAN_DEVICE_POLICY_OFF: return "off"; - default: - return NULL; + case CONNMAN_DEVICE_POLICY_AUTO: + return "auto"; + case CONNMAN_DEVICE_POLICY_MANUAL: + return "manual"; } + + return NULL; } -static int set_powered(struct connman_device *device, gboolean powered) +static enum connman_device_policy string2policy(const char *policy) +{ + if (g_str_equal(policy, "ignore") == TRUE) + return CONNMAN_DEVICE_POLICY_IGNORE; + else if (g_str_equal(policy, "off") == TRUE) + return CONNMAN_DEVICE_POLICY_OFF; + else if (g_str_equal(policy, "auto") == TRUE) + return CONNMAN_DEVICE_POLICY_AUTO; + else if (g_str_equal(policy, "manual") == TRUE) + return CONNMAN_DEVICE_POLICY_MANUAL; + else + return CONNMAN_DEVICE_POLICY_UNKNOWN; +} + +static int set_powered(struct connman_device *device, connman_bool_t powered) { struct connman_device_driver *driver = device->driver; int err; @@ -91,6 +145,8 @@ static int set_powered(struct connman_device *device, gboolean powered) else err = -EINVAL; } else { + g_hash_table_remove_all(device->networks); + if (driver->disable) err = driver->disable(device); else @@ -100,12 +156,89 @@ static int set_powered(struct connman_device *device, gboolean powered) return err; } +static int set_policy(DBusConnection *connection, + struct connman_device *device, + enum connman_device_policy policy) +{ + DBusMessage *signal; + DBusMessageIter entry, value; + const char *str, *key = "Policy"; + int err = 0; + + DBG("device %p policy %d", device, policy); + + if (device->policy == policy) + return 0; + + switch (policy) { + case CONNMAN_DEVICE_POLICY_UNKNOWN: + return -EINVAL; + case CONNMAN_DEVICE_POLICY_IGNORE: + break; + case CONNMAN_DEVICE_POLICY_OFF: + if (device->powered == TRUE) + err = set_powered(device, FALSE); + break; + case CONNMAN_DEVICE_POLICY_AUTO: + case CONNMAN_DEVICE_POLICY_MANUAL: + if (device->powered == FALSE) + err = set_powered(device, TRUE); + break; + } + + if (err < 0) + return err; + + device->policy = policy; + + signal = dbus_message_new_signal(device->element.path, + CONNMAN_DEVICE_INTERFACE, "PropertyChanged"); + if (signal == NULL) + return 0; + + dbus_message_iter_init_append(signal, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + str = policy2string(policy); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_STRING_AS_STRING, &value); + dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str); + dbus_message_iter_close_container(&entry, &value); + + g_dbus_send_message(connection, signal); + + return 0; +} + +static void append_networks(struct connman_device *device, + DBusMessageIter *entry) +{ + DBusMessageIter value, iter; + const char *key = "Networks"; + + dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, + &value); + + dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); + __connman_element_list((struct connman_element *) device, + CONNMAN_ELEMENT_TYPE_NETWORK, &iter); + dbus_message_iter_close_container(&value, &iter); + + dbus_message_iter_close_container(entry, &value); +} + static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct connman_device *device = data; DBusMessage *reply; - DBusMessageIter array, dict; + DBusMessageIter array, dict, entry; const char *str; DBG("conn %p", conn); @@ -121,6 +254,15 @@ static DBusMessage *get_properties(DBusConnection *conn, DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); + str = type2description(device->type); + if (str != NULL && device->interface != NULL) { + char *name = g_strdup_printf("%s (%s)", str, device->interface); + if (name != NULL) + connman_dbus_dict_append_variant(&dict, "Name", + DBUS_TYPE_STRING, &name); + g_free(name); + } + str = type2string(device->type); if (str != NULL) connman_dbus_dict_append_variant(&dict, "Type", @@ -142,6 +284,19 @@ static DBusMessage *get_properties(DBusConnection *conn, connman_dbus_dict_append_variant(&dict, "Scanning", DBUS_TYPE_BOOLEAN, &device->scanning); + switch (device->mode) { + case CONNMAN_DEVICE_MODE_UNKNOWN: + case CONNMAN_DEVICE_MODE_TRANSPORT_IP: + break; + case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: + case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: + dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + append_networks(device, &entry); + dbus_message_iter_close_container(&dict, &entry); + break; + } + dbus_message_iter_close_container(&array, &dict); return reply; @@ -167,7 +322,7 @@ static DBusMessage *set_property(DBusConnection *conn, return __connman_error_permission_denied(msg); if (g_str_equal(name, "Powered") == TRUE) { - gboolean powered; + connman_bool_t powered; int err; dbus_message_iter_get_basic(&value, &powered); @@ -178,9 +333,22 @@ static DBusMessage *set_property(DBusConnection *conn, err = set_powered(device, powered); if (err < 0 && err != -EINPROGRESS) return __connman_error_failed(msg); + } else if (g_str_equal(name, "Policy") == TRUE) { + enum connman_device_policy policy; + const char *str; + int err; + + dbus_message_iter_get_basic(&value, &str); + policy = string2policy(str); + if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN) + return __connman_error_invalid_arguments(msg); + + err = set_policy(conn, device, policy); + if (err < 0) + return __connman_error_failed(msg); } - __connman_element_store(&device->element); + __connman_storage_save_device(device); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } @@ -210,9 +378,31 @@ static DBusMessage *remove_network(DBusConnection *conn, static DBusMessage *propose_scan(DBusConnection *conn, DBusMessage *msg, void *data) { + struct connman_device *device = data; + int err; + DBG("conn %p", conn); - return __connman_error_failed(msg); + switch (device->mode) { + case CONNMAN_DEVICE_MODE_UNKNOWN: + case CONNMAN_DEVICE_MODE_TRANSPORT_IP: + return __connman_error_not_supported(msg); + case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: + case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: + break; + } + + if (!device->driver || !device->driver->scan) + return __connman_error_not_supported(msg); + + if (device->powered == FALSE) + return __connman_error_failed(msg); + + err = device->driver->scan(device); + if (err < 0) + return __connman_error_failed(msg); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static GDBusMethodTable device_methods[] = { @@ -231,12 +421,47 @@ static GDBusSignalTable device_signals[] = { static DBusConnection *connection; +static void append_devices(DBusMessageIter *entry) +{ + DBusMessageIter value, iter; + const char *key = "Devices"; + + dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, + &value); + + dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); + __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter); + dbus_message_iter_close_container(&value, &iter); + + dbus_message_iter_close_container(entry, &value); +} + +static void emit_devices_signal(void) +{ + DBusMessage *signal; + DBusMessageIter entry; + + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "PropertyChanged"); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &entry); + + append_devices(&entry); + + g_dbus_send_message(connection, signal); +} + static int register_interface(struct connman_element *element) { struct connman_device *device = element->device; - g_dbus_unregister_interface(connection, element->path, - CONNMAN_DEVICE_INTERFACE); + DBG("element %p name %s", element, element->name); if (g_dbus_register_interface(connection, element->path, CONNMAN_DEVICE_INTERFACE, @@ -246,15 +471,129 @@ static int register_interface(struct connman_element *element) return -EIO; } + device->registered = TRUE; + + emit_devices_signal(); + return 0; } static void unregister_interface(struct connman_element *element) { + struct connman_device *device = element->device; + + DBG("element %p name %s", element, element->name); + + device->registered = FALSE; + + emit_devices_signal(); + g_dbus_unregister_interface(connection, element->path, CONNMAN_DEVICE_INTERFACE); } +static void device_enable(struct connman_device *device) +{ + DBG("device %p", device); + + if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE || + device->policy == CONNMAN_DEVICE_POLICY_OFF) + return; + + if (device->powered == TRUE) + return; + + if (device->driver->enable) + device->driver->enable(device); +} + +static void device_disable(struct connman_device *device) +{ + DBG("device %p", device); + + if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE) + return; + + if (device->powered == FALSE) + return; + + g_hash_table_remove_all(device->networks); + + if (device->driver->disable) + device->driver->disable(device); +} + +static int setup_device(struct connman_device *device) +{ + int err; + + DBG("device %p", device); + + err = register_interface(&device->element); + if (err < 0) { + if (device->driver->remove) + device->driver->remove(device); + device->driver = NULL; + return err; + } + + device_enable(device); + + return 0; +} + +static void probe_driver(struct connman_element *element, gpointer user_data) +{ + struct connman_device_driver *driver = user_data; + + DBG("element %p name %s", element, element->name); + + if (element->device == NULL) + return; + + if (driver->probe(element->device) < 0) + return; + + element->device->driver = driver; + + setup_device(element->device); +} + +static void remove_device(struct connman_device *device) +{ + DBG("device %p", device); + + device_disable(device); + + unregister_interface(&device->element); + + if (device->driver->remove) + device->driver->remove(device); + + device->driver = NULL; +} + +static void remove_driver(struct connman_element *element, gpointer user_data) +{ + struct connman_device_driver *driver = user_data; + + DBG("element %p name %s", element, element->name); + + if (element->device == NULL) + return; + + if (element->device->driver == driver) + remove_device(element->device); +} + +connman_bool_t __connman_device_has_driver(struct connman_device *device) +{ + if (device == NULL || device->driver == NULL) + return FALSE; + + return device->registered; +} + static GSList *driver_list = NULL; static gint compare_priority(gconstpointer a, gconstpointer b) @@ -280,7 +619,8 @@ int connman_device_driver_register(struct connman_device_driver *driver) driver_list = g_slist_insert_sorted(driver_list, driver, compare_priority); - //__connman_driver_rescan(&device_driver); + __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, + probe_driver, driver); return 0; } @@ -296,6 +636,20 @@ void connman_device_driver_unregister(struct connman_device_driver *driver) DBG("driver %p name %s", driver, driver->name); driver_list = g_slist_remove(driver_list, driver); + + __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, + remove_driver, driver); +} + +static void unregister_network(gpointer data) +{ + struct connman_network *network = data; + + DBG("network %p", network); + + connman_element_unregister((struct connman_element *) network); + + connman_network_unref(network); } static void device_destruct(struct connman_element *element) @@ -304,7 +658,12 @@ static void device_destruct(struct connman_element *element) DBG("element %p name %s", element, element->name); + g_free(device->node); + g_free(device->name); g_free(device->interface); + + g_hash_table_destroy(device->networks); + device->networks = NULL; } /** @@ -329,16 +688,39 @@ struct connman_device *connman_device_create(const char *node, DBG("device %p", device); + device->element.refcount = 1; + device->element.name = g_strdup(node); device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE; device->element.index = -1; + switch (type) { + case CONNMAN_DEVICE_TYPE_UNKNOWN: + case CONNMAN_DEVICE_TYPE_VENDOR: + case CONNMAN_DEVICE_TYPE_WIFI: + case CONNMAN_DEVICE_TYPE_WIMAX: + case CONNMAN_DEVICE_TYPE_BLUETOOTH: + case CONNMAN_DEVICE_TYPE_HSO: + case CONNMAN_DEVICE_TYPE_NOZOMI: + case CONNMAN_DEVICE_TYPE_HUAWEI: + case CONNMAN_DEVICE_TYPE_NOVATEL: + device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN; + break; + case CONNMAN_DEVICE_TYPE_ETHERNET: + device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_ETHERNET; + break; + } + device->element.device = device; device->element.destruct = device_destruct; - device->type = type; + device->type = type; + device->mode = CONNMAN_DEVICE_MODE_UNKNOWN; device->policy = CONNMAN_DEVICE_POLICY_AUTO; + device->networks = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, unregister_network); + return device; } @@ -368,7 +750,29 @@ void connman_device_unref(struct connman_device *device) } /** - * connman_device_set_interface: + * connman_device_get_name: + * @device: device structure + * + * Get unique name of device + */ +const char *connman_device_get_name(struct connman_device *device) +{ + return device->element.name; +} + +/** + * connman_device_get_path: + * @device: device structure + * + * Get path name of device + */ +const char *connman_device_get_path(struct connman_device *device) +{ + return device->element.path; +} + +/** + * connman_device_set_index: * @device: device structure * @index: index number * @@ -419,6 +823,32 @@ const char *connman_device_get_interface(struct connman_device *device) } /** + * connman_device_set_policy: + * @device: device structure + * @policy: power and connection policy + * + * Change power and connection policy of device + */ +void connman_device_set_policy(struct connman_device *device, + enum connman_device_policy policy) +{ + device->policy = policy; +} + +/** + * connman_device_set_mode: + * @device: device structure + * @mode: network mode + * + * Change network mode of device + */ +void connman_device_set_mode(struct connman_device *device, + enum connman_device_mode mode) +{ + device->mode = mode; +} + +/** * connman_device_set_powered: * @device: device structure * @powered: powered state @@ -426,7 +856,7 @@ const char *connman_device_get_interface(struct connman_device *device) * Change power state of device */ int connman_device_set_powered(struct connman_device *device, - gboolean powered) + connman_bool_t powered) { DBusMessage *signal; DBusMessageIter entry, value; @@ -455,6 +885,15 @@ int connman_device_set_powered(struct connman_device *device, g_dbus_send_message(connection, signal); + if (powered == FALSE) + return 0; + + if (device->policy != CONNMAN_DEVICE_POLICY_AUTO) + return 0; + + if (device->driver->scan) + device->driver->scan(device); + return 0; } @@ -466,15 +905,18 @@ int connman_device_set_powered(struct connman_device *device, * Change carrier state of device (only for device without scanning) */ int connman_device_set_carrier(struct connman_device *device, - gboolean carrier) + connman_bool_t carrier) { DBG("driver %p carrier %d", device, carrier); - if (!device->driver) - return -EINVAL; - - if (device->driver->scan) + switch (device->mode) { + case CONNMAN_DEVICE_MODE_UNKNOWN: + case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: + case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: return -EINVAL; + case CONNMAN_DEVICE_MODE_TRANSPORT_IP: + break; + } if (device->carrier == carrier) return -EALREADY; @@ -486,8 +928,8 @@ int connman_device_set_carrier(struct connman_device *device, element = connman_element_create(NULL); if (element != NULL) { - element->type = CONNMAN_ELEMENT_TYPE_DEVICE; - element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK; + element->type = CONNMAN_ELEMENT_TYPE_DHCP; + element->subtype = device->element.subtype; element->index = device->element.index; if (connman_element_register(element, @@ -500,6 +942,11 @@ int connman_device_set_carrier(struct connman_device *device, return 0; } +static void connect_known_network(struct connman_device *device) +{ + DBG("device %p", device); +} + /** * connman_device_set_scanning: * @device: device structure @@ -508,7 +955,7 @@ int connman_device_set_carrier(struct connman_device *device, * Change scanning state of device */ int connman_device_set_scanning(struct connman_device *device, - gboolean scanning) + connman_bool_t scanning) { DBusMessage *signal; DBusMessageIter entry, value; @@ -516,10 +963,7 @@ int connman_device_set_scanning(struct connman_device *device, DBG("driver %p scanning %d", device, scanning); - if (!device->driver) - return -EINVAL; - - if (!device->driver->scan) + if (!device->driver || !device->driver->scan) return -EINVAL; if (device->scanning == scanning) @@ -543,6 +987,144 @@ int connman_device_set_scanning(struct connman_device *device, g_dbus_send_message(connection, signal); + if (scanning == TRUE) + return 0; + + if (device->connections > 0) + return 0; + + if (device->policy != CONNMAN_DEVICE_POLICY_AUTO) + return 0; + + connect_known_network(device); + + return 0; +} + +/** + * connman_device_set_string: + * @device: device structure + * @key: unique identifier + * @value: string value + * + * Set string value for specific key + */ +int connman_device_set_string(struct connman_device *device, + const char *key, const char *value) +{ + DBG("device %p key %s value %s", device, key, value); + + if (g_str_equal(key, "Name") == TRUE) { + g_free(device->name); + device->name = g_strdup(value); + } else if (g_str_equal(key, "Node") == TRUE) { + g_free(device->node); + device->node = g_strdup(value); + } + + return 0; +} + +/** + * connman_device_get_string: + * @device: device structure + * @key: unique identifier + * + * Get string value for specific key + */ +const char *connman_device_get_string(struct connman_device *device, + const char *key) +{ + DBG("device %p key %s", device); + + if (g_str_equal(key, "Name") == TRUE) + return device->name; + else if (g_str_equal(key, "Node") == TRUE) + return device->node; + + return NULL; +} + +void __connman_device_increase_connections(struct connman_device *device) +{ + device->connections++; +} + +void __connman_device_decrease_connections(struct connman_device *device) +{ + device->connections--; +} + +/** + * connman_device_add_network: + * @device: device structure + * @network: network structure + * + * Add new network to the device + */ +int connman_device_add_network(struct connman_device *device, + struct connman_network *network) +{ + const char *identifier = connman_network_get_identifier(network); + int err; + + DBG("device %p network %p", device, network); + + switch (device->mode) { + case CONNMAN_DEVICE_MODE_UNKNOWN: + case CONNMAN_DEVICE_MODE_TRANSPORT_IP: + return -EINVAL; + case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: + case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: + break; + } + + __connman_network_set_device(network, device); + + __connman_storage_load_network(network); + + err = connman_element_register((struct connman_element *) network, + &device->element); + if (err < 0) { + __connman_network_set_device(network, NULL); + return err; + } + + g_hash_table_insert(device->networks, g_strdup(identifier), + network); + + return 0; +} + +/** + * connman_device_get_network: + * @device: device structure + * @identifier: network identifier + * + * Get network for given identifier + */ +struct connman_network *connman_device_get_network(struct connman_device *device, + const char *identifier) +{ + DBG("device %p identifier %s", device, identifier); + + return g_hash_table_lookup(device->networks, identifier); +} + +/** + * connman_device_remove_network: + * @device: device structure + * @identifier: network identifier + * + * Remove network for given identifier + */ +int connman_device_remove_network(struct connman_device *device, + const char *identifier) +{ + DBG("device %p identifier %s", device, identifier); + + g_hash_table_remove(device->networks, identifier); + return 0; } @@ -554,6 +1136,8 @@ int connman_device_set_scanning(struct connman_device *device, */ int connman_device_register(struct connman_device *device) { + __connman_storage_load_device(device); + return connman_element_register(&device->element, NULL); } @@ -565,6 +1149,8 @@ int connman_device_register(struct connman_device *device) */ void connman_device_unregister(struct connman_device *device) { + __connman_storage_save_device(device); + connman_element_unregister(&device->element); } @@ -591,34 +1177,6 @@ void connman_device_set_data(struct connman_device *device, void *data) device->driver_data = data; } -static void device_enable(struct connman_device *device) -{ - DBG("device %p", device); - - if (device->policy != CONNMAN_DEVICE_POLICY_AUTO) - return; - - if (device->powered == TRUE) - return; - - if (device->driver->enable) - device->driver->enable(device); -} - -static void device_disable(struct connman_device *device) -{ - DBG("device %p", device); - - if (device->policy != CONNMAN_DEVICE_POLICY_AUTO) - return; - - if (device->powered == FALSE) - return; - - if (device->driver->disable) - device->driver->disable(device); -} - static gboolean match_driver(struct connman_device *device, struct connman_device_driver *driver) { @@ -633,17 +1191,12 @@ static int device_probe(struct connman_element *element) { struct connman_device *device = element->device; GSList *list; - int err; DBG("element %p name %s", element, element->name); if (device == NULL) return -ENODEV; - err = register_interface(element); - if (err < 0) - return err; - for (list = driver_list; list; list = list->next) { struct connman_device_driver *driver = list->data; @@ -654,12 +1207,14 @@ static int device_probe(struct connman_element *element) if (driver->probe(device) == 0) { device->driver = driver; - device_enable(device); break; } } - return 0; + if (device->driver == NULL) + return -ENODEV; + + return setup_device(device); } static void device_remove(struct connman_element *element) @@ -671,14 +1226,10 @@ static void device_remove(struct connman_element *element) if (device == NULL) return; - unregister_interface(element); - - if (device->driver) { - device_disable(device); + if (device->driver == NULL) + return; - if (device->driver->remove) - device->driver->remove(device); - } + remove_device(device); } static struct connman_driver device_driver = { @@ -689,12 +1240,110 @@ static struct connman_driver device_driver = { .remove = device_remove, }; +static int device_load(struct connman_device *device) +{ + GKeyFile *keyfile; + gchar *pathname, *data = NULL; + gsize length; + char *str; + + DBG("device %p", device); + + pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, + device->element.name); + if (pathname == NULL) + return -ENOMEM; + + keyfile = g_key_file_new(); + + if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) { + g_free(pathname); + return -ENOENT; + } + + g_free(pathname); + + if (g_key_file_load_from_data(keyfile, data, length, + 0, NULL) == FALSE) { + g_free(data); + return -EILSEQ; + } + + g_free(data); + + str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL); + if (str != NULL) { + device->policy = string2policy(str); + g_free(str); + } + + g_key_file_free(keyfile); + + return 0; +} + +static int device_save(struct connman_device *device) +{ + GKeyFile *keyfile; + gchar *pathname, *data = NULL; + gsize length; + const char *str; + + DBG("device %p", device); + + pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, + device->element.name); + if (pathname == NULL) + return -ENOMEM; + + keyfile = g_key_file_new(); + + if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) + goto update; + + if (length > 0) { + if (g_key_file_load_from_data(keyfile, data, length, + 0, NULL) == FALSE) + goto done; + } + + g_free(data); + +update: + str = policy2string(device->policy); + if (str != NULL) + g_key_file_set_string(keyfile, "Configuration", "Policy", str); + + data = g_key_file_to_data(keyfile, &length, NULL); + + g_file_set_contents(pathname, data, length, NULL); + +done: + g_free(data); + + g_key_file_free(keyfile); + + g_free(pathname); + + return 0; +} + +static struct connman_storage device_storage = { + .name = "device", + .priority = CONNMAN_STORAGE_PRIORITY_LOW, + .device_load = device_load, + .device_save = device_save, +}; + int __connman_device_init(void) { DBG(""); connection = connman_dbus_get_connection(); + if (connman_storage_register(&device_storage) < 0) + connman_error("Failed to register device storage"); + return connman_driver_register(&device_driver); } @@ -704,5 +1353,7 @@ void __connman_device_cleanup(void) connman_driver_unregister(&device_driver); + connman_storage_unregister(&device_storage); + dbus_connection_unref(connection); }