diff options
Diffstat (limited to 'plugins')
-rwxr-xr-x[-rw-r--r--] | plugins/bluetooth.c | 33 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/connman-nmcompat.conf | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/dundee.c | 0 | ||||
-rw-r--r-- | plugins/ethernet.c | 65 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/gadget.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/hh2serial-gps.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/iospm.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/loopback.c | 34 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/mcc.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/neard.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/nmcompat.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/ofono.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/pacrunner.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/polkit.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/polkit.policy | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/session_policy_local.c | 0 | ||||
-rwxr-xr-x | plugins/telephony.c | 1936 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/tist.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/vpn.c | 0 | ||||
-rw-r--r-- | plugins/wifi.c | 2192 |
20 files changed, 4235 insertions, 29 deletions
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c index f759a902..9e19de08 100644..100755 --- a/plugins/bluetooth.c +++ b/plugins/bluetooth.c @@ -192,8 +192,14 @@ static bool pan_connect(struct bluetooth_pan *pan, return false; } +#if defined TIZEN_EXT + if (pan->network) { +#endif connman_network_set_index(pan->network, index); connman_network_set_connected(pan->network, true); +#if defined TIZEN_EXT + } +#endif return true; } @@ -211,6 +217,18 @@ static void pan_connect_cb(DBusMessage *message, void *user_data) return; } +#ifdef TIZEN_EXT + /* + * Network could be removed because of BT adapter power off + * This is to handle the scenario where network is removed + * before the connect_cb is called + */ + if (!pan->network) { + DBG("network already removed"); + return; + } +#endif + if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) { const char *dbus_error = dbus_message_get_error_name(message); @@ -262,6 +280,9 @@ static int bluetooth_pan_connect(struct connman_network *network) g_strdup(path), g_free)) return -EIO; +#if defined TIZEN_EXT + if (pan->network) +#endif connman_network_set_associating(pan->network, true); return -EINPROGRESS; @@ -286,6 +307,9 @@ static void pan_disconnect_cb(DBusMessage *message, void *user_data) DBG("network %p", pan->network); +#if defined TIZEN_EXT + if (pan->network) +#endif connman_network_set_connected(pan->network, false); } @@ -299,6 +323,11 @@ static int bluetooth_pan_disconnect(struct connman_network *network) if (!pan) return -EINVAL; +#if defined TIZEN_EXT + if (connman_network_get_associating(network) == TRUE) + connman_network_clear_associating(network); +#endif + path = g_dbus_proxy_get_path(pan->btnetwork_proxy); if (!g_dbus_proxy_method_call(pan->btnetwork_proxy, "Disconnect", @@ -524,7 +553,9 @@ static void device_enable_cb(const DBusError *error, void *user_data) goto out; } +#if !defined TIZEN_EXT enable_device(device, path); +#endif out: g_free(path); } @@ -591,7 +622,9 @@ static void device_disable_cb(const DBusError *error, void *user_data) goto out; } +#if !defined TIZEN_EXT disable_device(device, path); +#endif out: g_free(path); diff --git a/plugins/connman-nmcompat.conf b/plugins/connman-nmcompat.conf index 5887a345..a051d927 100644..100755 --- a/plugins/connman-nmcompat.conf +++ b/plugins/connman-nmcompat.conf @@ -5,6 +5,10 @@ <allow own="org.freedesktop.NetworkManager"/> <allow send_destination="org.freedesktop.NetworkManager"/> </policy> + <policy user="network_fw"> + <allow own="org.freedesktop.NetworkManager"/> + <allow send_destination="org.freedesktop.NetworkManager"/> + </policy> <policy at_console="true"> <allow send_destination="org.freedesktop.NetworkManager"/> </policy> diff --git a/plugins/dundee.c b/plugins/dundee.c index b5420acf..b5420acf 100644..100755 --- a/plugins/dundee.c +++ b/plugins/dundee.c diff --git a/plugins/ethernet.c b/plugins/ethernet.c index b0395c83..9e157467 100644 --- a/plugins/ethernet.c +++ b/plugins/ethernet.c @@ -49,6 +49,9 @@ #include <connman/rtnl.h> #include <connman/log.h> #include <connman/setting.h> +#if defined TIZEN_EXT_WIFI_MESH +#include <connman/mesh.h> +#endif static bool eth_tethering = false; @@ -254,6 +257,10 @@ static void ethernet_newlink(unsigned flags, unsigned change, void *user_data) } else { DBG("carrier off"); remove_network(device, ethernet); +#if defined TIZEN_EXT_WIFI_MESH + /* Remove ethernet from mesh bridge */ + __connman_mesh_remove_ethernet_from_bridge(); +#endif } } @@ -432,6 +439,54 @@ static struct connman_technology_driver eth_tech_driver = { .set_tethering = eth_tech_set_tethering, }; +#if defined TIZEN_EXT_WIFI_MESH +static int eth_mesh_add_to_bridge(const char *bridge) +{ + GList *list; + struct ethernet_data *ethernet; + + DBG("Add ethernet to bridge %s", bridge); + + for (list = eth_interface_list; list; list = list->next) { + int index = GPOINTER_TO_INT(list->data); + struct connman_device *device = + connman_device_find_by_index(index); + + if (device) { + ethernet = connman_device_get_data(device); + if (ethernet) + remove_network(device, ethernet); + } + + connman_inet_ifup(index); + + connman_inet_add_to_bridge(index, bridge); + } + + return 0; +} + +static int eth_mesh_remove_from_bridge(const char *bridge) +{ + GList *list; + + DBG("Remove ethernet from bridge %s", bridge); + + for (list = eth_interface_list; list; list = list->next) { + int index = GPOINTER_TO_INT(list->data); + + connman_inet_remove_from_bridge(index, bridge); + } + + return 0; +} + +static struct connman_mesh_eth_driver eth_mesh_driver = { + .add_to_bridge = eth_mesh_add_to_bridge, + .remove_from_bridge = eth_mesh_remove_from_bridge, +}; +#endif + static int ethernet_init(void) { int err; @@ -440,6 +495,12 @@ static int ethernet_init(void) if (err < 0) return err; +#if defined TIZEN_EXT_WIFI_MESH + err = connman_mesh_eth_driver_register(ð_mesh_driver); + if (err < 0) + return err; +#endif + err = connman_network_driver_register(ð_network_driver); if (err < 0) return err; @@ -457,6 +518,10 @@ static void ethernet_exit(void) { connman_technology_driver_unregister(ð_tech_driver); +#if defined TIZEN_EXT_WIFI_MESH + connman_mesh_eth_driver_unregister(ð_mesh_driver); +#endif + connman_network_driver_unregister(ð_network_driver); connman_device_driver_unregister(ð_dev_driver); diff --git a/plugins/gadget.c b/plugins/gadget.c index 1b44bbb5..1b44bbb5 100644..100755 --- a/plugins/gadget.c +++ b/plugins/gadget.c diff --git a/plugins/hh2serial-gps.c b/plugins/hh2serial-gps.c index 99394e1c..99394e1c 100644..100755 --- a/plugins/hh2serial-gps.c +++ b/plugins/hh2serial-gps.c diff --git a/plugins/iospm.c b/plugins/iospm.c index cded9e00..cded9e00 100644..100755 --- a/plugins/iospm.c +++ b/plugins/iospm.c diff --git a/plugins/loopback.c b/plugins/loopback.c index e113887d..55c8a218 100644..100755 --- a/plugins/loopback.c +++ b/plugins/loopback.c @@ -32,8 +32,10 @@ #include <sys/socket.h> #include <arpa/inet.h> #include <net/if.h> +#include <stdio.h> #include <glib.h> +#include <glib/gprintf.h> #define CONNMAN_API_SUBJECT_TO_CHANGE #include <connman/plugin.h> @@ -62,10 +64,42 @@ static int setup_hostname(void) memset(system_hostname, 0, sizeof(system_hostname)); +#if defined TIZEN_EXT + FILE *fp = NULL; +#define WIFI_MAC "/opt/etc/.mac.info" + { + char* rv = 0; + gchar* dev_id = "TIZEN"; + char wifi_mac[HOST_NAME_MAX + 1]; + + fp = fopen(WIFI_MAC, "r"); + if(!fp){ + connman_error("Failed to get current hostname"); + strncpy(system_hostname, dev_id, strlen(dev_id)); + goto host_name_end; + } + + rv = fgets(wifi_mac, HOST_NAME_MAX, fp); + if(!rv){ + connman_error("Failed to get current hostname"); + strncpy(system_hostname, dev_id, strlen(dev_id)); + fclose(fp); + goto host_name_end; + } + + dev_id = g_base64_encode((const guchar *)wifi_mac, strlen(wifi_mac)); + g_sprintf(system_hostname, "TIZEN-%s", dev_id); + g_free(dev_id); + fclose(fp); + } + +host_name_end: +#else if (gethostname(system_hostname, HOST_NAME_MAX) < 0) { connman_error("Failed to get current hostname"); return -EIO; } +#endif if (strlen(system_hostname) > 0 && strcmp(system_hostname, "(none)") != 0) diff --git a/plugins/mcc.h b/plugins/mcc.h index 0e0407c9..0e0407c9 100644..100755 --- a/plugins/mcc.h +++ b/plugins/mcc.h diff --git a/plugins/neard.c b/plugins/neard.c index 69586df6..69586df6 100644..100755 --- a/plugins/neard.c +++ b/plugins/neard.c diff --git a/plugins/nmcompat.c b/plugins/nmcompat.c index 274baab4..274baab4 100644..100755 --- a/plugins/nmcompat.c +++ b/plugins/nmcompat.c diff --git a/plugins/ofono.c b/plugins/ofono.c index 82413b6e..82413b6e 100644..100755 --- a/plugins/ofono.c +++ b/plugins/ofono.c diff --git a/plugins/pacrunner.c b/plugins/pacrunner.c index 9c652f3b..9c652f3b 100644..100755 --- a/plugins/pacrunner.c +++ b/plugins/pacrunner.c diff --git a/plugins/polkit.c b/plugins/polkit.c index ae38364a..ae38364a 100644..100755 --- a/plugins/polkit.c +++ b/plugins/polkit.c diff --git a/plugins/polkit.policy b/plugins/polkit.policy index 0de152ce..0de152ce 100644..100755 --- a/plugins/polkit.policy +++ b/plugins/polkit.policy diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c index 9beb0980..9beb0980 100644..100755 --- a/plugins/session_policy_local.c +++ b/plugins/session_policy_local.c diff --git a/plugins/telephony.c b/plugins/telephony.c new file mode 100755 index 00000000..5c37d88a --- /dev/null +++ b/plugins/telephony.c @@ -0,0 +1,1936 @@ +/* + * + * Connection Manager + * + * 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 + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <gdbus.h> +#include <stdlib.h> +#include <string.h> + +#define CONNMAN_API_SUBJECT_TO_CHANGE +#include <connman/dbus.h> +#include <connman/inet.h> +#include <connman/plugin.h> +#include <connman/network.h> +#include <connman/setting.h> +#include <connman/technology.h> + +#include <connman.h> + +#define PS_DBUS_SERVICE "com.tcore.ps" +#define TELEPHONY_DBUS_SERVICE "org.tizen.telephony" + +#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_SERVICES "GetServices" +#define GET_CONTEXTS "GetContexts" +#define ACTIVATE_CONTEXT "Activate" +#define DEACTIVATE_CONTEXT "Deactivate" +#define GET_PROPERTIES "GetProperties" +#define SET_PROPERTY "SetProperties" + +/* signals */ +#define MODEM_ADDED "ModemAdded" +#define MODEM_REMOVED "ModemRemoved" +#define SERVICE_ADDED "ServiceAdded" +#define SERVICE_REMOVED "ServiceRemoved" +#define CONTEXT_ADDED "ContextAdded" +#define CONTEXT_REMOVED "ContextRemoved" +#define PROPERTY_CHANGED "PropertyChanged" + +#define TIMEOUT 130000 + +#define STRING2BOOL(a) (!(g_strcmp0(a, "TRUE")) ? (TRUE):(FALSE)) + +static DBusConnection *connection; +static GHashTable *modem_hash; +static GHashTable *service_hash; +static GHashTable *network_hash; + +struct telephony_service { + char *path; + + gpointer p_modem; + char *act; + gboolean roaming; /* global roaming state */ + gboolean ps_attached; /* packet service is available */ +}; + +struct telephony_modem { + char *path; + + char *operator; + gboolean powered; + gboolean sim_init; + gboolean flight_mode; + gboolean data_allowed; + gboolean roaming_allowed; + + struct connman_device *device; + struct telephony_service *s_service; +}; + +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; + struct connman_ipaddress *ipv4_address; + + enum connman_ipconfig_method ipv6_method; + 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); +static void __remove_modem(gpointer data); +static void __remove_service(gpointer data); +static void __remove_network(gpointer data); + +static int __modem_probe(struct connman_device *device); +static void __modem_remove(struct connman_device *device); +static int __modem_enable(struct connman_device *device); +static int __modem_disable(struct connman_device *device); + +static int __network_probe(struct connman_network *network); +static void __network_remove(struct connman_network *network); +static int __network_connect(struct connman_network *network); +static int __network_disconnect(struct connman_network *network); + + +/* dbus request and reply */ +static int __dbus_request(const char *service, const char *path, const char *interface, + const char *method, + DBusPendingCallNotifyFunction notify, void *user_data, + DBusFreeFunction free_function, int type, ...); + +static int __request_get_modems(void); +static void __response_get_modems(DBusPendingCall *call, void *user_data); +static int __request_get_services(const char *path); +static void __response_get_services(DBusPendingCall *call, void *user_data); +static int __request_get_contexts(struct telephony_modem *modem); +static void __response_get_contexts(DBusPendingCall *call, void *user_data); +static int __request_network_activate(struct connman_network *network); +static void __response_network_activate(DBusPendingCall *call, void *user_data); +static int __request_network_deactivate(struct connman_network *network); + +/* telephony internal function */ +static void __add_modem(const char *path, DBusMessageIter *prop); +static void __add_service(struct telephony_modem *modem, + const char *service_path, DBusMessageIter *prop); +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 int __add_context(struct connman_device *device, const char *path, + DBusMessageIter *prop); + +/* signal handler */ +static gboolean __changed_modem(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __added_modem(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __removed_modem(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __changed_service(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __added_service(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __removed_service(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __changed_context(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __added_context(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __removed_context(DBusConnection *connection, + DBusMessage *message, void *user_data); + +/* device driver */ +static struct connman_device_driver modem_driver = { + .name = "device", + .type = CONNMAN_DEVICE_TYPE_CELLULAR, + .probe = __modem_probe, + .remove = __modem_remove, + .enable = __modem_enable, + .disable = __modem_disable, +}; + +/* network driver */ +static struct connman_network_driver network_driver = { + .name = "network", + .type = CONNMAN_NETWORK_TYPE_CELLULAR, + .probe = __network_probe, + .remove = __network_remove, + .connect = __network_connect, + .disconnect = __network_disconnect, +}; + +static int tech_probe(struct connman_technology *technology) +{ + return 0; +} + +static void tech_remove(struct connman_technology *technology) +{ + return; +} + +static struct connman_technology_driver tech_driver = { + .name = "cellular", + .type = CONNMAN_SERVICE_TYPE_CELLULAR, + .probe = tech_probe, + .remove = tech_remove, +}; + +/* local function */ +static void telephony_connect(DBusConnection *connection, void *user_data) +{ + DBG("connection %p", connection); + modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, __remove_modem); + service_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, __remove_service); + network_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, __remove_network); + + __request_get_modems(); +} + +static void telephony_disconnect(DBusConnection *connection, void *user_data) +{ + DBG("connection %p", connection); + + if (modem_hash != NULL) { + g_hash_table_destroy(modem_hash); + modem_hash = NULL; + } + + if (network_hash != NULL) { + g_hash_table_destroy(network_hash); + network_hash = NULL; + } +} + +static void __remove_modem(gpointer data) +{ + struct telephony_modem *modem = data; + + __remove_connman_device(modem); + + g_free(modem->path); + g_free(modem->operator); + g_free(modem); +} + +static void __remove_service(gpointer data) +{ + struct telephony_service *service = data; + + g_free(service->path); + g_free(service->act); + g_free(service); +} + +static void __remove_network(gpointer data) +{ + struct telephony_network *info = data; + struct connman_device *device; + + device = connman_network_get_device(info->network); + if (device != NULL) + connman_device_remove_network(device, info->network); + + 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); + return 0; +} + +static void __modem_remove(struct connman_device *device) +{ + DBG("device %p", device); +} + +static int __modem_enable(struct connman_device *device) +{ + const char *path = connman_device_get_string(device, "Path"); + DBG("device %p, path, %s", device, path); + + return __check_device_powered(path, TRUE); +} + +static int __modem_disable(struct connman_device *device) +{ + const char *path = connman_device_get_string(device, "Path"); + DBG("device %p, path, %s", device, path); + + return __check_device_powered(path, FALSE); +} + +static int __network_probe(struct connman_network *network) +{ + DBG("network_prove network(%p)", network); + return 0; +} + +static int __network_connect(struct connman_network *network) +{ + DBG("network %p", network); + + return __request_network_activate(network); +} + +static int __network_disconnect(struct connman_network *network) +{ + DBG("network %p", network); + + if (connman_network_get_associating(network) == TRUE) + connman_network_clear_associating(network); + + connman_network_set_associating(network, FALSE); + + return __request_network_deactivate(network); +} + +static void __network_remove(struct connman_network *network) +{ + char const *path = connman_network_get_string(network, "Path"); + DBG("network %p path %s", network, path); + + g_hash_table_remove(network_hash, path); +} + +static int __dbus_request(const char *service, const char *path, const char *interface, + 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("path %s %s.%s", path, interface, method); + + if (path == NULL) + return -EINVAL; + + message = dbus_message_new_method_call(service, path, interface, method); + if (message == NULL) + return -ENOMEM; + + dbus_message_set_auto_start(message, FALSE); + + va_start(va, type); + ok = dbus_message_append_args_valist(message, type, va); + va_end(va); + + if (!ok) { + dbus_message_unref(message); + return -ENOMEM; + } + + if (dbus_connection_send_with_reply(connection, message, + &call, TIMEOUT) == FALSE) { + connman_error("Failed to call %s.%s", interface, method); + dbus_message_unref(message); + return -EINVAL; + } + + if (call == NULL) { + connman_error("D-Bus connection not available"); + dbus_message_unref(message); + return -EINVAL; + } + + dbus_pending_call_set_notify(call, notify, user_data, free_function); + + dbus_message_unref(message); + + return -EINPROGRESS; +} + +static int __request_get_modems(void) +{ + DBG("request get modem"); + /* call connect master */ + return __dbus_request(PS_DBUS_SERVICE, "/", PS_MASTER_INTERFACE, GET_MODEMS, + __response_get_modems, NULL, NULL, DBUS_TYPE_INVALID); +} + +static void __response_get_modems(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args, dict; + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetModems() %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_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; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &modem_path); + DBG("modem path (%s)", modem_path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &property); + + __add_modem(modem_path, &property); + + dbus_message_iter_next(&dict); + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_get_services(const char *path) +{ + DBG("request get service"); + return __dbus_request(PS_DBUS_SERVICE, path, PS_MODEM_INTERFACE, GET_SERVICES, + __response_get_services, g_strdup(path), + g_free, DBUS_TYPE_INVALID); +} + +static void __response_get_services(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args, dict; + + const char *path = user_data; + struct telephony_modem *modem; + + modem = g_hash_table_lookup(modem_hash, path); + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetServices() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + if (modem == NULL || modem->device == NULL) + goto done; + + DBG("message signature (%s)", dbus_message_get_signature(reply)); + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + 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; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &service_path); + DBG("service path (%s)", service_path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &property); + + __add_service(modem, service_path, &property); + + dbus_message_iter_next(&dict); + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_get_contexts(struct telephony_modem *modem) +{ + DBG("request get contexts"); + return __dbus_request(PS_DBUS_SERVICE, modem->s_service->path, + 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) +{ + DBusError error; + DBusMessage *reply; + DBusMessageIter args, dict; + + const char *path = user_data; + struct telephony_modem *modem; + + DBG(""); + + modem = g_hash_table_lookup(modem_hash, path); + if (modem == NULL) + return; + if (modem->s_service == NULL) + return; + if (modem->device == NULL) + return; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetContexts() %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_recurse(&args, &dict); + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry, property; + const char *context_path; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &context_path); + DBG("context path (%s)", context_path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &property); + + __add_context(modem->device, context_path, &property); + + dbus_message_iter_next(&dict); + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_network_activate(struct connman_network *network) +{ + int n_modems; + const char *path = NULL; + struct telephony_modem *modem = NULL; + + 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(PS_DBUS_SERVICE, 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"); + + DBusError error; + DBusMessage *reply; + + struct telephony_network *info; + const char *path = user_data; + + info = g_hash_table_lookup(network_hash, path); + reply = dbus_pending_call_steal_reply(call); + + if (info == NULL) + goto done; + + if (__check_network_available(info->network) == FALSE) { + g_hash_table_remove(network_hash, path); + goto done; + } + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + 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); + + dbus_error_free(&error); + goto done; + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_network_deactivate(struct connman_network *network) +{ + const char *path = connman_network_get_string(network, "Path"); + DBG("network %p, path %s", network, path); + + return __dbus_request(PS_DBUS_SERVICE, path, PS_CONTEXT_INTERFACE, DEACTIVATE_CONTEXT, + 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_DBUS_SERVICE, 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) +{ + struct telephony_modem *modem; + + modem = g_hash_table_lookup(modem_hash, path); + if (modem != NULL) + return; + + modem = g_try_new0(struct telephony_modem, 1); + if (modem == NULL) + return; + + modem->path = g_strdup(path); + modem->device = NULL; + modem->s_service = NULL; + + g_hash_table_insert(modem_hash, g_strdup(path), modem); + + while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(prop, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key (%s) value(%s)", key, tmp); + + if (g_strcmp0(key, "powered") == 0) { + modem->powered = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "operator") == 0) { + modem->operator = g_strdup(tmp); + } else if (g_strcmp0(key, "sim_init") == 0) { + modem->sim_init = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "flight_mode") == 0) { + modem->flight_mode = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "roaming_allowed") == 0) { + modem->roaming_allowed = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "data_allowed") == 0) { + modem->data_allowed = STRING2BOOL(tmp); + } + dbus_message_iter_next(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); +} + +static void __add_service(struct telephony_modem *modem, + const char *service_path, DBusMessageIter *prop) +{ + struct telephony_service *service; + + if (modem->s_service != NULL) + return; + + service = g_try_new0(struct telephony_service, 1); + if (service == NULL) + return; + + service->path = g_strdup(service_path); + service->p_modem = modem; + g_hash_table_insert(service_hash, g_strdup(service_path), service); + + while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(prop, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key (%s) value(%s)", key, tmp); + + if (g_strcmp0(key, "roaming") == 0) { + service->roaming = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "act") == 0) { + service->act = g_strdup(tmp); + } else if (g_strcmp0(key, "ps_attached") == 0) { + service->ps_attached = STRING2BOOL(tmp); + } + + dbus_message_iter_next(prop); + } + + modem->s_service = service; + __request_get_contexts(modem); +} + +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; + + DBG("path %s operator %s", modem_path, operator); + + if (modem_path == NULL) + return; + + if (operator == NULL) + return; + + modem = g_hash_table_lookup(modem_hash, modem_path); + if (modem == NULL) + return; + + if (modem->device) { + if (!g_strcmp0(operator, + connman_device_get_ident(modem->device))) + return; + + __remove_connman_device(modem); + } + + if (strlen(operator) == 0) + return; + + device = connman_device_create(operator, CONNMAN_DEVICE_TYPE_CELLULAR); + if (device == NULL) + return; + + 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); + + if (connman_device_register(device) < 0) { + connman_error("Failed to register cellular device"); + connman_device_unref(device); + return; + } + + modem->device = device; +} + +static void __remove_connman_device(struct telephony_modem *modem) +{ + DBG("modem %p path %s device %p", modem, modem->path, modem->device); + + if (modem->device == NULL) + return; + + __remove_connman_networks(modem->device); + + connman_device_unregister(modem->device); + connman_device_unref(modem->device); + + modem->device = NULL; +} + +static void __remove_connman_networks(struct connman_device *device) +{ + GHashTableIter iter; + gpointer key, value; + GSList *info_list = NULL; + GSList *list; + + if (network_hash == NULL) + return; + + g_hash_table_iter_init(&iter, network_hash); + + while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) { + struct telephony_network *info = value; + + if (connman_network_get_device(info->network) != device) + continue; + + info_list = g_slist_append(info_list, info); + } + + for (list = info_list; list != NULL; list = list->next) { + struct telephony_network *info = list->data; + connman_device_remove_network(device, info->network); + } + + g_slist_free(info_list); +} + +static gboolean connman_ipaddress_updated(struct connman_ipaddress *ipaddress, + const char *address, const char *gateway) +{ + if (ipaddress == NULL || address == NULL) + return FALSE; + + if (g_strcmp0(ipaddress->local, address) != 0) + return TRUE; + + if (g_strcmp0(ipaddress->gateway, gateway) != 0) + return TRUE; + + return FALSE; +} + +static void __set_network_connected(struct telephony_network *network, + gboolean connected) +{ + gboolean setip = FALSE; + + DBG("network %p connected %d", network, connected); + + connman_network_set_index(network->network, network->if_index); + if (connman_network_get_connected(network->network) == connected) + return; + + 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; + } + + 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; + } + + if (setip == TRUE) + connman_network_set_connected(network->network, connected); +} + +static gboolean __set_network_context( + struct telephony_network *network, + DBusMessageIter *dict) +{ + int index = 0; + gboolean active = FALSE; + 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; + struct connman_service *service; + + while (dbus_message_iter_get_arg_type(dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + + if (g_strcmp0(key, "dev_name") == 0) { + dbus_message_iter_get_basic(&entry, &dev_name); + DBG("dev_name (%s)", dev_name); + } else if (g_strcmp0(key, "proxy") == 0) { + dbus_message_iter_get_basic(&entry, &proxy_addr); + DBG("proxy_addr (%s)", proxy_addr); + } else if (g_strcmp0(key, "ipv4_address") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_addr); + DBG("ipv4_addr (%s)", ipv4_addr); + } else if (g_strcmp0(key, "ipv4_gateway") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_gw); + DBG("ipv4_gw (%s)", ipv4_gw); + } else if (g_strcmp0(key, "ipv4_netmask") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_netmask); + DBG("ipv4_netmask (%s)", ipv4_netmask); + } else if (g_strcmp0(key, "ipv4_dns1") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_dns1); + DBG("ipv4_dns1 (%s)", ipv4_dns1); + } else if (g_strcmp0(key, "ipv4_dns2") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_dns2); + 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_strcmp0(key, "ipv6_gateway") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_gw); + DBG("ipv6_gw (%s)", ipv6_gw); + } else if (g_strcmp0(key, "ipv6_netmask") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_netmask); + DBG("ipv6_netmask (%s)", ipv6_netmask); + } else if (g_strcmp0(key, "ipv6_dns1") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_dns1); + DBG("ipv6_dns1 (%s)", ipv6_dns1); + } else if (g_strcmp0(key, "ipv6_dns2") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_dns2); + 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); + } + + 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; + } + } + + /* interface index set */ + if (dev_name != NULL) { + index = connman_inet_ifindex(dev_name); + network->if_index = index; + DBG("interface index %d", index); + } + + /* proxy set */ + if (active == TRUE && + connman_network_get_connected(network->network) == TRUE) + active_proxy = TRUE; + + 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 (network->ipv4_address == NULL) + network->ipv4_address = + connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4); + + if (network->ipv4_address == NULL) + return FALSE; + + if (ipv4_addr == NULL && active == TRUE) + network->ipv4_method = CONNMAN_IPCONFIG_METHOD_OFF; + else + network->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED; + + 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) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv4_dns1, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV4); +#else + __connman_service_nameserver_append(service, ipv4_dns1, FALSE); +#endif + //if (ipv4_dns2) + if (ipv4_dns2 && !ipv4_dns1) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv4_dns2, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV4); +#else + __connman_service_nameserver_append(service, ipv4_dns2, FALSE); +#endif + /* ipv6 set */ + if (network->ipv6_address == NULL) + network->ipv6_address = + connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6); + + 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; + + if (ipv6_addr == NULL) + network->ipv6_method = CONNMAN_IPCONFIG_METHOD_OFF; + + connman_network_set_ipv6_method(network->network, network->ipv6_method); + + 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 (ipv6_dns1) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv6_dns1, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV6); +#else + __connman_service_nameserver_append(service, ipv6_dns1, FALSE); +#endif + //if (ipv6_dns2) + if (ipv6_dns2 && !ipv6_dns1) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv6_dns2, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV6); +#else + __connman_service_nameserver_append(service, ipv6_dns2, FALSE); +#endif + + 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); + + __set_network_connected(network, FALSE); + } else { + DBG("Already connected"); + + return active; + } + } + + if (active == TRUE) + connman_network_set_associating(network->network, TRUE); + + return active; +} + +static int __add_context(struct connman_device *device, const char *path, + DBusMessageIter *prop) +{ + 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; + + g_hash_table_remove(network_hash, path); + } + + network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR); + if (network == NULL) + return -ENOMEM; + + info = g_try_new0(struct telephony_network, 1); + if (info == NULL) { + connman_network_unref(network); + return -ENOMEM; + } + + 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); + + connman_network_set_group(network, ident); + + 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) +{ + gboolean old_powered; + DBusMessageIter args, dict; + struct telephony_modem *modem; + const char *path = dbus_message_get_path(message); + + DBG("modem changed signal %s", path); + + modem = g_hash_table_lookup(modem_hash, path); + if (modem == NULL) { + DBG("modem object does not exists"); + return TRUE; + } + + old_powered = modem->powered; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key(%s), value(%s)", key, tmp); + + if (g_strcmp0(key, "powered") == 0) { + modem->powered = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "operator") == 0) { + modem->operator = g_strdup(tmp); + } else if (g_strcmp0(key, "sim_init") == 0) { + modem->sim_init = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "flight_mode") == 0) { + modem->flight_mode = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "roaming_allowed") == 0) { + modem->roaming_allowed = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "data_allowed") == 0) { + modem->data_allowed = STRING2BOOL(tmp); + } + + dbus_message_iter_next(&dict); + } + + if (modem->device == NULL) + __add_connman_device(path, modem->operator); + + 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 == NULL) { + __request_get_services(modem->path); + return TRUE; + } + + DBG("modem(%s) flight mode(%d) data allowed(%d)", + modem->path, modem->flight_mode, modem->data_allowed); + + return TRUE; +} + +static gboolean __added_modem(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + const char *modem_path = NULL; + DBusMessageIter args, dict, tmp; + + 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; + } + + dbus_message_iter_recurse(&args, &dict); + memcpy(&tmp, &dict, sizeof(struct DBusMessageIter)); + + while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(&tmp, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &value); + + DBG("key (%s) value(%s)", key, value); + + if (g_strcmp0(key, "path") == 0) + modem_path = g_strdup(value); + + dbus_message_iter_next(&tmp); + } + + if (modem_path != NULL) + __add_modem(modem_path, &dict); + + return TRUE; +} + +static gboolean __removed_modem(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + 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; + } + + dbus_message_iter_get_basic(&iter, &modem_path); + g_hash_table_remove(modem_hash, modem_path); + + return TRUE; +} + +static gboolean __changed_service(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter args, dict; + struct telephony_modem *modem; + gboolean roaming_option = TRUE; + struct telephony_service *s_service; + const char *service_path = dbus_message_get_path(message); + + DBG("service changed signal %s", service_path); + + s_service = g_hash_table_lookup(service_hash, service_path); + if (s_service == NULL) { + DBG("service object does not exists"); + return TRUE; + } + + modem = s_service->p_modem; + if (modem == NULL) { + DBG("modem object does not exists"); + return TRUE; + } + + DBG("message signature (%s)", dbus_message_get_signature(message)); + + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key(%s), value(%s)", key, tmp); + + if (g_strcmp0(key, "roaming") == 0) { + s_service->roaming = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "act") == 0) { + s_service->act = g_strdup(tmp); + } else if (g_strcmp0(key, "ps_attached") == 0) { + s_service->ps_attached = STRING2BOOL(tmp); + } + + dbus_message_iter_next(&dict); + } + + roaming_option &= (!s_service->roaming && !modem->roaming_allowed) + || modem->roaming_allowed; + + return TRUE; +} + +static gboolean __added_service(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct telephony_modem *modem; + const char *service_path = NULL; + DBusMessageIter args, dict, tmp; + 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) + return TRUE; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + memcpy(&tmp, &dict, sizeof(struct DBusMessageIter)); + + while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(&tmp, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &value); + + DBG("key (%s) value(%s)", key, value); + + if (g_strcmp0(key, "path") == 0) + service_path = value; + + dbus_message_iter_next(&tmp); + } + + if (service_path != NULL) + __add_service(modem, service_path, &dict); + + return TRUE; +} + +static gboolean __removed_service(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + 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; + } + + dbus_message_iter_get_basic(&iter, &service_path); + g_hash_table_remove(service_hash, service_path); + + return TRUE; +} + +static gboolean __changed_context(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + gboolean active = FALSE; + DBusMessageIter args, dict; + struct telephony_network *info; + const char *path = dbus_message_get_path(message); + + DBG("network changed signal %s", path); + + info = g_hash_table_lookup(network_hash, path); + if (info == NULL) + return TRUE; + + if (__check_network_available(info->network) == FALSE) { + g_hash_table_remove(network_hash, path); + return TRUE; + } + + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &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) + 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; +} + +static gboolean __added_context(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + const char *network_path = 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) + return TRUE; + + modem = service->p_modem; + if (modem == NULL || modem->device == NULL) + return TRUE; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + memcpy(&tmp, &dict, sizeof(struct DBusMessageIter)); + + while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(&tmp, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &value); + + DBG("key (%s) value(%s)", key, value); + + if (g_strcmp0(key, "path") == 0) + network_path = g_strdup(value); + + dbus_message_iter_next(&tmp); + } + + if (network_path != NULL) + __add_context(modem->device, network_path, &dict); + + return TRUE; +} + +static gboolean __removed_context(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + 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) + return TRUE; + + if (dbus_message_iter_init(message, &iter) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_get_basic(&iter, &network_path); + g_hash_table_remove(network_hash, network_path); + + 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 = 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) +{ + int err; + + DBG("telephony plugin"); + + connection = connman_dbus_get_connection(); + if (connection == NULL) + return -EIO; + + /* telephony watch */ + watch = g_dbus_add_service_watch(connection, PS_DBUS_SERVICE, + telephony_connect, telephony_disconnect, + NULL, NULL); + + modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MODEM_INTERFACE, + PROPERTY_CHANGED, + __changed_modem, + NULL, NULL); + + modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MASTER_INTERFACE, + MODEM_ADDED, + __added_modem, + NULL, NULL); + + modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MASTER_INTERFACE, + MODEM_REMOVED, + __removed_modem, + NULL, NULL); + + service_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_SERVICE_INTERFACE, + PROPERTY_CHANGED, + __changed_service, + NULL, NULL); + + service_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MODEM_INTERFACE, + SERVICE_ADDED, + __added_service, + NULL, NULL); + + service_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MODEM_INTERFACE, + SERVICE_REMOVED, + __removed_service, + NULL, NULL); + + context_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_CONTEXT_INTERFACE, + PROPERTY_CHANGED, + __changed_context, + NULL, NULL); + + context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_SERVICE_INTERFACE, + CONTEXT_ADDED, + __added_context, + NULL, NULL); + + context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_SERVICE_INTERFACE, + CONTEXT_REMOVED, + __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 + || default_subscription_watch == 0) { + err = -EIO; + goto remove; + } + + err = connman_network_driver_register(&network_driver); + if (err < 0) + goto remove; + + err = connman_device_driver_register(&modem_driver); + if (err < 0) { + connman_network_driver_unregister(&network_driver); + goto remove; + } + + err = connman_technology_driver_register(&tech_driver); + if (err < 0) { + connman_device_driver_unregister(&modem_driver); + connman_network_driver_unregister(&network_driver); + goto remove; + } + + return 0; + +remove: + g_dbus_remove_watch(connection, watch); + g_dbus_remove_watch(connection, modem_watch); + g_dbus_remove_watch(connection, modem_added_watch); + g_dbus_remove_watch(connection, modem_removed_watch); + g_dbus_remove_watch(connection, service_watch); + g_dbus_remove_watch(connection, service_added_watch); + g_dbus_remove_watch(connection, service_removed_watch); + 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; +} + +static void telephony_exit(void) +{ + g_dbus_remove_watch(connection, watch); + g_dbus_remove_watch(connection, modem_watch); + g_dbus_remove_watch(connection, modem_added_watch); + g_dbus_remove_watch(connection, modem_removed_watch); + g_dbus_remove_watch(connection, service_watch); + g_dbus_remove_watch(connection, service_added_watch); + g_dbus_remove_watch(connection, service_removed_watch); + 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); + + connman_device_driver_unregister(&modem_driver); + connman_network_driver_unregister(&network_driver); + + dbus_connection_unref(connection); +} + +CONNMAN_PLUGIN_DEFINE(telephony, "Samsung Telephony Framework plug-in", VERSION, + CONNMAN_PLUGIN_PRIORITY_DEFAULT, telephony_init, telephony_exit) diff --git a/plugins/tist.c b/plugins/tist.c index cc2800a1..cc2800a1 100644..100755 --- a/plugins/tist.c +++ b/plugins/tist.c diff --git a/plugins/vpn.c b/plugins/vpn.c index 11bab154..11bab154 100644..100755 --- a/plugins/vpn.c +++ b/plugins/vpn.c diff --git a/plugins/wifi.c b/plugins/wifi.c index f8c22be3..f4e6d59f 100644 --- a/plugins/wifi.c +++ b/plugins/wifi.c @@ -73,7 +73,15 @@ #define P2P_LISTEN_INTERVAL 2000 #define ASSOC_STATUS_NO_CLIENT 17 +#if defined TIZEN_EXT +#define LOAD_SHAPING_MAX_RETRIES 7 +#else #define LOAD_SHAPING_MAX_RETRIES 3 +#endif + +#if defined TIZEN_EXT +#define WIFI_EAP_FAST_PAC_FILE "/var/lib/wifi/wifi.pac" /* path of Pac file for EAP-FAST */ +#endif static struct connman_technology *wifi_technology = NULL; static struct connman_technology *p2p_technology = NULL; @@ -159,10 +167,35 @@ struct wifi_data { bool p2p_connecting; bool p2p_device; int servicing; +#if defined TIZEN_EXT + int assoc_retry_count; + struct connman_network *scan_pending_network; + bool allow_full_scan; + unsigned int automaxspeed_timeout; + GSupplicantScanParams *hidden_scan_params; +#endif int disconnect_code; int assoc_code; +#if defined TIZEN_EXT_WIFI_MESH + bool mesh_interface; + struct wifi_mesh_info *mesh_info; +#endif }; +#if defined TIZEN_EXT +#include "connman.h" +#include "dbus.h" + +#define TIZEN_ASSOC_RETRY_COUNT 4 + +static gboolean wifi_first_scan = false; +static gboolean found_with_first_scan = false; +static gboolean is_wifi_notifier_registered = false; +static GHashTable *failed_bssids = NULL; +static unsigned char buff_bssid[WIFI_BSSID_LEN_MAX] = { 0, }; +#endif + + static GList *iface_list = NULL; static GList *pending_wifi_device = NULL; @@ -174,6 +207,123 @@ static int tech_set_tethering(struct connman_technology *technology, const char *identifier, const char *passphrase, const char *bridge, bool enabled); +#if defined TIZEN_EXT +#define NETCONFIG_SERVICE "net.netconfig" +#define NETCONFIG_WIFI_PATH "/net/netconfig/wifi" +#define NETCONFIG_WIFI_INTERFACE NETCONFIG_SERVICE ".wifi" + +struct enc_method_call_data { + DBusConnection *connection; + struct connman_network *network; +}; + +static struct enc_method_call_data encrypt_request_data; + +static void encryption_request_reply(DBusPendingCall *call, + void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args; + char *out_data; + struct connman_service *service; + gchar* encrypted_value = NULL; + struct connman_network *network = encrypt_request_data.network; + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + DBG("send_encryption_request() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + dbus_message_iter_get_basic(&args, &out_data); + + encrypted_value = g_strdup((const gchar *)out_data); + service = connman_service_lookup_from_network(network); + + if (!service) { + DBG("encryption result: no service"); + goto done; + } + + if (connman_service_get_favorite(service)) { + __connman_service_set_passphrase(service, encrypted_value); + __connman_service_save(service); + } else + connman_network_set_string(network, "WiFi.Passphrase", + encrypted_value); + + DBG("encryption result: succeeded"); + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); + dbus_connection_unref(encrypt_request_data.connection); + g_free(encrypted_value); + + encrypt_request_data.connection = NULL; + encrypt_request_data.network = NULL; +} + +static int send_encryption_request(const char *passphrase, + struct connman_network *network) +{ + DBusConnection *connection = NULL; + DBusMessage *msg = NULL; + DBusPendingCall *call; + + if (!passphrase) { + DBG("Invalid parameter"); + return -EINVAL; + } + + connection = connman_dbus_get_connection(); + if (!connection) { + DBG("dbus connection does not exist"); + return -EINVAL; + } + + msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_WIFI_PATH, + NETCONFIG_WIFI_INTERFACE, "EncryptPassphrase"); + if (!msg) { + dbus_connection_unref(connection); + return -EINVAL; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(connection, msg, + &call, DBUS_TIMEOUT_USE_DEFAULT)) { + dbus_message_unref(msg); + dbus_connection_unref(connection); + return -EIO; + } + + if (!call) { + dbus_message_unref(msg); + dbus_connection_unref(connection); + return -EIO; + } + + encrypt_request_data.connection = connection; + encrypt_request_data.network = network; + + dbus_pending_call_set_notify(call, encryption_request_reply, NULL, NULL); + dbus_message_unref(msg); + + return 0; +} +#endif + static int p2p_tech_probe(struct connman_technology *technology) { p2p_technology = technology; @@ -215,6 +365,506 @@ static void add_pending_wifi_device(struct wifi_data *wifi) pending_wifi_device = g_list_append(pending_wifi_device, wifi); } +#if defined TIZEN_EXT_WIFI_MESH +struct wifi_mesh_info { + struct wifi_data *wifi; + GSupplicantInterface *interface; + struct connman_mesh *mesh; + char *parent_ifname; + char *ifname; + char *identifier; + int index; +}; + +struct mesh_change_peer_status_info { + char *peer_address; + enum connman_mesh_peer_status peer_status; + mesh_change_peer_status_cb_t callback; + void *user_data; +}; + +static struct connman_technology_driver mesh_tech_driver = { + .name = "mesh", + .type = CONNMAN_SERVICE_TYPE_MESH, +}; + +static void mesh_interface_create_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct wifi_mesh_info *mesh_info = user_data; + struct wifi_data *wifi; + bool success = false; + + DBG("result %d ifname %s, mesh_info %p", result, + g_supplicant_interface_get_ifname(interface), + mesh_info); + + if (result < 0 || !mesh_info) + goto done; + + wifi = mesh_info->wifi; + + mesh_info->interface = interface; + mesh_info->identifier = connman_inet_ifaddr(mesh_info->ifname); + mesh_info->index = connman_inet_ifindex(mesh_info->ifname); + DBG("Mesh Interface identifier %s", mesh_info->identifier); + wifi->mesh_interface = true; + wifi->mesh_info = mesh_info; + g_supplicant_interface_set_data(interface, wifi); + success = true; + +done: + connman_mesh_notify_interface_create(success); +} + +static int add_mesh_interface(const char *ifname, const char *parent_ifname) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + const char *wifi_ifname; + bool parent_found = false; + const char *driver = "nl80211"; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (!g_supplicant_interface_has_mesh(wifi->interface)) + continue; + + wifi_ifname = g_supplicant_interface_get_ifname(wifi->interface); + if (!wifi_ifname) + continue; + + if (!g_strcmp0(wifi_ifname, parent_ifname)) { + parent_found = true; + break; + } + } + + if (!parent_found) { + DBG("Parent interface %s doesn't exist", parent_ifname); + return -ENODEV; + } + + mesh_info = g_try_malloc0(sizeof(struct wifi_mesh_info)); + if (!mesh_info) + return -ENOMEM; + + mesh_info->wifi = wifi; + mesh_info->ifname = g_strdup(ifname); + mesh_info->parent_ifname = g_strdup(parent_ifname); + + g_supplicant_mesh_interface_create(ifname, driver, NULL, parent_ifname, + mesh_interface_create_callback, mesh_info); + return -EINPROGRESS; +} + +static void mesh_interface_remove_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct wifi_data *wifi = user_data; + struct wifi_mesh_info *mesh_info = wifi->mesh_info; + bool success = false; + + DBG("result %d mesh_info %p", result, mesh_info); + + if (result < 0 || !mesh_info) + goto done; + + mesh_info->interface = NULL; + g_free(mesh_info->parent_ifname); + g_free(mesh_info->ifname); + g_free(mesh_info->identifier); + g_free(mesh_info); + wifi->mesh_interface = false; + wifi->mesh_info = NULL; + success = true; + +done: + connman_mesh_notify_interface_remove(success); +} + +static int remove_mesh_interface(const char *ifname) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + int ret; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface %s doesn't exist", ifname); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + ret = g_supplicant_interface_remove(mesh_info->interface, + mesh_interface_remove_callback, wifi); + if (ret < 0) + return ret; + + return -EINPROGRESS; +} + +static void mesh_disconnect_callback(int result, + GSupplicantInterface *interface, void *user_data) +{ + struct connman_mesh *mesh = user_data; + + DBG("result %d interface %p mesh %p", result, interface, mesh); +} + +static int mesh_peer_disconnect(struct connman_mesh *mesh) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + return g_supplicant_interface_disconnect(interface, + mesh_disconnect_callback, mesh); +} + +static void mesh_connect_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_mesh *mesh = user_data; + DBG("mesh %p result %d", mesh, result); + + if (result < 0) + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE); + else + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_ASSOCIATION); +} + +static GSupplicantSecurity mesh_network_security(const char *security) +{ + if (g_str_equal(security, "none")) + return G_SUPPLICANT_SECURITY_NONE; + else if (g_str_equal(security, "sae")) + return G_SUPPLICANT_SECURITY_SAE; + + return G_SUPPLICANT_SECURITY_UNKNOWN; +} + +static void mesh_ssid_init(GSupplicantSSID *ssid, struct connman_mesh *mesh) +{ + const char *name; + const char *security; + + if (ssid->ssid) + g_free(ssid->ssid); + + memset(ssid, 0, sizeof(*ssid)); + ssid->mode = G_SUPPLICANT_MODE_MESH; + + security = connman_mesh_get_security(mesh); + ssid->security = mesh_network_security(security); + + if (ssid->security == G_SUPPLICANT_SECURITY_SAE) + ssid->passphrase = connman_mesh_get_passphrase(mesh); + + ssid->freq = connman_mesh_get_frequency(mesh); + name = connman_mesh_get_name(mesh); + if (name) { + ssid->ssid_len = strlen(name); + ssid->ssid = g_malloc0(ssid->ssid_len + 1); + memcpy(ssid->ssid, name, ssid->ssid_len); + ssid->scan_ssid = 1; + } +} + +static int mesh_peer_connect(struct connman_mesh *mesh) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + GSupplicantSSID *ssid; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + + ssid = g_try_malloc0(sizeof(GSupplicantSSID)); + if (!ssid) + return -ENOMEM; + + mesh_info->mesh = mesh; + + mesh_ssid_init(ssid, mesh); + return g_supplicant_interface_connect(interface, ssid, + mesh_connect_callback, mesh); +} + +static void mesh_peer_change_status_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct mesh_change_peer_status_info *data = user_data; + + DBG("result %d Peer Status %d", result, data->peer_status); + + if (result == 0 && data->peer_status == CONNMAN_MESH_PEER_REMOVE) { + /* WLAN_REASON_MESH_PEERING_CANCELLED = 52 */ + connman_mesh_remove_connected_peer(data->peer_address, 52); + } + + if (data->callback) + data->callback(result, data->user_data); + + g_free(data->peer_address); + g_free(data); + return; +} + +static int mesh_change_peer_status(const char *peer_address, + enum connman_mesh_peer_status status, + mesh_change_peer_status_cb_t callback, void *user_data) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + struct mesh_change_peer_status_info *data; + const char *method; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + + switch (status) { + case CONNMAN_MESH_PEER_ADD: + method = "MeshPeerAdd"; + break; + case CONNMAN_MESH_PEER_REMOVE: + method = "MeshPeerRemove"; + break; + default: + DBG("Invalid method"); + return -EINVAL; + } + + data = g_try_malloc0(sizeof(struct mesh_change_peer_status_info)); + if (data == NULL) { + DBG("Memory allocation failed"); + return -ENOMEM; + } + + data->peer_address = g_strdup(peer_address); + data->peer_status = status; + data->callback = callback; + data->user_data = user_data; + + return g_supplicant_interface_mesh_peer_change_status(interface, + mesh_peer_change_status_callback, peer_address, method, + data); +} + +static struct connman_mesh_driver mesh_driver = { + .add_interface = add_mesh_interface, + .remove_interface = remove_mesh_interface, + .connect = mesh_peer_connect, + .disconnect = mesh_peer_disconnect, + .change_peer_status = mesh_change_peer_status, +}; + +static void mesh_support(GSupplicantInterface *interface) +{ + DBG(""); + + if (!g_supplicant_interface_has_mesh(interface)) + return; + + if (connman_technology_driver_register(&mesh_tech_driver) < 0) { + DBG("Could not register Mesh technology driver"); + return; + } + + connman_mesh_driver_register(&mesh_driver); +} + +static void check_mesh_technology(void) +{ + bool mesh_exists = false; + GList *list; + + for (list = iface_list; list; list = list->next) { + struct wifi_data *w = list->data; + + if (w->interface && + g_supplicant_interface_has_mesh(w->interface)) + mesh_exists = true; + } + + if (!mesh_exists) { + connman_technology_driver_unregister(&mesh_tech_driver); + connman_mesh_driver_unregister(&mesh_driver); + } +} + +static void mesh_group_started(GSupplicantInterface *interface) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + struct connman_mesh *mesh; + const unsigned char *ssid; + unsigned int ssid_len; + char name[33]; + + ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len); + memcpy(name, ssid, ssid_len); + name[ssid_len] = '\0'; + DBG("name %s", name); + wifi = g_supplicant_interface_get_data(interface); + DBG("wifi %p", wifi); + + if (!wifi) + return; + + mesh_info = wifi->mesh_info; + if (!mesh_info) + return; + + mesh = mesh_info->mesh; + if (!mesh) + return; + + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_CONFIGURATION); +} + +static void mesh_group_removed(GSupplicantInterface *interface) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + struct connman_mesh *mesh; + const unsigned char *ssid; + unsigned int ssid_len; + int disconnect_reason; + char name[33]; + + ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len); + memcpy(name, ssid, ssid_len); + name[ssid_len] = '\0'; + DBG("name %s", name); + + disconnect_reason = g_supplicant_mesh_get_disconnect_reason(interface); + DBG("Disconnect Reason %d", disconnect_reason); + + wifi = g_supplicant_interface_get_data(interface); + DBG("wifi %p", wifi); + + if (!wifi) + return; + + mesh_info = wifi->mesh_info; + if (!mesh_info) + return; + + mesh = connman_get_connected_mesh_from_name(name); + if (!mesh) { + DBG("%s is not connected", name); + mesh = connman_get_connecting_mesh_from_name(name); + if (!mesh) { + DBG("%s is not connecting", name); + return; + } + } + + connman_mesh_peer_set_disconnect_reason(mesh, disconnect_reason); + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_DISCONNECT); +} + +static void mesh_peer_connected(GSupplicantMeshPeer *mesh_peer) +{ + const char *peer_address; + + peer_address = g_supplicant_mesh_peer_get_address(mesh_peer); + + if (!peer_address) + return; + + DBG("Peer %s connected", peer_address); + connman_mesh_add_connected_peer(peer_address); +} + +static void mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer) +{ + const char *peer_address; + int reason; + + peer_address = g_supplicant_mesh_peer_get_address(mesh_peer); + + if (!peer_address) + return; + + reason = g_supplicant_mesh_peer_get_disconnect_reason(mesh_peer); + + DBG("Peer %s disconnected with reason %d", peer_address, reason); + connman_mesh_remove_connected_peer(peer_address, reason); +} +#endif + static struct wifi_data *get_pending_wifi_data(const char *ifname) { GList *list; @@ -552,6 +1202,11 @@ static void register_peer_service_cb(int result, struct wifi_data *wifi = g_supplicant_interface_get_data(iface); struct peer_service_registration *reg_data = user_data; +#if defined TIZEN_EXT + if (!wifi) + return; +#endif + DBG(""); if (result == 0) @@ -876,6 +1531,35 @@ static void check_p2p_technology(void) } } +struct last_connected { + GTimeVal modified; + gchar *ssid; + int freq; +}; + +static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data) +{ + GTimeVal *aval = (GTimeVal *)a; + GTimeVal *bval = (GTimeVal *)b; + + /* Note that the sort order is descending */ + if (aval->tv_sec < bval->tv_sec) + return 1; + + if (aval->tv_sec > bval->tv_sec) + return -1; + + return 0; +} + +static void free_entry(gpointer data) +{ + struct last_connected *entry = data; + + g_free(entry->ssid); + g_free(entry); +} + static void wifi_remove(struct connman_device *device) { struct wifi_data *wifi = connman_device_get_data(device); @@ -893,6 +1577,9 @@ static void wifi_remove(struct connman_device *device) iface_list = g_list_remove(iface_list, wifi); check_p2p_technology(); +#if defined TIZEN_EXT_WIFI_MESH + check_mesh_technology(); +#endif remove_pending_wifi_device(wifi); @@ -904,6 +1591,13 @@ static void wifi_remove(struct connman_device *device) if (wifi->p2p_connection_timeout) g_source_remove(wifi->p2p_connection_timeout); +#if defined TIZEN_EXT + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + } +#endif + remove_networks(device, wifi); remove_peers(wifi); @@ -918,6 +1612,16 @@ static void wifi_remove(struct connman_device *device) if (wifi->scan_params) g_supplicant_free_scan_params(wifi->scan_params); +#if defined TIZEN_EXT + if (wifi->hidden_scan_params) { + while (wifi->hidden_scan_params->ssids) { + struct scan_ssid *ssid; + ssid = wifi->hidden_scan_params->ssids->data; + wifi->hidden_scan_params->ssids = g_slist_remove(wifi->hidden_scan_params->ssids, ssid); + } + g_supplicant_free_scan_params(wifi->hidden_scan_params); + } +#endif g_free(wifi->autoscan); g_free(wifi->identifier); @@ -1043,12 +1747,25 @@ static int get_hidden_connections(GSupplicantScanParams *scan_data) { struct connman_config_entry **entries; GKeyFile *keyfile; +#if defined TIZEN_EXT + gchar **services = NULL; +#else gchar **services; +#endif /* defined TIZEN_EXT */ char *ssid, *name; int i, ret; bool value; int num_ssids = 0, add_param_failed = 0; +#if defined TIZEN_EXT + GSequenceIter *iter; + GSequence *latest_list; + struct last_connected *entry; + GTimeVal modified; + latest_list = g_sequence_new(free_entry); + if (!latest_list) + goto out; +#endif services = connman_storage_get_services(); for (i = 0; services && services[i]; i++) { if (strncmp(services[i], "wifi_", 5) != 0) @@ -1072,12 +1789,46 @@ static int get_hidden_connections(GSupplicantScanParams *scan_data) continue; } +#if defined TIZEN_EXT + value = g_key_file_get_boolean(keyfile, + services[i], "AutoConnect", NULL); + if (!value) { + g_key_file_free(keyfile); + continue; + } + + gchar *str = g_key_file_get_string(keyfile, + services[i], "Modified", NULL); + if (!str) { + g_key_file_free(keyfile); + continue; + } + g_time_val_from_iso8601(str, &modified); + g_free(str); +#endif + ssid = g_key_file_get_string(keyfile, services[i], "SSID", NULL); name = g_key_file_get_string(keyfile, services[i], "Name", NULL); +#if defined TIZEN_EXT + entry = g_try_new(struct last_connected, 1); + if (!entry) { + g_sequence_free(latest_list); + g_free(ssid); + g_free(name); + g_key_file_free(keyfile); + goto out; + } + + entry->modified = modified; + entry->ssid = ssid; + + g_sequence_insert_sorted(latest_list, entry, + sort_entry, NULL); +#else ret = add_scan_param(ssid, NULL, 0, 0, scan_data, 0, name); if (ret < 0) add_param_failed++; @@ -1085,10 +1836,30 @@ static int get_hidden_connections(GSupplicantScanParams *scan_data) num_ssids++; g_free(ssid); +#endif g_free(name); g_key_file_free(keyfile); } +#if defined TIZEN_EXT + gint length = g_sequence_get_length(latest_list); + iter = g_sequence_get_begin_iter(latest_list); + + for (i = 0; i < length; i++) { + entry = g_sequence_get(iter); + + ret = add_scan_param(entry->ssid, NULL, 0, 0, scan_data, 0, entry->ssid); + if (ret < 0) + add_param_failed++; + else if (ret > 0) + num_ssids++; + + iter = g_sequence_iter_next(iter); + } + + g_sequence_free(latest_list); +out: +#endif /* * Check if there are any hidden AP that needs to be provisioned. */ @@ -1145,6 +1916,22 @@ static int get_hidden_connections_params(struct wifi_data *wifi, DBG("max ssids %d", driver_max_ssids); +#if defined TIZEN_EXT + if (!wifi->hidden_scan_params) { + wifi->hidden_scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!wifi->hidden_scan_params) + return 0; + + if (get_hidden_connections(wifi->hidden_scan_params) == 0) { + g_supplicant_free_scan_params(wifi->hidden_scan_params); + wifi->hidden_scan_params = NULL; + + return 0; + } + } + + orig_params = wifi->hidden_scan_params; +#else if (!wifi->scan_params) { wifi->scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); if (!wifi->scan_params) @@ -1159,12 +1946,17 @@ static int get_hidden_connections_params(struct wifi_data *wifi, } orig_params = wifi->scan_params; +#endif /* Let's transfer driver_max_ssids params */ for (i = 0; i < driver_max_ssids; i++) { struct scan_ssid *ssid; +#if defined TIZEN_EXT + if (!wifi->hidden_scan_params->ssids) +#else if (!wifi->scan_params->ssids) +#endif break; ssid = orig_params->ssids->data; @@ -1192,8 +1984,13 @@ static int get_hidden_connections_params(struct wifi_data *wifi, err: g_slist_free_full(scan_params->ssids, g_free); +#if defined TIZEN_EXT + g_supplicant_free_scan_params(wifi->hidden_scan_params); + wifi->hidden_scan_params = NULL; +#else g_supplicant_free_scan_params(wifi->scan_params); wifi->scan_params = NULL; +#endif return 0; } @@ -1212,7 +2009,12 @@ static int throw_wifi_scan(struct connman_device *device, if (wifi->tethering) return -EBUSY; +#if defined TIZEN_EXT + if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI) + && !wifi->allow_full_scan) +#else if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) +#endif return -EALREADY; connman_device_ref(device); @@ -1241,6 +2043,48 @@ static void hidden_free(struct hidden_params *hidden) g_free(hidden); } +#if defined TIZEN_EXT +static void service_state_changed(struct connman_service *service, + enum connman_service_state state); + +static int network_connect(struct connman_network *network); + +static struct connman_notifier notifier = { + .name = "wifi", + .priority = CONNMAN_NOTIFIER_PRIORITY_DEFAULT, + .service_state_changed = service_state_changed, +}; + +static void service_state_changed(struct connman_service *service, + enum connman_service_state state) +{ + enum connman_service_type type; + + type = connman_service_get_type(service); + if (type != CONNMAN_SERVICE_TYPE_WIFI) + return; + + DBG("service %p state %d", service, state); + + switch (state) { + case CONNMAN_SERVICE_STATE_READY: + case CONNMAN_SERVICE_STATE_ONLINE: + case CONNMAN_SERVICE_STATE_FAILURE: + connman_notifier_unregister(¬ifier); + is_wifi_notifier_registered = FALSE; + + __connman_device_request_scan(type); + break; + + default: + break; + } +} + +static void scan_callback_hidden(int result, + GSupplicantInterface *interface, void *user_data); +#endif + static void scan_callback(int result, GSupplicantInterface *interface, void *user_data) { @@ -1261,6 +2105,13 @@ static void scan_callback(int result, GSupplicantInterface *interface, g_supplicant_free_scan_params(wifi->scan_params); wifi->scan_params = NULL; } + +#if defined TIZEN_EXT + if (wifi->hidden_scan_params && !wifi->hidden_scan_params->ssids) { + g_supplicant_free_scan_params(wifi->hidden_scan_params); + wifi->hidden_scan_params = NULL; + } +#endif } if (result < 0) @@ -1286,6 +2137,22 @@ static void scan_callback(int result, GSupplicantInterface *interface, return scan_callback(ret, interface, user_data); } +#if defined TIZEN_EXT + if (wifi && wifi->allow_full_scan) { + int ret; + DBG("Trigger Full Channel Scan"); + wifi->allow_full_scan = FALSE; + + ret = g_supplicant_interface_scan(wifi->interface, NULL, + scan_callback_hidden, device); + if (ret == 0) + return; + + /* On error, let's recall scan_callback, which will cleanup */ + return scan_callback(ret, interface, user_data); + } +#endif + scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI); if (scanning) { @@ -1294,6 +2161,9 @@ static void scan_callback(int result, GSupplicantInterface *interface, } if (result != -ENOLINK) +#if defined TIZEN_EXT + if (result != -EIO) +#endif start_autoscan(device); /* @@ -1305,6 +2175,23 @@ static void scan_callback(int result, GSupplicantInterface *interface, if (scanning) connman_device_unref(device); + +#if defined TIZEN_EXT + if (wifi && wifi->scan_pending_network && result != -EIO) { + network_connect(wifi->scan_pending_network); + wifi->scan_pending_network = NULL; + connman_network_set_connecting(wifi->network); + } + + if (is_wifi_notifier_registered != true && + wifi_first_scan == true && found_with_first_scan == true) { + wifi_first_scan = false; + found_with_first_scan = false; + + connman_notifier_register(¬ifier); + is_wifi_notifier_registered = true; + } +#endif } static void scan_callback_hidden(int result, @@ -1331,7 +2218,11 @@ static void scan_callback_hidden(int result, if (get_hidden_connections_params(wifi, scan_params) > 0) { ret = g_supplicant_interface_scan(wifi->interface, scan_params, +#if defined TIZEN_EXT + scan_callback, +#else scan_callback_hidden, +#endif device); if (ret == 0) return; @@ -1361,7 +2252,11 @@ static gboolean autoscan_timeout(gpointer data) } else interval = autoscan->interval * autoscan->base; +#if defined TIZEN_EXT + if (autoscan->interval >= autoscan->limit) +#else if (interval > autoscan->limit) +#endif interval = autoscan->limit; throw_wifi_scan(wifi->device, scan_callback_hidden); @@ -1593,6 +2488,13 @@ static int wifi_disable(struct connman_device *device) connman_device_unref(wifi->device); } +#if defined TIZEN_EXT + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + } +#endif + /* In case of a user scan, device is still referenced */ if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) { connman_device_set_scanning(device, @@ -1603,6 +2505,15 @@ static int wifi_disable(struct connman_device *device) remove_networks(device, wifi); remove_peers(wifi); +#if defined TIZEN_EXT + wifi->scan_pending_network = NULL; + + if (is_wifi_notifier_registered == true) { + connman_notifier_unregister(¬ifier); + is_wifi_notifier_registered = false; + } +#endif + ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL); if (ret < 0) return ret; @@ -1610,35 +2521,6 @@ static int wifi_disable(struct connman_device *device) return -EINPROGRESS; } -struct last_connected { - GTimeVal modified; - gchar *ssid; - int freq; -}; - -static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data) -{ - GTimeVal *aval = (GTimeVal *)a; - GTimeVal *bval = (GTimeVal *)b; - - /* Note that the sort order is descending */ - if (aval->tv_sec < bval->tv_sec) - return 1; - - if (aval->tv_sec > bval->tv_sec) - return -1; - - return 0; -} - -static void free_entry(gpointer data) -{ - struct last_connected *entry = data; - - g_free(entry->ssid); - g_free(entry); -} - static int get_latest_connections(int max_ssids, GSupplicantScanParams *scan_data) { @@ -1849,6 +2731,341 @@ static int p2p_find(struct connman_device *device) return ret; } +#if defined TIZEN_EXT +static void specific_scan_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_device *device = user_data; + struct wifi_data *wifi = connman_device_get_data(device); + bool scanning; + + DBG("result %d wifi %p", result, wifi); + + if (wifi && wifi->scan_params) { + g_supplicant_free_scan_params(wifi->scan_params); + wifi->scan_params = NULL; + } + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI); + if (scanning) { + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI, false); + connman_device_unref(device); + } +} + +static int wifi_specific_scan(enum connman_service_type type, + struct connman_device *device, int scan_type, + GSList *specific_scan_list, void *user_data) +{ + GSList *list = NULL; + char *ssid = NULL; + struct wifi_data *wifi = connman_device_get_data(device); + GSupplicantScanParams *scan_params = NULL; + struct scan_ssid *scan_ssid = NULL; + bool scanning; + int ret; + int freq; + int count = 0; + + if (!wifi) + return -ENODEV; + + if (wifi->p2p_device) + return 0; + + if (type == CONNMAN_SERVICE_TYPE_P2P) + return p2p_find(device); + + if (wifi->tethering) + return 0; + + scanning = + connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI); + if (scanning) + return -EALREADY; + + DBG("scan_type: %d", scan_type); + if (scan_type == CONNMAN_MULTI_SCAN_SSID) { /* ssid based scan */ + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) { + DBG("Failed to allocate memory."); + return -ENOMEM; + } + + for (list = specific_scan_list; list; list = list->next) { + ssid = (char *)list->data; + int ssid_len = strlen(ssid); + + scan_ssid = g_try_new0(struct scan_ssid, 1); + if (!scan_ssid) { + DBG("Failed to allocate memory."); + g_supplicant_free_scan_params(scan_params); + return -ENOMEM; + } + + memcpy(scan_ssid->ssid, ssid, (ssid_len + 1)); + /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */ + scan_ssid->ssid_len = ssid_len; + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + count++; + } + scan_params->num_ssids = count; + + } else if (scan_type == CONNMAN_MULTI_SCAN_FREQ) { /* frequency based scan */ + + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) { + DBG("Failed to allocate memory."); + return -ENOMEM; + } + + guint num_freqs = g_slist_length(specific_scan_list); + DBG("num_freqs: %d", num_freqs); + + scan_params->freqs = g_try_new0(uint16_t, num_freqs); + if (!scan_params->freqs) { + DBG("Failed to allocate memory."); + g_free(scan_params); + return -ENOMEM; + } + + count = 0; + for (list = specific_scan_list; list; list = list->next) { + freq = (int)list->data; + + scan_params->freqs[count] = freq; + DBG("scan_params->freqs[%d]: %d", count, scan_params->freqs[count]); + count++; + } + scan_params->num_freqs = count; + + } else if (scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { /* SSID & Frequency mixed scan */ + int freq_count, ap_count; + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) { + DBG("Failed to allocate memory."); + return -ENOMEM; + } + + guint size = g_slist_length(specific_scan_list); + + scan_params->freqs = g_try_new0(uint16_t, size/2); + if (!scan_params->freqs) { + DBG("Failed to allocate memory."); + g_free(scan_params); + return -ENOMEM; + } + + ap_count = freq_count = 0; + for (list = specific_scan_list; list; list = list->next) { + if (((connman_multi_scan_ap_s *)list->data)->flag == true) { /** ssid */ + ssid = ((connman_multi_scan_ap_s *)list->data)->str; + int ssid_len = strlen(ssid); + + scan_ssid = g_try_new0(struct scan_ssid, 1); + if (!scan_ssid) { + DBG("Failed to allocate memory."); + g_supplicant_free_scan_params(scan_params); + return -ENOMEM; + } + + memcpy(scan_ssid->ssid, ssid, (ssid_len + 1)); + /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */ + scan_ssid->ssid_len = ssid_len; + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + ap_count++; + + } else { /* freq */ + freq = atoi(((connman_multi_scan_ap_s *)list->data)->str); + scan_params->freqs[freq_count] = freq; + DBG("scan_params->freqs[%d]: %d", freq_count, scan_params->freqs[freq_count]); + freq_count++; + } + } + scan_params->num_ssids = ap_count; + scan_params->num_freqs = freq_count; + } else { + DBG("Invalid scan"); + return -EINVAL; + } + + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(wifi->interface, scan_params, + specific_scan_callback, device); + + if (ret == 0) { + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI, true); + } else { + g_supplicant_free_scan_params(scan_params); + connman_device_unref(device); + } + + return ret; +} +#endif + +#if defined TIZEN_EXT_WIFI_MESH +static void mesh_scan_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_device *device = user_data; + struct wifi_data *wifi = connman_device_get_data(device); + bool scanning; + + DBG("result %d wifi %p", result, wifi); + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_MESH); + if (scanning) + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, false); + + if (scanning) + connman_device_unref(device); +} + +static int mesh_scan(struct connman_device *device) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + int ret; + + DBG(""); + + wifi = connman_device_get_data(device); + + if (!wifi->mesh_interface) + return -ENOTSUP; + + mesh_info = wifi->mesh_info; + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(mesh_info->interface, NULL, + mesh_scan_callback, device); + if (ret) + connman_device_unref(device); + else + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, true); + + return ret; +} + +static void abort_scan_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_device *device = user_data; + struct wifi_data *wifi = connman_device_get_data(device); + + DBG("result %d wifi %p", result, wifi); + + __connman_technology_notify_abort_scan(CONNMAN_SERVICE_TYPE_MESH, result); +} + +static int mesh_abort_scan(enum connman_service_type type, + struct connman_device *device) +{ + struct wifi_data *wifi = connman_device_get_data(device); + struct wifi_mesh_info *mesh_info; + bool scanning; + int ret; + + if (!wifi || !wifi->mesh_interface) + return -ENODEV; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; + + mesh_info = wifi->mesh_info; + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_MESH); + if (!scanning) + return -EEXIST; + + ret = g_supplicant_interface_abort_scan(mesh_info->interface, + abort_scan_callback, device); + + return ret; +} + +static int mesh_specific_scan(enum connman_service_type type, + struct connman_device *device, const char *ssid, + unsigned int freq, void *user_data) +{ + struct wifi_data *wifi = connman_device_get_data(device); + GSupplicantScanParams *scan_params = NULL; + struct wifi_mesh_info *mesh_info; + struct scan_ssid *scan_ssid; + bool scanning; + int ret; + + if (!wifi || !wifi->mesh_interface) + return -ENODEV; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; + + if (wifi->p2p_device) + return 0; + + mesh_info = wifi->mesh_info; + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_MESH); + if (scanning) + return -EALREADY; + + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) + return -ENOMEM; + + scan_ssid = g_try_new(struct scan_ssid, 1); + if (!scan_ssid) { + g_free(scan_params); + return -ENOMEM; + } + + scan_ssid->ssid_len = strlen(ssid); + memcpy(scan_ssid->ssid, ssid, scan_ssid->ssid_len); + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + scan_params->num_ssids = 1; + + scan_params->freqs = g_try_new(uint16_t, 1); + if (!scan_params->freqs) { + g_slist_free_full(scan_params->ssids, g_free); + g_free(scan_params); + return -ENOMEM; + } + + scan_params->freqs[0] = freq; + scan_params->num_freqs = 1; + + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(mesh_info->interface, scan_params, + mesh_scan_callback, device); + + if (ret == 0) { + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, true); + } else { + g_supplicant_free_scan_params(scan_params); + connman_device_unref(device); + } + + return ret; +} +#endif + /* * Note that the hidden scan is only used when connecting to this specific * hidden AP first time. It is not used when system autoconnects to hidden AP. @@ -1877,6 +3094,11 @@ static int wifi_scan(struct connman_device *device, if (params->type == CONNMAN_SERVICE_TYPE_P2P) return p2p_find(device); +#if defined TIZEN_EXT_WIFI_MESH + if (params->type == CONNMAN_SERVICE_TYPE_MESH) + return mesh_scan(device); +#endif + DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, params->ssid); @@ -1967,6 +3189,14 @@ static int wifi_scan(struct connman_device *device, if (ret == 0) { connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_WIFI, true); +#if defined TIZEN_EXT + /*To allow the Full Scan after ssid based scan, set the flag here + It is required because Tizen does not use the ConnMan specific + backgroung Scan feature.Tizen has added the BG Scan feature in + net-config. To sync with up ConnMan, we need to issue the Full Scan + after SSID specific scan.*/ + wifi->allow_full_scan = TRUE; +#endif } else { g_supplicant_free_scan_params(scan_params); connman_device_unref(device); @@ -2039,6 +3269,13 @@ static struct connman_device_driver wifi_ng_driver = { .scan = wifi_scan, .stop_scan = wifi_stop_scan, .set_regdom = wifi_set_regdom, +#if defined TIZEN_EXT + .specific_scan = wifi_specific_scan, +#endif +#if defined TIZEN_EXT_WIFI_MESH + .abort_scan = mesh_abort_scan, + .mesh_specific_scan = mesh_specific_scan, +#endif }; static void system_ready(void) @@ -2078,15 +3315,44 @@ static void network_remove(struct connman_network *network) return; wifi->network = NULL; + +#if defined TIZEN_EXT + wifi->disconnecting = false; + + if (wifi->pending_network == network) + wifi->pending_network = NULL; + + if (wifi->scan_pending_network == network) + wifi->scan_pending_network = NULL; +#endif } static void connect_callback(int result, GSupplicantInterface *interface, void *user_data) { +#if defined TIZEN_EXT + GList *list; + struct wifi_data *wifi; +#endif struct connman_network *network = user_data; DBG("network %p result %d", network, result); +#if defined TIZEN_EXT + set_connman_bssid(RESET_BSSID, NULL); + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi && wifi->network == network) + goto found; + } + + /* wifi_data may be invalid because wifi is already disabled */ + return; + +found: +#endif if (result == -ENOKEY) { connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY); @@ -2112,21 +3378,63 @@ static GSupplicantSecurity network_security(const char *security) return G_SUPPLICANT_SECURITY_PSK; else if (g_str_equal(security, "ieee8021x")) return G_SUPPLICANT_SECURITY_IEEE8021X; +#if defined TIZEN_EXT + else if (g_str_equal(security, "ft_psk") == TRUE) + return G_SUPPLICANT_SECURITY_FT_PSK; + else if (g_str_equal(security, "ft_ieee8021x") == TRUE) + return G_SUPPLICANT_SECURITY_FT_IEEE8021X; + else if (g_str_equal(security, "sae")) + return G_SUPPLICANT_SECURITY_SAE; + else if (g_str_equal(security, "owe")) + return G_SUPPLICANT_SECURITY_OWE; +#endif return G_SUPPLICANT_SECURITY_UNKNOWN; } +#if defined TIZEN_EXT +static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security) +{ + if (security == NULL) + return G_SUPPLICANT_EAP_KEYMGMT_NONE; + + if (g_str_equal(security, "FT") == TRUE) + return G_SUPPLICANT_EAP_KEYMGMT_FT; + else if (g_str_equal(security, "CCKM") == TRUE) + return G_SUPPLICANT_EAP_KEYMGMT_CCKM; + + return G_SUPPLICANT_EAP_KEYMGMT_NONE; +} +#endif + static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) { const char *security; +#if defined TIZEN_EXT + const void *ssid_data; +#endif memset(ssid, 0, sizeof(*ssid)); ssid->mode = G_SUPPLICANT_MODE_INFRA; +#if defined TIZEN_EXT + ssid_data = connman_network_get_blob(network, "WiFi.SSID", + &ssid->ssid_len); + ssid->ssid = g_try_malloc0(ssid->ssid_len); + + if (!ssid->ssid) + ssid->ssid_len = 0; + else + memcpy(ssid->ssid, ssid_data, ssid->ssid_len); +#else ssid->ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid->ssid_len); +#endif ssid->scan_ssid = 1; security = connman_network_get_string(network, "WiFi.Security"); ssid->security = network_security(security); +#if defined TIZEN_EXT + ssid->ieee80211w = 1; +#endif ssid->passphrase = connman_network_get_string(network, "WiFi.Passphrase"); @@ -2173,6 +3481,72 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS"); ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS"); +#if defined TIZEN_EXT + if (set_connman_bssid(CHECK_BSSID, NULL) == 6) { + ssid->bssid_for_connect_len = 6; + set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect); + DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x", + ssid->bssid_for_connect[0], ssid->bssid_for_connect[1], + ssid->bssid_for_connect[2], ssid->bssid_for_connect[3], + ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]); + } else { + ssid->freq = connman_network_get_frequency(network); + } + + GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network); + if (bssid_list && g_slist_length(bssid_list) > 1) { + + /* If there are more than one bssid, + * the user-specified bssid is tried only once at the beginning. + * After that, the bssids in the list are tried in order. + */ + if (set_connman_bssid(CHECK_BSSID, NULL) == 6) { + set_connman_bssid(RESET_BSSID, NULL); + goto done; + } + + GSList *list; + char buff[MAC_ADDRESS_LENGTH]; + for (list = bssid_list; list; list = list->next) { + struct connman_bssids * bssids = (struct connman_bssids *)list->data; + + g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x", + bssids->bssid[0], bssids->bssid[1], bssids->bssid[2], + bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]); + buff[MAC_ADDRESS_LENGTH - 1] = '\0'; + + gchar *curr_bssid = g_strdup((const gchar *)buff); + + if (g_hash_table_contains(failed_bssids, curr_bssid)) { + DBG("bssid match, try next bssid"); + g_free(curr_bssid); + continue; + } else { + g_hash_table_add(failed_bssids, curr_bssid); + + memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX); + ssid->bssid = buff_bssid; + ssid->freq = (unsigned int)bssids->frequency; + break; + } + } + + if (!list) { + ssid->bssid = connman_network_get_bssid(network); + g_hash_table_remove_all(failed_bssids); + } + } else + ssid->bssid = connman_network_get_bssid(network); + +done: + ssid->eap_keymgmt = network_eap_keymgmt( + connman_network_get_string(network, "WiFi.KeymgmtType")); + ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1"); + + if(g_strcmp0(ssid->eap, "fast") == 0) + ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE); +#endif + if (connman_setting_get_bool("BackgroundScanning")) ssid->bgscan = BGSCAN_DEFAULT; } @@ -2203,10 +3577,16 @@ static int network_connect(struct connman_network *network) if (wifi->disconnecting) { wifi->pending_network = network; +#if defined TIZEN_EXT + g_free(ssid->ssid); +#endif g_free(ssid); } else { wifi->network = connman_network_ref(network); wifi->retries = 0; +#if defined TIZEN_EXT + wifi->scan_pending_network = NULL; +#endif return g_supplicant_interface_connect(interface, ssid, connect_callback, network); @@ -2218,7 +3598,30 @@ static int network_connect(struct connman_network *network) static void disconnect_callback(int result, GSupplicantInterface *interface, void *user_data) { +#if defined TIZEN_EXT + GList *list; + struct wifi_data *wifi; + struct connman_network *network = user_data; + + DBG("network %p result %d", network, result); + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->network == NULL && wifi->disconnecting == true) + wifi->disconnecting = false; + + if (wifi->network == network) + goto found; + } + + /* wifi_data may be invalid because wifi is already disabled */ + return; + +found: +#else struct wifi_data *wifi = user_data; +#endif DBG("result %d supplicant interface %p wifi %p", result, interface, wifi); @@ -2248,6 +3651,9 @@ static int network_disconnect(struct connman_network *network) struct connman_device *device = connman_network_get_device(network); struct wifi_data *wifi; int err; +#if defined TIZEN_EXT + struct connman_service *service; +#endif DBG("network %p", network); @@ -2255,6 +3661,29 @@ static int network_disconnect(struct connman_network *network) if (!wifi || !wifi->interface) return -ENODEV; +#if defined TIZEN_EXT + if (connman_network_get_associating(network) == true) { + connman_network_clear_associating(network); + connman_network_set_bool(network, "WiFi.UseWPS", false); + } else { + service = connman_service_lookup_from_network(network); + + if (service != NULL && + (__connman_service_is_connected_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4) == false && + __connman_service_is_connected_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6) == false) && + (connman_service_get_favorite(service) == false)) + __connman_service_set_passphrase(service, NULL); + } + + if (wifi->pending_network == network) + wifi->pending_network = NULL; + + if (wifi->scan_pending_network == network) + wifi->scan_pending_network = NULL; + +#endif connman_network_set_associating(network, false); if (wifi->disconnecting) @@ -2262,14 +3691,150 @@ static int network_disconnect(struct connman_network *network) wifi->disconnecting = true; +#if defined TIZEN_EXT + err = g_supplicant_interface_disconnect(wifi->interface, + disconnect_callback, network); +#else err = g_supplicant_interface_disconnect(wifi->interface, disconnect_callback, wifi); +#endif + if (err < 0) wifi->disconnecting = false; return err; } +#if defined TIZEN_EXT +static void set_connection_mode(struct connman_network *network, + int linkspeed) +{ + ieee80211_modes_e phy_mode; + connection_mode_e conn_mode; + + phy_mode = connman_network_get_phy_mode(network); + switch (phy_mode) { + case IEEE80211_MODE_B: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_BG: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else if (linkspeed > 11 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211G; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_BGN: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else if (linkspeed > 11 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211G; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_A: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_AN: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_ANAC: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else if (linkspeed > 450 && linkspeed <= 1300) + conn_mode = CONNECTION_MODE_IEEE80211AC; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + default: + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + break; + } + + DBG("connection mode(%d)", conn_mode); + connman_network_set_connection_mode(network, conn_mode); +} + +static void signalpoll_callback(int result, int maxspeed, uint8_t strength, + void *user_data) +{ + struct connman_network *network = user_data; + + if (result != 0) { + DBG("Failed to get maxspeed from signalpoll !"); + return; + } + + strength += 120; + if (strength > 100) + strength = 100; + + DBG("maxspeed = %d, strength = %d", maxspeed, strength); + if (network) { + connman_network_set_strength(network, strength); + connman_network_set_maxspeed(network, maxspeed); + set_connection_mode(network, maxspeed); + } +} + +static int network_signalpoll(struct wifi_data *wifi) +{ + GSupplicantInterface *interface; + struct connman_network *network; + + if (!wifi || !wifi->network) + return -ENODEV; + + interface = wifi->interface; + network = wifi->network; + + DBG("network %p", network); + + return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network); +} + +static gboolean autosignalpoll_timeout(gpointer data) +{ + struct wifi_data *wifi = data; + + if (!wifi || !wifi->automaxspeed_timeout) { + DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!"); + return FALSE; + } + + int ret = network_signalpoll(wifi); + if (ret < 0) { + DBG("Fail to get max speed !!"); + wifi->automaxspeed_timeout = 0; + return FALSE; + } + + return TRUE; +} +#endif + static struct connman_network_driver network_driver = { .name = "wifi", .type = CONNMAN_NETWORK_TYPE_WIFI, @@ -2284,6 +3849,10 @@ static void interface_added(GSupplicantInterface *interface) { const char *ifname = g_supplicant_interface_get_ifname(interface); const char *driver = g_supplicant_interface_get_driver(interface); +#if defined TIZEN_EXT + bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface); +#endif + struct wifi_data *wifi; wifi = g_supplicant_interface_get_data(interface); @@ -2307,6 +3876,12 @@ static void interface_added(GSupplicantInterface *interface) } connman_device_set_powered(wifi->device, true); +#if defined TIZEN_EXT + connman_techonology_wifi_set_5ghz_supported(wifi_technology, is_5_0_ghz_supported); + /* Max number of SSIDs supported by wlan chipset that can be scanned */ + int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface); + connman_techonology_set_max_scan_ssids(wifi_technology, max_scan_ssids); +#endif } static bool is_idle(struct wifi_data *wifi) @@ -2386,16 +3961,49 @@ static bool handle_wps_completion(GSupplicantInterface *interface, if (!wps_ssid || wps_ssid_len != ssid_len || memcmp(ssid, wps_ssid, ssid_len) != 0) { connman_network_set_associating(network, false); +#if defined TIZEN_EXT + g_supplicant_interface_disconnect(wifi->interface, + disconnect_callback, wifi->network); + + connman_network_set_bool(network, "WiFi.UseWPS", false); + connman_network_set_string(network, "WiFi.PinWPS", NULL); +#else g_supplicant_interface_disconnect(wifi->interface, disconnect_callback, wifi); +#endif return false; } wps_key = g_supplicant_interface_get_wps_key(interface); +#if defined TIZEN_EXT + /* Check the passphrase and encrypt it + */ + int ret; + gchar *passphrase = g_strdup(wps_key); + + connman_network_set_string(network, "WiFi.PinWPS", NULL); + + if (check_passphrase_ext(network, passphrase) < 0) { + DBG("[WPS] Invalid passphrase"); + g_free(passphrase); + return true; + } + + ret = send_encryption_request(passphrase, network); + + g_free(passphrase); + + if (!ret) + DBG("[WPS] Encryption request succeeded"); + else + DBG("[WPS] Encryption request failed %d", ret); + +#else connman_network_set_string(network, "WiFi.Passphrase", wps_key); connman_network_set_string(network, "WiFi.PinWPS", NULL); +#endif } return true; @@ -2405,7 +4013,11 @@ static bool handle_assoc_status_code(GSupplicantInterface *interface, struct wifi_data *wifi) { if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING && +#if defined TIZEN_EXT + wifi->assoc_code > 0 && +#else wifi->assoc_code == ASSOC_STATUS_NO_CLIENT && +#endif wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) { wifi->load_shaping_retries ++; return TRUE; @@ -2418,6 +4030,26 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface, struct connman_network *network, struct wifi_data *wifi) { +#if defined TIZEN_EXT + const char *security; + struct connman_service *service; + + if (wifi->connected) + return false; + + security = connman_network_get_string(network, "WiFi.Security"); + + if (security && g_str_equal(security, "ieee8021x") == true && + wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) { + wifi->retries = 0; + connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY); + + return false; + } + + if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) + return false; +#else struct connman_service *service; if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) @@ -2425,6 +4057,7 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface, if (wifi->connected) return false; +#endif service = connman_service_lookup_from_network(network); if (!service) @@ -2443,6 +4076,47 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface, return false; } +#if defined TIZEN_EXT +static bool handle_wifi_assoc_retry(struct connman_network *network, + struct wifi_data *wifi) +{ + const char *security; + + if (!wifi->network || wifi->connected || wifi->disconnecting || + connman_network_get_connecting(network) != true) { + wifi->assoc_retry_count = 0; + return false; + } + + if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING && + wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) { + wifi->assoc_retry_count = 0; + return false; + } + + security = connman_network_get_string(network, "WiFi.Security"); + if (security && g_str_equal(security, "ieee8021x") == true && + wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) { + wifi->assoc_retry_count = 0; + return false; + } + + if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) { + wifi->assoc_retry_count = 0; + + /* Honestly it's not an invalid-key error, + * however QA team recommends that the invalid-key error + * might be better to display for user experience. + */ + connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + + return false; + } + + return true; +} +#endif + static void interface_state(GSupplicantInterface *interface) { struct connman_network *network; @@ -2493,7 +4167,11 @@ static void interface_state(GSupplicantInterface *interface) case G_SUPPLICANT_STATE_AUTHENTICATING: case G_SUPPLICANT_STATE_ASSOCIATING: +#if defined TIZEN_EXT + reset_autoscan(device); +#else stop_autoscan(device); +#endif if (!wifi->connected) connman_network_set_associating(network, true); @@ -2501,8 +4179,37 @@ static void interface_state(GSupplicantInterface *interface) break; case G_SUPPLICANT_STATE_COMPLETED: +#if defined TIZEN_EXT + /* though it should be already reset: */ + reset_autoscan(device); + + wifi->assoc_retry_count = 0; + + wifi->scan_pending_network = NULL; + + /* should be cleared scanning flag */ + bool scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI); + if (scanning){ + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI, false); + connman_device_unref(device); + } + + if (!wifi->automaxspeed_timeout) { + DBG("Going to start signalpoll timer!!"); + int ret = network_signalpoll(wifi); + if (ret < 0) + DBG("Fail to get max speed !!"); + else + wifi->automaxspeed_timeout = g_timeout_add_seconds(10, autosignalpoll_timeout, wifi); + } + + g_hash_table_remove_all(failed_bssids); +#else /* though it should be already stopped: */ stop_autoscan(device); +#endif if (!handle_wps_completion(interface, network, device, wifi)) break; @@ -2515,6 +4222,16 @@ static void interface_state(GSupplicantInterface *interface) break; case G_SUPPLICANT_STATE_DISCONNECTED: +#if defined TIZEN_EXT + connman_network_set_strength(network, 0); + connman_network_set_maxspeed(network, 0); + + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + DBG("Remove signalpoll timer!!"); + } +#endif /* * If we're in one of the idle modes, we have * not started association yet and thus setting @@ -2529,8 +4246,27 @@ static void interface_state(GSupplicantInterface *interface) if (is_idle(wifi)) break; +#if defined TIZEN_EXT + if (handle_assoc_status_code(interface, wifi)) { + GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network); + guint bssid_length = 0; + + if (bssid_list) + bssid_length = g_slist_length(bssid_list); + + if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) { + network_connect(network); + break; + } + + wifi->load_shaping_retries = 0; + } + + g_hash_table_remove_all(failed_bssids); +#else if (handle_assoc_status_code(interface, wifi)) break; +#endif /* If previous state was 4way-handshake, then * it's either: psk was incorrect and thus we retry @@ -2554,6 +4290,21 @@ static void interface_state(GSupplicantInterface *interface) break; } +#if defined TIZEN_EXT + /* Some of Wi-Fi networks are not comply Wi-Fi specification. + * Retry association until its retry count is expired */ + if (handle_wifi_assoc_retry(network, wifi) == true) { + throw_wifi_scan(wifi->device, scan_callback); + wifi->scan_pending_network = wifi->network; + break; + } + + if(wifi->disconnect_code > 0){ + DBG("Set disconnect reason code(%d)", wifi->disconnect_code); + connman_network_set_disconnect_reason(network, wifi->disconnect_code); + } +#endif + if (network != wifi->pending_network) { connman_network_set_connected(network, false); connman_network_set_associating(network, false); @@ -2565,6 +4316,10 @@ static void interface_state(GSupplicantInterface *interface) break; case G_SUPPLICANT_STATE_INACTIVE: +#if defined TIZEN_EXT + if (handle_wps_completion(interface, network, device, wifi) == false) + break; +#endif connman_network_set_associating(network, false); start_autoscan(device); @@ -2625,6 +4380,21 @@ static void interface_removed(GSupplicantInterface *interface) wifi = g_supplicant_interface_get_data(interface); +#if defined TIZEN_EXT_WIFI_MESH + if (wifi && wifi->mesh_interface) { + DBG("Notify mesh interface remove"); + connman_mesh_notify_interface_remove(true); + struct wifi_mesh_info *mesh_info = wifi->mesh_info; + g_free(mesh_info->parent_ifname); + g_free(mesh_info->ifname); + g_free(mesh_info->identifier); + g_free(mesh_info); + wifi->mesh_interface = false; + wifi->mesh_info = NULL; + return; + } +#endif + if (wifi) wifi->interface = NULL; @@ -2639,6 +4409,9 @@ static void interface_removed(GSupplicantInterface *interface) connman_device_set_powered(wifi->device, false); check_p2p_technology(); +#if defined TIZEN_EXT_WIFI_MESH + check_mesh_technology(); +#endif } static void set_device_type(const char *type, char dev_type[17]) @@ -2701,7 +4474,38 @@ static void scan_started(GSupplicantInterface *interface) static void scan_finished(GSupplicantInterface *interface) { +#if defined TIZEN_EXT + struct wifi_data *wifi; + bool is_associating = false; + static bool is_scanning = true; +#endif + DBG(""); + +#if defined TIZEN_EXT + wifi = g_supplicant_interface_get_data(interface); + if (wifi && wifi->scan_pending_network) { + network_connect(wifi->scan_pending_network); + wifi->scan_pending_network = NULL; + } + + //service state - associating + if(!wifi || !wifi->network) + return; + + is_associating = connman_network_get_associating(wifi->network); + if(is_associating && is_scanning){ + is_scanning = false; + DBG("send scan for connecting"); + throw_wifi_scan(wifi->device, scan_callback); + + return; + } + is_scanning = true; + + //go scan + +#endif } static void ap_create_fail(GSupplicantInterface *interface) @@ -2737,12 +4541,105 @@ static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network) unsigned char strength; strength = 120 + g_supplicant_network_get_signal(supplicant_network); +#if !defined TIZEN_EXT if (strength > 100) strength = 100; +#endif return strength; } +#if defined TIZEN_EXT_WIFI_MESH +static void mesh_peer_added(GSupplicantNetwork *supplicant_network) +{ + GSupplicantInterface *interface; + struct wifi_data *wifi; + const char *name, *security; + struct connman_mesh *connman_mesh; + struct wifi_mesh_info *mesh_info; + const unsigned char *bssid; + const char *identifier; + char *address; + uint16_t frequency; + int ret; + + interface = g_supplicant_network_get_interface(supplicant_network); + wifi = g_supplicant_interface_get_data(interface); + if (!wifi || !wifi->mesh_interface) { + DBG("Virtual Mesh interface not created"); + return; + } + + bssid = g_supplicant_network_get_bssid(supplicant_network); + address = g_malloc0(19); + snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1], + bssid[2], bssid[3], bssid[4], bssid[5]); + + identifier = g_supplicant_network_get_identifier(supplicant_network); + name = g_supplicant_network_get_name(supplicant_network); + security = g_supplicant_network_get_security(supplicant_network); + frequency = g_supplicant_network_get_frequency(supplicant_network); + + mesh_info = wifi->mesh_info; + connman_mesh = connman_mesh_get(mesh_info->identifier, identifier); + if (connman_mesh) + goto done; + + DBG("Mesh Peer name %s identifier %s security %s added", name, identifier, + security); + connman_mesh = connman_mesh_create(mesh_info->identifier, identifier); + connman_mesh_set_name(connman_mesh, name); + connman_mesh_set_security(connman_mesh, security); + connman_mesh_set_frequency(connman_mesh, frequency); + connman_mesh_set_address(connman_mesh, address); + connman_mesh_set_index(connman_mesh, mesh_info->index); + connman_mesh_set_strength(connman_mesh, + calculate_strength(supplicant_network)); + connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED); + + ret = connman_mesh_register(connman_mesh); + if (ret == -EALREADY) + DBG("Mesh Peer is already registered"); + +done: + g_free(address); +} + +static void mesh_peer_removed(GSupplicantNetwork *supplicant_network) +{ + GSupplicantInterface *interface; + struct wifi_data *wifi; + struct connman_mesh *connman_mesh; + struct wifi_mesh_info *mesh_info; + const char *identifier; + + interface = g_supplicant_network_get_interface(supplicant_network); + wifi = g_supplicant_interface_get_data(interface); + if (!wifi || !wifi->mesh_interface) { + DBG("Virtual Mesh interface not created"); + return; + } + + identifier = g_supplicant_network_get_identifier(supplicant_network); + if (!identifier) { + DBG("Failed to get Mesh Peer identifier"); + return; + } + + mesh_info = wifi->mesh_info; + connman_mesh = connman_mesh_get(mesh_info->identifier, identifier); + if (connman_mesh) { + /* Do not unregister connected mesh peer */ + if (connman_mesh_peer_is_connected_state(connman_mesh)) { + DBG("Mesh Peer %s is connected", identifier); + return; + } + DBG("Mesh Peer identifier %s removed", identifier); + connman_mesh_unregister(connman_mesh); + } +} +#endif + static void network_added(GSupplicantNetwork *supplicant_network) { struct connman_network *network; @@ -2756,6 +4653,12 @@ static void network_added(GSupplicantNetwork *supplicant_network) bool wps_ready; bool wps_advertizing; +#if defined TIZEN_EXT + GSList *vsie_list = NULL; + const unsigned char *country_code; + ieee80211_modes_e phy_mode; +#endif + mode = g_supplicant_network_get_mode(supplicant_network); identifier = g_supplicant_network_get_identifier(supplicant_network); @@ -2764,6 +4667,13 @@ static void network_added(GSupplicantNetwork *supplicant_network) if (!g_strcmp0(mode, "adhoc")) return; +#if defined TIZEN_EXT_WIFI_MESH + if (!g_strcmp0(mode, "mesh")) { + mesh_peer_added(supplicant_network); + return; + } +#endif + interface = g_supplicant_network_get_interface(supplicant_network); wifi = g_supplicant_interface_get_data(interface); name = g_supplicant_network_get_name(supplicant_network); @@ -2803,6 +4713,17 @@ static void network_added(GSupplicantNetwork *supplicant_network) connman_network_set_blob(network, "WiFi.SSID", ssid, ssid_len); +#if defined TIZEN_EXT + vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network); + if (vsie_list) + connman_network_set_vsie_list(network, vsie_list); + else + DBG("vsie_list is NULL"); + country_code = g_supplicant_network_get_countrycode(supplicant_network); + connman_network_set_countrycode(network, country_code); + phy_mode = g_supplicant_network_get_phy_mode(supplicant_network); + connman_network_set_phy_mode(network, phy_mode); +#endif connman_network_set_string(network, "WiFi.Security", security); connman_network_set_strength(network, calculate_strength(supplicant_network)); @@ -2815,20 +4736,54 @@ static void network_added(GSupplicantNetwork *supplicant_network) * If so, we decide to use WPS by default */ if (wps_ready && wps_pbc && wps_advertizing) +#if !defined TIZEN_EXT connman_network_set_bool(network, "WiFi.UseWPS", true); +#else + DBG("wps is activating by ap but ignore it."); +#endif } connman_network_set_frequency(network, g_supplicant_network_get_frequency(supplicant_network)); +#if defined TIZEN_EXT + connman_network_set_bssid(network, + g_supplicant_network_get_bssid(supplicant_network)); + connman_network_set_maxrate(network, + g_supplicant_network_get_maxrate(supplicant_network)); + connman_network_set_enc_mode(network, + g_supplicant_network_get_enc_mode(supplicant_network)); + connman_network_set_rsn_mode(network, + g_supplicant_network_get_rsn_mode(supplicant_network)); + connman_network_set_keymgmt(network, + g_supplicant_network_get_keymgmt(supplicant_network)); + connman_network_set_bool(network, "WiFi.HS20AP", + g_supplicant_network_is_hs20AP(supplicant_network)); + connman_network_set_bssid_list(network, + (GSList *)g_supplicant_network_get_bssid_list(supplicant_network)); +#endif connman_network_set_available(network, true); connman_network_set_string(network, "WiFi.Mode", mode); +#if defined TIZEN_EXT + if (group) +#else if (ssid) +#endif connman_network_set_group(network, group); +#if defined TIZEN_EXT + if (wifi_first_scan == true) + found_with_first_scan = true; +#endif + if (wifi->hidden && ssid) { +#if defined TIZEN_EXT + if (network_security(wifi->hidden->security) == + network_security(security) && +#else if (!g_strcmp0(wifi->hidden->security, security) && +#endif wifi->hidden->ssid_len == ssid_len && !memcmp(wifi->hidden->ssid, ssid, ssid_len)) { connman_network_connect_hidden(network, @@ -2849,6 +4804,15 @@ static void network_removed(GSupplicantNetwork *network) const char *name, *identifier; struct connman_network *connman_network; +#if defined TIZEN_EXT_WIFI_MESH + const char *mode; + mode = g_supplicant_network_get_mode(network); + if (!g_strcmp0(mode, "mesh")) { + mesh_peer_removed(network); + return; + } +#endif + interface = g_supplicant_network_get_interface(network); wifi = g_supplicant_interface_get_data(interface); identifier = g_supplicant_network_get_identifier(network); @@ -2863,6 +4827,18 @@ static void network_removed(GSupplicantNetwork *network) if (!connman_network) return; +#if defined TIZEN_EXT + if (connman_network == wifi->scan_pending_network) + wifi->scan_pending_network = NULL; + + if (connman_network == wifi->pending_network) + wifi->pending_network = NULL; + + if(connman_network_get_connecting(connman_network) == true){ + connman_network_set_connected(connman_network, false); + } +#endif + wifi->networks = g_slist_remove(wifi->networks, connman_network); connman_device_remove_network(wifi->device, connman_network); @@ -2877,6 +4853,16 @@ static void network_changed(GSupplicantNetwork *network, const char *property) struct connman_network *connman_network; bool update_needed; +#if defined TIZEN_EXT + const unsigned char *bssid; + unsigned int maxrate; + uint16_t frequency; + bool wps; + const unsigned char *country_code; + ieee80211_modes_e phy_mode; + GSList *bssid_list; +#endif + interface = g_supplicant_network_get_interface(network); wifi = g_supplicant_interface_get_data(interface); identifier = g_supplicant_network_get_identifier(network); @@ -2927,6 +4913,28 @@ static void network_changed(GSupplicantNetwork *network, const char *property) if (update_needed) connman_network_update(connman_network); + +#if defined TIZEN_EXT + bssid = g_supplicant_network_get_bssid(network); + maxrate = g_supplicant_network_get_maxrate(network); + frequency = g_supplicant_network_get_frequency(network); + wps = g_supplicant_network_get_wps(network); + phy_mode = g_supplicant_network_get_phy_mode(network); + + connman_network_set_bssid(connman_network, bssid); + connman_network_set_maxrate(connman_network, maxrate); + connman_network_set_frequency(connman_network, frequency); + connman_network_set_bool(connman_network, "WiFi.WPS", wps); + country_code = g_supplicant_network_get_countrycode(network); + connman_network_set_countrycode(connman_network, country_code); + bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network); + connman_network_set_bssid_list(connman_network, bssid_list); + connman_network_set_phy_mode(connman_network, phy_mode); + + if (g_str_equal(property, "CheckMultiBssidConnect") && + connman_network_get_associating(connman_network)) + network_connect(connman_network); +#endif } static void network_associated(GSupplicantNetwork *network) @@ -3035,6 +5043,10 @@ static void peer_found(GSupplicantPeer *peer) const char *identifier, *name; int ret; +#if defined TIZEN_EXT + if (!wifi) + return; +#endif identifier = g_supplicant_peer_get_identifier(peer); name = g_supplicant_peer_get_name(peer); @@ -3180,6 +5192,11 @@ static void peer_request(GSupplicantPeer *peer) struct connman_peer *connman_peer; const char *identifier; +#if defined TIZEN_EXT + if (!wifi) + return; +#endif + identifier = g_supplicant_peer_get_identifier(peer); DBG("ident: %s", identifier); @@ -3191,6 +5208,100 @@ static void peer_request(GSupplicantPeer *peer) connman_peer_request_connection(connman_peer); } +#if defined TIZEN_EXT +static void system_power_off(void) +{ + GList *list; + struct wifi_data *wifi; + struct connman_service *service; + struct connman_ipconfig *ipconfig_ipv4; + + if (connman_setting_get_bool("WiFiDHCPRelease") == true) { + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->network != NULL) { + service = connman_service_lookup_from_network(wifi->network); + ipconfig_ipv4 = __connman_service_get_ip4config(service); + __connman_dhcp_stop(ipconfig_ipv4); + } + } + } +} + +static void network_merged(GSupplicantNetwork *network) +{ + GSupplicantInterface *interface; + GSupplicantState state; + struct wifi_data *wifi; + const char *identifier; + struct connman_network *connman_network; + bool ishs20AP = 0; + char *temp = NULL; + + interface = g_supplicant_network_get_interface(network); + if (!interface) + return; + + state = g_supplicant_interface_get_state(interface); + if (state < G_SUPPLICANT_STATE_AUTHENTICATING) + return; + + wifi = g_supplicant_interface_get_data(interface); + if (!wifi) + return; + + identifier = g_supplicant_network_get_identifier(network); + + connman_network = connman_device_get_network(wifi->device, identifier); + if (!connman_network) + return; + + DBG("merged identifier %s", identifier); + + if (wifi->connected == FALSE) { + switch (state) { + case G_SUPPLICANT_STATE_AUTHENTICATING: + case G_SUPPLICANT_STATE_ASSOCIATING: + case G_SUPPLICANT_STATE_ASSOCIATED: + case G_SUPPLICANT_STATE_4WAY_HANDSHAKE: + case G_SUPPLICANT_STATE_GROUP_HANDSHAKE: + connman_network_set_associating(connman_network, TRUE); + break; + case G_SUPPLICANT_STATE_COMPLETED: + connman_network_set_connected(connman_network, TRUE); + break; + default: + DBG("Not handled the state : %d", state); + break; + } + } + + ishs20AP = g_supplicant_network_is_hs20AP(network); + + if (ishs20AP && + g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) { + temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1); + connman_network_set_string(connman_network, "WiFi.EAP", + temp); + connman_network_set_string(connman_network, "WiFi.Identity", + g_supplicant_network_get_identity(network)); + connman_network_set_string(connman_network, "WiFi.Phase2", + g_supplicant_network_get_phase2(network)); + + g_free(temp); + } + + wifi->network = connman_network; +} + +static void assoc_failed(void *user_data) +{ + struct connman_network *network = user_data; + connman_network_set_associating(network, false); +} +#endif + static void debug(const char *str) { if (getenv("CONNMAN_SUPPLICANT_DEBUG")) @@ -3236,9 +5347,21 @@ static const GSupplicantCallbacks callbacks = { .peer_lost = peer_lost, .peer_changed = peer_changed, .peer_request = peer_request, +#if defined TIZEN_EXT + .system_power_off = system_power_off, + .network_merged = network_merged, + .assoc_failed = assoc_failed, +#endif .debug = debug, .disconnect_reasoncode = disconnect_reasoncode, .assoc_status_code = assoc_status_code, +#if defined TIZEN_EXT_WIFI_MESH + .mesh_support = mesh_support, + .mesh_group_started = mesh_group_started, + .mesh_group_removed = mesh_group_removed, + .mesh_peer_connected = mesh_peer_connected, + .mesh_peer_disconnected = mesh_peer_disconnected, +#endif }; @@ -3263,7 +5386,11 @@ static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase) return NULL; ap->mode = G_SUPPLICANT_MODE_MASTER; +#if defined TIZEN_EXT + ap->ssid = (void *) ssid; +#else ap->ssid = ssid; +#endif ap->ssid_len = strlen(ssid); ap->scan_ssid = 0; ap->freq = 2412; @@ -3567,6 +5694,9 @@ static int wifi_init(void) return err; } +#if defined TIZEN_EXT + failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); +#endif return 0; } @@ -3579,6 +5709,10 @@ static void wifi_exit(void) g_supplicant_unregister(&callbacks); connman_network_driver_unregister(&network_driver); + +#if defined TIZEN_EXT + g_hash_table_unref(failed_bssids); +#endif } CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION, |