X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fdevice.c;h=eb52ff605a3d5c48b5b7d46b28e9db738f4c90a2;hb=5d5856602967fb8e1055bb5923bac117093a8214;hp=590b9557a2d208576d63732b7eb2dc5f0ca9d84c;hpb=4c9720135427e44a128e80462acec3cf55eba31d;p=connman diff --git a/src/device.c b/src/device.c index 590b955..eb52ff6 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 @@ -33,21 +33,27 @@ struct connman_device { enum connman_device_type type; enum connman_device_mode mode; enum connman_device_policy policy; - gboolean powered; - gboolean carrier; - gboolean scanning; - char *path; + connman_bool_t powered; + connman_bool_t carrier; + connman_bool_t scanning; + char *name; + char *node; char *interface; struct connman_device_driver *driver; void *driver_data; + 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: @@ -57,15 +63,21 @@ static const char *type2description(enum connman_device_type type) 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"; - default: - return NULL; } + + 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: @@ -75,15 +87,20 @@ static const char *type2string(enum connman_device_type type) case CONNMAN_DEVICE_TYPE_BLUETOOTH: return "bluetooth"; case CONNMAN_DEVICE_TYPE_HSO: + case CONNMAN_DEVICE_TYPE_HUAWEI: + case CONNMAN_DEVICE_TYPE_NOZOMI: + case CONNMAN_DEVICE_TYPE_NOVATEL: return "cellular"; - default: - return NULL; } + + 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_OFF: @@ -92,9 +109,9 @@ static const char *policy2string(enum connman_device_policy policy) return "auto"; case CONNMAN_DEVICE_POLICY_MANUAL: return "manual"; - default: - return NULL; } + + return NULL; } static enum connman_device_policy string2policy(const char *policy) @@ -111,7 +128,7 @@ static enum connman_device_policy string2policy(const char *policy) return CONNMAN_DEVICE_POLICY_UNKNOWN; } -static int set_powered(struct connman_device *device, gboolean powered) +static int set_powered(struct connman_device *device, connman_bool_t powered) { struct connman_device_driver *driver = device->driver; int err; @@ -127,6 +144,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 @@ -151,6 +170,10 @@ static int set_policy(DBusConnection *connection, 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); @@ -160,8 +183,6 @@ static int set_policy(DBusConnection *connection, if (device->powered == FALSE) err = set_powered(device, TRUE); break; - default: - break; } if (err < 0) @@ -262,11 +283,17 @@ static DBusMessage *get_properties(DBusConnection *conn, connman_dbus_dict_append_variant(&dict, "Scanning", DBUS_TYPE_BOOLEAN, &device->scanning); - if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK) { + 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); @@ -294,7 +321,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); @@ -320,7 +347,7 @@ static DBusMessage *set_property(DBusConnection *conn, return __connman_error_failed(msg); } - __connman_element_store(&device->element); + __connman_storage_save_device(device); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } @@ -355,12 +382,21 @@ static DBusMessage *propose_scan(DBusConnection *conn, DBG("conn %p", conn); - if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK) + 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); @@ -424,6 +460,8 @@ static int register_interface(struct connman_element *element) { struct connman_device *device = element->device; + DBG("element %p name %s", element, element->name); + if (g_dbus_register_interface(connection, element->path, CONNMAN_DEVICE_INTERFACE, device_methods, device_signals, @@ -432,6 +470,8 @@ static int register_interface(struct connman_element *element) return -EIO; } + device->registered = TRUE; + emit_devices_signal(); return 0; @@ -439,12 +479,120 @@ static int register_interface(struct connman_element *element) 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) @@ -470,7 +618,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; } @@ -486,6 +635,9 @@ 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) @@ -505,9 +657,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; } /** @@ -539,19 +694,27 @@ struct connman_device *connman_device_create(const char *node, 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; - default: - device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN; - break; } device->element.device = device; device->element.destruct = device_destruct; - device->type = type; - device->mode = CONNMAN_DEVICE_MODE_NO_NETWORK; + 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, @@ -586,22 +749,6 @@ void connman_device_unref(struct connman_device *device) } /** - * connman_device_set_path: - * @device: device structure - * @path: path name - * - * Set path name of device - */ -void connman_device_set_path(struct connman_device *device, const char *path) -{ - g_free(device->element.devpath); - device->element.devpath = g_strdup(path); - - g_free(device->path); - device->path = g_strdup(path); -} - -/** * connman_device_get_path: * @device: device structure * @@ -609,7 +756,7 @@ void connman_device_set_path(struct connman_device *device, const char *path) */ const char *connman_device_get_path(struct connman_device *device) { - return device->path; + return device->element.path; } /** @@ -697,7 +844,7 @@ void connman_device_set_mode(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; @@ -737,12 +884,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->mode != CONNMAN_DEVICE_MODE_NO_NETWORK) + 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; @@ -754,8 +907,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, @@ -776,7 +929,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; @@ -812,6 +965,50 @@ int connman_device_set_scanning(struct connman_device *device, } /** + * 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; +} + +/** * connman_device_add_network: * @device: device structure * @network: network structure @@ -826,13 +1023,25 @@ int connman_device_add_network(struct connman_device *device, DBG("device %p network %p", device, network); - if (device->mode == CONNMAN_DEVICE_MODE_NO_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) + if (err < 0) { + __connman_network_set_device(network, NULL); return err; + } g_hash_table_insert(device->networks, g_strdup(identifier), network); @@ -880,6 +1089,8 @@ int connman_device_remove_network(struct connman_device *device, */ int connman_device_register(struct connman_device *device) { + __connman_storage_load_device(device); + return connman_element_register(&device->element, NULL); } @@ -891,6 +1102,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); } @@ -917,35 +1130,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_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; - - if (device->driver->disable) - device->driver->disable(device); -} - static gboolean match_driver(struct connman_device *device, struct connman_device_driver *driver) { @@ -960,7 +1144,6 @@ 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); @@ -981,19 +1164,10 @@ static int device_probe(struct connman_element *element) } } - if (!device->driver) + if (device->driver == NULL) return -ENODEV; - err = register_interface(element); - if (err < 0) { - if (device->driver->remove) - device->driver->remove(device); - return err; - } - - device_enable(device); - - return 0; + return setup_device(device); } static void device_remove(struct connman_element *element) @@ -1005,15 +1179,10 @@ static void device_remove(struct connman_element *element) if (device == NULL) return; - if (!device->driver) + if (device->driver == NULL) return; - device_disable(device); - - unregister_interface(element); - - if (device->driver->remove) - device->driver->remove(device); + remove_device(device); } static struct connman_driver device_driver = { @@ -1024,12 +1193,108 @@ 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; + 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) { + 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_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); } @@ -1039,5 +1304,7 @@ void __connman_device_cleanup(void) connman_driver_unregister(&device_driver); + connman_storage_unregister(&device_storage); + dbus_connection_unref(connection); }