X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fdevice.c;h=a2b8f6f120da5f7b0ef5290a798bea68e36be064;hb=621adb59b0fc8d576e5372ae7221aae3e055b726;hp=48f3f7d275043ad79fb7d74a1b55d5a06b665a3f;hpb=e061175d100cbb068b572030b88981f83984287c;p=connman diff --git a/src/device.c b/src/device.c index 48f3f7d..a2b8f6f 100644 --- a/src/device.c +++ b/src/device.c @@ -33,18 +33,23 @@ struct connman_device { 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; + connman_bool_t disconnected; + connman_uint8_t priority; char *name; char *node; char *interface; + unsigned int connections; struct connman_device_driver *driver; void *driver_data; connman_bool_t registered; + char *last_network; + struct connman_network *network; GHashTable *networks; }; @@ -128,7 +133,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; @@ -242,6 +247,10 @@ static DBusMessage *get_properties(DBusConnection *conn, DBG("conn %p", conn); + if (__connman_security_check_privilege(msg, + CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0) + return __connman_error_permission_denied(msg); + reply = dbus_message_new_method_return(msg); if (reply == NULL) return NULL; @@ -276,6 +285,10 @@ static DBusMessage *get_properties(DBusConnection *conn, connman_dbus_dict_append_variant(&dict, "Policy", DBUS_TYPE_STRING, &str); + if (device->priority > 0) + connman_dbus_dict_append_variant(&dict, "Priority", + DBUS_TYPE_BYTE, &device->priority); + connman_dbus_dict_append_variant(&dict, "Powered", DBUS_TYPE_BOOLEAN, &device->powered); @@ -285,7 +298,9 @@ static DBusMessage *get_properties(DBusConnection *conn, switch (device->mode) { case CONNMAN_DEVICE_MODE_UNKNOWN: + break; case CONNMAN_DEVICE_MODE_TRANSPORT_IP: + __connman_element_append_ipv4(&device->element, &dict); break; case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: @@ -307,6 +322,7 @@ static DBusMessage *set_property(DBusConnection *conn, struct connman_device *device = data; DBusMessageIter iter, value; const char *name; + int type; DBG("conn %p", conn); @@ -317,13 +333,19 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &value); - if (__connman_security_check_privileges(msg) < 0) + if (__connman_security_check_privilege(msg, + CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) return __connman_error_permission_denied(msg); + type = dbus_message_iter_get_arg_type(&value); + if (g_str_equal(name, "Powered") == TRUE) { - gboolean powered; + connman_bool_t powered; int err; + if (type != DBUS_TYPE_BOOLEAN) + return __connman_error_invalid_arguments(msg); + dbus_message_iter_get_basic(&value, &powered); if (device->powered == powered) @@ -337,6 +359,9 @@ static DBusMessage *set_property(DBusConnection *conn, const char *str; int err; + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + dbus_message_iter_get_basic(&value, &str); policy = string2policy(str); if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN) @@ -345,9 +370,29 @@ static DBusMessage *set_property(DBusConnection *conn, err = set_policy(conn, device, policy); if (err < 0) return __connman_error_failed(msg); + } else if (g_str_equal(name, "Priority") == TRUE) { + connman_uint8_t priority; + + if (type != DBUS_TYPE_BYTE) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value, &priority); + + device->priority = priority; + } else if (g_str_has_prefix(name, "IPv4") == TRUE) { + switch (device->mode) { + case CONNMAN_DEVICE_MODE_UNKNOWN: + case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: + case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: + return __connman_error_invalid_arguments(msg); + case CONNMAN_DEVICE_MODE_TRANSPORT_IP: + __connman_element_set_ipv4(&device->element, + name, &value); + break; + } } - __connman_element_store(&device->element); + __connman_storage_save_device(device); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } @@ -357,7 +402,8 @@ static DBusMessage *create_network(DBusConnection *conn, { DBG("conn %p", conn); - if (__connman_security_check_privileges(msg) < 0) + if (__connman_security_check_privilege(msg, + CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) return __connman_error_permission_denied(msg); return __connman_error_invalid_arguments(msg); @@ -368,7 +414,8 @@ static DBusMessage *remove_network(DBusConnection *conn, { DBG("conn %p", conn); - if (__connman_security_check_privileges(msg) < 0) + if (__connman_security_check_privilege(msg, + CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) return __connman_error_permission_denied(msg); return __connman_error_invalid_arguments(msg); @@ -550,6 +597,9 @@ static void probe_driver(struct connman_element *element, gpointer user_data) if (element->device == NULL) return; + if (element->device->driver != NULL) + return; + if (driver->probe(element->device) < 0) return; @@ -587,7 +637,7 @@ static void remove_driver(struct connman_element *element, gpointer user_data) connman_bool_t __connman_device_has_driver(struct connman_device *device) { - if (device->driver == NULL) + if (device == NULL || device->driver == NULL) return FALSE; return device->registered; @@ -661,6 +711,8 @@ static void device_destruct(struct connman_element *element) g_free(device->name); g_free(device->interface); + g_free(device->last_network); + g_hash_table_destroy(device->networks); device->networks = NULL; } @@ -678,6 +730,7 @@ struct connman_device *connman_device_create(const char *node, enum connman_device_type type) { struct connman_device *device; + const char *str; DBG("node %s type %d", node, type); @@ -687,36 +740,48 @@ struct connman_device *connman_device_create(const char *node, DBG("device %p", device); - device->element.refcount = 1; + __connman_element_initialize(&device->element); 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; + + str = type2string(type); + if (str != NULL) + connman_element_set_static_property(&device->element, + "Type", DBUS_TYPE_STRING, &str); + + device->element.ipv4.method = CONNMAN_IPV4_METHOD_DHCP; + + device->type = type; + device->mode = CONNMAN_DEVICE_MODE_UNKNOWN; + device->policy = CONNMAN_DEVICE_POLICY_AUTO; switch (type) { case CONNMAN_DEVICE_TYPE_UNKNOWN: case CONNMAN_DEVICE_TYPE_VENDOR: + device->priority = 0; + break; + case CONNMAN_DEVICE_TYPE_ETHERNET: case CONNMAN_DEVICE_TYPE_WIFI: + device->priority = 100; + break; case CONNMAN_DEVICE_TYPE_WIMAX: + device->priority = 20; + break; case CONNMAN_DEVICE_TYPE_BLUETOOTH: + device->priority = 50; + break; 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; + device->priority = 60; break; } - device->element.device = device; - device->element.destruct = device_destruct; - - 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); @@ -749,6 +814,17 @@ void connman_device_unref(struct connman_device *device) } /** + * 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 * @@ -837,6 +913,17 @@ void connman_device_set_mode(struct connman_device *device, } /** + * connman_device_get_mode: + * @device: device structure + * + * Get network mode of device + */ +enum connman_device_mode connman_device_get_mode(struct connman_device *device) +{ + return device->mode; +} + +/** * connman_device_set_powered: * @device: device structure * @powered: powered state @@ -873,6 +960,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; } @@ -903,13 +999,25 @@ int connman_device_set_carrier(struct connman_device *device, device->carrier = carrier; if (carrier == TRUE) { + enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN; struct connman_element *element; + switch (device->element.ipv4.method) { + case CONNMAN_IPV4_METHOD_UNKNOWN: + case CONNMAN_IPV4_METHOD_OFF: + return 0; + case CONNMAN_IPV4_METHOD_STATIC: + type = CONNMAN_ELEMENT_TYPE_IPV4; + break; + case CONNMAN_IPV4_METHOD_DHCP: + type = CONNMAN_ELEMENT_TYPE_DHCP; + break; + } + element = connman_element_create(NULL); if (element != NULL) { - element->type = CONNMAN_ELEMENT_TYPE_DHCP; - element->subtype = device->element.subtype; - element->index = device->element.index; + element->type = type; + element->index = device->element.index; if (connman_element_register(element, &device->element) < 0) @@ -921,6 +1029,118 @@ int connman_device_set_carrier(struct connman_device *device, return 0; } +void __connman_device_disconnect(struct connman_device *device) +{ + GHashTableIter iter; + gpointer key, value; + + DBG("device %p", device); + + connman_device_set_disconnected(device, TRUE); + + g_hash_table_iter_init(&iter, device->networks); + + while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) { + struct connman_network *network = value; + + if (connman_network_get_connected(network) == TRUE) + __connman_network_disconnect(network); + } +} + +static void connect_known_network(struct connman_device *device) +{ + struct connman_network *network = NULL; + GHashTableIter iter; + gpointer key, value; + unsigned int count = 0; + + DBG("device %p", device); + + g_hash_table_iter_init(&iter, device->networks); + + while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) { + connman_uint8_t old_priority, new_priority; + connman_uint8_t old_strength, new_strength; + const char *name; + + count++; + + name = connman_network_get_string(value, "Name"); + if (name != NULL && device->last_network != NULL) { + if (g_str_equal(name, device->last_network) == TRUE) { + network = value; + break; + } + } + + if (connman_network_get_remember(value) == FALSE) + continue; + + if (network == NULL) { + network = value; + continue; + } + + old_priority = connman_network_get_uint8(network, "Priority"); + new_priority = connman_network_get_uint8(value, "Priority"); + + if (new_priority != old_priority) { + if (new_priority > old_priority) + network = value; + continue; + } + + old_strength = connman_network_get_uint8(network, "Strength"); + new_strength = connman_network_get_uint8(value, "Strength"); + + if (new_strength > old_strength) + network = value; + } + + if (network != NULL) { + int err; + + err = connman_network_connect(network); + if (err == 0 || err == -EINPROGRESS) + return; + } + + if (count > 0) + return; + + if (device->driver && device->driver->scan) + device->driver->scan(device); +} + +static void mark_network_unavailable(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_network *network = value; + + if (connman_network_get_connected(network) == TRUE) + return; + + connman_network_set_available(network, FALSE); +} + +static gboolean remove_unavailable_network(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_network *network = value; + + if (connman_network_get_connected(network) == TRUE) + return FALSE; + + if (connman_network_get_remember(network) == TRUE) + return FALSE; + + if (connman_network_get_available(network) == TRUE) + return FALSE; + + return TRUE; +} + /** * connman_device_set_scanning: * @device: device structure @@ -961,6 +1181,55 @@ int connman_device_set_scanning(struct connman_device *device, g_dbus_send_message(connection, signal); + if (scanning == TRUE) { + g_hash_table_foreach(device->networks, + mark_network_unavailable, NULL); + return 0; + } + + g_hash_table_foreach_remove(device->networks, + remove_unavailable_network, NULL); + + if (device->connections > 0) + return 0; + + if (device->disconnected == TRUE) + return 0; + + if (device->policy != CONNMAN_DEVICE_POLICY_AUTO) + return 0; + + connect_known_network(device); + + return 0; +} + +/** + * connman_device_set_disconnected: + * @device: device structure + * @disconnected: disconnected state + * + * Change disconnected state of device (only for device with networks) + */ +int connman_device_set_disconnected(struct connman_device *device, + connman_bool_t disconnected) +{ + DBG("driver %p disconnected %d", device, disconnected); + + 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; + } + + if (device->disconnected == disconnected) + return -EALREADY; + + device->disconnected = disconnected; + return 0; } @@ -998,7 +1267,7 @@ int connman_device_set_string(struct connman_device *device, const char *connman_device_get_string(struct connman_device *device, const char *key) { - DBG("device %p key %s", device); + DBG("device %p key %s", device, key); if (g_str_equal(key, "Name") == TRUE) return device->name; @@ -1008,6 +1277,45 @@ const char *connman_device_get_string(struct connman_device *device, return NULL; } +static void set_offlinemode(struct connman_element *element, gpointer user_data) +{ + struct connman_device *device = element->device; + connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data); + connman_bool_t powered; + + DBG("element %p name %s", element, element->name); + + if (device == NULL) + return; + + powered = (offlinemode == TRUE) ? FALSE : TRUE; + + if (device->powered == powered) + return; + + set_powered(device, powered); +} + +int __connman_device_set_offlinemode(connman_bool_t offlinemode) +{ + DBG("offlinmode %d", offlinemode); + + __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, + set_offlinemode, GUINT_TO_POINTER(offlinemode)); + + return 0; +} + +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 @@ -1081,6 +1389,19 @@ int connman_device_remove_network(struct connman_device *device, return 0; } +void __connman_device_set_network(struct connman_device *device, + struct connman_network *network) +{ + const char *name; + + if (network != NULL) { + name = connman_network_get_string(network, "Name"); + device->last_network = g_strdup(name); + } + + device->network = network; +} + /** * connman_device_register: * @device: device structure @@ -1091,6 +1412,16 @@ int connman_device_register(struct connman_device *device) { __connman_storage_load_device(device); + 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: + __connman_storage_init_network(device); + break; + } + return connman_element_register(&device->element, NULL); } @@ -1150,6 +1481,9 @@ static int device_probe(struct connman_element *element) if (device == NULL) return -ENODEV; + if (device->driver != NULL) + return -EALREADY; + for (list = driver_list; list; list = list->next) { struct connman_device_driver *driver = list->data; @@ -1198,7 +1532,8 @@ static int device_load(struct connman_device *device) GKeyFile *keyfile; gchar *pathname, *data = NULL; gsize length; - const char *str; + char *str; + int val; DBG("device %p", device); @@ -1225,8 +1560,20 @@ static int device_load(struct connman_device *device) g_free(data); str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL); - if (str != NULL) + if (str != NULL) { device->policy = string2policy(str); + g_free(str); + } + + val = g_key_file_get_integer(keyfile, "Configuration", + "Priority", NULL); + if (val > 0) + device->priority = val; + + str = g_key_file_get_string(keyfile, "Configuration", + "LastNetwork", NULL); + if (str != NULL) + device->last_network = str; g_key_file_free(keyfile); @@ -1265,6 +1612,14 @@ update: if (str != NULL) g_key_file_set_string(keyfile, "Configuration", "Policy", str); + if (device->priority > 0) + g_key_file_set_integer(keyfile, "Configuration", + "Priority", device->priority); + + if (device->last_network != NULL) + g_key_file_set_string(keyfile, "Configuration", + "LastNetwork", device->last_network); + data = g_key_file_to_data(keyfile, &length, NULL); g_file_set_contents(pathname, data, length, NULL); @@ -1276,6 +1631,9 @@ done: g_free(pathname); + if (device->network != NULL) + __connman_storage_save_network(device->network); + return 0; }