X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fdevice.c;h=05e27ab28c5eaeb84a6b9f45f25df0d0a07d3a56;hb=e45a1a34604973498c3fa509c44913b20fd1d9ec;hp=4afb2f44e014a39950d5a2d3e36b8e1ff4a5f038;hpb=bce87dffa9157ec6d9ee9621b526e72f4798d906;p=platform%2Fupstream%2Fconnman.git diff --git a/src/device.c b/src/device.c index 4afb2f4..05e27ab 100644 --- a/src/device.c +++ b/src/device.c @@ -36,20 +36,24 @@ struct connman_device { struct connman_element element; enum connman_device_type type; enum connman_device_mode mode; - connman_bool_t secondary; + connman_bool_t offlinemode; + connman_bool_t blocked; connman_bool_t powered; - connman_bool_t carrier; + connman_bool_t powered_pending; + connman_bool_t powered_persistent; connman_bool_t scanning; connman_bool_t disconnected; + connman_bool_t reconnect; connman_uint16_t scan_interval; char *name; char *node; char *address; char *interface; + char *control; char *ident; + int phyindex; unsigned int connections; guint scan_timeout; - struct connman_ipconfig *ipconfig; struct connman_device_driver *driver; void *driver_data; @@ -81,6 +85,38 @@ static gboolean device_scan_trigger(gpointer user_data) return TRUE; } +static void clear_scan_trigger(struct connman_device *device) +{ + if (device->scan_timeout > 0) { + g_source_remove(device->scan_timeout); + device->scan_timeout = 0; + } +} + +static void reset_scan_trigger(struct connman_device *device) +{ + clear_scan_trigger(device); + + if (device->scan_interval > 0) { + guint interval = device->scan_interval; + device->scan_timeout = g_timeout_add_seconds(interval, + device_scan_trigger, device); + } +} + +static void force_scan_trigger(struct connman_device *device) +{ + clear_scan_trigger(device); + + device->scan_timeout = g_timeout_add_seconds(5, + device_scan_trigger, device); +} + +void connman_device_schedule_scan(struct connman_device *device) +{ + reset_scan_trigger(device); +} + static const char *type2description(enum connman_device_type type) { switch (type) { @@ -97,10 +133,9 @@ static const char *type2description(enum connman_device_type type) return "Bluetooth"; case CONNMAN_DEVICE_TYPE_GPS: return "GPS"; + case CONNMAN_DEVICE_TYPE_CELLULAR: + case CONNMAN_DEVICE_TYPE_MBM: case CONNMAN_DEVICE_TYPE_HSO: - case CONNMAN_DEVICE_TYPE_NOZOMI: - case CONNMAN_DEVICE_TYPE_HUAWEI: - case CONNMAN_DEVICE_TYPE_NOVATEL: return "Cellular"; } @@ -123,104 +158,105 @@ static const char *type2string(enum connman_device_type type) return "bluetooth"; case CONNMAN_DEVICE_TYPE_GPS: return "gps"; + case CONNMAN_DEVICE_TYPE_CELLULAR: + case CONNMAN_DEVICE_TYPE_MBM: 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 int set_connected(struct connman_device *device, - connman_bool_t connected) +enum connman_service_type __connman_device_get_service_type(struct connman_device *device) { - if (connected == TRUE) { - enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN; - struct connman_element *element; - - device->disconnected = TRUE; + enum connman_device_type type = connman_device_get_type(device); - switch (device->element.ipv4.method) { - case CONNMAN_IPCONFIG_METHOD_UNKNOWN: - case CONNMAN_IPCONFIG_METHOD_OFF: - return 0; - case CONNMAN_IPCONFIG_METHOD_STATIC: - type = CONNMAN_ELEMENT_TYPE_IPV4; - break; - case CONNMAN_IPCONFIG_METHOD_DHCP: - type = CONNMAN_ELEMENT_TYPE_DHCP; - break; - } - - element = connman_element_create(NULL); - if (element != NULL) { - struct connman_service *service; - - element->type = type; - element->index = device->element.index; - - if (connman_element_register(element, - &device->element) < 0) - connman_element_unref(element); - - device->disconnected = FALSE; - - service = __connman_service_lookup_from_device(device); - __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_CONFIGURATION); - } - } else { - connman_element_unregister_children(&device->element); - - device->disconnected = TRUE; + switch (type) { + case CONNMAN_DEVICE_TYPE_UNKNOWN: + case CONNMAN_DEVICE_TYPE_VENDOR: + case CONNMAN_DEVICE_TYPE_GPS: + break; + case CONNMAN_DEVICE_TYPE_ETHERNET: + return CONNMAN_SERVICE_TYPE_ETHERNET; + case CONNMAN_DEVICE_TYPE_WIFI: + return CONNMAN_SERVICE_TYPE_WIFI; + case CONNMAN_DEVICE_TYPE_WIMAX: + return CONNMAN_SERVICE_TYPE_WIMAX; + case CONNMAN_DEVICE_TYPE_BLUETOOTH: + return CONNMAN_SERVICE_TYPE_BLUETOOTH; + case CONNMAN_DEVICE_TYPE_CELLULAR: + case CONNMAN_DEVICE_TYPE_MBM: + case CONNMAN_DEVICE_TYPE_HSO: + return CONNMAN_SERVICE_TYPE_CELLULAR; } - return 0; + return CONNMAN_SERVICE_TYPE_UNKNOWN; } -static int set_carrier(struct connman_device *device, connman_bool_t carrier) +static void powered_changed(struct connman_device *device) { - struct connman_service *service; - - service = __connman_service_lookup_from_device(device); - __connman_service_set_carrier(service, carrier); - - return set_connected(device, carrier); + connman_dbus_property_changed_basic(device->element.path, + CONNMAN_DEVICE_INTERFACE, "Powered", + DBUS_TYPE_BOOLEAN, &device->powered); } static int set_powered(struct connman_device *device, connman_bool_t powered) { struct connman_device_driver *driver = device->driver; + enum connman_service_type type; int err; DBG("device %p powered %d", device, powered); + if (device->powered_pending == powered) + return -EALREADY; + if (!driver) return -EINVAL; + type = __connman_device_get_service_type(device); + if (powered == TRUE) { if (driver->enable) { + device->powered_pending = powered; + err = driver->enable(device); - __connman_notifier_device_type_increase(device->type); + if (err == 0) + __connman_notifier_enable(type); } else err = -EINVAL; } else { - g_hash_table_remove_all(device->networks); + device->powered_pending = powered; - set_carrier(device, FALSE); + device->reconnect = FALSE; + + clear_scan_trigger(device); + + g_hash_table_remove_all(device->networks); if (driver->disable) { err = driver->disable(device); - __connman_notifier_device_type_decrease(device->type); + if (err == 0) + __connman_notifier_disable(type); } else err = -EINVAL; } + if (err == 0) { + device->powered = powered; + + if (device->registered == TRUE) + powered_changed(device); + } + return err; } +void __connman_device_list(DBusMessageIter *iter, void *user_data) +{ + __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, iter); +} + static void append_path(gpointer key, gpointer value, gpointer user_data) { struct connman_element *element = value; @@ -270,10 +306,7 @@ static DBusMessage *get_properties(DBusConnection *conn, dbus_message_iter_init_append(reply, &array); - dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING - DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); + connman_dbus_dict_open(&array, &dict); if (device->name != NULL) connman_dbus_dict_append_variant(&dict, "Name", @@ -302,9 +335,6 @@ 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: if (device->scan_interval > 0) @@ -318,7 +348,7 @@ static DBusMessage *get_properties(DBusConnection *conn, break; } - dbus_message_iter_close_container(&array, &dict); + connman_dbus_dict_close(&array, &dict); return reply; } @@ -377,6 +407,10 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_get_basic(&value, &powered); + device->powered_persistent = powered; + + __connman_storage_save_device(device); + if (device->powered == powered) return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); @@ -384,22 +418,22 @@ static DBusMessage *set_property(DBusConnection *conn, return __connman_error_in_progress(msg); err = set_powered(device, powered); - if (err < 0 && err != -EINPROGRESS) - return __connman_error_failed(msg, -err); + if (err < 0) { + if (err != -EINPROGRESS) + return __connman_error_failed(msg, -err); - device->pending = dbus_message_ref(msg); + device->pending = dbus_message_ref(msg); - device->timeout = g_timeout_add_seconds(15, + device->timeout = g_timeout_add_seconds(15, powered_timeout, device); - return NULL; + return NULL; + } } else if (g_str_equal(name, "ScanInterval") == TRUE) { connman_uint16_t interval; switch (device->mode) { case CONNMAN_DEVICE_MODE_UNKNOWN: - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - return __connman_error_invalid_arguments(msg); case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: break; @@ -410,168 +444,19 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_get_basic(&value, &interval); - device->scan_interval = interval; + if (device->scan_interval != interval) { + device->scan_interval = interval; - if (device->scan_timeout > 0) { - g_source_remove(device->scan_timeout); - device->scan_timeout = 0; - } + __connman_storage_save_device(device); - if (device->scan_interval > 0) { - guint interval = device->scan_interval; - device->scan_timeout = g_timeout_add_seconds(interval, - device_scan_trigger, device); + reset_scan_trigger(device); } - } else if (g_str_has_prefix(name, "IPv4.") == TRUE) { - int err; - - 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: - break; - } - - err = __connman_ipconfig_set_ipv4(device->ipconfig, - name + 5, &value); - if (err < 0) - return __connman_error_failed(msg, -err); } else return __connman_error_invalid_property(msg); - __connman_storage_save_device(device); - - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); -} - -static char *build_group(const unsigned char *ssid, unsigned int ssid_len, - const char *mode, const char *security) -{ - GString *str; - unsigned int i; - - str = g_string_sized_new((ssid_len * 2) + 24); - if (str == NULL) - return NULL; - - if (ssid_len > 0 && ssid[0] != '\0') { - for (i = 0; i < ssid_len; i++) - g_string_append_printf(str, "%02x", ssid[i]); - } - - g_string_append_printf(str, "_%s_%s", mode, security); - - return g_string_free(str, FALSE); -} - -static DBusMessage *join_network(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct connman_device *device = data; - struct connman_network *network; - enum connman_network_type type; - unsigned int ssid_size; - const char *group, *mode, *security; - const void *ssid; - DBusMessageIter iter, array; - int err, index; - - DBG("conn %p", conn); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) - return __connman_error_permission_denied(msg); - - if (!device->driver || !device->driver->join) - return __connman_error_not_supported(msg); - - dbus_message_iter_init(msg, &iter); - dbus_message_iter_recurse(&iter, &array); - - switch (device->type) { - case CONNMAN_DEVICE_TYPE_WIFI: - type = CONNMAN_NETWORK_TYPE_WIFI; - break; - default: - return __connman_error_not_supported(msg); - } - - network = connman_network_create("00_00_00_00_00_00", type); - if (network == NULL) - return __connman_error_failed(msg, ENOMEM); - - while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) { - DBusMessageIter entry, value; - const char *key, *str; - - dbus_message_iter_recurse(&array, &entry); - dbus_message_iter_get_basic(&entry, &key); - - dbus_message_iter_next(&entry); - dbus_message_iter_recurse(&entry, &value); - - switch (dbus_message_iter_get_arg_type(&value)) { - case DBUS_TYPE_STRING: - dbus_message_iter_get_basic(&value, &str); - if (g_str_equal(key, "WiFi.SSID") == TRUE) - connman_network_set_blob(network, key, - str, strlen(str)); - else - connman_network_set_string(network, key, str); - break; - } - - dbus_message_iter_next(&array); - } - - ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_size); - mode = connman_network_get_string(network, "WiFi.Mode"); - security = connman_network_get_string(network, "WiFi.Security"); - group = build_group(ssid, ssid_size, mode, security); - - connman_network_set_group(network, group); - - index = connman_device_get_index(device); - connman_network_set_index(network, index); - - connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP); - - err = device->driver->join(device, network); - - connman_network_unref(network); - - if (err < 0) - return __connman_error_failed(msg, -err); - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static DBusMessage *create_network(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBG("conn %p", conn); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) - return __connman_error_permission_denied(msg); - - return __connman_error_invalid_arguments(msg); -} - -static DBusMessage *remove_network(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBG("conn %p", conn); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0) - return __connman_error_permission_denied(msg); - - return __connman_error_invalid_arguments(msg); -} - static DBusMessage *propose_scan(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -582,20 +467,13 @@ static DBusMessage *propose_scan(DBusConnection *conn, 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, EINVAL); - - err = device->driver->scan(device); + err = __connman_device_scan(device); if (err < 0) return __connman_error_failed(msg, -err); @@ -606,9 +484,6 @@ static GDBusMethodTable device_methods[] = { { "GetProperties", "", "a{sv}", get_properties }, { "SetProperty", "sv", "", set_property, G_DBUS_METHOD_FLAG_ASYNC }, - { "JoinNetwork", "a{sv}", "", join_network }, - { "CreateNetwork", "a{sv}", "o", create_network }, - { "RemoveNetwork", "o", "", remove_network }, { "ProposeScan", "", "", propose_scan }, { }, }; @@ -618,38 +493,19 @@ static GDBusSignalTable device_signals[] = { { }, }; -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; + DBusMessageIter iter; 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); + dbus_message_iter_init_append(signal, &iter); + connman_dbus_property_append_variable_array(&iter, "Devices", + DBUS_TYPE_OBJECT_PATH, __connman_device_list); g_dbus_send_message(connection, signal); } @@ -689,36 +545,9 @@ static void unregister_interface(struct connman_element *element) CONNMAN_DEVICE_INTERFACE); } -static void device_enable(struct connman_device *device) -{ - DBG("device %p", device); - - if (device->powered == TRUE) - return; - - if (device->driver->enable) { - device->driver->enable(device); - __connman_notifier_device_type_increase(device->type); - } -} - -static void device_disable(struct connman_device *device) -{ - DBG("device %p", device); - - if (device->powered == FALSE) - return; - - g_hash_table_remove_all(device->networks); - - if (device->driver->disable) { - device->driver->disable(device); - __connman_notifier_device_type_decrease(device->type); - } -} - static int setup_device(struct connman_device *device) { + enum connman_service_type type; int err; DBG("device %p", device); @@ -731,18 +560,19 @@ static int setup_device(struct connman_device *device) return err; } + type = __connman_device_get_service_type(device); + __connman_notifier_register(type); + switch (device->mode) { case CONNMAN_DEVICE_MODE_UNKNOWN: case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: break; - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - if (device->secondary == FALSE) - __connman_profile_add_device(device); - break; } - device_enable(device); + if (device->offlinemode == FALSE && + device->powered_persistent == TRUE) + __connman_device_enable(device); return 0; } @@ -772,21 +602,22 @@ static void probe_driver(struct connman_element *element, gpointer user_data) static void remove_device(struct connman_device *device) { + enum connman_service_type type; + DBG("device %p", device); - device_disable(device); + __connman_device_disable(device); switch (device->mode) { case CONNMAN_DEVICE_MODE_UNKNOWN: case CONNMAN_DEVICE_MODE_NETWORK_SINGLE: case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE: break; - case CONNMAN_DEVICE_MODE_TRANSPORT_IP: - if (device->secondary == FALSE) - __connman_profile_remove_device(device); - break; } + type = __connman_device_get_service_type(device); + __connman_notifier_unregister(type); + unregister_interface(&device->element); if (device->driver->remove) @@ -885,6 +716,8 @@ static void device_destruct(struct connman_element *element) device->timeout = 0; } + clear_scan_trigger(device); + if (device->pending != NULL) { dbus_message_unref(device->pending); device->pending = NULL; @@ -894,10 +727,9 @@ static void device_destruct(struct connman_element *element) g_free(device->node); g_free(device->name); g_free(device->address); + g_free(device->control); g_free(device->interface); - connman_ipconfig_unref(device->ipconfig); - g_free(device->last_network); g_hash_table_destroy(device->networks); @@ -942,10 +774,13 @@ struct connman_device *connman_device_create(const char *node, device->element.ipv4.method = CONNMAN_IPCONFIG_METHOD_DHCP; - device->type = type; - device->name = g_strdup(type2description(device->type)); - device->mode = CONNMAN_DEVICE_MODE_UNKNOWN; - device->secondary = FALSE; + device->type = type; + device->name = g_strdup(type2description(device->type)); + device->mode = CONNMAN_DEVICE_MODE_UNKNOWN; + + device->powered_persistent = TRUE; + + device->phyindex = -1; switch (type) { case CONNMAN_DEVICE_TYPE_UNKNOWN: @@ -965,20 +800,13 @@ struct connman_device *connman_device_create(const char *node, case CONNMAN_DEVICE_TYPE_GPS: device->scan_interval = 0; break; + case CONNMAN_DEVICE_TYPE_CELLULAR: + case CONNMAN_DEVICE_TYPE_MBM: case CONNMAN_DEVICE_TYPE_HSO: - case CONNMAN_DEVICE_TYPE_NOZOMI: - case CONNMAN_DEVICE_TYPE_HUAWEI: - case CONNMAN_DEVICE_TYPE_NOVATEL: device->scan_interval = 0; break; } - device->ipconfig = connman_ipconfig_create(); - if (device->ipconfig == NULL) { - connman_device_unref(device); - return NULL; - } - device->networks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, unregister_network); @@ -1071,15 +899,27 @@ int connman_device_get_index(struct connman_device *device) return device->element.index; } +int __connman_device_get_phyindex(struct connman_device *device) +{ + return device->phyindex; +} + +void __connman_device_set_phyindex(struct connman_device *device, + int phyindex) +{ + device->phyindex = phyindex; +} + /** * connman_device_set_interface: * @device: device structure * @interface: interface name + * @control: control interface * * Set interface name of device */ void connman_device_set_interface(struct connman_device *device, - const char *interface) + const char *interface, const char *control) { g_free(device->element.devname); device->element.devname = g_strdup(interface); @@ -1087,6 +927,9 @@ void connman_device_set_interface(struct connman_device *device, g_free(device->interface); device->interface = g_strdup(interface); + g_free(device->control); + device->control = g_strdup(control); + if (device->name == NULL) { const char *str = type2description(device->type); if (str != NULL && device->interface != NULL) @@ -1095,15 +938,9 @@ void connman_device_set_interface(struct connman_device *device, } } -/** - * connman_device_get_interface: - * @device: device structure - * - * Get interface name of device - */ -const char *connman_device_get_interface(struct connman_device *device) +const char *connman_device_get_control(struct connman_device *device) { - return device->interface; + return device->control; } /** @@ -1150,30 +987,6 @@ enum connman_device_mode connman_device_get_mode(struct connman_device *device) } /** - * connman_device_set_secondary: - * @device: device structure - * @secondary: secondary value - * - * Change secondary value of device - */ -void connman_device_set_secondary(struct connman_device *device, - connman_bool_t secondary) -{ - device->secondary = secondary; -} - -/** - * connman_device_get_secondary: - * @device: device structure - * - * Get secondary value of device - */ -connman_bool_t connman_device_get_secondary(struct connman_device *device) -{ - return device->secondary; -} - -/** * connman_device_set_powered: * @device: device structure * @powered: powered state @@ -1183,9 +996,7 @@ connman_bool_t connman_device_get_secondary(struct connman_device *device) int connman_device_set_powered(struct connman_device *device, connman_bool_t powered) { - DBusMessage *signal; - DBusMessageIter entry, value; - const char *key = "Powered"; + enum connman_service_type type; DBG("driver %p powered %d", device, powered); @@ -1199,178 +1010,192 @@ int connman_device_set_powered(struct connman_device *device, DBUS_TYPE_INVALID); dbus_message_unref(device->pending); + device->pending = NULL; } if (device->powered == powered) return -EALREADY; device->powered = powered; + device->powered_pending = powered; + + type = __connman_device_get_service_type(device); + + if (device->powered == TRUE) + __connman_notifier_enable(type); + else + __connman_notifier_disable(type); if (device->registered == FALSE) return 0; - signal = dbus_message_new_signal(device->element.path, - CONNMAN_DEVICE_INTERFACE, "PropertyChanged"); - if (signal == NULL) + powered_changed(device); + + if (powered == FALSE) return 0; - dbus_message_iter_init_append(signal, &entry); + reset_scan_trigger(device); - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + if (device->driver->scan) + device->driver->scan(device); - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_BOOLEAN_AS_STRING, &value); - dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered); - dbus_message_iter_close_container(&entry, &value); + return 0; +} - g_dbus_send_message(connection, signal); +int __connman_device_set_blocked(struct connman_device *device, + connman_bool_t blocked) +{ + connman_bool_t powered; - if (powered == FALSE) + DBG("device %p blocked %d", device, blocked); + + device->blocked = blocked; + + if (device->offlinemode == TRUE) return 0; - if (device->scan_timeout > 0) { - g_source_remove(device->scan_timeout); - device->scan_timeout = 0; - } + connman_info("%s {rfkill} blocked %d", device->interface, blocked); - if (device->scan_interval > 0) { - guint interval = device->scan_interval; - device->scan_timeout = g_timeout_add_seconds(interval, - device_scan_trigger, device); - } + if (blocked == FALSE) + powered = device->powered_persistent; + else + powered = FALSE; - if (device->driver->scan) - device->driver->scan(device); + return set_powered(device, powered); +} - return 0; +int __connman_device_scan(struct connman_device *device) +{ + if (!device->driver || !device->driver->scan) + return -EOPNOTSUPP; + + if (device->powered == FALSE) + return -ENOLINK; + + reset_scan_trigger(device); + + return device->driver->scan(device); } -/** - * 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, - connman_bool_t carrier) +int __connman_device_enable(struct connman_device *device) { - DBG("device %p carrier %d", device, carrier); + enum connman_service_type type; + int err; - 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; - } + DBG("device %p", device); - if (device->carrier == carrier) + if (!device->driver || !device->driver->enable) + return -EOPNOTSUPP; + + if (device->powered_pending == TRUE) return -EALREADY; - device->carrier = carrier; + device->powered_pending = TRUE; + + err = device->driver->enable(device); + if (err < 0) + return err; + + device->powered = TRUE; - return set_carrier(device, device->carrier); + type = __connman_device_get_service_type(device); + __connman_notifier_enable(type); + + return 0; } -int __connman_device_connect(struct connman_device *device) +int __connman_device_enable_persistent(struct connman_device *device) { DBG("device %p", device); - if (device->disconnected == FALSE) - return -EINVAL; + device->powered_persistent = TRUE; - if (device->driver && device->driver->connect) - device->driver->connect(device); + __connman_storage_save_device(device); - return 0; + return __connman_device_enable(device); } -int __connman_device_disconnect(struct connman_device *device) +int __connman_device_disable(struct connman_device *device) { - GHashTableIter iter; - gpointer key, value; + enum connman_service_type type; + int err; DBG("device %p", device); - connman_device_set_disconnected(device, TRUE); + if (!device->driver || !device->driver->disable) + return -EOPNOTSUPP; - g_hash_table_iter_init(&iter, device->networks); + if (device->powered == FALSE) + return -ENOLINK; - while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) { - struct connman_network *network = value; + if (device->powered_pending == FALSE) + return -EALREADY; - if (connman_network_get_connected(network) == TRUE) - __connman_network_disconnect(network); - } + device->powered_pending = FALSE; + + device->reconnect = FALSE; + + clear_scan_trigger(device); + + g_hash_table_remove_all(device->networks); - if (device->driver && device->driver->disconnect) - device->driver->disconnect(device); + err = device->driver->disable(device); + if (err < 0) + return err; + + device->powered = FALSE; + + type = __connman_device_get_service_type(device); + __connman_notifier_disable(type); return 0; } -static void connect_known_network(struct connman_device *device) +int __connman_device_disable_persistent(struct connman_device *device) +{ + DBG("device %p", device); + + device->powered_persistent = FALSE; + + __connman_storage_save_device(device); + + return __connman_device_disable(device); +} + +int __connman_device_disconnect(struct connman_device *device) { - struct connman_network *network = NULL; GHashTableIter iter; gpointer key, value; - const char *name; - unsigned int count = 0; 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) { - connman_uint8_t old_strength, new_strength; - - count++; - - if (connman_network_get_available(value) == FALSE) - continue; - - name = connman_network_get_string(value, - CONNMAN_PROPERTY_ID_NAME); - if (name != NULL && device->last_network != NULL) { - if (g_str_equal(name, device->last_network) == TRUE) { - network = value; - break; - } - } + struct connman_network *network = value; - if (network == NULL) { - network = value; + if (__connman_network_get_connecting(network) == TRUE) { + /* + * Skip network in the process of connecting. + * This is a workaround for WiFi networks serviced + * by the supplicant plugin that hold a reference + * to the network. If we disconnect the network + * here then the referenced object will not be + * registered and usage (like launching DHCP client) + * will fail. There is nothing to be gained by + * removing the network here anyway. + */ + connman_warn("Skipping disconnect of %s", + connman_network_get_identifier(network)); continue; } - old_strength = connman_network_get_uint8(network, - CONNMAN_PROPERTY_ID_STRENGTH); - new_strength = connman_network_get_uint8(value, - CONNMAN_PROPERTY_ID_STRENGTH); - - if (new_strength > old_strength) - network = value; - } - - if (network != NULL) { - int err; - - name = connman_network_get_string(value, - CONNMAN_PROPERTY_ID_NAME); - if (name != NULL) { - err = __connman_network_connect(network); - if (err == 0 || err == -EINPROGRESS) - return; - } + __connman_network_disconnect(network); } - if (count > 0) - return; - - if (device->driver && device->driver->scan) - device->driver->scan(device); + return 0; } static void mark_network_unavailable(gpointer key, gpointer value, @@ -1398,6 +1223,37 @@ static gboolean remove_unavailable_network(gpointer key, gpointer value, return TRUE; } +void __connman_device_cleanup_networks(struct connman_device *device) +{ + g_hash_table_foreach_remove(device->networks, + remove_unavailable_network, NULL); +} + +static void scanning_changed(struct connman_device *device) +{ + connman_dbus_property_changed_basic(device->element.path, + CONNMAN_DEVICE_INTERFACE, "Scanning", + DBUS_TYPE_BOOLEAN, &device->scanning); +} + +static void mark_network_available(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_network *network = value; + + connman_network_set_available(network, TRUE); +} + +void connman_device_cleanup_scanning(struct connman_device *device) +{ + device->scanning = FALSE; + + scanning_changed(device); + + g_hash_table_foreach(device->networks, + mark_network_available, NULL); +} + /** * connman_device_set_scanning: * @device: device structure @@ -1408,10 +1264,6 @@ static gboolean remove_unavailable_network(gpointer key, gpointer value, int connman_device_set_scanning(struct connman_device *device, connman_bool_t scanning) { - DBusMessage *signal; - DBusMessageIter entry, value; - const char *key = "Scanning"; - DBG("device %p scanning %d", device, scanning); if (!device->driver || !device->driver->scan) @@ -1422,41 +1274,18 @@ int connman_device_set_scanning(struct connman_device *device, 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); + scanning_changed(device); if (scanning == TRUE) { - if (device->scan_timeout > 0) { - g_source_remove(device->scan_timeout); - device->scan_timeout = 0; - } - - if (device->scan_interval > 0) { - guint interval = device->scan_interval; - device->scan_timeout = g_timeout_add_seconds(interval, - device_scan_trigger, device); - } + reset_scan_trigger(device); g_hash_table_foreach(device->networks, mark_network_unavailable, NULL); + return 0; } - g_hash_table_foreach_remove(device->networks, - remove_unavailable_network, NULL); + __connman_device_cleanup_networks(device); if (device->connections > 0) return 0; @@ -1464,7 +1293,7 @@ int connman_device_set_scanning(struct connman_device *device, if (device->disconnected == TRUE) return 0; - connect_known_network(device); + __connman_service_auto_connect(); return 0; } @@ -1483,7 +1312,6 @@ int connman_device_set_disconnected(struct connman_device *device, 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: @@ -1495,34 +1323,21 @@ int connman_device_set_disconnected(struct connman_device *device, device->disconnected = disconnected; + if (disconnected == TRUE) + force_scan_trigger(device); + return 0; } /** - * connman_device_set_connected: + * connman_device_get_disconnected: * @device: device structure - * @connected: connected state * - * Change connected state of device (for Ethernet like devices) + * Get device disconnected state */ -int connman_device_set_connected(struct connman_device *device, - connman_bool_t connected) +connman_bool_t connman_device_get_disconnected(struct connman_device *device) { - DBG("device %p connected %d", device, connected); - - 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 == FALSE) - return -ENOTCONN; - - return set_connected(device, connected); + return device->disconnected; } /** @@ -1585,11 +1400,16 @@ static void set_offlinemode(struct connman_element *element, gpointer user_data) if (device == NULL) return; + device->offlinemode = offlinemode; + powered = (offlinemode == TRUE) ? FALSE : TRUE; if (device->powered == powered) return; + if (device->powered_persistent == FALSE) + powered = FALSE; + set_powered(device, powered); } @@ -1600,7 +1420,7 @@ int __connman_device_set_offlinemode(connman_bool_t offlinemode) __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, set_offlinemode, GUINT_TO_POINTER(offlinemode)); - __connman_notifier_offline_mode(offlinemode); + __connman_notifier_offlinemode(offlinemode); return 0; } @@ -1630,9 +1450,11 @@ int connman_device_add_network(struct connman_device *device, DBG("device %p network %p", device, network); + if (identifier == NULL) + return -EINVAL; + 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: @@ -1641,8 +1463,6 @@ int connman_device_add_network(struct connman_device *device, __connman_network_set_device(network, device); - __connman_storage_load_network(network); - err = connman_element_register((struct connman_element *) network, &device->element); if (err < 0) { @@ -1688,6 +1508,11 @@ int connman_device_remove_network(struct connman_device *device, return 0; } +void connman_device_remove_all_networks(struct connman_device *device) +{ + g_hash_table_remove_all(device->networks); +} + void __connman_device_set_network(struct connman_device *device, struct connman_network *network) { @@ -1714,6 +1539,18 @@ void __connman_device_set_network(struct connman_device *device, } } +void __connman_device_set_reconnect(struct connman_device *device, + connman_bool_t reconnect) +{ + device->reconnect = reconnect; +} + +connman_bool_t __connman_device_get_reconnect( + struct connman_device *device) +{ + return device->reconnect; +} + /** * connman_device_register: * @device: device structure @@ -1724,15 +1561,7 @@ 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; - } + device->offlinemode = __connman_profile_get_offlinemode(); return connman_element_register(&device->element, NULL); } @@ -1841,94 +1670,71 @@ static struct connman_driver device_driver = { static int device_load(struct connman_device *device) { + const char *ident = __connman_profile_active_ident(); GKeyFile *keyfile; - gchar *pathname, *identifier, *data = NULL; - gsize length; + GError *error = NULL; + gchar *identifier; + connman_bool_t powered; int val; DBG("device %p", device); - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, - __connman_profile_active_ident()); - 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); + keyfile = __connman_storage_open_profile(ident); + if (keyfile == NULL) + return 0; identifier = g_strdup_printf("device_%s", device->element.name); if (identifier == NULL) goto done; + powered = g_key_file_get_boolean(keyfile, identifier, + "Powered", &error); + if (error == NULL) + device->powered_persistent = powered; + g_clear_error(&error); + 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: val = g_key_file_get_integer(keyfile, identifier, - "ScanInterval", NULL); - if (val > 0) + "ScanInterval", &error); + if (error == NULL && val > 0) device->scan_interval = val; + g_clear_error(&error); break; } done: - g_key_file_free(keyfile); - g_free(identifier); + __connman_storage_close_profile(ident, keyfile, FALSE); + return 0; } static int device_save(struct connman_device *device) { + const char *ident = __connman_profile_active_ident(); GKeyFile *keyfile; - gchar *pathname, *identifier = NULL, *data = NULL; - gsize length; + gchar *identifier; DBG("device %p", device); - pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, - __connman_profile_active_ident()); - 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); + keyfile = __connman_storage_open_profile(ident); + if (keyfile == NULL) + return 0; -update: identifier = g_strdup_printf("device_%s", device->element.name); if (identifier == NULL) goto done; + g_key_file_set_boolean(keyfile, identifier, + "Powered", device->powered_persistent); + 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: @@ -1938,18 +1744,10 @@ update: break; } - data = g_key_file_to_data(keyfile, &length, NULL); - - if (g_file_set_contents(pathname, data, length, NULL) == FALSE) - connman_error("Failed to store device information"); - done: - g_free(data); - - g_key_file_free(keyfile); - g_free(identifier); - g_free(pathname); + + __connman_storage_close_profile(ident, keyfile, TRUE); return 0; }