From 87ae92a8fff91a11db13a615d9fdc1133f9e7b7a Mon Sep 17 00:00:00 2001 From: Jaehyun Kim Date: Tue, 30 Jun 2015 09:40:43 +0900 Subject: [PATCH] Fix MMS connection failure Change-Id: Id3847d1d8233c2177cfbd65ba42ead8ff44a06a8 --- include/network.h | 2 + include/service.h | 41 ++ plugins/telephony.c | 1041 +++++++++++++++++++++++++++++---------------------- src/connman.h | 13 + src/ipconfig.c | 8 + src/network.c | 147 +++++++- src/provider.c | 4 + src/service.c | 455 +++++++++++++++++++++- 8 files changed, 1259 insertions(+), 452 deletions(-) diff --git a/include/network.h b/include/network.h index e433c22..5528f19 100644 --- a/include/network.h +++ b/include/network.h @@ -134,6 +134,8 @@ const char *connman_network_get_enc_mode(struct connman_network *network); int connman_network_set_proxy(struct connman_network *network, const char *proxies); + +void connman_network_clear_associating(struct connman_network *network); #endif int connman_network_set_name(struct connman_network *network, diff --git a/include/service.h b/include/service.h index 31dfce7..fe55d4b 100644 --- a/include/service.h +++ b/include/service.h @@ -24,6 +24,10 @@ #include +#if defined TIZEN_EXT +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -135,6 +139,43 @@ void connman_service_create_ip4config(struct connman_service *service, void connman_service_create_ip6config(struct connman_service *service, int index); +#if defined TIZEN_EXT +/* + * Description: TIZEN implements system global connection management. + * It's only for PDP (cellular) bearer. Wi-Fi is managed by ConnMan automatically. + * Reference count can help to manage open/close connection requests by each application. + */ + +/* + * Increase reference count of user-initiated packet data network connection + */ +void connman_service_user_pdn_connection_ref(struct connman_service *service); + +/* + * Decrease reference count of user initiated packet data network connection + * and return TRUE if counter is zero. + */ +gboolean connman_service_user_pdn_connection_unref_and_test( + struct connman_service *service); + +/* + * Test reference count of user initiated packet data network connection + * and return TRUE if counter is zero. No impact to reference count + */ +gboolean connman_service_is_no_ref_user_pdn_connection( + struct connman_service *service); +#endif + +#if defined TIZEN_EXT +struct connman_service *connman_service_get_default_connection(void); + +/* + * Description: telephony plug-in requires manual PROXY setting + */ +int connman_service_set_proxy(struct connman_service *service, + const char *proxy, gboolean active); +#endif + #ifdef __cplusplus } #endif diff --git a/plugins/telephony.c b/plugins/telephony.c index 88703ed..459095d 100644 --- a/plugins/telephony.c +++ b/plugins/telephony.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2011-2013 Samsung Electronics Co., Ltd. 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 @@ -19,36 +19,34 @@ * */ - #ifdef HAVE_CONFIG_H #include #endif #include -#include - #include +#include #include #define CONNMAN_API_SUBJECT_TO_CHANGE -#include -#include -#include -#include #include #include +#include +#include +#include #include -#include + +#include #define PS_DBUS_SERVICE "com.tcore.ps" -#define PS_MASTER_INTERFACE PS_DBUS_SERVICE ".master" -#define PS_MODEM_INTERFACE PS_DBUS_SERVICE ".modem" +#define PS_MASTER_INTERFACE PS_DBUS_SERVICE ".master" +#define PS_MODEM_INTERFACE PS_DBUS_SERVICE ".modem" #define PS_SERVICE_INTERFACE PS_DBUS_SERVICE ".service" #define PS_CONTEXT_INTERFACE PS_DBUS_SERVICE ".context" /* methods */ -#define GET_MODEMS "GetModems" +#define GET_MODEMS "GetModems" #define GET_SERVICES "GetServices" #define GET_CONTEXTS "GetContexts" #define ACTIVATE_CONTEXT "Activate" @@ -57,7 +55,7 @@ #define SET_PROPERTY "SetProperties" /* signals */ -#define MODEM_ADDED "ModemAdded" +#define MODEM_ADDED "ModemAdded" #define MODEM_REMOVED "ModemRemoved" #define SERVICE_ADDED "ServiceAdded" #define SERVICE_REMOVED "ServiceRemoved" @@ -65,9 +63,9 @@ #define CONTEXT_REMOVED "ContextRemoved" #define PROPERTY_CHANGED "PropertyChanged" -#define TIMEOUT 40000 +#define TIMEOUT 130000 -#define STRING2BOOL(a) ((g_str_equal(a, "TRUE")) ? (TRUE):(FALSE)) +#define STRING2BOOL(a) (!(g_strcmp0(a, "TRUE")) ? (TRUE):(FALSE)) static DBusConnection *connection; static GHashTable *modem_hash; @@ -99,6 +97,10 @@ struct telephony_modem { struct telephony_network { char *path; + int if_index; + gboolean routing_only; + gboolean ipv6_link_only; + struct connman_network *network; enum connman_ipconfig_method ipv4_method; @@ -108,6 +110,8 @@ struct telephony_network { struct connman_ipaddress *ipv6_address; }; +static int telephony_default_subscription_id = 0; + /* function prototype */ static void telephony_connect(DBusConnection *connection, void *user_data); static void telephony_disconnect(DBusConnection *connection, void *user_data); @@ -149,18 +153,8 @@ static void __add_service(struct telephony_modem *modem, static void __add_connman_device(const char *modem_path, const char *operator); static void __remove_connman_device(struct telephony_modem *modem); static void __remove_connman_networks(struct connman_device *device); -static void __set_device_powered(struct telephony_modem *modem, - gboolean powered); -static int __check_device_powered(const char *path, gboolean online); -static gboolean __check_network_available(struct connman_network *network); -static void __create_service(struct connman_network *network); static int __add_context(struct connman_device *device, const char *path, DBusMessageIter *prop); -static gboolean __set_network_ipconfig(struct telephony_network *network, - DBusMessageIter *dict); -static void __set_network_connected(struct telephony_network *network, - gboolean connected); -static char *__get_ident(const char *path); /* signal handler */ static gboolean __changed_modem(DBusConnection *connection, @@ -209,6 +203,7 @@ static int tech_probe(struct connman_technology *technology) static void tech_remove(struct connman_technology *technology) { + return; } static struct connman_technology_driver tech_driver = { @@ -228,8 +223,8 @@ static void telephony_connect(DBusConnection *connection, void *user_data) g_free, __remove_service); network_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, __remove_network); + __request_get_modems(); - return; } static void telephony_disconnect(DBusConnection *connection, void *user_data) @@ -245,8 +240,6 @@ static void telephony_disconnect(DBusConnection *connection, void *user_data) g_hash_table_destroy(network_hash); network_hash = NULL; } - - return; } static void __remove_modem(gpointer data) @@ -281,11 +274,37 @@ static void __remove_network(gpointer data) connman_network_unref(info->network); g_free(info->path); + connman_ipaddress_free(info->ipv4_address); connman_ipaddress_free(info->ipv6_address); + g_free(info); } +static void __set_device_powered(struct telephony_modem *modem, + gboolean powered) +{ + DBG("set modem(%s) powered(%d)", modem->path, powered); + + if (modem->device) + connman_device_set_powered(modem->device, powered); +} + +static int __check_device_powered(const char *path, gboolean powered) +{ + struct telephony_modem *modem = g_hash_table_lookup(modem_hash, path); + + if (modem == NULL) + return -ENODEV; + + DBG("check modem (%s) powered (%d)", modem->path, modem->powered); + + if (modem->powered == powered) + return -EALREADY; + + return 0; +} + static int __modem_probe(struct connman_device *device) { DBG("device %p", device); @@ -321,30 +340,8 @@ static int __network_probe(struct connman_network *network) static int __network_connect(struct connman_network *network) { - struct connman_device *device; - struct telephony_modem *modem; - struct telephony_service *service; - DBG("network %p", network); - device = connman_network_get_device(network); - if (device == NULL) - return -ENODEV; - - modem = connman_device_get_data(device); - if (modem == NULL) - return -ENODEV; - - service = modem->s_service; - if (service == NULL) - return -ENOLINK; - - if (modem->powered == FALSE) - return -ENOLINK; - - if (modem->data_allowed == FALSE || service->ps_attached == FALSE) - return -ENOLINK; - return __request_network_activate(network); } @@ -352,8 +349,8 @@ static int __network_disconnect(struct connman_network *network) { DBG("network %p", network); - if (connman_network_get_index(network) < 0) - return -ENOTCONN; + if (connman_network_get_associating(network) == TRUE) + connman_network_clear_associating(network); connman_network_set_associating(network, FALSE); @@ -366,26 +363,24 @@ static void __network_remove(struct connman_network *network) DBG("network %p path %s", network, path); g_hash_table_remove(network_hash, path); - return; } static int __dbus_request(const char *path, const char *interface, - const char *method, - DBusPendingCallNotifyFunction notify, void *user_data, - DBusFreeFunction free_function, int type, ...) + const char *method, + DBusPendingCallNotifyFunction notify, void *user_data, + DBusFreeFunction free_function, int type, ...) { DBusMessage *message; DBusPendingCall *call; dbus_bool_t ok; va_list va; - DBG("Telephony request path %s %s.%s", path, interface, method); + DBG("path %s %s.%s", path, interface, method); if (path == NULL) return -EINVAL; - message = dbus_message_new_method_call(PS_DBUS_SERVICE, path, - interface, method); + message = dbus_message_new_method_call(PS_DBUS_SERVICE, path, interface, method); if (message == NULL) return -ENOMEM; @@ -451,6 +446,10 @@ static void __response_get_modems(DBusPendingCall *call, void *user_data) dbus_message_iter_recurse(&args, &dict); + /* DBG("message type (%d) dic(%d)", + * dbus_message_iter_get_arg_type(&dict), DBUS_TYPE_DICT_ENTRY); + */ + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { DBusMessageIter entry, property; const char *modem_path; @@ -470,15 +469,14 @@ static void __response_get_modems(DBusPendingCall *call, void *user_data) done: dbus_message_unref(reply); dbus_pending_call_unref(call); - return; } static int __request_get_services(const char *path) { DBG("request get service"); return __dbus_request(path, PS_MODEM_INTERFACE, GET_SERVICES, - __response_get_services, g_strdup(path), - g_free, DBUS_TYPE_INVALID); + __response_get_services, g_strdup(path), + g_free, DBUS_TYPE_INVALID); } static void __response_get_services(DBusPendingCall *call, void *user_data) @@ -515,6 +513,10 @@ static void __response_get_services(DBusPendingCall *call, void *user_data) dbus_message_iter_recurse(&args, &dict); + /* DBG("message type (%d) dic(%d)", + * dbus_message_iter_get_arg_type(&dict), DBUS_TYPE_DICT_ENTRY); + */ + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { DBusMessageIter entry, property; const char *service_path; @@ -534,16 +536,15 @@ static void __response_get_services(DBusPendingCall *call, void *user_data) done: dbus_message_unref(reply); dbus_pending_call_unref(call); - return; } static int __request_get_contexts(struct telephony_modem *modem) { DBG("request get contexts"); return __dbus_request(modem->s_service->path, - PS_SERVICE_INTERFACE, GET_CONTEXTS, - __response_get_contexts, g_strdup(modem->path), - g_free, DBUS_TYPE_INVALID); + PS_SERVICE_INTERFACE, GET_CONTEXTS, + __response_get_contexts, g_strdup(modem->path), + g_free, DBUS_TYPE_INVALID); } static void __response_get_contexts(DBusPendingCall *call, void *user_data) @@ -601,21 +602,43 @@ static void __response_get_contexts(DBusPendingCall *call, void *user_data) done: dbus_message_unref(reply); dbus_pending_call_unref(call); - return; } static int __request_network_activate(struct connman_network *network) { - DBG("request network activate"); + int n_modems; + const char *path = NULL; + struct telephony_modem *modem = NULL; - const char *path = connman_network_get_string(network, "Path"); - DBG("network %p, path %s", network, path); + n_modems = g_hash_table_size(modem_hash); + path = connman_network_get_string(network, "Path"); + modem = connman_device_get_data(connman_network_get_device(network)); + DBG("network %p, path %s, modem %s[%d]", network, path, modem->path, + telephony_default_subscription_id); + + if (modem && n_modems > 1 && g_str_has_suffix(path, "_1") == TRUE) { + char *subscribe_id = g_strdup_printf("%d", telephony_default_subscription_id); + + if (g_str_has_suffix(modem->path, subscribe_id) != TRUE) { + g_free(subscribe_id); + return -ENOLINK; + } + g_free(subscribe_id); + } return __dbus_request(path, PS_CONTEXT_INTERFACE, ACTIVATE_CONTEXT, __response_network_activate, g_strdup(path), NULL, DBUS_TYPE_INVALID); } +static gboolean __check_network_available(struct connman_network *network) +{ + if (network == NULL || connman_network_get_device(network) == NULL) + return FALSE; + + return TRUE; +} + static void __response_network_activate(DBusPendingCall *call, void *user_data) { DBG("network activation response"); @@ -632,7 +655,7 @@ static void __response_network_activate(DBusPendingCall *call, void *user_data) if (info == NULL) goto done; - if (!__check_network_available(info->network)) { + if (__check_network_available(info->network) == FALSE) { g_hash_table_remove(network_hash, path); goto done; } @@ -642,6 +665,14 @@ static void __response_network_activate(DBusPendingCall *call, void *user_data) connman_error("connection activate() %s %s", error.name, error.message); + if (connman_network_get_associating(info->network) == TRUE) + connman_network_set_error(info->network, + CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + + if (connman_network_get_connecting(info->network) == TRUE) + connman_network_set_error(info->network, + CONNMAN_NETWORK_ERROR_CONNECT_FAIL); + if (connman_network_get_index(info->network) < 0) connman_network_set_error(info->network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); @@ -653,18 +684,62 @@ static void __response_network_activate(DBusPendingCall *call, void *user_data) done: dbus_message_unref(reply); dbus_pending_call_unref(call); - return; } static int __request_network_deactivate(struct connman_network *network) { - DBG("request network deactivate"); - const char *path = connman_network_get_string(network, "Path"); DBG("network %p, path %s", network, path); return __dbus_request(path, PS_CONTEXT_INTERFACE, DEACTIVATE_CONTEXT, - NULL, NULL, NULL, DBUS_TYPE_INVALID); + NULL, NULL, NULL, DBUS_TYPE_INVALID); +} + +static void __response_get_default_subscription_id(DBusPendingCall *call, + void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args; + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetDefaultDataSubscription() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + DBG("message signature (%s)", dbus_message_get_signature(reply)); + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + dbus_message_iter_get_basic(&args, &telephony_default_subscription_id); + DBG("default subscription: %d", telephony_default_subscription_id); + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_get_default_subscription_id(const char *path) +{ + int ret; + char *telephony_modem_path = NULL; + + telephony_modem_path = g_strdup_printf("/org/tizen/telephony%s", path); + DBG("request get default subscription id %s", telephony_modem_path); + + ret = __dbus_request(telephony_modem_path, + "org.tizen.telephony.Network", "GetDefaultDataSubscription", + __response_get_default_subscription_id, NULL, NULL, DBUS_TYPE_INVALID); + + g_free(telephony_modem_path); + return ret; } static void __add_modem(const char *path, DBusMessageIter *prop) @@ -675,9 +750,9 @@ static void __add_modem(const char *path, DBusMessageIter *prop) if (modem != NULL) return; - modem = (struct telephony_modem *)malloc( - sizeof(struct telephony_modem)); - memset(modem, 0, sizeof(struct telephony_modem)); + modem = g_try_new0(struct telephony_modem, 1); + if (modem == NULL) + return; modem->path = g_strdup(path); modem->device = NULL; @@ -697,17 +772,17 @@ static void __add_modem(const char *path, DBusMessageIter *prop) DBG("key (%s) value(%s)", key, tmp); - if (g_str_equal(key, "powered") == TRUE) { + if (g_strcmp0(key, "powered") == 0) { modem->powered = STRING2BOOL(tmp); - } else if (g_str_equal(key, "operator") == TRUE) { + } else if (g_strcmp0(key, "operator") == 0) { modem->operator = g_strdup(tmp); - } else if (g_str_equal(key, "sim_init") == TRUE) { + } else if (g_strcmp0(key, "sim_init") == 0) { modem->sim_init = STRING2BOOL(tmp); - } else if (g_str_equal(key, "flight_mode") == TRUE) { + } else if (g_strcmp0(key, "flight_mode") == 0) { modem->flight_mode = STRING2BOOL(tmp); - } else if (g_str_equal(key, "roaming_allowed") == TRUE) { + } else if (g_strcmp0(key, "roaming_allowed") == 0) { modem->roaming_allowed = STRING2BOOL(tmp); - } else if (g_str_equal(key, "data_allowed") == TRUE) { + } else if (g_strcmp0(key, "data_allowed") == 0) { modem->data_allowed = STRING2BOOL(tmp); } dbus_message_iter_next(prop); @@ -716,14 +791,15 @@ static void __add_modem(const char *path, DBusMessageIter *prop) __add_connman_device(path, modem->operator); __set_device_powered(modem, modem->powered); + if (g_hash_table_size(modem_hash) > 1) + __request_get_default_subscription_id(modem->path); + if (modem->powered != TRUE) { DBG("modem is not powered"); return; } __request_get_services(modem->path); - - return; } static void __add_service(struct telephony_modem *modem, @@ -734,13 +810,10 @@ static void __add_service(struct telephony_modem *modem, if (modem->s_service != NULL) return; - service = (struct telephony_service *)g_try_malloc( - sizeof(struct telephony_service)); + service = g_try_new0(struct telephony_service, 1); if (service == NULL) return; - memset(service, 0, sizeof(struct telephony_service)); - service->path = g_strdup(service_path); service->p_modem = modem; g_hash_table_insert(service_hash, g_strdup(service_path), service); @@ -757,11 +830,11 @@ static void __add_service(struct telephony_modem *modem, DBG("key (%s) value(%s)", key, tmp); - if (g_str_equal(key, "roaming") == TRUE) { + if (g_strcmp0(key, "roaming") == 0) { service->roaming = STRING2BOOL(tmp); - } else if (g_str_equal(key, "act") == TRUE) { + } else if (g_strcmp0(key, "act") == 0) { service->act = g_strdup(tmp); - } else if (g_str_equal(key, "ps_attached") == TRUE) { + } else if (g_strcmp0(key, "ps_attached") == 0) { service->ps_attached = STRING2BOOL(tmp); } @@ -770,12 +843,25 @@ static void __add_service(struct telephony_modem *modem, modem->s_service = service; __request_get_contexts(modem); +} - return; +static char *__get_ident(const char *path) +{ + char *pos; + + if (*path != '/') + return NULL; + + pos = strrchr(path, '/'); + if (pos == NULL) + return NULL; + + return pos + 1; } static void __add_connman_device(const char *modem_path, const char *operator) { + char* ident = NULL; struct telephony_modem *modem; struct connman_device *device; @@ -806,7 +892,10 @@ static void __add_connman_device(const char *modem_path, const char *operator) if (device == NULL) return; - connman_device_set_ident(device, operator); + ident = g_strdup_printf("%s_%s", __get_ident(modem_path), operator); + connman_device_set_ident(device, ident); + g_free(ident); + connman_device_set_string(device, "Path", modem_path); connman_device_set_data(device, modem); @@ -817,8 +906,6 @@ static void __add_connman_device(const char *modem_path, const char *operator) } modem->device = device; - - return; } static void __remove_connman_device(struct telephony_modem *modem) @@ -834,8 +921,6 @@ static void __remove_connman_device(struct telephony_modem *modem) connman_device_unref(modem->device); modem->device = NULL; - - return; } static void __remove_connman_networks(struct connman_device *device) @@ -867,387 +952,409 @@ static void __remove_connman_networks(struct connman_device *device) g_slist_free(info_list); } -static void __set_device_powered(struct telephony_modem *modem, - gboolean powered) -{ - DBG("set modem(%s) powered(%d)", modem->path, powered); - - if (modem->device) - connman_device_set_powered(modem->device, powered); - - return; -} - -static int __check_device_powered(const char *path, gboolean powered) +static gboolean connman_ipaddress_updated(struct connman_ipaddress *ipaddress, + const char *address, const char *gateway) { - struct telephony_modem *modem = g_hash_table_lookup(modem_hash, path); - - if (modem == NULL) - return -ENODEV; - - DBG("check modem (%s) powered (%d)", modem->path, modem->powered); - - if (modem->powered == powered) - return -EALREADY; + if (ipaddress == NULL || address == NULL) + return FALSE; - return 0; -} + if (g_strcmp0(ipaddress->local, address) != 0) + return TRUE; -static gboolean __check_network_available(struct connman_network *network) -{ - if (network == NULL || connman_network_get_device(network) == NULL) { - DBG("Modem or network was removed"); - return FALSE; - } + if (g_strcmp0(ipaddress->gateway, gateway) != 0) + return TRUE; - return TRUE; + return FALSE; } -static int __add_context(struct connman_device *device, const char *path, - DBusMessageIter *prop) +static void __set_network_connected(struct telephony_network *network, + gboolean connected) { - char *ident; - gboolean active = FALSE; - - struct telephony_modem *modem = connman_device_get_data(device); - struct connman_network *network; - struct telephony_network *info; - - DBG("modem %p device %p path %s", modem, device, path); - - ident = __get_ident(path); - - network = connman_device_get_network(device, ident); - if (network != NULL) - return -EALREADY; - - info = g_hash_table_lookup(network_hash, path); - if (info != NULL) { - DBG("path %p already exists with device %p", path, - connman_network_get_device(info->network)); - - if (connman_network_get_device(info->network)) - return -EALREADY; + gboolean setip = FALSE; - g_hash_table_remove(network_hash, path); - } + DBG("network %p connected %d", network, connected); - network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR); - if (network == NULL) - return -ENOMEM; + connman_network_set_index(network->network, network->if_index); + if (connman_network_get_connected(network->network) == connected) + return; - info = (struct telephony_network *)g_try_malloc( - sizeof(struct telephony_network)); - if (info == NULL) { - connman_network_unref(network); - return -ENOMEM; + switch (network->ipv4_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_DHCP: + case CONNMAN_IPCONFIG_METHOD_AUTO: + case CONNMAN_IPCONFIG_METHOD_OFF: + connman_network_set_ipv4_method(network->network, + network->ipv4_method); + break; + case CONNMAN_IPCONFIG_METHOD_MANUAL: + case CONNMAN_IPCONFIG_METHOD_FIXED: + connman_network_set_ipv4_method(network->network, + network->ipv4_method); + connman_network_set_ipaddress(network->network, + network->ipv4_address); + setip = TRUE; + break; } - memset(info, 0, sizeof(struct telephony_network)); - - info->path = g_strdup(path); - - connman_ipaddress_clear(info->ipv4_address); - connman_ipaddress_clear(info->ipv6_address); - info->network = network; - - connman_network_set_string(network, "Path", path); - connman_network_set_name(network, path); - - __create_service(network); - - g_hash_table_insert(network_hash, g_strdup(path), info); - - connman_network_set_available(network, TRUE); - connman_network_set_index(network, -1); - connman_network_set_bool(network, "Roaming", modem->s_service->roaming); - - if (connman_device_add_network(device, network) != 0) { - g_hash_table_remove(network_hash, path); - return -EIO; + switch (network->ipv6_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_DHCP: + break; + case CONNMAN_IPCONFIG_METHOD_AUTO: + connman_network_set_ipv6_method(network->network, + network->ipv6_method); + setip = TRUE; + break; + case CONNMAN_IPCONFIG_METHOD_MANUAL: + case CONNMAN_IPCONFIG_METHOD_FIXED: + connman_network_set_ipv6_method(network->network, + network->ipv6_method); + connman_network_set_ipaddress(network->network, + network->ipv6_address); + setip = TRUE; + break; } - active = __set_network_ipconfig(info, prop); - - if (active && (connman_network_get_connecting(network) || - connman_network_get_associating(network))) - __set_network_connected(info, active); - - return 0; -} - -static void __create_service(struct connman_network *network) -{ - const char *path; - char *group; - - DBG(""); - - path = connman_network_get_string(network, "Path"); - - group = __get_ident(path); - - connman_network_set_group(network, group); + if (setip == TRUE) + connman_network_set_connected(network->network, connected); } -static gboolean __set_network_ipconfig(struct telephony_network *network, - DBusMessageIter *dict) +static gboolean __set_network_context( + struct telephony_network *network, + DBusMessageIter *dict) { - DBG("set network info"); - + int index = 0; gboolean active = FALSE; - char *dev_name = NULL, *proxy_addr = NULL; + gboolean routing_only = FALSE; + gboolean ipv4_updated = FALSE; + gboolean ipv6_updated = FALSE; + gboolean ipv6_link_only = FALSE; + gboolean default_internet = FALSE; + gboolean active_proxy = FALSE; + char **proxies = NULL; + const char *dev_name = NULL; + const char *proxy_addr = NULL; char *ipv4_addr = NULL, *ipv4_gw = NULL, *ipv4_netmask = NULL, *ipv4_dns1 = NULL, *ipv4_dns2 = NULL; char *ipv6_addr = NULL, *ipv6_gw = NULL, *ipv6_netmask = NULL, *ipv6_dns1 = NULL, *ipv6_dns2 = NULL; - int index; - int dns_flag = 0; + struct connman_service *service; while (dbus_message_iter_get_arg_type(dict) != DBUS_TYPE_INVALID) { DBusMessageIter entry; - const char *key, *tmp; + const char *key, *value; dbus_message_iter_recurse(dict, &entry); dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); - DBG("key (%s)", key); - - if (g_str_equal(key, "dev_name") == TRUE) { + if (g_strcmp0(key, "dev_name") == 0) { dbus_message_iter_get_basic(&entry, &dev_name); DBG("dev_name (%s)", dev_name); - } else if (g_str_equal(key, "proxy") == TRUE) { + } else if (g_strcmp0(key, "proxy") == 0) { dbus_message_iter_get_basic(&entry, &proxy_addr); - } else if (g_str_equal(key, "ipv4_address") == TRUE) { + DBG("proxy_addr (%s)", proxy_addr); + } else if (g_strcmp0(key, "ipv4_address") == 0) { dbus_message_iter_get_basic(&entry, &ipv4_addr); - DBG("ipv4 address (%s)", ipv4_addr); - } else if (g_str_equal(key, "ipv4_gateway") == TRUE) { + DBG("ipv4_addr (%s)", ipv4_addr); + } else if (g_strcmp0(key, "ipv4_gateway") == 0) { dbus_message_iter_get_basic(&entry, &ipv4_gw); - } else if (g_str_equal(key, "ipv4_netmask") == TRUE) { + DBG("ipv4_gw (%s)", ipv4_gw); + } else if (g_strcmp0(key, "ipv4_netmask") == 0) { dbus_message_iter_get_basic(&entry, &ipv4_netmask); - } else if (g_str_equal(key, "ipv4_dns1") == TRUE) { + DBG("ipv4_netmask (%s)", ipv4_netmask); + } else if (g_strcmp0(key, "ipv4_dns1") == 0) { dbus_message_iter_get_basic(&entry, &ipv4_dns1); - } else if (g_str_equal(key, "ipv4_dns2") == TRUE) { + DBG("ipv4_dns1 (%s)", ipv4_dns1); + } else if (g_strcmp0(key, "ipv4_dns2") == 0) { dbus_message_iter_get_basic(&entry, &ipv4_dns2); - } else if (g_str_equal(key, "ipv6_address") == TRUE) { + DBG("ipv4_dns2 (%s)", ipv4_dns2); + } else if (g_strcmp0(key, "ipv6_address") == 0) { dbus_message_iter_get_basic(&entry, &ipv6_addr); DBG("ipv6 address (%s)", ipv6_addr); - } else if (g_str_equal(key, "ipv6_gateway") == TRUE) { + } else if (g_strcmp0(key, "ipv6_gateway") == 0) { dbus_message_iter_get_basic(&entry, &ipv6_gw); - } else if (g_str_equal(key, "ipv6_netmask") == TRUE) { + DBG("ipv6_gw (%s)", ipv6_gw); + } else if (g_strcmp0(key, "ipv6_netmask") == 0) { dbus_message_iter_get_basic(&entry, &ipv6_netmask); - } else if (g_str_equal(key, "ipv6_dns1") == TRUE) { + DBG("ipv6_netmask (%s)", ipv6_netmask); + } else if (g_strcmp0(key, "ipv6_dns1") == 0) { dbus_message_iter_get_basic(&entry, &ipv6_dns1); - } else if (g_str_equal(key, "ipv6_dns2") == TRUE) { + DBG("ipv6_dns1 (%s)", ipv6_dns1); + } else if (g_strcmp0(key, "ipv6_dns2") == 0) { dbus_message_iter_get_basic(&entry, &ipv6_dns2); - } else if (g_str_equal(key, "active") == TRUE) { - dbus_message_iter_get_basic(&entry, &tmp); - DBG("active (%s)", tmp); - active = STRING2BOOL(tmp); + DBG("ipv6_dns2 (%s)", ipv6_dns2); + } else if (g_strcmp0(key, "active") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("active (%s)", value); + active = STRING2BOOL(value); + } else if (g_strcmp0(key, "routing_only") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("routing_only (%s)", value); + routing_only = STRING2BOOL(value); + network->routing_only = routing_only; + } else if (g_strcmp0(key, "ipv6_link_only") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("ipv6_link_only (%s)", value); + ipv6_link_only = STRING2BOOL(value); + network->ipv6_link_only = ipv6_link_only; + } + else if (g_strcmp0(key, "default_internet_conn") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("default_internet (%s)", value); + default_internet = STRING2BOOL(value); } dbus_message_iter_next(dict); } - /* interface index set */ - if (dev_name == NULL) - dev_name = ""; + if(routing_only){ + //context active does not effect the connman service status. + //it only for setting the routing path. + DBG("routing_only(%d), active(%d)", routing_only, active); + return active; + } + + if (g_strcmp0(proxy_addr, ":") == 0) + proxy_addr = NULL; + if (g_strcmp0(ipv4_addr, "0.0.0.0") == 0) + ipv4_addr = NULL; + if (g_strcmp0(ipv4_gw, "0.0.0.0") == 0) + ipv4_gw = NULL; + if (g_strcmp0(ipv4_netmask, "0.0.0.0") == 0) + ipv4_netmask = NULL; + if (g_strcmp0(ipv4_dns1, "0.0.0.0") == 0) + ipv4_dns1 = NULL; + if (g_strcmp0(ipv4_dns2, "0.0.0.0") == 0) + ipv4_dns2 = NULL; + if (g_strcmp0(ipv6_addr, "::") == 0) + ipv6_addr = NULL; + if (g_strcmp0(ipv6_gw, "::") == 0) + ipv6_gw = NULL; + if (g_strcmp0(ipv6_netmask, "::") == 0) + ipv6_netmask = NULL; + if (g_strcmp0(ipv6_dns1, "::") == 0) + ipv6_dns1 = NULL; + if (g_strcmp0(ipv6_dns2, "::") == 0) + ipv6_dns2 = NULL; + + connman_network_set_bool(network->network, "DefaultInternet", + (bool)default_internet); + + service = connman_service_lookup_from_network(network->network); + if (service == NULL) + return FALSE; + + if (connman_setting_get_bool("SingleConnectedTechnology") == TRUE) { + /* Wi-Fi technology is always a top priority */ + if (active == TRUE && + connman_service_is_no_ref_user_pdn_connection(service) == TRUE && + connman_service_get_type(connman_service_get_default_connection()) + == CONNMAN_SERVICE_TYPE_WIFI) { + __request_network_deactivate(network->network); + + return FALSE; + } + } - if (!g_str_equal(dev_name, "")) { + /* interface index set */ + if (dev_name != NULL) { index = connman_inet_ifindex(dev_name); - DBG("interface %s, index %d", dev_name, index); - connman_network_set_index(network->network, index); + network->if_index = index; + DBG("interface index %d", index); } /* proxy set */ - if (proxy_addr == NULL) - proxy_addr = ""; + if (active == TRUE && + connman_network_get_connected(network->network) == TRUE) + active_proxy = TRUE; - DBG("proxy (%s) is set", proxy_addr); - connman_network_set_proxy(network->network, proxy_addr); + proxies = connman_service_get_proxy_servers(service); + if (proxies != NULL) { + if (proxy_addr == NULL) + connman_service_set_proxy(service, proxy_addr, active_proxy); + else if (g_strcmp0(proxy_addr, proxies[0]) != 0) + connman_service_set_proxy(service, proxy_addr, active_proxy); + } else if (proxy_addr != NULL) + connman_service_set_proxy(service, proxy_addr, active_proxy); + + if (proxies != NULL) + g_strfreev(proxies); + + __connman_service_nameserver_clear(service); /* ipv4 set */ - if (ipv4_addr == NULL) - ipv4_addr = "0.0.0.0"; + if (network->ipv4_address == NULL) + network->ipv4_address = + connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4); + + if (network->ipv4_address == NULL) + return FALSE; - if (g_str_equal(ipv4_addr, "0.0.0.0")) { + if (ipv4_addr == NULL && active == TRUE) network->ipv4_method = CONNMAN_IPCONFIG_METHOD_OFF; - } else { + else network->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED; - network->ipv4_address = - connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4); - if (network->ipv4_address == NULL) - return FALSE; + connman_network_set_ipv4_method(network->network, network->ipv4_method); + + ipv4_updated = connman_ipaddress_updated(network->ipv4_address, + ipv4_addr, ipv4_gw); + if (ipv4_updated == TRUE) connman_ipaddress_set_ipv4(network->ipv4_address, ipv4_addr, ipv4_netmask, ipv4_gw); - if (ipv4_dns1 == NULL) - ipv4_dns1 = "0.0.0.0"; - if (ipv4_dns2 == NULL) - ipv4_dns2 = "0.0.0.0"; - - if (g_str_equal(ipv4_dns1, "0.0.0.0")) - dns_flag += 1; - - if (g_str_equal(ipv4_dns2, "0.0.0.0")) - dns_flag += 2; - - gchar *nameservers = NULL; - - switch (dns_flag) { - case 0: - nameservers = g_strdup_printf("%s %s", ipv4_dns1, - ipv4_dns2); - break; - case 1: - nameservers = g_strdup_printf("%s", ipv4_dns2); - break; - case 2: - nameservers = g_strdup_printf("%s", ipv4_dns1); - } - - connman_network_set_nameservers(network->network, nameservers); - g_free(nameservers); - } + if (ipv4_dns1) + __connman_service_nameserver_append(service, ipv4_dns1, FALSE); + //if (ipv4_dns2) + if (ipv4_dns2 && !ipv4_dns1) + __connman_service_nameserver_append(service, ipv4_dns2, FALSE); /* ipv6 set */ - if (ipv6_addr == NULL) - ipv6_addr = "::"; + if (network->ipv6_address == NULL) + network->ipv6_address = + connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6); - if (g_str_equal(ipv6_addr, "::")) { - network->ipv6_method = CONNMAN_IPCONFIG_METHOD_OFF; - } else { + if (network->ipv6_address == NULL) + return FALSE; + + if(ipv6_link_only) + network->ipv6_method = CONNMAN_IPCONFIG_METHOD_AUTO; + else network->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED; - unsigned char prefix_length = 64; - network->ipv6_address = - connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6); - if (network->ipv6_address == NULL) - return FALSE; - connman_ipaddress_set_ipv6(network->ipv6_address, ipv6_addr, - prefix_length, ipv6_gw); + if (ipv6_addr == NULL) + network->ipv6_method = CONNMAN_IPCONFIG_METHOD_OFF; - dns_flag = 0; + connman_network_set_ipv6_method(network->network, network->ipv6_method); - if (ipv6_dns1 == NULL) - ipv6_dns1 = "::"; - if (ipv6_dns2 == NULL) - ipv6_dns2 = "::"; + ipv6_updated = connman_ipaddress_updated(network->ipv6_address, + ipv6_addr, ipv6_gw); + if (ipv6_updated == TRUE) + connman_ipaddress_set_ipv6(network->ipv6_address, ipv6_addr, + 64, ipv6_gw); - if (g_str_equal(ipv6_dns1, "::")) - dns_flag += 1; + if (ipv6_dns1) + __connman_service_nameserver_append(service, ipv6_dns1, FALSE); + //if (ipv6_dns2) + if (ipv6_dns2 && !ipv6_dns1) + __connman_service_nameserver_append(service, ipv6_dns2, FALSE); - if (g_str_equal(ipv6_dns2, "::")) - dns_flag += 2; + if (active == TRUE && + connman_network_get_connected(network->network) == TRUE) { + if (ipv4_updated == TRUE || ipv6_updated == TRUE) { + DBG("IPv4 updated %d, IPv6 updated %d", ipv4_updated, ipv6_updated); - gchar *nameservers = NULL; + __set_network_connected(network, FALSE); + } else { + DBG("Already connected"); - switch (dns_flag) { - case 0: - nameservers = g_strdup_printf("%s %s", ipv6_dns1, - ipv6_dns2); - break; - case 1: - nameservers = g_strdup_printf("%s", ipv6_dns2); - break; - case 2: - nameservers = g_strdup_printf("%s", ipv6_dns1); + return active; } - - connman_network_set_nameservers(network->network, nameservers); - g_free(nameservers); } - if (active) + if (active == TRUE) connman_network_set_associating(network->network, TRUE); return active; } -static void __set_network_connected(struct telephony_network *network, - gboolean connected) +static int __add_context(struct connman_device *device, const char *path, + DBusMessageIter *prop) { - gboolean setip = FALSE; + char *ident; + gboolean active = FALSE; - DBG("network %p connected %d", network, connected); + struct telephony_modem *modem = connman_device_get_data(device); + struct connman_network *network; + struct telephony_network *info; - switch (network->ipv4_method) { - case CONNMAN_IPCONFIG_METHOD_UNKNOWN: - case CONNMAN_IPCONFIG_METHOD_OFF: - case CONNMAN_IPCONFIG_METHOD_MANUAL: - case CONNMAN_IPCONFIG_METHOD_AUTO: - setip = TRUE; - break; + DBG("modem %p device %p path %s", modem, device, path); - case CONNMAN_IPCONFIG_METHOD_FIXED: - connman_network_set_ipv4_method(network->network, - network->ipv4_method); - connman_network_set_ipaddress(network->network, - network->ipv4_address); - setip = TRUE; - break; + ident = __get_ident(path); - case CONNMAN_IPCONFIG_METHOD_DHCP: - connman_network_set_ipv4_method(network->network, - network->ipv4_method); - setip = TRUE; - break; + network = connman_device_get_network(device, ident); + if (network != NULL) + return -EALREADY; + + info = g_hash_table_lookup(network_hash, path); + if (info != NULL) { + DBG("path %p already exists with device %p", path, + connman_network_get_device(info->network)); + + if (connman_network_get_device(info->network)) + return -EALREADY; + + g_hash_table_remove(network_hash, path); } - switch (network->ipv6_method) { - case CONNMAN_IPCONFIG_METHOD_UNKNOWN: - case CONNMAN_IPCONFIG_METHOD_OFF: - case CONNMAN_IPCONFIG_METHOD_MANUAL: - case CONNMAN_IPCONFIG_METHOD_DHCP: - break; - case CONNMAN_IPCONFIG_METHOD_AUTO: - connman_network_set_ipv6_method(network->network, - network->ipv6_method); - setip = TRUE; - break; + network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR); + if (network == NULL) + return -ENOMEM; - case CONNMAN_IPCONFIG_METHOD_FIXED: - connman_network_set_ipv6_method(network->network, - network->ipv6_method); - connman_network_set_ipaddress(network->network, - network->ipv6_address); - setip = TRUE; - break; + info = g_try_new0(struct telephony_network, 1); + if (info == NULL) { + connman_network_unref(network); + return -ENOMEM; } - if (setip == TRUE) - connman_network_set_connected(network->network, connected); + info->path = g_strdup(path); - return; -} + connman_ipaddress_clear(info->ipv4_address); + connman_ipaddress_clear(info->ipv6_address); -static char *__get_ident(const char *path) -{ - char *pos; + info->network = network; - if (*path != '/') - return NULL; + connman_network_set_string(network, "Path", path); + connman_network_set_name(network, path); - pos = strrchr(path, '/'); - if (pos == NULL) - return NULL; + connman_network_set_group(network, ident); - return pos + 1; + g_hash_table_insert(network_hash, g_strdup(path), info); + + connman_network_set_available(network, TRUE); + connman_network_set_bool(network, "Roaming", (bool)modem->s_service->roaming); + + if (connman_device_add_network(device, network) != 0) { + g_hash_table_remove(network_hash, path); + return -EIO; + } + + active = __set_network_context(info, prop); + if(info->routing_only){ + int err = 0; + struct connman_service *routing_service; + struct connman_ipconfig *routing_ipconfig; + + if(!active) + return TRUE; + + routing_service = connman_service_lookup_from_network(info->network); + routing_ipconfig = __connman_service_get_ip4config(routing_service); + err = __connman_ipconfig_gateway_add(routing_ipconfig, routing_service); + + DBG("set gateway rv(%d)", err); + return TRUE; + } + + if (active == TRUE && (connman_network_get_associating(network) == TRUE || + connman_network_get_connecting(network) == TRUE)) + __set_network_connected(info, active); + + return 0; } static gboolean __changed_modem(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("modem changed signal"); - + gboolean old_powered; DBusMessageIter args, dict; - const char *path = dbus_message_get_path(message); struct telephony_modem *modem; + const char *path = dbus_message_get_path(message); - DBG("modem path %s", path); + DBG("modem changed signal %s", path); modem = g_hash_table_lookup(modem_hash, path); if (modem == NULL) { @@ -1255,6 +1362,8 @@ static gboolean __changed_modem(DBusConnection *connection, return TRUE; } + old_powered = modem->powered; + DBG("message signature (%s)", dbus_message_get_signature(message)); if (dbus_message_iter_init(message, &args) == FALSE) { @@ -1276,17 +1385,17 @@ static gboolean __changed_modem(DBusConnection *connection, DBG("key(%s), value(%s)", key, tmp); - if (g_str_equal(key, "powered") == TRUE) { + if (g_strcmp0(key, "powered") == 0) { modem->powered = STRING2BOOL(tmp); - } else if (g_str_equal(key, "operator") == TRUE) { + } else if (g_strcmp0(key, "operator") == 0) { modem->operator = g_strdup(tmp); - } else if (g_str_equal(key, "sim_init") == TRUE) { + } else if (g_strcmp0(key, "sim_init") == 0) { modem->sim_init = STRING2BOOL(tmp); - } else if (g_str_equal(key, "flight_mode") == TRUE) { + } else if (g_strcmp0(key, "flight_mode") == 0) { modem->flight_mode = STRING2BOOL(tmp); - } else if (g_str_equal(key, "roaming_allowed") == TRUE) { + } else if (g_strcmp0(key, "roaming_allowed") == 0) { modem->roaming_allowed = STRING2BOOL(tmp); - } else if (g_str_equal(key, "data_allowed") == TRUE) { + } else if (g_strcmp0(key, "data_allowed") == 0) { modem->data_allowed = STRING2BOOL(tmp); } @@ -1296,23 +1405,21 @@ static gboolean __changed_modem(DBusConnection *connection, if (modem->device == NULL) __add_connman_device(path, modem->operator); - __set_device_powered(modem, modem->powered); + if (old_powered != modem->powered) + __set_device_powered(modem, modem->powered); if (modem->powered != TRUE) { DBG("modem is not powered"); return TRUE; } - if (!modem->s_service) { + if (modem->s_service == NULL) { __request_get_services(modem->path); return TRUE; } - if (modem->flight_mode || !modem->data_allowed) { - DBG("modem(%s) flight mode(%d) data allowed(%d)", + DBG("modem(%s) flight mode(%d) data allowed(%d)", modem->path, modem->flight_mode, modem->data_allowed); - return TRUE; - } return TRUE; } @@ -1320,12 +1427,11 @@ static gboolean __changed_modem(DBusConnection *connection, static gboolean __added_modem(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("modem added signal"); - const char *modem_path = NULL; DBusMessageIter args, dict, tmp; - DBG("message signature (%s)", dbus_message_get_signature(message)); + DBG("modem added signal (%s)", dbus_message_get_signature(message)); + if (dbus_message_iter_init(message, &args) == FALSE) { DBG("error to read message"); return TRUE; @@ -1346,7 +1452,7 @@ static gboolean __added_modem(DBusConnection *connection, DBG("key (%s) value(%s)", key, value); - if (g_str_equal(key, "path") == TRUE) + if (g_strcmp0(key, "path") == 0) modem_path = g_strdup(value); dbus_message_iter_next(&tmp); @@ -1361,11 +1467,11 @@ static gboolean __added_modem(DBusConnection *connection, static gboolean __removed_modem(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("modem removed signal"); - DBusMessageIter iter; const char *modem_path; + DBG("modem removed signal"); + if (dbus_message_iter_init(message, &iter) == FALSE) { DBG("error to read message"); return TRUE; @@ -1380,15 +1486,13 @@ static gboolean __removed_modem(DBusConnection *connection, static gboolean __changed_service(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("service changed signal"); - DBusMessageIter args, dict; - const char *service_path = dbus_message_get_path(message); struct telephony_modem *modem; - struct telephony_service *s_service; gboolean roaming_option = TRUE; + struct telephony_service *s_service; + const char *service_path = dbus_message_get_path(message); - DBG("service path %s", service_path); + DBG("service changed signal %s", service_path); s_service = g_hash_table_lookup(service_hash, service_path); if (s_service == NULL) { @@ -1423,11 +1527,11 @@ static gboolean __changed_service(DBusConnection *connection, DBG("key(%s), value(%s)", key, tmp); - if (g_str_equal(key, "roaming") == TRUE) { + if (g_strcmp0(key, "roaming") == 0) { s_service->roaming = STRING2BOOL(tmp); - } else if (g_str_equal(key, "act") == TRUE) { + } else if (g_strcmp0(key, "act") == 0) { s_service->act = g_strdup(tmp); - } else if (g_str_equal(key, "ps_attached") == TRUE) { + } else if (g_strcmp0(key, "ps_attached") == 0) { s_service->ps_attached = STRING2BOOL(tmp); } @@ -1440,16 +1544,15 @@ static gboolean __changed_service(DBusConnection *connection, return TRUE; } - static gboolean __added_service(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("service added signal"); - - const char *path = dbus_message_get_path(message); + struct telephony_modem *modem; const char *service_path = NULL; DBusMessageIter args, dict, tmp; - struct telephony_modem *modem; + const char *path = dbus_message_get_path(message); + + DBG("service added signal %s", path); modem = g_hash_table_lookup(modem_hash, path); if (modem == NULL || modem->device == NULL) @@ -1476,9 +1579,8 @@ static gboolean __added_service(DBusConnection *connection, DBG("key (%s) value(%s)", key, value); - if (g_str_equal(key, "path") == TRUE) { - service_path = g_strdup(value); - } + if (g_strcmp0(key, "path") == 0) + service_path = value; dbus_message_iter_next(&tmp); } @@ -1492,11 +1594,11 @@ static gboolean __added_service(DBusConnection *connection, static gboolean __removed_service(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("service removed signal"); - DBusMessageIter iter; const char *service_path; + DBG("service removed signal"); + if (dbus_message_iter_init(message, &iter) == FALSE) { DBG("error to read message"); return TRUE; @@ -1511,19 +1613,18 @@ static gboolean __removed_service(DBusConnection *connection, static gboolean __changed_context(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("network changed signal"); - gboolean active = FALSE; - const char *path = dbus_message_get_path(message); - struct telephony_network *info; DBusMessageIter args, dict; + struct telephony_network *info; + const char *path = dbus_message_get_path(message); + + DBG("network changed signal %s", path); - DBG("path %s", path); info = g_hash_table_lookup(network_hash, path); if (info == NULL) return TRUE; - if (!__check_network_available(info->network)) { + if (__check_network_available(info->network) == FALSE) { g_hash_table_remove(network_hash, path); return TRUE; } @@ -1535,13 +1636,28 @@ static gboolean __changed_context(DBusConnection *connection, dbus_message_iter_recurse(&args, &dict); - active = __set_network_ipconfig(info, &dict); + active = __set_network_context(info, &dict); + if(info->routing_only){ + int err = 0; + struct connman_service *routing_service; + struct connman_ipconfig *routing_ipconfig; - if (active == FALSE) - __set_network_connected(info, active); - else if ((connman_network_get_connecting(info->network) || - connman_network_get_associating(info->network))) - __set_network_connected(info, active); + if(!active) + return TRUE; + + routing_service = connman_service_lookup_from_network(info->network); + routing_ipconfig = __connman_service_get_ip4config(routing_service); + err = __connman_ipconfig_gateway_add(routing_ipconfig, routing_service); + + DBG("set gateway rv(%d)", err); + return TRUE; + } + + __set_network_connected(info, active); + + if (active == FALSE && + connman_network_get_connecting(info->network) == TRUE) + connman_network_set_connected(info->network, FALSE); return TRUE; } @@ -1549,13 +1665,13 @@ static gboolean __changed_context(DBusConnection *connection, static gboolean __added_context(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("network added signal"); - - DBusMessageIter args, dict, tmp; - const char *path = dbus_message_get_path(message); const char *network_path = NULL; - struct telephony_service *service = NULL; + DBusMessageIter args, dict, tmp; struct telephony_modem *modem = NULL; + struct telephony_service *service = NULL; + const char *path = dbus_message_get_path(message); + + DBG("network added signal %s", path); service = g_hash_table_lookup(service_hash, path); if (service == NULL || service->p_modem == NULL) @@ -1586,7 +1702,7 @@ static gboolean __added_context(DBusConnection *connection, DBG("key (%s) value(%s)", key, value); - if (g_str_equal(key, "path") == TRUE) + if (g_strcmp0(key, "path") == 0) network_path = g_strdup(value); dbus_message_iter_next(&tmp); @@ -1601,12 +1717,12 @@ static gboolean __added_context(DBusConnection *connection, static gboolean __removed_context(DBusConnection *connection, DBusMessage *message, void *user_data) { - DBG("network removed signal"); - DBusMessageIter iter; - const char *path = dbus_message_get_path(message); const char *network_path = NULL; struct telephony_service *service = NULL; + const char *path = dbus_message_get_path(message); + + DBG("network removed signal %s", path); service = g_hash_table_lookup(service_hash, path); if (service == NULL || service->p_modem == NULL) @@ -1623,23 +1739,40 @@ static gboolean __removed_context(DBusConnection *connection, return TRUE; } +static gboolean __changed_default_subscription(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter args; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + if (dbus_message_iter_init(message, &args) == FALSE) + return TRUE; + + dbus_message_iter_get_basic(&args, &telephony_default_subscription_id); + DBG("default subscription: %d", telephony_default_subscription_id); + + return TRUE; +} + /* telephony initialization */ -static guint watch; -static guint modem_watch; -static guint modem_added_watch; -static guint modem_removed_watch; -static guint service_watch; -static guint service_added_watch; -static guint service_removed_watch; -static guint context_watch; -static guint context_added_watch; -static guint context_removed_watch; +static guint watch = 0; +static guint modem_watch = 0; +static guint modem_added_watch = 0; +static guint modem_removed_watch = 0; +static guint service_watch = 0; +static guint service_added_watch = 0; +static guint service_removed_watch = 0; +static guint context_watch = 0; +static guint context_added_watch = 0; +static guint context_removed_watch = 0; +static guint default_subscription_watch = 0; static int telephony_init(void) { - DBG("telephony plugin"); int err; + DBG("telephony plugin"); + connection = connman_dbus_get_connection(); if (connection == NULL) return -EIO; @@ -1652,16 +1785,19 @@ static int telephony_init(void) modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL, PS_MODEM_INTERFACE, PROPERTY_CHANGED, - __changed_modem, NULL, NULL); + __changed_modem, + NULL, NULL); modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, PS_MASTER_INTERFACE, - MODEM_ADDED, __added_modem, + MODEM_ADDED, + __added_modem, NULL, NULL); modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, PS_MASTER_INTERFACE, - MODEM_REMOVED, __removed_modem, + MODEM_REMOVED, + __removed_modem, NULL, NULL); service_watch = g_dbus_add_signal_watch(connection, NULL, NULL, @@ -1672,7 +1808,8 @@ static int telephony_init(void) service_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, PS_MODEM_INTERFACE, - SERVICE_ADDED, __added_service, + SERVICE_ADDED, + __added_service, NULL, NULL); service_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, @@ -1689,7 +1826,8 @@ static int telephony_init(void) context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, PS_SERVICE_INTERFACE, - CONTEXT_ADDED, __added_context, + CONTEXT_ADDED, + __added_context, NULL, NULL); context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, @@ -1698,12 +1836,19 @@ static int telephony_init(void) __removed_context, NULL, NULL); + default_subscription_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + "org.tizen.telephony.Network", + "DefaultDataSubscription", + __changed_default_subscription, + NULL, NULL); + if (watch == 0 || modem_watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 || service_watch == 0 || service_added_watch == 0 || context_watch == 0 || service_removed_watch == 0 || context_added_watch == 0 - || context_removed_watch == 0) { + || context_removed_watch == 0 + || default_subscription_watch == 0) { err = -EIO; goto remove; } @@ -1738,6 +1883,7 @@ remove: g_dbus_remove_watch(connection, context_watch); g_dbus_remove_watch(connection, context_added_watch); g_dbus_remove_watch(connection, context_removed_watch); + g_dbus_remove_watch(connection, default_subscription_watch); dbus_connection_unref(connection); return err; @@ -1755,6 +1901,7 @@ static void telephony_exit(void) g_dbus_remove_watch(connection, context_watch); g_dbus_remove_watch(connection, context_added_watch); g_dbus_remove_watch(connection, context_removed_watch); + g_dbus_remove_watch(connection, default_subscription_watch); telephony_disconnect(connection, NULL); diff --git a/src/connman.h b/src/connman.h index 386e8c8..733f87c 100644 --- a/src/connman.h +++ b/src/connman.h @@ -395,7 +395,15 @@ enum connman_ipconfig_method __connman_ipconfig_get_method( int __connman_ipconfig_address_add(struct connman_ipconfig *ipconfig); int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig); int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig); +#if defined TIZEN_EXT +/* + * Description: __connman_service_lookup_from_index cannot find correct service + * e.g. same interface or same APN of cellular profile + */ +int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig, struct connman_service *service); +#else int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig); +#endif void __connman_ipconfig_gateway_remove(struct connman_ipconfig *ipconfig); int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig, @@ -757,6 +765,11 @@ void __connman_service_timeserver_changed(struct connman_service *service, void __connman_service_set_pac(struct connman_service *service, const char *pac); #if defined TIZEN_EXT +/* + * Returns profile count if there is any connected profiles + * that use same interface + */ +int __connman_service_get_connected_count_of_iface(struct connman_service *service); void __connman_service_set_proxy(struct connman_service *service, const char *proxies); #endif diff --git a/src/ipconfig.c b/src/ipconfig.c index ae70745..29c5a3d 100644 --- a/src/ipconfig.c +++ b/src/ipconfig.c @@ -1077,16 +1077,24 @@ void __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig, ipconfig->address->gateway = g_strdup(gateway); } +#if defined TIZEN_EXT +int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig, struct connman_service *service) +#else int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig) +#endif { +#if !defined TIZEN_EXT struct connman_service *service; +#endif DBG(""); if (!ipconfig->address) return -EINVAL; +#if !defined TIZEN_EXT service = __connman_service_lookup_from_index(ipconfig->index); +#endif if (!service) return -EINVAL; diff --git a/src/network.c b/src/network.c index eba068b..4047e17 100644 --- a/src/network.c +++ b/src/network.c @@ -99,6 +99,11 @@ struct connman_network { #endif } wifi; +#if defined TIZEN_EXT + /* Multiple APN services and a default APN which a user selected */ + bool default_internet; +#endif + }; static const char *type2string(enum connman_network_type type) @@ -178,7 +183,11 @@ static void dhcp_success(struct connman_network *network) if (err < 0) goto err; +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig_ipv4, service); +#else err = __connman_ipconfig_gateway_add(ipconfig_ipv4); +#endif if (err < 0) goto err; @@ -244,7 +253,12 @@ static int set_connected_fixed(struct connman_network *network) if (err < 0) goto err; +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig_ipv4, service); +#else err = __connman_ipconfig_gateway_add(ipconfig_ipv4); +#endif + if (err < 0) goto err; @@ -278,7 +292,11 @@ static void set_connected_manual(struct connman_network *network) if (err < 0) goto err; +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig, service); +#else err = __connman_ipconfig_gateway_add(ipconfig); +#endif if (err < 0) goto err; @@ -341,7 +359,11 @@ static int manual_ipv6_set(struct connman_network *network, return err; } +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig_ipv6, service); +#else err = __connman_ipconfig_gateway_add(ipconfig_ipv6); +#endif if (err < 0) return err; @@ -405,7 +427,11 @@ static int dhcpv6_set_addresses(struct connman_network *network) if (err < 0) goto err; +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig_ipv6, service); +#else err = __connman_ipconfig_gateway_add(ipconfig_ipv6); +#endif if (err < 0) goto err; @@ -792,12 +818,22 @@ static void set_disconnected(struct connman_network *network) CONNMAN_IPCONFIG_TYPE_IPV6); if (network->connected) { +#if defined TIZEN_EXT + /** + * Do not remove gateway and its address, + * if there are connected profiles that use same interface (multiple PDN) + */ + if (connman_service_get_type(service) != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_get_connected_count_of_iface(service) <= 0) { +#endif __connman_connection_gateway_remove(service, CONNMAN_IPCONFIG_TYPE_ALL); __connman_ipconfig_address_unset(ipconfig_ipv4); __connman_ipconfig_address_unset(ipconfig_ipv6); - +#if defined TIZEN_EXT + } +#endif /* * Special handling for IPv6 autoconfigured address. * The simplest way to remove autoconfigured routes is to @@ -1299,6 +1335,93 @@ bool connman_network_get_available(struct connman_network *network) return network->available; } +#if defined TIZEN_EXT +void connman_network_clear_associating(struct connman_network *network) +{ + struct connman_service *service; + enum connman_service_state state; + + DBG("network %p", network); + + network->connecting = FALSE; + network->associating = FALSE; + + service = connman_service_lookup_from_network(network); + if (!service) + return; + + state = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4); + if (state != CONNMAN_SERVICE_STATE_IDLE && + state != CONNMAN_SERVICE_STATE_FAILURE) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV4); + + state = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6); + if (state != CONNMAN_SERVICE_STATE_IDLE && + state != CONNMAN_SERVICE_STATE_FAILURE) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV6); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); +} + +static gboolean __connman_network_clear_associating_delayed(gpointer user_data) +{ + GSList *list; + gboolean found = FALSE; + enum connman_service_state state_ipv4; + enum connman_service_state state_ipv6; + struct connman_service *service; + struct connman_network *network = (struct connman_network *)user_data; + + for (list = network_list; list != NULL; list = list->next) { + struct connman_network *item = list->data; + + if (item == network) { + found = TRUE; + break; + } + } + + if (found != TRUE) + return FALSE; + + DBG("network %p name %s", network, network->name); + service = connman_service_lookup_from_network(network); + + state_ipv4 = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4); + state_ipv6 = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6); + + DBG("service %p state %d/%d", service, state_ipv4, state_ipv6); + + if (network->associating == FALSE && + state_ipv4 == CONNMAN_SERVICE_STATE_ASSOCIATION && + state_ipv6 == CONNMAN_SERVICE_STATE_ASSOCIATION) { + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); + } + + return FALSE; +} +#endif + /** * connman_network_set_associating: * @network: network structure @@ -1568,13 +1691,19 @@ int __connman_network_connect(struct connman_network *network) network->connecting = true; +#if defined TIZEN_EXT + if (network->type != CONNMAN_NETWORK_TYPE_CELLULAR) +#endif __connman_device_disconnect(network->device); err = network->driver->connect(network); if (err < 0) { - if (err == -EINPROGRESS) + if (err == -EINPROGRESS) { +#if defined TIZEN_EXT + if (network->type != CONNMAN_NETWORK_TYPE_CELLULAR) +#endif connman_network_set_associating(network, true); - else + } else network->connecting = false; return err; @@ -1632,7 +1761,11 @@ static int manual_ipv4_set(struct connman_network *network, return err; } +#if defined TIZEN_EXT + return __connman_ipconfig_gateway_add(ipconfig, service); +#else return __connman_ipconfig_gateway_add(ipconfig); +#endif } int __connman_network_clear_ipconfig(struct connman_network *network, @@ -2086,6 +2219,10 @@ int connman_network_set_bool(struct connman_network *network, network->wifi.wps = value; else if (g_strcmp0(key, "WiFi.UseWPS") == 0) network->wifi.use_wps = value; +#if defined TIZEN_EXT + else if (g_strcmp0(key, "DefaultInternet") == 0) + network->default_internet = value; +#endif return -EINVAL; } @@ -2108,6 +2245,10 @@ bool connman_network_get_bool(struct connman_network *network, return network->wifi.wps; else if (g_str_equal(key, "WiFi.UseWPS")) return network->wifi.use_wps; +#if defined TIZEN_EXT + else if (g_str_equal(key, "DefaultInternet")) + return network->default_internet; +#endif return false; } diff --git a/src/provider.c b/src/provider.c index 693552e..22ff08a 100644 --- a/src/provider.c +++ b/src/provider.c @@ -242,7 +242,11 @@ static int set_connected(struct connman_provider *provider, } __connman_ipconfig_address_add(ipconfig); +#if defined TIZEN_EXT + __connman_ipconfig_gateway_add(ipconfig, service); +#else __connman_ipconfig_gateway_add(ipconfig); +#endif provider_indicate_state(provider, CONNMAN_SERVICE_STATE_READY); diff --git a/src/service.c b/src/service.c index 974a087..fb4a61f 100644 --- a/src/service.c +++ b/src/service.c @@ -140,6 +140,18 @@ struct connman_service { bool hidden_service; char *config_file; char *config_entry; +#if defined TIZEN_EXT + /* + * Description: TIZEN implements system global connection management. + * It's only for PDP (cellular) bearer. Wi-Fi is managed + * by ConnMan automatically. Reference count can help to + * manage open/close connection requests by each application. + */ + int user_pdn_connection_refcount; +#endif +#if defined TIZEN_TV_EXT + enum connman_dnsconfig_method dns_config_method; +#endif }; static bool allow_property_changed(struct connman_service *service); @@ -155,6 +167,50 @@ struct find_data { struct connman_service *service; }; +#if defined TIZEN_EXT +/* + * Public APIs to use user_pdn_connection_refcount + */ +void connman_service_user_pdn_connection_ref(struct connman_service *service) +{ + __sync_fetch_and_add(&service->user_pdn_connection_refcount, 1); + + DBG("User made PDN connection referenced: %d", + service->user_pdn_connection_refcount); +} + +gboolean connman_service_user_pdn_connection_unref_and_test( + struct connman_service *service) +{ + __sync_synchronize(); + + DBG("User made PDN connection referenced: %d, which will be decreased", + service->user_pdn_connection_refcount); + + if (service->user_pdn_connection_refcount < 1) + return TRUE; + + if (__sync_sub_and_fetch(&service->user_pdn_connection_refcount, 1) == 0) + return TRUE; + + return FALSE; +} + +gboolean connman_service_is_no_ref_user_pdn_connection( + struct connman_service *cellular) +{ + if (cellular == NULL) + return TRUE; + + __sync_synchronize(); + if (cellular->type == CONNMAN_SERVICE_TYPE_CELLULAR && + cellular->user_pdn_connection_refcount == 0) + return TRUE; + + return FALSE; +} +#endif + static void compare_path(gpointer value, gpointer user_data) { struct connman_service *service = value; @@ -1518,6 +1574,71 @@ static void reset_stats(struct connman_service *service) g_timer_reset(service->stats_roaming.timer); } +#if defined TIZEN_EXT +static gboolean __connman_service_is_internet_profile( + struct connman_service *cellular) +{ + const char internet_suffix[] = "_1"; + + DBG("Service path: %s", cellular->path); + + if (g_str_has_suffix(cellular->path, internet_suffix) == TRUE) + return TRUE; + + return FALSE; +} + +static gboolean __connman_service_is_tethering_profile( + struct connman_service *cellular) +{ + const char tethering_suffix[] = "_5"; + + DBG("Service path: %s", cellular->path); + + if (g_str_has_suffix(cellular->path, tethering_suffix) == TRUE) + return TRUE; + + return FALSE; +} + +struct connman_service *connman_service_get_default_connection(void) +{ + GList *list; + struct connman_service *service; + struct connman_service *default_service = NULL; + + for (list = service_list; list; list = list->next) { + service = list->data; + + DBG("service: %p %s %s %s", service, service->name, + state2string(service->state), + __connman_service_type2string(service->type)); + + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + is_connected(service) == TRUE) { + return service; + } else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + __connman_service_is_internet_profile(service) == TRUE) { + if (default_service == NULL) + default_service = service; + else if (is_connected(service) == TRUE && + is_connected(default_service) == FALSE) + default_service = service; + } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET && + is_connected(service) == TRUE) { + if (default_service == NULL) + default_service = service; + } else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH && + is_connected(service) == TRUE) { + if (default_service == NULL) + default_service = service; + } + } + + return default_service; +} +#endif + struct connman_service *__connman_service_get_default(void) { struct connman_service *service; @@ -2710,6 +2831,54 @@ char **connman_service_get_timeservers(struct connman_service *service) return service->timeservers; } +#if defined TIZEN_EXT +/* + * Description: Telephony plug-in requires manual PROXY setting function + */ +int connman_service_set_proxy(struct connman_service *service, + const char *proxy, gboolean active) +{ + char **proxies_array = NULL; + + if (service == NULL) + return -EINVAL; + + switch (service->type) { + case CONNMAN_SERVICE_TYPE_CELLULAR: + case CONNMAN_SERVICE_TYPE_ETHERNET: + case CONNMAN_SERVICE_TYPE_WIFI: + break; + + default: + return -EINVAL; + } + + g_strfreev(service->proxies); + service->proxies = NULL; + + if (proxy != NULL) + proxies_array = g_strsplit(proxy, " ", 0); + + service->proxies = proxies_array; + + if (proxy == NULL) { + service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + DBG("proxy changed (%d)", active); + } else { + service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL; + DBG("proxy chagned %s (%d)", proxy, active); + } + + if (active == TRUE) { + proxy_changed(service); + + __connman_notifier_proxy_changed(service); + } + + return 0; +} +#endif + void connman_service_set_proxy_method(struct connman_service *service, enum connman_service_proxy_method method) { @@ -3816,6 +3985,14 @@ static GList *preferred_tech_list_get(void) CONNMAN_SERVICE_CONNECT_REASON_USER) { DBG("service %p name %s is user connected", service, service->name); +#if defined TIZEN_EXT + /* We can connect to a favorite service like + * wifi even we have a userconnect for cellular + * because we have refount for cellular service + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + break; +#endif return NULL; } } @@ -4132,6 +4309,14 @@ static DBusMessage *connect_service(DBusConnection *conn, DBG("service %p", service); +#if defined TIZEN_EXT + /* + * Description: TIZEN implements system global connection management. + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + connman_service_user_pdn_connection_ref(service); +#endif + if (service->pending) return __connman_error_in_progress(msg); @@ -4165,6 +4350,10 @@ static DBusMessage *connect_service(DBusConnection *conn, for (list = service_list; list; list = list->next) { struct connman_service *temp = list->data; +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + break; +#endif if (!is_connecting(temp) && !is_connected(temp)) break; @@ -4211,6 +4400,20 @@ static DBusMessage *disconnect_service(DBusConnection *conn, DBG("service %p", service); +#if defined TIZEN_EXT + /* + * Description: TIZEN implements system global connection management. + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) { + if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE) + return __connman_error_failed(msg, EISCONN); + + if (is_connected(service) == TRUE && + service == connman_service_get_default_connection()) + return __connman_error_failed(msg, EISCONN); + } +#endif + if (service->type == CONNMAN_SERVICE_TYPE_WIFI) { uid_t uid; if (connman_dbus_get_connection_unix_user_sync(conn, @@ -4819,6 +5022,13 @@ static void service_initialize(struct connman_service *service) service->provider = NULL; service->wps = false; +#if defined TIZEN_EXT + /* + * Description: TIZEN implements system global connection management. + */ + service->user_pdn_connection_refcount = 0; + __sync_synchronize(); +#endif } /** @@ -5161,6 +5371,46 @@ void __connman_service_mark_dirty(void) services_dirty = true; } +#if defined TIZEN_EXT +/** + * Returns profile count if there is any connected profiles + * that use same interface + */ +int __connman_service_get_connected_count_of_iface( + struct connman_service *service) +{ + GList *list; + int count = 0; + int index1 = 0; + int index2 = 0; + + DBG(""); + + index1 = __connman_service_get_index(service); + + if (index1 <= 0) + return 0; + + for (list = service_list; list; list = list->next) { + struct connman_service *service2 = list->data; + + if (service == service2) + continue; + + index2 = __connman_service_get_index(service2); + + if (is_connected(service2) && index2 > 0 && index1 == index2) + count++; + + index2 = 0; + } + + DBG("Interface index %d, count %d", index1, count); + + return count; +} +#endif + /** * __connman_service_set_favorite_delayed: * @service: service structure @@ -5173,6 +5423,10 @@ int __connman_service_set_favorite_delayed(struct connman_service *service, bool favorite, bool delay_ordering) { +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + return -EIO; +#endif if (service->hidden) return -EOPNOTSUPP; @@ -5512,6 +5766,126 @@ static int service_update_preferred_order(struct connman_service *default_servic return -EALREADY; } +#if defined TIZEN_EXT +static gboolean __connman_service_can_drop(struct connman_service *service) +{ + if (is_connected(service) == TRUE || is_connecting(service) == TRUE) { + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR) + return TRUE; + else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE) + return TRUE; + } + return FALSE; +} + +static struct connman_device *default_connecting_device = NULL; + +static void __connman_service_disconnect_default(struct connman_service *service) +{ + struct connman_device *default_device = NULL; + + if (default_connecting_device == NULL) + return; + + default_device = connman_network_get_device( + __connman_service_get_network(service)); + + DBG("Disconnecting service %p %s", service, service->path); + DBG("Disconnecting device %p %p %s", + default_connecting_device, + default_device, + connman_device_get_string(default_device, "Name")); + + if (default_connecting_device == default_device) + default_connecting_device = NULL; +} + +static void __connman_service_connect_default(struct connman_service *current) +{ + int err; + GList *list; + bool default_internet; + struct connman_service *service; + struct connman_service *default_service = NULL; + struct connman_device *default_device = NULL; + + if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) { + switch (current->state) { + case CONNMAN_SERVICE_STATE_UNKNOWN: + case CONNMAN_SERVICE_STATE_ASSOCIATION: + case CONNMAN_SERVICE_STATE_CONFIGURATION: + return; + default: + break; + } + + if (default_connecting_device && + __connman_service_is_internet_profile(current) == TRUE) { + if (current->network == NULL) + return; + + default_device = connman_network_get_device(current->network); + if (default_connecting_device == default_device) { + DBG("Cellular service[%s] %p %s", + state2string(current->state), current, current->path); + DBG("Cellular device %p %p %s", + default_connecting_device, default_device, + connman_device_get_string(default_device, "Name")); + + default_connecting_device = NULL; + } + } + + return; + } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE) + return; + + /* Always-on: keep default cellular connection as possible */ + for (list = service_list; list; list = list->next) { + service = list->data; + + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_is_internet_profile(service) != TRUE || + service->network == NULL) { + continue; + } + + default_internet = + connman_network_get_bool(service->network, "DefaultInternet"); + + DBG("service: %p %s %s %s (default: %d)", service, service->name, + __connman_service_type2string(service->type), + state2string(service->state), default_internet); + + if (default_internet) { + default_service = service; + if (is_connected(default_service) == TRUE || + is_connecting(default_service) == TRUE) + return; + + default_device = connman_network_get_device(default_service->network); + if (default_connecting_device == default_device) { + DBG("Device is connecting (%p)", default_connecting_device); + return; + } + + default_connecting_device = default_device; + default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER; + + err = __connman_network_connect(default_service->network); + DBG("Connecting default service %p %s [%d]", + default_service, default_service->path, err); + DBG("Connecting device %p %s", default_connecting_device, + connman_device_get_string(default_connecting_device, "Name")); + if (err < 0 && err != -EINPROGRESS) { + default_connecting_device = NULL; + } else + break; + } + } +} +#endif + static void single_connected_tech(struct connman_service *allowed) { struct connman_service *service; @@ -5523,12 +5897,16 @@ static void single_connected_tech(struct connman_service *allowed) for (iter = service_list; iter; iter = iter->next) { service = iter->data; +#if defined TIZEN_EXT + if (service != allowed && service->type != allowed->type && + __connman_service_can_drop(service) == TRUE) +#else if (!is_connected(service)) break; if (service == allowed) continue; - +#endif services = g_slist_prepend(services, service); } @@ -5536,6 +5914,9 @@ static void single_connected_tech(struct connman_service *allowed) service = list->data; DBG("disconnecting %p %s", service, service->path); +#if defined TIZEN_EXT + __connman_service_disconnect_default(service); +#endif __connman_service_disconnect(service); } @@ -5701,9 +6082,21 @@ static int service_indicate_state(struct connman_service *service) __connman_wpad_stop(service); +#if defined TIZEN_EXT + /** + * Skip the functions if there is any connected profiles + * that use same interface + */ + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_get_connected_count_of_iface( + service) <= 0) { +#endif dns_changed(service); domain_changed(service); proxy_changed(service); +#if defined TIZEN_EXT + } +#endif /* * Previous services which are connected and which states @@ -5734,6 +6127,10 @@ static int service_indicate_state(struct connman_service *service) service_list_sort(); +#if defined TIZEN_EXT + __connman_service_connect_default(service); +#endif + __connman_connection_update_gateway(); if ((old_state == CONNMAN_SERVICE_STATE_ONLINE && @@ -6017,6 +6414,18 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, if (*old_state == new_state) return -EALREADY; +#if defined TIZEN_EXT + __sync_synchronize(); + if (service->user_pdn_connection_refcount > 0 && + service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + if (new_state == CONNMAN_SERVICE_STATE_FAILURE || + new_state == CONNMAN_SERVICE_STATE_DISCONNECT || + new_state == CONNMAN_SERVICE_STATE_IDLE) { + service->user_pdn_connection_refcount = 0; + __sync_synchronize(); + } +#endif + DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)", service, service ? service->identifier : NULL, *old_state, state2string(*old_state), @@ -6032,6 +6441,15 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, __connman_ipconfig_enable(ipconfig); break; case CONNMAN_SERVICE_STATE_READY: +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + __connman_service_is_internet_profile(service) != TRUE) { + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + service_rp_filter(service, TRUE); + + break; + } +#endif if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { check_proxy_setup(service); service_rp_filter(service, true); @@ -6393,6 +6811,14 @@ int __connman_service_disconnect(struct connman_service *service) __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6, NULL); +#if defined TIZEN_EXT + /** + * Skip the functions If there is any connected profiles + * that use same interface + */ + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_get_connected_count_of_iface(service) <= 0) { +#endif __connman_ipconfig_address_remove(service->ipconfig_ipv4); settings_changed(service, service->ipconfig_ipv4); @@ -6401,6 +6827,9 @@ int __connman_service_disconnect(struct connman_service *service) __connman_ipconfig_disable(service->ipconfig_ipv4); __connman_ipconfig_disable(service->ipconfig_ipv6); +#if defined TIZEN_EXT + } +#endif __connman_stats_service_unregister(service); @@ -6867,6 +7296,28 @@ unsigned int __connman_service_get_order(struct connman_service *service) if (!service->favorite) return 0; +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_VPN && + service->do_split_routing == FALSE) + order = 10; + else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) { + if (service->order < 5) + order = 5; + } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET) + order = 4; + else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH) + order = 3; + else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + __connman_service_is_internet_profile(service) == TRUE) + order = 1; + else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + __connman_service_is_tethering_profile(service) == TRUE) + order = 0; + else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + order = 0; + else + order = 2; +#else if (service == service_list->data) order = 1; @@ -6875,7 +7326,7 @@ unsigned int __connman_service_get_order(struct connman_service *service) service->order = 10; order = 10; } - +#endif DBG("service %p name %s order %d split %d", service, service->name, order, service->do_split_routing); -- 2.7.4