X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fdevice.c;h=ef899332551b37f0f7d22810658fdea2ecef660d;hb=b972ec96236afc662b21ace09d6adaa29d222411;hp=23fd1b1589bca34d8f1cceb298c60046bf819441;hpb=37b70174dc7f7e8e048a95bca7ecd9e102d14038;p=connman diff --git a/src/device.c b/src/device.c index 23fd1b1..ef89933 100644 --- a/src/device.c +++ b/src/device.c @@ -28,6 +28,91 @@ #include "connman.h" +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; + char *path; + char *interface; + + struct connman_device_driver *driver; + void *driver_data; + + GHashTable *networks; +}; + +static const char *type2description(enum connman_device_type type) +{ + switch (type) { + 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: + return "Cellular"; + default: + return NULL; + } +} + +static const char *type2string(enum connman_device_type type) +{ + switch (type) { + 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"; + case CONNMAN_DEVICE_TYPE_HSO: + return "cellular"; + default: + return NULL; + } +} + +static const char *policy2string(enum connman_device_policy policy) +{ + switch (policy) { + case CONNMAN_DEVICE_POLICY_IGNORE: + return "ignore"; + case CONNMAN_DEVICE_POLICY_OFF: + return "off"; + case CONNMAN_DEVICE_POLICY_AUTO: + return "auto"; + case CONNMAN_DEVICE_POLICY_MANUAL: + return "manual"; + default: + return NULL; + } +} + +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, gboolean powered) { struct connman_device_driver *driver = device->driver; @@ -53,12 +138,88 @@ 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_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; + default: + 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); @@ -73,9 +234,43 @@ 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", + DBUS_TYPE_STRING, &str); + + if (device->interface != NULL) + connman_dbus_dict_append_variant(&dict, "Interface", + DBUS_TYPE_STRING, &device->interface); + + str = policy2string(device->policy); + if (str != NULL) + connman_dbus_dict_append_variant(&dict, "Policy", + DBUS_TYPE_STRING, &str); + connman_dbus_dict_append_variant(&dict, "Powered", DBUS_TYPE_BOOLEAN, &device->powered); + if (device->driver && device->driver->scan) + connman_dbus_dict_append_variant(&dict, "Scanning", + DBUS_TYPE_BOOLEAN, &device->scanning); + + if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK) { + dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + append_networks(device, &entry); + dbus_message_iter_close_container(&dict, &entry); + } + dbus_message_iter_close_container(&array, &dict); return reply; @@ -112,9 +307,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_element_store(&device->element); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } @@ -144,9 +352,22 @@ 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); + if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK) + return __connman_error_not_supported(msg); + + if (!device->driver || !device->driver->scan) + return __connman_error_not_supported(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[] = { @@ -165,12 +386,45 @@ static GDBusSignalTable device_signals[] = { static DBusConnection *connection; -static int register_interface(struct connman_element *element) +static void append_devices(DBusMessageIter *entry) { - struct connman_device *device = connman_element_get_data(element); + DBusMessageIter value, iter; + const char *key = "Devices"; - g_dbus_unregister_interface(connection, element->path, - CONNMAN_DEVICE_INTERFACE); + 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; if (g_dbus_register_interface(connection, element->path, CONNMAN_DEVICE_INTERFACE, @@ -180,11 +434,15 @@ static int register_interface(struct connman_element *element) return -EIO; } + emit_devices_signal(); + return 0; } static void unregister_interface(struct connman_element *element) { + emit_devices_signal(); + g_dbus_unregister_interface(connection, element->path, CONNMAN_DEVICE_INTERFACE); } @@ -232,9 +490,202 @@ void connman_device_driver_unregister(struct connman_device_driver *driver) driver_list = g_slist_remove(driver_list, 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) +{ + struct connman_device *device = element->device; + + DBG("element %p name %s", element, element->name); + + g_free(device->interface); + + g_hash_table_destroy(device->networks); +} + +/** + * connman_device_create: + * @node: device node name (for example an address) + * @type: device type + * + * Allocate a new device of given #type and assign the #node name to it. + * + * Returns: a newly-allocated #connman_device structure + */ +struct connman_device *connman_device_create(const char *node, + enum connman_device_type type) +{ + struct connman_device *device; + + DBG("node %s type %d", node, type); + + device = g_try_new0(struct connman_device, 1); + if (device == NULL) + return NULL; + + 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; + + device->element.device = device; + device->element.destruct = device_destruct; + + device->type = type; + device->mode = CONNMAN_DEVICE_MODE_NO_NETWORK; + 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; +} + +/** + * connman_device_ref: + * @device: device structure + * + * Increase reference counter of device + */ +struct connman_device *connman_device_ref(struct connman_device *device) +{ + if (connman_element_ref(&device->element) == NULL) + return NULL; + + return device; +} + +/** + * connman_device_unref: + * @device: device structure + * + * Decrease reference counter of device + */ +void connman_device_unref(struct connman_device *device) +{ + connman_element_unref(&device->element); +} + +/** + * 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 + * + * Get path name of device + */ +const char *connman_device_get_path(struct connman_device *device) +{ + return device->path; +} + +/** + * connman_device_set_index: + * @device: device structure + * @index: index number + * + * Set index number of device + */ +void connman_device_set_index(struct connman_device *device, int index) +{ + device->element.index = index; +} + +/** + * connman_device_get_index: + * @device: device structure + * + * Get index number of device + */ +int connman_device_get_index(struct connman_device *device) +{ + return device->element.index; +} + +/** + * connman_device_set_interface: + * @device: device structure + * @interface: interface name + * + * Set interface name of device + */ +void connman_device_set_interface(struct connman_device *device, + const char *interface) +{ + g_free(device->element.devname); + device->element.devname = g_strdup(interface); + + g_free(device->interface); + device->interface = g_strdup(interface); +} + +/** + * connman_device_get_interface: + * @device: device structure + * + * Get interface name of device + */ +const char *connman_device_get_interface(struct connman_device *device) +{ + return device->interface; +} + +/** + * 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 * * Change power state of device */ @@ -252,7 +703,7 @@ int connman_device_set_powered(struct connman_device *device, device->powered = powered; - signal = dbus_message_new_signal(device->element->path, + signal = dbus_message_new_signal(device->element.path, CONNMAN_DEVICE_INTERFACE, "PropertyChanged"); if (signal == NULL) return 0; @@ -271,10 +722,227 @@ int connman_device_set_powered(struct connman_device *device, return 0; } +/** + * connman_device_set_carrier: + * @device: device structure + * @carrier: carrier state + * + * Change carrier state of device (only for device without scanning) + */ +int connman_device_set_carrier(struct connman_device *device, + gboolean carrier) +{ + DBG("driver %p carrier %d", device, carrier); + + if (device->mode != CONNMAN_DEVICE_MODE_NO_NETWORK) + return -EINVAL; + + if (device->carrier == carrier) + return -EALREADY; + + device->carrier = carrier; + + if (carrier == TRUE) { + struct connman_element *element; + + element = connman_element_create(NULL); + if (element != NULL) { + element->type = CONNMAN_ELEMENT_TYPE_DEVICE; + element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK; + element->index = device->element.index; + + if (connman_element_register(element, + &device->element) < 0) + connman_element_unref(element); + } + } else + connman_element_unregister_children(&device->element); + + return 0; +} + +/** + * connman_device_set_scanning: + * @device: device structure + * @scanning: scanning state + * + * Change scanning state of device + */ +int connman_device_set_scanning(struct connman_device *device, + gboolean scanning) +{ + DBusMessage *signal; + DBusMessageIter entry, value; + const char *key = "Scanning"; + + DBG("driver %p scanning %d", device, scanning); + + if (!device->driver || !device->driver->scan) + return -EINVAL; + + if (device->scanning == scanning) + return -EALREADY; + + device->scanning = scanning; + + 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); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_BOOLEAN_AS_STRING, &value); + dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning); + dbus_message_iter_close_container(&entry, &value); + + g_dbus_send_message(connection, signal); + + return 0; +} + +/** + * 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); + + if (device->mode == CONNMAN_DEVICE_MODE_NO_NETWORK) + return -EINVAL; + + err = connman_element_register((struct connman_element *) network, + &device->element); + if (err < 0) + 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; +} + +/** + * connman_device_register: + * @device: device structure + * + * Register device with the system + */ +int connman_device_register(struct connman_device *device) +{ + return connman_element_register(&device->element, NULL); +} + +/** + * connman_device_unregister: + * @device: device structure + * + * Unregister device with the system + */ +void connman_device_unregister(struct connman_device *device) +{ + connman_element_unregister(&device->element); +} + +/** + * connman_device_get_data: + * @device: device structure + * + * Get private device data pointer + */ +void *connman_device_get_data(struct connman_device *device) +{ + return device->driver_data; +} + +/** + * connman_device_set_data: + * @device: device structure + * @data: data pointer + * + * Set private device data pointer + */ +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) { - if (device->element->subtype == driver->type || + if (device->type == driver->type || driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN) return TRUE; @@ -283,28 +951,14 @@ static gboolean match_driver(struct connman_device *device, static int device_probe(struct connman_element *element) { - struct connman_device *device; + struct connman_device *device = element->device; GSList *list; int err; DBG("element %p name %s", element, element->name); - if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK) - return -ENODEV; - - device = g_try_new0(struct connman_device, 1); if (device == NULL) - return -ENOMEM; - - device->element = element; - - connman_element_set_data(element, device); - - err = register_interface(element); - if (err < 0) { - g_free(device); - return err; - } + return -ENODEV; for (list = driver_list; list; list = list->next) { struct connman_device_driver *driver = list->data; @@ -320,23 +974,39 @@ static int device_probe(struct connman_element *element) } } + if (!device->driver) + return -ENODEV; + + err = register_interface(element); + if (err < 0) { + if (device->driver->remove) + device->driver->remove(device); + return err; + } + + device_enable(device); + return 0; } static void device_remove(struct connman_element *element) { - struct connman_device *device = connman_element_get_data(element); + struct connman_device *device = element->device; DBG("element %p name %s", element, element->name); - unregister_interface(element); + if (device == NULL) + return; - if (device->driver && device->driver->remove) - device->driver->remove(device); + if (!device->driver) + return; - connman_element_set_data(element, NULL); + device_disable(device); - g_free(device); + unregister_interface(element); + + if (device->driver->remove) + device->driver->remove(device); } static struct connman_driver device_driver = {