X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftechnology.c;h=de0fab8f305f4898097d4ca871af49fd4e1ff597;hb=76a486a7cbdbb549c229cb2593c96f1c1402bb48;hp=fb7f0580a16affeea87ff7263b123d9120abb7ca;hpb=eca384a6167bd4b90d229c3fe9ba7d23d020e68b;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/technology.c b/src/technology.c index fb7f058..de0fab8 100644 --- a/src/technology.c +++ b/src/technology.c @@ -34,6 +34,8 @@ static DBusConnection *connection; static GSList *technology_list = NULL; +static connman_bool_t global_offlinemode; + struct connman_rfkill { unsigned int index; enum connman_service_type type; @@ -44,20 +46,18 @@ struct connman_rfkill { enum connman_technology_state { CONNMAN_TECHNOLOGY_STATE_UNKNOWN = 0, CONNMAN_TECHNOLOGY_STATE_OFFLINE = 1, - CONNMAN_TECHNOLOGY_STATE_AVAILABLE = 2, - CONNMAN_TECHNOLOGY_STATE_ENABLED = 3, - CONNMAN_TECHNOLOGY_STATE_CONNECTED = 4, + CONNMAN_TECHNOLOGY_STATE_ENABLED = 2, + CONNMAN_TECHNOLOGY_STATE_CONNECTED = 3, }; struct connman_technology { - gint refcount; + int refcount; enum connman_service_type type; enum connman_technology_state state; char *path; GHashTable *rfkill_list; GSList *device_list; - gint enabled; - gint blocked; + int enabled; char *regdom; connman_bool_t tethering; @@ -154,6 +154,8 @@ static void tethering_changed(struct connman_technology *technology) void connman_technology_tethering_notify(struct connman_technology *technology, connman_bool_t enabled) { + GSList *list; + DBG("technology %p enabled %u", technology, enabled); if (technology->tethering == enabled) @@ -165,14 +167,21 @@ void connman_technology_tethering_notify(struct connman_technology *technology, if (enabled == TRUE) __connman_tethering_set_enabled(); - else - __connman_tethering_set_disabled(); + else { + for (list = technology_list; list; list = list->next) { + struct connman_technology *other_tech = list->data; + if (other_tech->tethering == TRUE) + break; + } + if (list == NULL) + __connman_tethering_set_disabled(); + } } static int set_tethering(struct connman_technology *technology, - const char *bridge, connman_bool_t enabled) + connman_bool_t enabled) { - const char *ident, *passphrase; + const char *ident, *passphrase, *bridge; ident = technology->tethering_ident; passphrase = technology->tethering_passphrase; @@ -181,6 +190,10 @@ static int set_tethering(struct connman_technology *technology, technology->driver->set_tethering == NULL) return -EOPNOTSUPP; + bridge = __connman_tethering_get_bridge(); + if (bridge == NULL) + return -EOPNOTSUPP; + if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && (ident == NULL || passphrase == NULL)) return -EINVAL; @@ -256,8 +269,6 @@ static const char *state2string(enum connman_technology_state state) break; case CONNMAN_TECHNOLOGY_STATE_OFFLINE: return "offline"; - case CONNMAN_TECHNOLOGY_STATE_AVAILABLE: - return "available"; case CONNMAN_TECHNOLOGY_STATE_ENABLED: return "enabled"; case CONNMAN_TECHNOLOGY_STATE_CONNECTED: @@ -298,12 +309,121 @@ static const char *get_name(enum connman_service_type type) case CONNMAN_SERVICE_TYPE_BLUETOOTH: return "Bluetooth"; case CONNMAN_SERVICE_TYPE_CELLULAR: - return "3G"; + return "Cellular"; } return NULL; } +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(); + /* Fallback on disabling technology if file not found. */ + if (keyfile == NULL) { + technology->enable_persistent = FALSE; + return; + } + + 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); + } +done: + g_free(identifier); + + g_key_file_free(keyfile); + + return; +} + +static void save_state(struct connman_technology *technology) +{ + GKeyFile *keyfile; + gchar *identifier; + + DBG("technology %p", technology); + + keyfile = __connman_storage_load_global(); + if (keyfile == NULL) + keyfile = g_key_file_new(); + + 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); + +done: + g_free(identifier); + + __connman_storage_save_global(keyfile); + + g_key_file_free(keyfile); + + return; +} + +connman_bool_t __connman_technology_get_offlinemode(void) +{ + return global_offlinemode; +} + +static void connman_technology_save_offlinemode() +{ + GKeyFile *keyfile; + + keyfile = __connman_storage_load_global(); + if (keyfile == NULL) + keyfile = g_key_file_new(); + + g_key_file_set_boolean(keyfile, "global", + "OfflineMode", global_offlinemode); + + __connman_storage_save_global(keyfile); + + g_key_file_free(keyfile); + + return; +} + +static connman_bool_t connman_technology_load_offlinemode() +{ + GKeyFile *keyfile; + GError *error = NULL; + connman_bool_t offlinemode; + + /* If there is a error, we enable offlinemode */ + keyfile = __connman_storage_load_global(); + if (keyfile == NULL) + return TRUE; + + offlinemode = g_key_file_get_boolean(keyfile, "global", + "OfflineMode", &error); + if (error != NULL) { + offlinemode = TRUE; + g_clear_error(&error); + } + + g_key_file_free(keyfile); + + return offlinemode; +} + static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *message, void *user_data) { @@ -378,7 +498,6 @@ static DBusMessage *set_property(DBusConnection *conn, if (g_str_equal(name, "Tethering") == TRUE) { int err; connman_bool_t tethering; - const char *bridge; if (type != DBUS_TYPE_BOOLEAN) return __connman_error_invalid_arguments(msg); @@ -388,11 +507,7 @@ static DBusMessage *set_property(DBusConnection *conn, if (technology->tethering == tethering) return __connman_error_in_progress(msg); - bridge = __connman_tethering_get_bridge(); - if (bridge == NULL) - return __connman_error_not_supported(msg); - - err = set_tethering(technology, bridge, tethering); + err = set_tethering(technology, tethering); if (err < 0) return __connman_error_failed(msg, -err); @@ -460,7 +575,7 @@ static struct connman_technology *technology_get(enum connman_service_type type) technology = technology_find(type); if (technology != NULL) { - g_atomic_int_inc(&technology->refcount); + __sync_fetch_and_add(&technology->refcount, 1); goto done; } @@ -485,7 +600,7 @@ static struct connman_technology *technology_get(enum connman_service_type type) technology->pending_reply = NULL; technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE; - __connman_storage_load_technology(technology); + load_state(technology); if (g_dbus_register_interface(connection, technology->path, CONNMAN_TECHNOLOGY_INTERFACE, @@ -527,7 +642,7 @@ static void technology_put(struct connman_technology *technology) { DBG("technology %p", technology); - if (g_atomic_int_dec_and_test(&technology->refcount) == FALSE) + if (__sync_fetch_and_sub(&technology->refcount, 1) != 1) return; if (technology->driver) { @@ -631,14 +746,11 @@ int __connman_technology_add_device(struct connman_device *device) if (technology == NULL) return -ENXIO; - if (g_atomic_int_get(&technology->blocked)) - goto done; - - technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE; - - state_changed(technology); - -done: + if (technology->enable_persistent && !global_offlinemode) + __connman_device_enable(device); + /* if technology persistent state is offline */ + if (!technology->enable_persistent) + __connman_device_disable(device); technology->device_list = g_slist_append(technology->device_list, device); @@ -697,24 +809,16 @@ int __connman_technology_enabled(enum connman_service_type type) if (technology == NULL) return -ENXIO; - if (g_atomic_int_get(&technology->blocked)) - return -ERFKILL; - - __connman_notifier_enable(type); - - if (g_atomic_int_exchange_and_add(&technology->enabled, 1) == 0) { + if (__sync_fetch_and_add(&technology->enabled, 1) == 0) { + __connman_notifier_enable(type); technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED; state_changed(technology); } - if (__connman_profile_get_offlinemode() == TRUE) { - __connman_profile_set_offlinemode(FALSE, FALSE); - __connman_profile_save_default(); - } - if (technology->pending_reply != NULL) { g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID); dbus_message_unref(technology->pending_reply); + g_source_remove(technology->pending_timeout); technology->pending_reply = NULL; technology->pending_timeout = 0; } @@ -744,20 +848,28 @@ int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg } if (msg != NULL) { - technology->pending_reply = dbus_message_ref(msg); /* * This is a bit of a trick. When msg is not NULL it means * thats technology_enable was invoked from the manager API. Hence we save * the state here. */ technology->enable_persistent = TRUE; - __connman_storage_save_technology(technology); + save_state(technology); } + __connman_rfkill_block(technology->type, FALSE); + + /* + * An empty device list means that devices in the technology + * were rfkill blocked. The unblock above will enable the devs. + */ + if (technology->device_list == NULL) + return 0; + for (list = technology->device_list; list; list = list->next) { struct connman_device *device = list->data; - err = __connman_device_enable_persistent(device); + err = __connman_device_enable(device); /* * err = 0 : Device was enabled right away. * If atleast one device gets enabled, we consider @@ -768,14 +880,18 @@ int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg } done: - if (ret == 0) + if (ret == 0) { + if (msg != NULL) + g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID); return ret; + } if (msg != NULL) { - if (err == -EINPROGRESS) + if (err == -EINPROGRESS) { + technology->pending_reply = dbus_message_ref(msg); technology->pending_timeout = g_timeout_add_seconds(10, technology_pending_reply, technology); - else { + } else { reply = __connman_error_failed(msg, -err); if (reply != NULL) g_dbus_send_message(connection, reply); @@ -788,7 +904,6 @@ done: int __connman_technology_disabled(enum connman_service_type type) { struct connman_technology *technology; - GSList *list; technology = technology_find(type); if (technology == NULL) @@ -797,23 +912,15 @@ int __connman_technology_disabled(enum connman_service_type type) if (technology->pending_reply != NULL) { g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID); dbus_message_unref(technology->pending_reply); + g_source_remove(technology->pending_timeout); technology->pending_reply = NULL; + technology->pending_timeout = 0; } - if (g_atomic_int_dec_and_test(&technology->enabled) == TRUE) { - __connman_notifier_disable(type); - - technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE; - state_changed(technology); - } - - for (list = technology->device_list; list; list = list->next) { - struct connman_device *device = list->data; - - if (__connman_device_get_blocked(device) == FALSE) - return 0; - } + if (__sync_fetch_and_sub(&technology->enabled, 1) != 1) + return 0; + __connman_notifier_disable(type); technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE; state_changed(technology); @@ -841,29 +948,37 @@ int __connman_technology_disable(enum connman_service_type type, DBusMessage *ms goto done; } + if (technology->tethering == TRUE) + set_tethering(technology, FALSE); + if (msg != NULL) { - technology->pending_reply = dbus_message_ref(msg); technology->enable_persistent = FALSE; - __connman_storage_save_technology(technology); + save_state(technology); } + __connman_rfkill_block(technology->type, TRUE); + for (list = technology->device_list; list; list = list->next) { struct connman_device *device = list->data; - err = __connman_device_disable_persistent(device); + err = __connman_device_disable(device); if (err == 0) ret = 0; } done: - if (ret == 0) + if (ret == 0) { + if (msg != NULL) + g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID); return ret; + } if (msg != NULL) { - if (err == -EINPROGRESS) + if (err == -EINPROGRESS) { + technology->pending_reply = dbus_message_ref(msg); technology->pending_timeout = g_timeout_add_seconds(10, technology_pending_reply, technology); - else { + } else { reply = __connman_error_failed(msg, -err); if (reply != NULL) g_dbus_send_message(connection, reply); @@ -873,16 +988,45 @@ done: return err; } -static void technology_blocked(struct connman_technology *technology, - connman_bool_t blocked) +int __connman_technology_set_offlinemode(connman_bool_t offlinemode) { GSList *list; + int err = -EINVAL; - for (list = technology->device_list; list; list = list->next) { - struct connman_device *device = list->data; + if (global_offlinemode == offlinemode) + return 0; + + DBG("offlinemode %s", offlinemode ? "On" : "Off"); + + /* + * This is a bit tricky. When you set offlinemode, there is no + * way to differentiate between attempting offline mode and + * resuming offlinemode from last saved profile. We need that + * information in rfkill_update, otherwise it falls back on the + * technology's persistent state. Hence we set the offline mode here + * but save it & call the notifier only if its successful. + */ + + global_offlinemode = offlinemode; + + /* Traverse technology list, enable/disable each technology. */ + for (list = technology_list; list; list = list->next) { + struct connman_technology *technology = list->data; - __connman_device_set_blocked(device, blocked); + if (offlinemode) + err = __connman_technology_disable(technology->type, NULL); + + if (!offlinemode && technology->enable_persistent) + err = __connman_technology_enable(technology->type, NULL); } + + if (err == 0 || err == -EINPROGRESS || err == -EALREADY) { + connman_technology_save_offlinemode(); + __connman_notifier_offlinemode(offlinemode); + } else + global_offlinemode = connman_technology_load_offlinemode(); + + return err; } int __connman_technology_add_rfkill(unsigned int index, @@ -892,7 +1036,6 @@ int __connman_technology_add_rfkill(unsigned int index, { struct connman_technology *technology; struct connman_rfkill *rfkill; - connman_bool_t blocked; DBG("index %u type %d soft %u hard %u", index, type, softblock, hardblock); @@ -905,6 +1048,8 @@ int __connman_technology_add_rfkill(unsigned int index, if (rfkill == NULL) return -ENOMEM; + __connman_notifier_register(type); + rfkill->index = index; rfkill->type = type; rfkill->softblock = softblock; @@ -912,15 +1057,24 @@ int __connman_technology_add_rfkill(unsigned int index, g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill); - blocked = (softblock || hardblock) ? TRUE : FALSE; - if (blocked == FALSE) + if (hardblock) { + DBG("%s is switched off.", get_name(type)); return 0; + } - if (g_atomic_int_exchange_and_add(&technology->blocked, 1) == 0) { - technology_blocked(technology, TRUE); - - technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE; - state_changed(technology); + /* + * If Offline mode is on, we softblock the device if it isnt already. + * If Offline mode is off, we rely on the persistent state of tech. + */ + if (global_offlinemode) { + if (!softblock) + return __connman_rfkill_block(type, TRUE); + } else { + if (technology->enable_persistent && softblock) + return __connman_rfkill_block(type, FALSE); + /* if technology persistent state is offline */ + if (!technology->enable_persistent && !softblock) + return __connman_rfkill_block(type, TRUE); } return 0; @@ -933,7 +1087,6 @@ int __connman_technology_update_rfkill(unsigned int index, { struct connman_technology *technology; struct connman_rfkill *rfkill; - connman_bool_t blocked, old_blocked; DBG("index %u soft %u hard %u", index, softblock, hardblock); @@ -945,33 +1098,23 @@ int __connman_technology_update_rfkill(unsigned int index, if (rfkill == NULL) return -ENXIO; - old_blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE; - blocked = (softblock || hardblock) ? TRUE : FALSE; + if (rfkill->softblock == softblock && + rfkill->hardblock == hardblock) + return 0; rfkill->softblock = softblock; rfkill->hardblock = hardblock; - if (blocked == old_blocked) + if (hardblock) { + DBG("%s is switched off.", get_name(type)); return 0; + } - if (blocked) { - guint n_blocked; - - n_blocked = - g_atomic_int_exchange_and_add(&technology->blocked, 1); - if (n_blocked != g_hash_table_size(technology->rfkill_list) - 1) - return 0; - - technology_blocked(technology, blocked); - technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE; - state_changed(technology); - } else { - if (g_atomic_int_dec_and_test(&technology->blocked) == FALSE) - return 0; - - technology_blocked(technology, blocked); - technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE; - state_changed(technology); + if (!global_offlinemode) { + if (technology->enable_persistent && softblock) + return __connman_rfkill_block(type, FALSE); + if (!technology->enable_persistent && !softblock) + return __connman_rfkill_block(type, TRUE); } return 0; @@ -982,7 +1125,6 @@ int __connman_technology_remove_rfkill(unsigned int index, { struct connman_technology *technology; struct connman_rfkill *rfkill; - connman_bool_t blocked; DBG("index %u", index); @@ -994,108 +1136,22 @@ int __connman_technology_remove_rfkill(unsigned int index, if (rfkill == NULL) return -ENXIO; - blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE; - g_hash_table_remove(technology->rfkill_list, &index); - if (blocked && - g_atomic_int_dec_and_test(&technology->blocked) == TRUE) { - technology_blocked(technology, FALSE); - technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE; - state_changed(technology); - } - - return 0; -} - -connman_bool_t __connman_technology_get_blocked(enum connman_service_type type) -{ - struct connman_technology *technology; - - technology = technology_find(type); - if (technology == NULL) - return FALSE; - - if (g_atomic_int_get(&technology->blocked)) - return TRUE; - - return FALSE; -} - -static int technology_load(struct connman_technology *technology) -{ - const char *ident = __connman_profile_active_ident(); - GKeyFile *keyfile; - gchar *identifier; - GError *error = NULL; - connman_bool_t enable; - - DBG("technology %p", technology); - - keyfile = __connman_storage_open_profile(ident); - if (keyfile == NULL) - return 0; - - 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); -done: - g_free(identifier); - - __connman_storage_close_profile(ident, keyfile, FALSE); - - return 0; -} - -static int technology_save(struct connman_technology *technology) -{ - const char *ident = __connman_profile_active_ident(); - GKeyFile *keyfile; - gchar *identifier; - - DBG("technology %p", technology); - - keyfile = __connman_storage_open_profile(ident); - if (keyfile == NULL) - return 0; - - 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); - -done: - g_free(identifier); - - __connman_storage_close_profile(ident, keyfile, TRUE); + technology_put(technology); return 0; } -static struct connman_storage tech_storage = { - .name = "technology", - .priority = CONNMAN_STORAGE_PRIORITY_LOW, - .tech_load = technology_load, - .tech_save = technology_save, -}; - int __connman_technology_init(void) { DBG(""); connection = connman_dbus_get_connection(); - return connman_storage_register(&tech_storage); + global_offlinemode = connman_technology_load_offlinemode(); + + return 0; } void __connman_technology_cleanup(void) @@ -1103,6 +1159,4 @@ void __connman_technology_cleanup(void) DBG(""); dbus_connection_unref(connection); - - connman_storage_unregister(&tech_storage); }