X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftechnology.c;h=2edb48f28355b3613f8b62adacde84c5ef624ad6;hb=6c8213f23b60fb46e6cd2572a6adc7ce4da13691;hp=24de48f0cda4947256b0badc9243f7f4d94dc9b7;hpb=9ba0fd876d58ce22aab3c15ca063713ba1fb865f;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/technology.c b/src/technology.c index 24de48f..2edb48f 100644 --- a/src/technology.c +++ b/src/technology.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2012 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 @@ -39,6 +39,7 @@ static GSList *technology_list = NULL; * no compiled in support or the driver is not yet loaded. */ static GSList *techless_device_list = NULL; +static GHashTable *rfkill_list; static connman_bool_t global_offlinemode; @@ -53,7 +54,6 @@ struct connman_technology { int refcount; enum connman_service_type type; char *path; - GHashTable *rfkill_list; GSList *device_list; int enabled; char *regdom; @@ -70,6 +70,8 @@ struct connman_technology { DBusMessage *pending_reply; guint pending_timeout; + + GSList *scan_pending; }; static GSList *driver_list = NULL; @@ -82,6 +84,17 @@ static gint compare_priority(gconstpointer a, gconstpointer b) return driver2->priority - driver1->priority; } +static void rfkill_check(gpointer key, gpointer value, gpointer user_data) +{ + struct connman_rfkill *rfkill = value; + enum connman_service_type type = GPOINTER_TO_INT(user_data); + + /* Calling _technology_rfkill_add will update the tech. */ + if (rfkill->type == type) + __connman_technology_add_rfkill(rfkill->index, type, + rfkill->softblock, rfkill->hardblock); +} + /** * connman_technology_driver_register: * @driver: Technology driver definition @@ -102,7 +115,7 @@ int connman_technology_driver_register(struct connman_technology_driver *driver) compare_priority); if (techless_device_list == NULL) - return 0; + goto check_rfkill; /* * Check for technology less devices if this driver @@ -121,6 +134,11 @@ int connman_technology_driver_register(struct connman_technology_driver *driver) __connman_technology_add_device(device); } +check_rfkill: + /* Check for orphaned rfkill switches. */ + g_hash_table_foreach(rfkill_list, rfkill_check, + GINT_TO_POINTER(driver->type)); + return 0; } @@ -274,64 +292,73 @@ static const char *get_name(enum connman_service_type type) return NULL; } -static void load_state(struct connman_technology *technology) +static void save_state(struct connman_technology *technology) { GKeyFile *keyfile; gchar *identifier; - GError *error = NULL; - connman_bool_t enable; DBG("technology %p", technology); keyfile = __connman_storage_load_global(); - /* Fallback on disabling technology if file not found. */ - if (keyfile == NULL) { - technology->enable_persistent = FALSE; - return; - } + if (keyfile == NULL) + keyfile = g_key_file_new(); identifier = g_strdup_printf("%s", get_name(technology->type)); if (identifier == NULL) goto done; - enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error); - if (error == NULL) - technology->enable_persistent = enable; - else { - technology->enable_persistent = FALSE; - g_clear_error(&error); - } + g_key_file_set_boolean(keyfile, identifier, "Enable", + technology->enable_persistent); + done: g_free(identifier); + __connman_storage_save_global(keyfile); + g_key_file_free(keyfile); return; } -static void save_state(struct connman_technology *technology) +static void load_state(struct connman_technology *technology) { GKeyFile *keyfile; gchar *identifier; + GError *error = NULL; + connman_bool_t enable; DBG("technology %p", technology); keyfile = __connman_storage_load_global(); - if (keyfile == NULL) - keyfile = g_key_file_new(); + /* Fallback on disabling technology if file not found. */ + if (keyfile == NULL) { + if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET) + /* We enable ethernet by default */ + technology->enable_persistent = TRUE; + else + technology->enable_persistent = FALSE; + return; + } identifier = g_strdup_printf("%s", get_name(technology->type)); if (identifier == NULL) goto done; - g_key_file_set_boolean(keyfile, identifier, "Enable", - technology->enable_persistent); + enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error); + if (error == NULL) + technology->enable_persistent = enable; + else { + if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET) + technology->enable_persistent = TRUE; + else + technology->enable_persistent = FALSE; + save_state(technology); + g_clear_error(&error); + } done: g_free(identifier); - __connman_storage_save_global(keyfile); - g_key_file_free(keyfile); return; @@ -369,12 +396,12 @@ static connman_bool_t connman_technology_load_offlinemode() /* If there is a error, we enable offlinemode */ keyfile = __connman_storage_load_global(); if (keyfile == NULL) - return TRUE; + return FALSE; offlinemode = g_key_file_get_boolean(keyfile, "global", "OfflineMode", &error); if (error != NULL) { - offlinemode = TRUE; + offlinemode = FALSE; g_clear_error(&error); } @@ -665,8 +692,15 @@ static DBusMessage *set_property(DBusConnection *conn, if (dbus_message_iter_init(msg, &iter) == FALSE) return __connman_error_invalid_arguments(msg); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + dbus_message_iter_get_basic(&iter, &name); dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + dbus_message_iter_recurse(&iter, &value); type = dbus_message_iter_get_arg_type(&value); @@ -728,17 +762,6 @@ static DBusMessage *set_property(DBusConnection *conn, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static GDBusMethodTable technology_methods[] = { - { "GetProperties", "", "a{sv}", get_properties }, - { "SetProperty", "sv", "", set_property }, - { }, -}; - -static GDBusSignalTable technology_signals[] = { - { "PropertyChanged", "sv" }, - { }, -}; - static struct connman_technology *technology_find(enum connman_service_type type) { GSList *list; @@ -755,6 +778,103 @@ static struct connman_technology *technology_find(enum connman_service_type type return NULL; } +static void reply_scan_pending(struct connman_technology *technology, int err) +{ + DBusMessage *reply; + + DBG("technology %p err %d", technology, err); + + while (technology->scan_pending != NULL) { + DBusMessage *msg = technology->scan_pending->data; + + DBG("reply to %s", dbus_message_get_sender(msg)); + + if (err == 0) + reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + else + reply = __connman_error_failed(msg, -err); + g_dbus_send_message(connection, reply); + dbus_message_unref(msg); + + technology->scan_pending = + g_slist_delete_link(technology->scan_pending, + technology->scan_pending); + } +} + +void __connman_technology_scan_started(struct connman_device *device) +{ + DBG("device %p", device); +} + +void __connman_technology_scan_stopped(struct connman_device *device) +{ + int count = 0; + struct connman_technology *technology; + enum connman_service_type type; + GSList *list; + + type = __connman_device_get_service_type(device); + technology = technology_find(type); + + DBG("technology %p device %p", technology, device); + + if (technology == NULL) + return; + + for (list = technology->device_list; list != NULL; list = list->next) { + struct connman_device *other_device = list->data; + + if (device == other_device) + continue; + + if (__connman_device_get_service_type(other_device) != type) + continue; + + if (connman_device_get_scanning(other_device) == TRUE) + count += 1; + } + + if (count == 0) + reply_scan_pending(technology, 0); +} + +static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data) +{ + struct connman_technology *technology = data; + int err; + + DBG ("technology %p request from %s", technology, + dbus_message_get_sender(msg)); + + dbus_message_ref(msg); + technology->scan_pending = + g_slist_prepend(technology->scan_pending, msg); + + err = __connman_device_request_scan(technology->type); + if (err < 0) + reply_scan_pending(technology, err); + + return NULL; +} + +static const GDBusMethodTable technology_methods[] = { + { GDBUS_DEPRECATED_METHOD("GetProperties", + NULL, GDBUS_ARGS({ "properties", "a{sv}" }), + get_properties) }, + { GDBUS_METHOD("SetProperty", + GDBUS_ARGS({ "name", "s" }, { "value", "v" }), + NULL, set_property) }, + { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) }, + { }, +}; + +static const GDBusSignalTable technology_signals[] = { + { GDBUS_SIGNAL("PropertyChanged", + GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, + { }, +}; + static struct connman_technology *technology_get(enum connman_service_type type) { struct connman_technology *technology; @@ -770,8 +890,10 @@ static struct connman_technology *technology_get(enum connman_service_type type) return NULL; technology = technology_find(type); - if (technology != NULL) + if (technology != NULL) { + __sync_fetch_and_add(&technology->refcount, 1); return technology; + } /* First check if we have a driver for this technology type */ for (list = driver_list; list; list = list->next) { @@ -799,8 +921,6 @@ static struct connman_technology *technology_get(enum connman_service_type type) technology->path = g_strdup_printf("%s/technology/%s", CONNMAN_PATH, str); - technology->rfkill_list = g_hash_table_new_full(g_int_hash, g_int_equal, - NULL, free_rfkill); technology->device_list = NULL; technology->pending_reply = NULL; @@ -834,9 +954,11 @@ static void technology_put(struct connman_technology *technology) { DBG("technology %p", technology); - if (__sync_fetch_and_sub(&technology->refcount, 1) != 1) + if (__sync_sub_and_fetch(&technology->refcount, 1) > 0) return; + reply_scan_pending(technology, -EINTR); + if (technology->driver) { technology->driver->remove(technology); technology->driver = NULL; @@ -850,7 +972,6 @@ static void technology_put(struct connman_technology *technology) CONNMAN_TECHNOLOGY_INTERFACE); g_slist_free(technology->device_list); - g_hash_table_destroy(technology->rfkill_list); g_free(technology->path); g_free(technology->regdom); @@ -943,8 +1064,17 @@ int __connman_technology_add_device(struct connman_device *device) return -ENXIO; } - if (technology->enable_persistent && !global_offlinemode) - __connman_device_enable(device); + if (technology->enable_persistent && !global_offlinemode) { + int err = __connman_device_enable(device); + /* + * connman_technology_add_device() calls __connman_device_enable() + * but since the device is already enabled, the calls does not + * propagate through to connman_technology_enabled via + * connman_device_set_powered. + */ + if (err == -EALREADY) + __connman_technology_enabled(type); + } /* if technology persistent state is offline */ if (!technology->enable_persistent) __connman_device_disable(device); @@ -971,8 +1101,13 @@ int __connman_technology_remove_device(struct connman_device *device) return -ENXIO; } + if (connman_device_get_scanning(device) == TRUE) + __connman_technology_scan_stopped(device); + technology->device_list = g_slist_remove(technology->device_list, device); + technology_put(technology); + return 0; } @@ -1105,9 +1240,9 @@ int __connman_technology_add_rfkill(unsigned int index, DBG("index %u type %d soft %u hard %u", index, type, softblock, hardblock); - technology = technology_get(type); - if (technology == NULL) - return -ENXIO; + rfkill = g_hash_table_lookup(rfkill_list, &index); + if (rfkill != NULL) + goto done; rfkill = g_try_new0(struct connman_rfkill, 1); if (rfkill == NULL) @@ -1118,7 +1253,13 @@ int __connman_technology_add_rfkill(unsigned int index, rfkill->softblock = softblock; rfkill->hardblock = hardblock; - g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill); + g_hash_table_insert(rfkill_list, &rfkill->index, rfkill); + +done: + technology = technology_get(type); + /* If there is no driver for this type, ignore it. */ + if (technology == NULL) + return -ENXIO; if (hardblock) { DBG("%s is switched off.", get_name(type)); @@ -1153,11 +1294,7 @@ int __connman_technology_update_rfkill(unsigned int index, DBG("index %u soft %u hard %u", index, softblock, hardblock); - technology = technology_find(type); - if (technology == NULL) - return -ENXIO; - - rfkill = g_hash_table_lookup(technology->rfkill_list, &index); + rfkill = g_hash_table_lookup(rfkill_list, &index); if (rfkill == NULL) return -ENXIO; @@ -1173,6 +1310,11 @@ int __connman_technology_update_rfkill(unsigned int index, return 0; } + technology = technology_find(type); + /* If there is no driver for this type, ignore it. */ + if (technology == NULL) + return -ENXIO; + if (!global_offlinemode) { if (technology->enable_persistent && softblock) return __connman_rfkill_block(type, FALSE); @@ -1191,15 +1333,15 @@ int __connman_technology_remove_rfkill(unsigned int index, DBG("index %u", index); - technology = technology_find(type); - if (technology == NULL) - return -ENXIO; - - rfkill = g_hash_table_lookup(technology->rfkill_list, &index); + rfkill = g_hash_table_lookup(rfkill_list, &index); if (rfkill == NULL) return -ENXIO; - g_hash_table_remove(technology->rfkill_list, &index); + g_hash_table_remove(rfkill_list, &index); + + technology = technology_find(type); + if (technology == NULL) + return -ENXIO; technology_put(technology); @@ -1212,8 +1354,14 @@ int __connman_technology_init(void) connection = connman_dbus_get_connection(); + rfkill_list = g_hash_table_new_full(g_int_hash, g_int_equal, + NULL, free_rfkill); + global_offlinemode = connman_technology_load_offlinemode(); + /* This will create settings file if it is missing */ + connman_technology_save_offlinemode(); + return 0; } @@ -1221,5 +1369,7 @@ void __connman_technology_cleanup(void) { DBG(""); + g_hash_table_destroy(rfkill_list); + dbus_connection_unref(connection); }