diff options
author | Seonah Moon <seonah1.moon@samsung.com> | 2018-01-23 14:50:50 +0900 |
---|---|---|
committer | Seonah Moon <seonah1.moon@samsung.com> | 2018-01-23 14:50:55 +0900 |
commit | 30602f521a85820a9f6b7ac04876400e00c68b15 (patch) | |
tree | f035a4fcc014a034f3b492886d1e8395f327fd25 /plugins | |
parent | a079cfe6f815f8c69055de834d1ccbdf1fd94ba7 (diff) | |
parent | 9362752a471a5c892d679548fbf2828d5fc5684b (diff) | |
download | connman-30602f521a85820a9f6b7ac04876400e00c68b15.tar.gz connman-30602f521a85820a9f6b7ac04876400e00c68b15.tar.bz2 connman-30602f521a85820a9f6b7ac04876400e00c68b15.zip |
Updated connman to version 1.35
Change-Id: I13526fbf80296a79be15548fc226a308941ac9ec
Signed-off-by: Taesub Kim <taesub.kim@samsung.com>
Diffstat (limited to 'plugins')
-rwxr-xr-x | plugins/bluetooth.c | 28 | ||||
-rwxr-xr-x | plugins/bluetooth_legacy.c | 1461 | ||||
-rwxr-xr-x | plugins/ethernet.c | 61 | ||||
-rwxr-xr-x | plugins/gadget.c | 2 | ||||
-rw-r--r-- | plugins/iwd.c | 1108 | ||||
-rwxr-xr-x | plugins/neard.c | 4 | ||||
-rwxr-xr-x | plugins/ofono.c | 561 | ||||
-rwxr-xr-x | plugins/pacrunner.c | 10 | ||||
-rwxr-xr-x | plugins/session_policy_local.c | 4 | ||||
-rwxr-xr-x | plugins/vpn.c | 39 | ||||
-rwxr-xr-x | plugins/wifi.c | 504 |
11 files changed, 1964 insertions, 1818 deletions
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c index f72a4af6..f89edfa0 100755 --- a/plugins/bluetooth.c +++ b/plugins/bluetooth.c @@ -212,7 +212,7 @@ static void pan_connect_cb(DBusMessage *message, void *user_data) DBusMessageIter iter; pan = g_hash_table_lookup(networks, path); - if (!pan) { + if (!pan || !pan->network) { DBG("network already removed"); return; } @@ -236,6 +236,7 @@ static void pan_connect_cb(DBusMessage *message, void *user_data) if (strcmp(dbus_error, "org.bluez.Error.AlreadyConnected") != 0) { + connman_network_set_associating(pan->network, false); connman_network_set_error(pan->network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); return; @@ -293,7 +294,7 @@ static void pan_disconnect_cb(DBusMessage *message, void *user_data) struct bluetooth_pan *pan; pan = g_hash_table_lookup(networks, path); - if (!pan) { + if (!pan || !pan->network) { DBG("network already removed"); return; } @@ -366,6 +367,7 @@ static void pan_create_nap(struct bluetooth_pan *pan) { struct connman_device *device; const char* role; + const char *adapter; role = proxy_get_role(pan->btdevice_proxy); if (!role) { @@ -373,8 +375,12 @@ static void pan_create_nap(struct bluetooth_pan *pan) return; } - device = g_hash_table_lookup(devices, - proxy_get_string(pan->btdevice_proxy, "Adapter")); + adapter = proxy_get_string(pan->btdevice_proxy, "Adapter"); + + if (!adapter) + return; + + device = g_hash_table_lookup(devices, adapter); if (!device || !connman_device_get_powered(device)) return; @@ -740,21 +746,23 @@ static bool tethering_create(const char *path, struct connman_technology *technology, const char *bridge, bool enabled) { - struct tethering_info *tethering; + struct tethering_info *tethering = g_new0(struct tethering_info, 1); GDBusProxy *proxy; const char *method; bool result; DBG("path %s bridge %s", path, bridge); - if (!bridge) - return -EINVAL; + if (!bridge) { + g_free(tethering); + return false; + } proxy = g_dbus_proxy_new(client, path, "org.bluez.NetworkServer1"); - if (!proxy) + if (!proxy) { + g_free(tethering); return false; - - tethering = g_new0(struct tethering_info, 1); + } tethering->technology = technology; tethering->bridge = g_strdup(bridge); diff --git a/plugins/bluetooth_legacy.c b/plugins/bluetooth_legacy.c deleted file mode 100755 index 16d717ed..00000000 --- a/plugins/bluetooth_legacy.c +++ /dev/null @@ -1,1461 +0,0 @@ -/* - * - * Connection Manager - * - * Copyright (C) 2007-2013 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 <stdio.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <netinet/ether.h> - -#include <gdbus.h> - -#define CONNMAN_API_SUBJECT_TO_CHANGE -#include <connman/plugin.h> -#include <connman/technology.h> -#include <connman/device.h> -#include <connman/inet.h> -#include <connman/dbus.h> -#include <connman/log.h> - -#define BLUEZ_SERVICE "org.bluez" -#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager" -#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter" -#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device" -#define BLUEZ_NETWORK_INTERFACE BLUEZ_SERVICE ".Network" -#define BLUEZ_NETWORK_SERVER BLUEZ_SERVICE ".NetworkServer" - -#define LIST_ADAPTERS "ListAdapters" -#define ADAPTER_ADDED "AdapterAdded" -#define ADAPTER_REMOVED "AdapterRemoved" -#define DEVICE_REMOVED "DeviceRemoved" - -#define PEER_CONNECTED "PeerConnected" -#define PEER_DISCONNECTED "PeerDisconnected" - -#define PROPERTY_CHANGED "PropertyChanged" -#define GET_PROPERTIES "GetProperties" -#define SET_PROPERTY "SetProperty" - -#define CONNECT "Connect" -#define DISCONNECT "Disconnect" - -#define REGISTER "Register" -#define UNREGISTER "Unregister" - -#define UUID_NAP "00001116-0000-1000-8000-00805f9b34fb" - -#define TIMEOUT 60000 - -static DBusConnection *connection; - -static GHashTable *bluetooth_devices = NULL; -static GHashTable *bluetooth_networks = NULL; -static GHashTable *pending_networks = NULL; - -static int pan_probe(struct connman_network *network) -{ - GHashTableIter iter; - gpointer key, val; - - g_hash_table_iter_init(&iter, bluetooth_networks); - while (g_hash_table_iter_next(&iter, &key, &val)) { - struct connman_network *known = val; - - if (network != known) - continue; - - DBG("network %p", network); - - return 0; - } - - return -EOPNOTSUPP; -} - -static void pan_remove(struct connman_network *network) -{ - DBG("network %p", network); -} - -static void connect_reply(DBusPendingCall *call, void *user_data) -{ - char *path = user_data; - struct connman_network *network; - DBusMessage *reply; - DBusError error; - const char *interface = NULL; - int index; - - network = g_hash_table_lookup(bluetooth_networks, path); - if (!network) - return; - - DBG("network %p", network); - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&error); - - if (dbus_set_error_from_message(&error, reply)) { - connman_error("%s", error.message); - dbus_error_free(&error); - - goto err; - } - - if (!dbus_message_get_args(reply, &error, DBUS_TYPE_STRING, - &interface, DBUS_TYPE_INVALID)) { - if (dbus_error_is_set(&error)) { - connman_error("%s", error.message); - dbus_error_free(&error); - } else - connman_error("Wrong arguments for connect"); - goto err; - } - - if (!interface) - goto err; - - DBG("interface %s", interface); - - index = connman_inet_ifindex(interface); - - connman_network_set_index(network, index); - - connman_network_set_connected(network, true); - - dbus_message_unref(reply); - - dbus_pending_call_unref(call); - - return; -err: - - connman_network_set_connected(network, false); - - dbus_message_unref(reply); - - dbus_pending_call_unref(call); -} - -static int pan_connect(struct connman_network *network) -{ - const char *path = connman_network_get_string(network, "Path"); - const char *uuid = "nap"; - DBusMessage *message; - DBusPendingCall *call; - - DBG("network %p", network); - - if (!path) - return -EINVAL; - - message = dbus_message_new_method_call(BLUEZ_SERVICE, path, - BLUEZ_NETWORK_INTERFACE, CONNECT); - if (!message) - return -ENOMEM; - - dbus_message_set_auto_start(message, FALSE); - - dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid, - DBUS_TYPE_INVALID); - - if (!dbus_connection_send_with_reply(connection, message, - &call, TIMEOUT * 10)) { - connman_error("Failed to connect service"); - dbus_message_unref(message); - return -EINVAL; - } - - if (!call) { - connman_error("D-Bus connection not available"); - dbus_message_unref(message); - return -EINVAL; - } - - dbus_pending_call_set_notify(call, connect_reply, g_strdup(path), - g_free); - - dbus_message_unref(message); - - return -EINPROGRESS; -} - -static void disconnect_reply(DBusPendingCall *call, void *user_data) -{ - char *path = user_data; - struct connman_network *network; - DBusMessage *reply; - DBusError error; - - network = g_hash_table_lookup(bluetooth_networks, path); - if (!network) - return; - - DBG("network %p", network); - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&error); - - if (dbus_set_error_from_message(&error, reply)) { - connman_error("%s", error.message); - dbus_error_free(&error); - goto done; - } - - if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID)) { - if (dbus_error_is_set(&error)) { - connman_error("%s", error.message); - dbus_error_free(&error); - } else - connman_error("Wrong arguments for disconnect"); - goto done; - } - - connman_network_set_connected(network, false); - -done: - dbus_message_unref(reply); - - dbus_pending_call_unref(call); - - connman_network_unref(network); -} - -static int pan_disconnect(struct connman_network *network) -{ - const char *path = connman_network_get_string(network, "Path"); - DBusMessage *message; - DBusPendingCall *call; - - DBG("network %p", network); - - if (!path) - return -EINVAL; - -#if defined TIZEN_EXT - if (connman_network_get_associating(network) == TRUE) { - connman_network_set_error(network, - CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); - } -#endif - - message = dbus_message_new_method_call(BLUEZ_SERVICE, path, - BLUEZ_NETWORK_INTERFACE, DISCONNECT); - if (!message) - return -ENOMEM; - - dbus_message_set_auto_start(message, FALSE); - - dbus_message_append_args(message, DBUS_TYPE_INVALID); - - if (!dbus_connection_send_with_reply(connection, message, - &call, TIMEOUT)) { - connman_error("Failed to disconnect service"); - dbus_message_unref(message); - return -EINVAL; - } - - if (!call) { - connman_error("D-Bus connection not available"); - dbus_message_unref(message); - return -EINVAL; - } - - connman_network_ref(network); - - connman_network_set_associating(network, false); - - dbus_pending_call_set_notify(call, disconnect_reply, g_strdup(path), - g_free); - - dbus_message_unref(message); - - return 0; -} - -static struct connman_network_driver pan_driver = { - .name = "bluetooth_legacy-pan", - .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN, - .priority = CONNMAN_NETWORK_PRIORITY_LOW, - .probe = pan_probe, - .remove = pan_remove, - .connect = pan_connect, - .disconnect = pan_disconnect, -}; - -static gboolean network_changed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path = dbus_message_get_path(message); - struct connman_network *network; - DBusMessageIter iter, value; - const char *key; - - DBG("path %s", path); - - network = g_hash_table_lookup(bluetooth_networks, path); - if (!network) - return TRUE; - - if (!dbus_message_iter_init(message, &iter)) - return TRUE; - - dbus_message_iter_get_basic(&iter, &key); - - dbus_message_iter_next(&iter); - dbus_message_iter_recurse(&iter, &value); - - if (g_str_equal(key, "Connected")) { - dbus_bool_t connected; - - dbus_message_iter_get_basic(&value, &connected); - - if (connected) - return TRUE; - - connman_network_set_associating(network, false); - connman_network_set_connected(network, false); - } - - return TRUE; -} - -static void parse_peer_device(DBusMessage *message, char **dev, - char **address) -{ - const char *path = dbus_message_get_path(message); - DBusMessageIter iter; - - DBG("path %s", path); - - if (dbus_message_iter_init(message, &iter) == FALSE) - return; - - dbus_message_iter_get_basic(&iter, dev); - dbus_message_iter_next(&iter); - dbus_message_iter_get_basic(&iter, address); -} - -static gboolean peer_connected(DBusConnection *connection, - DBusMessage *message, void *user_data) -{ - char *dev, *address; - - parse_peer_device(message, &dev, &address); - - DBG("connection device is %s", dev); - DBG("connection address is %s", address); - - connman_technology_tethering_add_station( - CONNMAN_SERVICE_TYPE_BLUETOOTH, address); - - return TRUE; -} - -static gboolean peer_disconnected(DBusConnection *connection, - DBusMessage *message, void *user_data) -{ - char *dev, *address; - - parse_peer_device(message, &dev, &address); - - DBG("disconnection device is %s", dev); - DBG("disconnection address is %s", address); - - connman_technology_tethering_remove_station(address); - - return TRUE; -} - -static void extract_properties(DBusMessage *reply, const char **parent, - const char **address, - const char **name, - const char **alias, - dbus_bool_t *powered, - dbus_bool_t *scanning, - DBusMessageIter *uuids, - DBusMessageIter *networks) -{ - DBusMessageIter array, dict; - - if (!dbus_message_iter_init(reply, &array)) - return; - - if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(&array, &dict); - - while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { - DBusMessageIter entry, value; - const char *key; - - dbus_message_iter_recurse(&dict, &entry); - dbus_message_iter_get_basic(&entry, &key); - - dbus_message_iter_next(&entry); - dbus_message_iter_recurse(&entry, &value); - - if (g_str_equal(key, "Adapter")) { - if (parent) - dbus_message_iter_get_basic(&value, parent); - } else if (g_str_equal(key, "Address")) { - if (address) - dbus_message_iter_get_basic(&value, address); - } else if (g_str_equal(key, "Name")) { - if (name) - dbus_message_iter_get_basic(&value, name); - } else if (g_str_equal(key, "Alias")) { - if (alias) - dbus_message_iter_get_basic(&value, alias); - } else if (g_str_equal(key, "Powered")) { - if (powered) - dbus_message_iter_get_basic(&value, powered); - } else if (g_str_equal(key, "Discovering")) { - if (scanning) - dbus_message_iter_get_basic(&value, scanning); - } else if (g_str_equal(key, "Devices")) { - if (networks) - memcpy(networks, &value, sizeof(value)); - } else if (g_str_equal(key, "UUIDs")) { - if (uuids) - memcpy(uuids, &value, sizeof(value)); - } - - dbus_message_iter_next(&dict); - } -} - -static dbus_bool_t has_pan(DBusMessageIter *array) -{ - DBusMessageIter value; - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return FALSE; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) { - const char *uuid; - - dbus_message_iter_get_basic(&value, &uuid); - - if (g_strcmp0(uuid, UUID_NAP) == 0) - return TRUE; - - dbus_message_iter_next(&value); - } - - return FALSE; -} - -static void network_properties_reply(DBusPendingCall *call, void *user_data) -{ - char *path = user_data; - struct connman_device *device; - struct connman_network *network; - DBusMessage *reply; - DBusMessageIter uuids; - const char *parent = NULL, *address = NULL, *name = NULL; - struct ether_addr addr; - char ident[13]; - - reply = dbus_pending_call_steal_reply(call); - - extract_properties(reply, &parent, &address, NULL, &name, - NULL, NULL, &uuids, NULL); - - if (!parent) - goto done; - - device = g_hash_table_lookup(bluetooth_devices, parent); - if (!device) - goto done; - - if (!address) - goto done; - - ether_aton_r(address, &addr); - - snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x", - addr.ether_addr_octet[0], - addr.ether_addr_octet[1], - addr.ether_addr_octet[2], - addr.ether_addr_octet[3], - addr.ether_addr_octet[4], - addr.ether_addr_octet[5]); - - if (!has_pan(&uuids)) - goto done; - - network = connman_device_get_network(device, ident); - if (network) - goto done; - - network = connman_network_create(ident, - CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN); - if (!network) - goto done; - - connman_network_set_string(network, "Path", path); - - connman_network_set_name(network, name); - - g_hash_table_replace(bluetooth_networks, g_strdup(path), network); - - connman_device_add_network(device, network); - - connman_network_set_group(network, ident); - -done: - dbus_message_unref(reply); - - dbus_pending_call_unref(call); -} - -static void add_network(const char *path) -{ - DBusMessage *message; - DBusPendingCall *call; - - DBG("path %s", path); - - message = dbus_message_new_method_call(BLUEZ_SERVICE, path, - BLUEZ_DEVICE_INTERFACE, GET_PROPERTIES); - if (!message) - return; - - dbus_message_set_auto_start(message, FALSE); - - if (!dbus_connection_send_with_reply(connection, message, - &call, TIMEOUT)) { - connman_error("Failed to get network properties for %s", path); - goto done; - } - - if (!call) { - connman_error("D-Bus connection not available"); - goto done; - } - - dbus_pending_call_set_notify(call, network_properties_reply, - g_strdup(path), g_free); - -done: - dbus_message_unref(message); -} - -static void check_networks(DBusMessageIter *array) -{ - DBusMessageIter value; - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - add_network(path); - - dbus_message_iter_next(&value); - } -} - -static void check_pending_networks(const char *adapter) -{ - GSList *networks, *list; - - networks = g_hash_table_lookup(pending_networks, adapter); - if (!networks) - return; - - for (list = networks; list; list = list->next) { - char *path = list->data; - - add_network(path); - } - - g_hash_table_remove(pending_networks, adapter); -} - -static gboolean adapter_changed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path = dbus_message_get_path(message); - struct connman_device *device; - DBusMessageIter iter, value; - const char *key; - - DBG("path %s", path); - - device = g_hash_table_lookup(bluetooth_devices, path); - if (!device) - return TRUE; - - if (!dbus_message_iter_init(message, &iter)) - return TRUE; - - dbus_message_iter_get_basic(&iter, &key); - - dbus_message_iter_next(&iter); - dbus_message_iter_recurse(&iter, &value); - - if (g_str_equal(key, "Powered")) { - dbus_bool_t val; - - dbus_message_iter_get_basic(&value, &val); - connman_device_set_powered(device, val); - if (val) - check_pending_networks(path); - } else if (g_str_equal(key, "Discovering")) { - dbus_bool_t val; - - dbus_message_iter_get_basic(&value, &val); - connman_device_set_scanning(device, - CONNMAN_SERVICE_TYPE_BLUETOOTH, val); - } else if (g_str_equal(key, "Devices")) { - check_networks(&value); - } - - return TRUE; -} - -static gboolean device_removed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *network_path; - struct connman_network *network; - struct connman_device *device; - DBusMessageIter iter; - - DBG(""); - - if (!dbus_message_iter_init(message, &iter)) - return TRUE; - - dbus_message_iter_get_basic(&iter, &network_path); - - network = g_hash_table_lookup(bluetooth_networks, network_path); - if (!network) - return TRUE; - - device = connman_network_get_device(network); - if (!device) - return TRUE; - - g_hash_table_remove(bluetooth_networks, network_path); - - return TRUE; -} - -static gboolean device_changed(DBusConnection *conn, - DBusMessage *message, void *user_data) -{ - const char *path = dbus_message_get_path(message); - DBusMessageIter iter, value; - const char *key; - - DBG("path %s", path); - - if (!dbus_message_iter_init(message, &iter)) - return TRUE; - - dbus_message_iter_get_basic(&iter, &key); - - dbus_message_iter_next(&iter); - dbus_message_iter_recurse(&iter, &value); - - DBG("key %s", key); - - if (g_str_equal(key, "UUIDs")) - add_network(path); - - return TRUE; -} - -static void remove_device_networks(struct connman_device *device) -{ - GHashTableIter iter; - gpointer key, value; - GSList *key_list = NULL; - GSList *list; - - if (!bluetooth_networks) - return; - - g_hash_table_iter_init(&iter, bluetooth_networks); - - while (g_hash_table_iter_next(&iter, &key, &value)) { - struct connman_network *network = value; - - if (connman_network_get_device(network) != device) - continue; - - key_list = g_slist_prepend(key_list, key); - } - - for (list = key_list; list; list = list->next) { - const char *network_path = list->data; - - g_hash_table_remove(bluetooth_networks, network_path); - } - - g_slist_free(key_list); -} - -static void add_pending_networks(const char *adapter, DBusMessageIter *array) -{ - DBusMessageIter value; - GSList *list = NULL; - - if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(array, &value); - - while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) { - const char *path; - - dbus_message_iter_get_basic(&value, &path); - - list = g_slist_prepend(list, g_strdup(path)); - - dbus_message_iter_next(&value); - } - - if (!list) - return; - - g_hash_table_replace(pending_networks, g_strdup(adapter), list); -} - -static void adapter_properties_reply(DBusPendingCall *call, void *user_data) -{ - char *path = user_data; - struct connman_device *device; - DBusMessage *reply; - DBusMessageIter networks; - const char *address = NULL, *name = NULL; - dbus_bool_t powered = FALSE, scanning = FALSE; - struct ether_addr addr; - char ident[13]; - - DBG("path %s", path); - - reply = dbus_pending_call_steal_reply(call); - - if (!path) - goto done; - - extract_properties(reply, NULL, &address, &name, NULL, - &powered, &scanning, NULL, &networks); - - if (!address) - goto done; - - if (g_strcmp0(address, "00:00:00:00:00:00") == 0) - goto done; - - device = g_hash_table_lookup(bluetooth_devices, path); - if (device) - goto update; - - ether_aton_r(address, &addr); - - snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x", - addr.ether_addr_octet[0], - addr.ether_addr_octet[1], - addr.ether_addr_octet[2], - addr.ether_addr_octet[3], - addr.ether_addr_octet[4], - addr.ether_addr_octet[5]); - - device = connman_device_create("bluetooth_legacy", - CONNMAN_DEVICE_TYPE_BLUETOOTH); - if (!device) - goto done; - - g_hash_table_insert(bluetooth_devices, g_strdup(path), device); - - connman_device_set_ident(device, ident); - - connman_device_set_string(device, "Path", path); - - if (connman_device_register(device) < 0) { - connman_device_unref(device); - g_hash_table_remove(bluetooth_devices, path); - goto done; - } - -update: - connman_device_set_string(device, "Address", address); - connman_device_set_string(device, "Name", name); - connman_device_set_string(device, "Path", path); - - connman_device_set_powered(device, powered); - connman_device_set_scanning(device, - CONNMAN_SERVICE_TYPE_BLUETOOTH, scanning); - - if (!powered) { - remove_device_networks(device); - add_pending_networks(path, &networks); - } else - check_networks(&networks); - -done: - dbus_message_unref(reply); - - dbus_pending_call_unref(call); -} - -static void add_adapter(DBusConnection *conn, const char *path) -{ - DBusMessage *message; - DBusPendingCall *call; - - DBG("path %s", path); - - message = dbus_message_new_method_call(BLUEZ_SERVICE, path, - BLUEZ_ADAPTER_INTERFACE, GET_PROPERTIES); - if (!message) - return; - - dbus_message_set_auto_start(message, FALSE); - - if (!dbus_connection_send_with_reply(conn, message, &call, TIMEOUT)) { - connman_error("Failed to get adapter properties for %s", path); - goto done; - } - - if (!call) { - connman_error("D-Bus connection not available"); - goto done; - } - - dbus_pending_call_set_notify(call, adapter_properties_reply, - g_strdup(path), g_free); - -done: - dbus_message_unref(message); -} - -static gboolean adapter_added(DBusConnection *conn, DBusMessage *message, - void *user_data) -{ - const char *path; - - dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - add_adapter(conn, path); - return TRUE; -} - -static void remove_adapter(DBusConnection *conn, const char *path) -{ - DBG("path %s", path); - - g_hash_table_remove(bluetooth_devices, path); - g_hash_table_remove(pending_networks, path); -} - -static gboolean adapter_removed(DBusConnection *conn, DBusMessage *message, - void *user_data) -{ - const char *path; - - dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - remove_adapter(conn, path); - return TRUE; -} - -static void list_adapters_reply(DBusPendingCall *call, void *user_data) -{ - DBusMessage *reply; - DBusError error; - char **adapters; - int i, num_adapters; - - DBG(""); - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&error); - - if (dbus_set_error_from_message(&error, reply)) { - connman_error("%s", error.message); - dbus_error_free(&error); - goto done; - } - - if (!dbus_message_get_args(reply, &error, DBUS_TYPE_ARRAY, - DBUS_TYPE_OBJECT_PATH, &adapters, - &num_adapters, DBUS_TYPE_INVALID)) { - if (dbus_error_is_set(&error)) { - connman_error("%s", error.message); - dbus_error_free(&error); - } else - connman_error("Wrong arguments for adapter list"); - goto done; - } - - for (i = 0; i < num_adapters; i++) - add_adapter(connection, adapters[i]); - - g_strfreev(adapters); - -done: - dbus_message_unref(reply); - - dbus_pending_call_unref(call); -} - -static void unregister_device(gpointer data) -{ - struct connman_device *device = data; - - DBG(""); - - remove_device_networks(device); - - connman_device_unregister(device); - connman_device_unref(device); -} - -static void remove_network(gpointer data) -{ - struct connman_network *network = data; - struct connman_device *device; - - DBG("network %p", network); - - device = connman_network_get_device(network); - if (device) - connman_device_remove_network(device, network); - - connman_network_unref(network); -} - -static void remove_pending_networks(gpointer data) -{ - GSList *list = data; - - g_slist_free_full(list, g_free); -} - -static void bluetooth_connect(DBusConnection *conn, void *user_data) -{ - DBusMessage *message; - DBusPendingCall *call; - - DBG("connection %p", conn); - - bluetooth_devices = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, unregister_device); - - bluetooth_networks = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, remove_network); - - pending_networks = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, remove_pending_networks); - - message = dbus_message_new_method_call(BLUEZ_SERVICE, "/", - BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS); - if (!message) - return; - - dbus_message_set_auto_start(message, FALSE); - - if (!dbus_connection_send_with_reply(conn, message, &call, TIMEOUT)) { - connman_error("Failed to get Bluetooth adapters"); - goto done; - } - - if (!call) { - connman_error("D-Bus connection not available"); - goto done; - } - - dbus_pending_call_set_notify(call, list_adapters_reply, NULL, NULL); - -done: - dbus_message_unref(message); -} - -static void bluetooth_disconnect(DBusConnection *conn, void *user_data) -{ - DBG("connection %p", conn); - - if (!bluetooth_devices) - return; - - g_hash_table_destroy(bluetooth_networks); - bluetooth_networks = NULL; - g_hash_table_destroy(bluetooth_devices); - bluetooth_devices = NULL; - g_hash_table_destroy(pending_networks); - pending_networks = NULL; -} - -static int bluetooth_probe(struct connman_device *device) -{ - GHashTableIter iter; - gpointer key, value; - - DBG("device %p", device); - - if (!bluetooth_devices) - return -ENOTSUP; - - g_hash_table_iter_init(&iter, bluetooth_devices); - - while (g_hash_table_iter_next(&iter, &key, &value)) { - struct connman_device *device_pan = value; - - if (device == device_pan) - return 0; - } - - return -ENOTSUP; -} - -static void bluetooth_remove(struct connman_device *device) -{ - DBG("device %p", device); -} - -static void powered_reply(DBusPendingCall *call, void *user_data) -{ - DBusError error; - DBusMessage *reply; - - DBG(""); - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&error); - - if (dbus_set_error_from_message(&error, reply)) { - connman_error("%s", error.message); - dbus_error_free(&error); - dbus_message_unref(reply); - dbus_pending_call_unref(call); - return; - } - - dbus_message_unref(reply); - dbus_pending_call_unref(call); - - add_adapter(connection, user_data); -} - -static int change_powered(DBusConnection *conn, const char *path, - dbus_bool_t powered) -{ - DBusMessage *message; - DBusMessageIter iter; - DBusPendingCall *call; - - DBG(""); - - if (!path) - return -EINVAL; - - message = dbus_message_new_method_call(BLUEZ_SERVICE, path, - BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY); - if (!message) - return -ENOMEM; - - dbus_message_set_auto_start(message, FALSE); - - dbus_message_iter_init_append(message, &iter); - connman_dbus_property_append_basic(&iter, "Powered", - DBUS_TYPE_BOOLEAN, &powered); - - if (!dbus_connection_send_with_reply(conn, message, &call, TIMEOUT)) { - connman_error("Failed to change Powered property"); - dbus_message_unref(message); - return -EINVAL; - } - - if (!call) { - connman_error("D-Bus connection not available"); - dbus_message_unref(message); - return -EINVAL; - } - - dbus_pending_call_set_notify(call, powered_reply, - g_strdup(path), g_free); - - dbus_message_unref(message); - - return -EINPROGRESS; -} - -static int bluetooth_enable(struct connman_device *device) -{ - const char *path = connman_device_get_string(device, "Path"); - - DBG("device %p", device); - - return change_powered(connection, path, TRUE); -} - -static int bluetooth_disable(struct connman_device *device) -{ - const char *path = connman_device_get_string(device, "Path"); - - DBG("device %p", device); - - return change_powered(connection, path, FALSE); -} - -static struct connman_device_driver bluetooth_driver = { - .name = "bluetooth_legacy", - .type = CONNMAN_DEVICE_TYPE_BLUETOOTH, - .probe = bluetooth_probe, - .remove = bluetooth_remove, - .enable = bluetooth_enable, - .disable = bluetooth_disable, -}; - -static int tech_probe(struct connman_technology *technology) -{ - return 0; -} - -static void tech_remove(struct connman_technology *technology) -{ -} - -static void server_register_reply(DBusPendingCall *call, void *user_data) -{ - struct connman_technology *technology = user_data; - DBusError error; - DBusMessage *reply; - - DBG(""); - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&error); - - if (dbus_set_error_from_message(&error, reply)) { - connman_error("%s", error.message); - dbus_error_free(&error); - dbus_message_unref(reply); - dbus_pending_call_unref(call); - return; - } - - dbus_message_unref(reply); - dbus_pending_call_unref(call); - - connman_technology_tethering_notify(technology, true); -} - -static void server_unregister_reply(DBusPendingCall *call, void *user_data) -{ - struct connman_technology *technology = user_data; - DBusError error; - DBusMessage *reply; - - DBG(""); - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&error); - - if (dbus_set_error_from_message(&error, reply)) { - connman_error("%s", error.message); - dbus_error_free(&error); - dbus_message_unref(reply); - dbus_pending_call_unref(call); - return; - } - - dbus_message_unref(reply); - dbus_pending_call_unref(call); - - connman_technology_tethering_notify(technology, false); -} - - -static void server_register(const char *path, const char *uuid, - struct connman_technology *technology, - const char *bridge, bool enabled) -{ - DBusMessage *message; - DBusPendingCall *call; - char *command; - - DBG("path %s enabled %d", path, enabled); - - command = enabled ? REGISTER : UNREGISTER; - - message = dbus_message_new_method_call(BLUEZ_SERVICE, path, - BLUEZ_NETWORK_SERVER, command); - if (!message) - return; - - dbus_message_set_auto_start(message, FALSE); - - dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid, - DBUS_TYPE_INVALID); - - if (enabled) - dbus_message_append_args(message, DBUS_TYPE_STRING, &bridge, - DBUS_TYPE_INVALID); - - if (!dbus_connection_send_with_reply(connection, message, - &call, TIMEOUT)) { - connman_error("Failed to enable PAN server"); - dbus_message_unref(message); - return; - } - - if (!call) { - connman_error("D-Bus connection not available"); - dbus_message_unref(message); - return; - } - - if (enabled) - dbus_pending_call_set_notify(call, server_register_reply, - technology, NULL); - else - dbus_pending_call_set_notify(call, server_unregister_reply, - technology, NULL); - - dbus_message_unref(message); -} - -struct tethering_info { - struct connman_technology *technology; - const char *bridge; -}; - -static void enable_nap(gpointer key, gpointer value, gpointer user_data) -{ - struct tethering_info *info = user_data; - struct connman_device *device = value; - const char *path; - - DBG(""); - - path = connman_device_get_string(device, "Path"); - - server_register(path, "nap", info->technology, info->bridge, true); -} - -static void disable_nap(gpointer key, gpointer value, gpointer user_data) -{ - struct tethering_info *info = user_data; - struct connman_device *device = value; - const char *path; - - DBG(""); - - path = connman_device_get_string(device, "Path"); - - server_register(path, "nap", info->technology, info->bridge, false); -} - -static int tech_set_tethering(struct connman_technology *technology, - const char *identifier, const char *passphrase, - const char *bridge, bool enabled, bool hidden) -{ - struct tethering_info info = { - .technology = technology, - .bridge = bridge, - }; - - DBG("bridge %s", bridge); - - if (!bluetooth_devices) - return -ENOTCONN; - - if (enabled) - g_hash_table_foreach(bluetooth_devices, enable_nap, &info); - else - g_hash_table_foreach(bluetooth_devices, disable_nap, &info); - - return 0; -} - -static struct connman_technology_driver tech_driver = { - .name = "bluetooth_legacy", - .type = CONNMAN_SERVICE_TYPE_BLUETOOTH, - .priority = -10, - .probe = tech_probe, - .remove = tech_remove, - .set_tethering = tech_set_tethering, -}; - -static guint watch; -static guint added_watch; -static guint removed_watch; -static guint adapter_watch; -static guint device_watch; -static guint device_removed_watch; -static guint network_watch; -static guint peerconnected_watch; -static guint peerdisconnected_watch; - -static int bluetooth_init(void) -{ - int err; - - connection = connman_dbus_get_connection(); - if (!connection) - return -EIO; - - watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE, - bluetooth_connect, bluetooth_disconnect, NULL, NULL); - - added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, NULL, - BLUEZ_MANAGER_INTERFACE, - ADAPTER_ADDED, adapter_added, - NULL, NULL); - - removed_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, NULL, - BLUEZ_MANAGER_INTERFACE, - ADAPTER_REMOVED, adapter_removed, - NULL, NULL); - - adapter_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, - NULL, BLUEZ_ADAPTER_INTERFACE, - PROPERTY_CHANGED, adapter_changed, - NULL, NULL); - - device_removed_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, NULL, - BLUEZ_ADAPTER_INTERFACE, - DEVICE_REMOVED, device_removed, - NULL, NULL); - - device_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, NULL, - BLUEZ_DEVICE_INTERFACE, - PROPERTY_CHANGED, device_changed, - NULL, NULL); - - network_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, - NULL, BLUEZ_NETWORK_INTERFACE, - PROPERTY_CHANGED, network_changed, - NULL, NULL); - - peerconnected_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, - NULL, BLUEZ_NETWORK_SERVER, - PEER_CONNECTED, peer_connected, - NULL, NULL); - - peerdisconnected_watch = g_dbus_add_signal_watch(connection, - BLUEZ_SERVICE, - NULL, BLUEZ_NETWORK_SERVER, - PEER_DISCONNECTED, - peer_disconnected, - NULL, NULL); - - if (watch == 0 || added_watch == 0 || removed_watch == 0 - || adapter_watch == 0 || network_watch == 0 || device_watch == 0 - || peerconnected_watch == 0 || peerdisconnected_watch == 0 - || device_removed_watch == 0) { - err = -EIO; - goto remove; - } - - err = connman_network_driver_register(&pan_driver); - if (err < 0) - goto remove; - - err = connman_device_driver_register(&bluetooth_driver); - if (err < 0) { - connman_network_driver_unregister(&pan_driver); - goto remove; - } - - err = connman_technology_driver_register(&tech_driver); - if (err < 0) { - connman_device_driver_unregister(&bluetooth_driver); - connman_network_driver_unregister(&pan_driver); - goto remove; - } - - return 0; - -remove: - g_dbus_remove_watch(connection, watch); - g_dbus_remove_watch(connection, added_watch); - g_dbus_remove_watch(connection, removed_watch); - g_dbus_remove_watch(connection, adapter_watch); - g_dbus_remove_watch(connection, device_removed_watch); - g_dbus_remove_watch(connection, device_watch); - g_dbus_remove_watch(connection, network_watch); - g_dbus_remove_watch(connection, peerconnected_watch); - g_dbus_remove_watch(connection, peerdisconnected_watch); - - dbus_connection_unref(connection); - - return err; -} - -static void bluetooth_exit(void) -{ - g_dbus_remove_watch(connection, watch); - g_dbus_remove_watch(connection, added_watch); - g_dbus_remove_watch(connection, removed_watch); - g_dbus_remove_watch(connection, adapter_watch); - g_dbus_remove_watch(connection, device_removed_watch); - g_dbus_remove_watch(connection, device_watch); - g_dbus_remove_watch(connection, network_watch); - g_dbus_remove_watch(connection, peerconnected_watch); - g_dbus_remove_watch(connection, peerdisconnected_watch); - - /* - * We unset the disabling of the Bluetooth device when shutting down - * so that non-PAN BT connections are not affected. - */ - bluetooth_driver.disable = NULL; - - bluetooth_disconnect(connection, NULL); - - connman_technology_driver_unregister(&tech_driver); - - connman_device_driver_unregister(&bluetooth_driver); - connman_network_driver_unregister(&pan_driver); - - dbus_connection_unref(connection); -} - -CONNMAN_PLUGIN_DEFINE(bluetooth_legacy, "Bluetooth technology plugin (legacy)", - VERSION, CONNMAN_PLUGIN_PRIORITY_LOW, - bluetooth_init, bluetooth_exit) diff --git a/plugins/ethernet.c b/plugins/ethernet.c index 73494f15..9a4d7413 100755 --- a/plugins/ethernet.c +++ b/plugins/ethernet.c @@ -32,6 +32,7 @@ #include <linux/if_vlan.h> #include <linux/sockios.h> +#include <linux/ethtool.h> #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 @@ -83,6 +84,48 @@ static int get_vlan_vid(const char *ifname) return vid; } +static int get_dsa_port(const char *ifname) +{ + int sk; + int dsaport = -1; + struct ifreq ifr; + struct ethtool_cmd cmd; + struct ethtool_drvinfo drvinfocmd; + struct vlan_ioctl_args vifr; + + sk = socket(AF_INET, SOCK_STREAM, 0); + if (sk < 0) + return -errno; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + /* check if it is a vlan and get physical interface name*/ + vifr.cmd = GET_VLAN_REALDEV_NAME_CMD; + strncpy(vifr.device1, ifname, sizeof(vifr.device1)); + + if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0) + strncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name)); + + /* get driver info */ + drvinfocmd.cmd = ETHTOOL_GDRVINFO; + ifr.ifr_data = (caddr_t)&drvinfocmd; + + if (!ioctl(sk, SIOCETHTOOL, &ifr)) { + if(!strcmp(drvinfocmd.driver, "dsa")) { + /* get dsa port*/ + cmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = (caddr_t)&cmd; + + if (!ioctl(sk, SIOCETHTOOL, &ifr)) + dsaport = cmd.phy_address; + } + } + close(sk); + + return dsaport; +} + static int eth_network_probe(struct connman_network *network) { DBG("network %p", network); @@ -126,7 +169,7 @@ static void add_network(struct connman_device *device, struct ethernet_data *ethernet) { struct connman_network *network; - int index, vid; + int index; char *ifname; network = connman_network_create("carrier", @@ -139,7 +182,6 @@ static void add_network(struct connman_device *device, ifname = connman_inet_ifname(index); if (!ifname) return; - vid = get_vlan_vid(ifname); connman_network_set_name(network, "Wired"); @@ -149,14 +191,23 @@ static void add_network(struct connman_device *device, } if (!eth_tethering) { - char group[10] = "cable"; + char group[16] = "cable"; + int vid, dsaport; + + vid = get_vlan_vid(ifname); + dsaport = get_dsa_port(ifname); + /* * Prevent service from starting the reconnect * procedure as we do not want the DHCP client * to run when tethering. */ - if (vid >= 0) + if((vid >= 0) && (dsaport >= 0)) + snprintf(group, sizeof(group), "p%02x_%03x_cable", dsaport, vid); + else if (vid >= 0) snprintf(group, sizeof(group), "%03x_cable", vid); + else if (dsaport >= 0) + snprintf(group, sizeof(group), "p%02x_cable", dsaport); connman_network_set_group(network, group); } @@ -353,7 +404,7 @@ static void eth_tech_disable_tethering(struct connman_technology *technology, static int eth_tech_set_tethering(struct connman_technology *technology, const char *identifier, const char *passphrase, - const char *bridge, bool enabled, bool hidden) + const char *bridge, bool enabled) { if (!connman_technology_is_tethering_allowed( CONNMAN_SERVICE_TYPE_ETHERNET)) diff --git a/plugins/gadget.c b/plugins/gadget.c index 6bc37a7b..cce51e26 100755 --- a/plugins/gadget.c +++ b/plugins/gadget.c @@ -364,7 +364,7 @@ static void gadget_tech_disable_tethering(struct connman_technology *technology, static int gadget_tech_set_tethering(struct connman_technology *technology, const char *identifier, const char *passphrase, - const char *bridge, bool enabled, bool hidden) + const char *bridge, bool enabled) { DBG("bridge %s enabled %d", bridge, enabled); diff --git a/plugins/iwd.c b/plugins/iwd.c new file mode 100644 index 00000000..b5191654 --- /dev/null +++ b/plugins/iwd.c @@ -0,0 +1,1108 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2016 BMW Car IT GmbH. + * + * 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 <string.h> +#include <stdbool.h> +#include <linux/if_ether.h> + +#define CONNMAN_API_SUBJECT_TO_CHANGE +#include <connman/plugin.h> +#include <connman/dbus.h> +#include <connman/network.h> +#include <connman/technology.h> +#include <connman/inet.h> +#include <gdbus.h> + +static DBusConnection *connection; +static GDBusClient *client; +static GDBusProxy *agent_proxy; +static GHashTable *adapters; +static GHashTable *devices; +static GHashTable *networks; +static bool agent_registered; + +#define IWD_SERVICE "net.connman.iwd" +#define IWD_PATH "/" +#define IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager" +#define IWD_ADAPTER_INTERFACE "net.connman.iwd.Adapter" +#define IWD_DEVICE_INTERFACE "net.connman.iwd.Device" +#define IWD_NETWORK_INTERFACE "net.connman.iwd.Network" + +#define IWD_AGENT_INTERFACE "net.connman.iwd.Agent" +#define IWD_AGENT_ERROR_INTERFACE "net.connman.iwd.Agent.Error" +#define AGENT_PATH "/net/connman/iwd_agent" + +enum iwd_device_state { + IWD_DEVICE_STATE_UNKNOWN, + IWD_DEVICE_STATE_CONNECTED, + IWD_DEVICE_STATE_DISCONNECTED, + IWD_DEVICE_STATE_CONNECTING, + IWD_DEVICE_STATE_DISCONNECTING, +}; + +struct iwd_adapter { + GDBusProxy *proxy; + char *path; + char *vendor; + char *model; + bool powered; +}; + +struct iwd_device { + GDBusProxy *proxy; + char *path; + char *adapter; + char *name; + char *address; + enum iwd_device_state state; + bool powered; + bool scanning; + + struct connman_device *device; +}; + +struct iwd_network { + GDBusProxy *proxy; + char *path; + char *device; + char *name; + char *type; + bool connected; + + struct iwd_device *iwdd; + struct connman_network *network; +}; + +static enum iwd_device_state string2state(const char *str) +{ + if (!strcmp(str, "connected")) + return IWD_DEVICE_STATE_CONNECTED; + else if (!strcmp(str, "disconnected")) + return IWD_DEVICE_STATE_DISCONNECTED; + else if (!strcmp(str, "connecting")) + return IWD_DEVICE_STATE_CONNECTING; + else if (!strcmp(str, "disconnecting")) + return IWD_DEVICE_STATE_DISCONNECTING; + + return IWD_DEVICE_STATE_UNKNOWN; +} + +static const char *state2string(enum iwd_device_state state) +{ + switch (state) { + case IWD_DEVICE_STATE_CONNECTED: + return "connected"; + case IWD_DEVICE_STATE_DISCONNECTED: + return "disconnected"; + case IWD_DEVICE_STATE_CONNECTING: + return "connecting"; + case IWD_DEVICE_STATE_DISCONNECTING: + return "disconnecting"; + default: + break; + } + + return "unknown"; +} + +static const char *proxy_get_string(GDBusProxy *proxy, const char *property) +{ + DBusMessageIter iter; + const char *str; + + if (!g_dbus_proxy_get_property(proxy, property, &iter)) + return NULL; + + dbus_message_iter_get_basic(&iter, &str); + + return str; +} + +static bool proxy_get_bool(GDBusProxy *proxy, const char *property) +{ + DBusMessageIter iter; + dbus_bool_t value; + + if (!g_dbus_proxy_get_property(proxy, property, &iter)) + return false; + + dbus_message_iter_get_basic(&iter, &value); + + return value; +} + +static void address2ident(const char *address, char *ident) +{ + int i; + + for (i = 0; i < ETH_ALEN; i++) { + ident[i * 2] = address[i * 3]; + ident[i * 2 + 1] = address[i * 3 + 1]; + } + ident[ETH_ALEN * 2] = '\0'; +} + +static int cm_network_probe(struct connman_network *network) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, networks); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + struct iwd_network *iwdn = value; + + if (network == iwdn->network) + return 0; + } + + return -EOPNOTSUPP; +} + +static void update_network_connected(struct iwd_network *iwdn) +{ + struct iwd_device *iwdd; + int index; + + iwdd = g_hash_table_lookup(devices, iwdn->device); + if (!iwdd) + return; + + index = connman_inet_ifindex(iwdd->name); + if (index < 0) + return; + + DBG("interface name %s index %d", iwdd->name, index); + connman_network_set_index(iwdn->network, index); + connman_network_set_connected(iwdn->network, true); +} + +static void update_network_disconnected(struct iwd_network *iwdn) +{ + DBG("interface name %s", iwdn->name); + connman_network_set_connected(iwdn->network, false); +} + +static void cm_network_connect_cb(DBusMessage *message, void *user_data) +{ + const char *path = user_data; + struct iwd_network *iwdn; + + iwdn = g_hash_table_lookup(networks, path); + if (!iwdn) + return; + + if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) { + const char *dbus_error = dbus_message_get_error_name(message); + + if (!strcmp(dbus_error, "net.connman.iwd.InProgress")) + return; + + DBG("%s connect failed: %s", path, dbus_error); + connman_network_set_error(iwdn->network, + CONNMAN_NETWORK_ERROR_CONNECT_FAIL); + return; + } + + update_network_connected(iwdn); +} + +static int cm_network_connect(struct connman_network *network) +{ + struct iwd_network *iwdn = connman_network_get_data(network); + + if (!iwdn) + return -EINVAL; + + if (!g_dbus_proxy_method_call(iwdn->proxy, "Connect", + NULL, cm_network_connect_cb, + g_strdup(iwdn->path), g_free)) + return -EIO; + + connman_network_set_associating(iwdn->network, true); + + return -EINPROGRESS; +} + +static void cm_network_disconnect_cb(DBusMessage *message, void *user_data) +{ + const char *path = user_data; + struct iwd_network *iwdn; + + iwdn = g_hash_table_lookup(networks, path); + if (!iwdn) + return; + + if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) { + const char *dbus_error = dbus_message_get_error_name(message); + + if (!strcmp(dbus_error, "net.connman.iwd.NotConnected")) { + /* fall through */ + } else { + DBG("%s disconnect failed: %s", path, dbus_error); + return; + } + } + + /* + * We end up in a tight loop in the error case. That is + * when we can't connect, bail out in cm_network_connect_cb() with + * an error. + */ + if (connman_network_get_connected(iwdn->network)) + update_network_disconnected(iwdn); +} + +static int cm_network_disconnect(struct connman_network *network) +{ + struct iwd_network *iwdn = connman_network_get_data(network); + struct iwd_device *iwdd; + + if (!iwdn) + return -EINVAL; + + iwdd = g_hash_table_lookup(devices, iwdn->device); + if (!iwdd) + return -EIO; + + if (!g_dbus_proxy_method_call(iwdd->proxy, "Disconnect", + NULL, cm_network_disconnect_cb, g_strdup(iwdn->path), g_free)) + return -EIO; + + return -EINPROGRESS; +} + +static struct connman_network_driver network_driver = { + .name = "iwd", + .type = CONNMAN_NETWORK_TYPE_WIFI, + .probe = cm_network_probe, + .connect = cm_network_connect, + .disconnect = cm_network_disconnect, +}; + +static int cm_device_probe(struct connman_device *device) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, devices); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + struct iwd_device *iwdd = value; + + if (device == iwdd->device) + return 0; + } + + return -EOPNOTSUPP; +} + +static void cm_device_remove(struct connman_device *device) +{ +} + +struct dev_cb_data { + char *path; + bool powered; +}; + +static void device_powered_cb(const DBusError *error, void *user_data) +{ + struct dev_cb_data *cbd = user_data; + struct iwd_device *iwdd; + + iwdd = g_hash_table_lookup(devices, cbd->path); + if (!iwdd) + goto out; + + if (dbus_error_is_set(error)) { + connman_warn("WiFi device %s not enabled %s", + cbd->path, error->message); + goto out; + } + + connman_device_set_powered(iwdd->device, cbd->powered); +out: + g_free(cbd->path); + g_free(cbd); +} + +static int set_device_powered(struct connman_device *device, bool powered) +{ + struct iwd_device *iwdd = connman_device_get_data(device); + dbus_bool_t device_powered = powered; + struct dev_cb_data *cbd; + + if (proxy_get_bool(iwdd->proxy, "Powered")) + return -EALREADY; + + cbd = g_new(struct dev_cb_data, 1); + cbd->path = g_strdup(iwdd->path); + cbd->powered = powered; + + g_dbus_proxy_set_property_basic(iwdd->proxy, "Powered", + DBUS_TYPE_BOOLEAN, &device_powered, + device_powered_cb, cbd, NULL); + + return -EINPROGRESS; +} + +static int cm_device_enable(struct connman_device *device) +{ + return set_device_powered(device, true); +} + +static int cm_device_disable(struct connman_device *device) +{ + return set_device_powered(device, false); +} + +static struct connman_device_driver device_driver = { + .name = "iwd", + .type = CONNMAN_DEVICE_TYPE_WIFI, + .probe = cm_device_probe, + .remove = cm_device_remove, + .enable = cm_device_enable, + .disable = cm_device_disable, +}; + +static int cm_tech_probe(struct connman_technology *technology) +{ + return 0; +} + +static void cm_tech_remove(struct connman_technology *technology) +{ +} + +static struct connman_technology_driver tech_driver = { + .name = "iwd", + .type = CONNMAN_SERVICE_TYPE_WIFI, + .probe = cm_tech_probe, + .remove = cm_tech_remove, +}; + +static unsigned char calculate_strength(int strength) +{ + unsigned char res; + + /* + * Network's maximum signal strength expressed in 100 * dBm. + * The value is the range of 0 (strongest signal) to -10000 + * (weakest signal) + * + * ConnMan expects it in the range from 100 (strongest) to 0 + * (weakest). + */ + res = (unsigned char)((strength * -10000) / 100); + + return res; +} + +static void _update_signal_strength(const char *path, int16_t signal_strength) +{ + struct iwd_network *iwdn; + + iwdn = g_hash_table_lookup(networks, path); + if (!iwdn) + return; + + if (!iwdn->network) + return; + + connman_network_set_strength(iwdn->network, + calculate_strength(signal_strength)); +} + +static void ordered_networks_cb(DBusMessage *message, void *user_data) +{ + DBusMessageIter array, entry; + + DBG(""); + + if (!dbus_message_iter_init(message, &array)) + return; + + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(&array, &entry); + while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) { + DBusMessageIter value; + const char *path, *name, *type; + int16_t signal_strength; + + + dbus_message_iter_recurse(&entry, &value); + + dbus_message_iter_get_basic(&value, &path); + + dbus_message_iter_next(&value); + dbus_message_iter_get_basic(&value, &name); + + dbus_message_iter_next(&value); + dbus_message_iter_get_basic(&value, &signal_strength); + + dbus_message_iter_next(&value); + dbus_message_iter_get_basic(&value, &type); + + _update_signal_strength(path, signal_strength); + + dbus_message_iter_next(&entry); + } +} + +static void update_signal_strength(struct iwd_device *iwdd) +{ + if (!g_dbus_proxy_method_call(iwdd->proxy, + "GetOrderedNetworks", + NULL, ordered_networks_cb, + NULL, NULL)) + DBG("GetOrderedNetworks() failed"); +} + +static void add_network(const char *path, struct iwd_network *iwdn) +{ + struct iwd_device *iwdd; + const char *identifier; + + iwdd = g_hash_table_lookup(devices, iwdn->device); + if (!iwdd) + return; + + identifier = strrchr(path, '/'); + identifier++; /* strip leading slash as well */ + iwdn->network = connman_network_create(identifier, + CONNMAN_NETWORK_TYPE_WIFI); + connman_network_set_data(iwdn->network, iwdn); + + connman_network_set_name(iwdn->network, iwdn->name); + connman_network_set_blob(iwdn->network, "WiFi.SSID", iwdn->name, + strlen(iwdn->name)); + connman_network_set_string(iwdn->network, "WiFi.Security", + iwdn->type); + + if (connman_device_add_network(iwdd->device, iwdn->network) < 0) { + connman_network_unref(iwdn->network); + iwdn->network = NULL; + return; + } + iwdn->iwdd = iwdd; + + connman_network_set_available(iwdn->network, true); + connman_network_set_group(iwdn->network, identifier); +} + +static void remove_network(struct iwd_network *iwdn) +{ + if (!iwdn->network) + return; + + if (iwdn->iwdd) + connman_device_remove_network(iwdn->iwdd->device, + iwdn->network); + + connman_network_unref(iwdn->network); + iwdn->network = NULL; +} + +static void add_device(const char *path, struct iwd_device *iwdd) +{ + char ident[ETH_ALEN * 2 + 1]; + + iwdd->device = connman_device_create("wifi", CONNMAN_DEVICE_TYPE_WIFI); + if (!iwdd->device) + return; + + connman_device_set_data(iwdd->device, iwdd); + + address2ident(iwdd->address, ident); + connman_device_set_ident(iwdd->device, ident); + + if (connman_device_register(iwdd->device) < 0) { + g_hash_table_remove(devices, path); + return; + } + + connman_device_set_powered(iwdd->device, iwdd->powered); +} + +static void remove_device_networks(struct iwd_device *iwdd) +{ + GHashTableIter iter; + gpointer key, value; + struct iwd_network *iwdn; + GSList *list, *nets = NULL; + + g_hash_table_iter_init(&iter, networks); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + iwdn = value; + + if (!strcmp(iwdd->path, iwdn->device)) + nets = g_slist_prepend(nets, iwdn); + } + + for (list = nets; list; list = list->next) { + iwdn = list->data; + g_hash_table_remove(networks, iwdn->path); + } + + g_slist_free(nets); +} + +static void remove_device(struct iwd_device *iwdd) +{ + if (!iwdd->device) + return; + + remove_device_networks(iwdd); + connman_device_unregister(iwdd->device); + connman_device_unref(iwdd->device); + iwdd->device = NULL; +} + +static void adapter_property_change(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter, void *user_data) +{ + struct iwd_adapter *adapter; + const char *path; + + path = g_dbus_proxy_get_path(proxy); + adapter = g_hash_table_lookup(adapters, path); + if (!adapter) + return; + + if (!strcmp(name, "Powered")) { + dbus_bool_t powered; + + dbus_message_iter_get_basic(iter, &powered); + adapter->powered = powered; + + DBG("%p powered %d", path, adapter->powered); + } +} + +static void device_property_change(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter, void *user_data) +{ + struct iwd_device *iwdd; + const char *path; + + path = g_dbus_proxy_get_path(proxy); + iwdd = g_hash_table_lookup(devices, path); + if (!iwdd) + return; + + if (!strcmp(name, "Name")) { + const char *name; + + dbus_message_iter_get_basic(iter, &name); + g_free(iwdd->name); + iwdd->name = g_strdup(name); + + DBG("%p name %s", path, iwdd->name); + } else if (!strcmp(name, "State")) { + const char *state; + + dbus_message_iter_get_basic(iter, &state); + iwdd->state = string2state(state); + + DBG("%s state %s", path, state2string(iwdd->state)); + } else if (!strcmp(name, "Powered")) { + dbus_bool_t powered; + + dbus_message_iter_get_basic(iter, &powered); + iwdd->powered = powered; + + DBG("%s powered %d", path, iwdd->powered); + } else if (!strcmp(name, "Scanning")) { + dbus_bool_t scanning; + + dbus_message_iter_get_basic(iter, &scanning); + iwdd->scanning = scanning; + + DBG("%s scanning %d", path, iwdd->scanning); + + if (!iwdd->scanning) + update_signal_strength(iwdd); + + } +} + +static void network_property_change(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter, void *user_data) +{ + struct iwd_network *iwdn; + const char *path; + + path = g_dbus_proxy_get_path(proxy); + iwdn = g_hash_table_lookup(networks, path); + if (!iwdn) + return; + + if (!strcmp(name, "Connected")) { + dbus_bool_t connected; + + dbus_message_iter_get_basic(iter, &connected); + iwdn->connected = connected; + + DBG("%s connected %d", path, iwdn->connected); + + if (iwdn->connected) + update_network_connected(iwdn); + else + update_network_disconnected(iwdn); + } +} + +static void adapter_free(gpointer data) +{ + struct iwd_adapter *iwda = data; + + if (iwda->proxy) { + g_dbus_proxy_unref(iwda->proxy); + iwda->proxy = NULL; + } + + g_free(iwda->path); + g_free(iwda->vendor); + g_free(iwda->model); + g_free(iwda); +} + +static void device_free(gpointer data) +{ + struct iwd_device *iwdd = data; + + if (iwdd->proxy) { + g_dbus_proxy_unref(iwdd->proxy); + iwdd->proxy = NULL; + } + + remove_device(iwdd); + + g_free(iwdd->path); + g_free(iwdd->adapter); + g_free(iwdd->name); + g_free(iwdd->address); + g_free(iwdd); +} + +static void network_free(gpointer data) +{ + struct iwd_network *iwdn = data; + + if (iwdn->proxy) { + g_dbus_proxy_unref(iwdn->proxy); + iwdn->proxy = NULL; + } + + remove_network(iwdn); + + g_free(iwdn->path); + g_free(iwdn->device); + g_free(iwdn->name); + g_free(iwdn->type); + g_free(iwdn); +} + +static void create_adapter(GDBusProxy *proxy) +{ + const char *path = g_dbus_proxy_get_path(proxy); + struct iwd_adapter *iwda; + + iwda = g_try_new0(struct iwd_adapter, 1); + + if (!iwda) { + connman_error("Out of memory creating IWD adapter"); + return; + } + + iwda->path = g_strdup(path); + g_hash_table_replace(adapters, iwda->path, iwda); + + iwda->proxy = g_dbus_proxy_ref(proxy); + + if (!iwda->proxy) { + connman_error("Cannot create IWD adapter watcher %s", path); + g_hash_table_remove(adapters, path); + return; + } + + iwda->vendor = g_strdup(proxy_get_string(proxy, "Vendor")); + iwda->model = g_strdup(proxy_get_string(proxy, "Model")); + iwda->powered = proxy_get_bool(proxy, "Powered"); + + DBG("%s vendor '%s' model '%s' powered %d", path, iwda->vendor, + iwda->model, iwda->powered); + + g_dbus_proxy_set_property_watch(iwda->proxy, + adapter_property_change, NULL); +} + +static void create_device(GDBusProxy *proxy) +{ + const char *path = g_dbus_proxy_get_path(proxy); + struct iwd_device *iwdd; + + iwdd = g_try_new0(struct iwd_device, 1); + + if (!iwdd) { + connman_error("Out of memory creating IWD device"); + return; + } + + iwdd->path = g_strdup(path); + g_hash_table_replace(devices, iwdd->path, iwdd); + + iwdd->proxy = g_dbus_proxy_ref(proxy); + + if (!iwdd->proxy) { + connman_error("Cannot create IWD device watcher %s", path); + g_hash_table_remove(devices, path); + return; + } + + iwdd->adapter = g_strdup(proxy_get_string(proxy, "Adapter")); + iwdd->name = g_strdup(proxy_get_string(proxy, "Name")); + iwdd->address = g_strdup(proxy_get_string(proxy, "Address")); + iwdd->state = string2state(proxy_get_string(proxy, "State")); + iwdd->powered = proxy_get_bool(proxy, "Powered"); + iwdd->scanning = proxy_get_bool(proxy, "Scanning"); + + DBG("adapter %s name %s address %s state %s powered %d scanning %d", + iwdd->adapter, iwdd->name, iwdd->address, + state2string(iwdd->state), + iwdd->powered, iwdd->scanning); + + g_dbus_proxy_set_property_watch(iwdd->proxy, + device_property_change, NULL); + + add_device(path, iwdd); +} + +static void unregister_agent(); + +static DBusMessage *agent_release_method(DBusConnection *dbus_conn, + DBusMessage *message, void *user_data) +{ + unregister_agent(); + return g_dbus_create_reply(message, DBUS_TYPE_INVALID); +} + +static DBusMessage *get_reply_on_error(DBusMessage *message, int error) +{ + return g_dbus_create_error(message, + IWD_AGENT_ERROR_INTERFACE ".Failed", "Invalid parameters"); +} + +static DBusMessage *agent_request_passphrase(DBusConnection *dbus_conn, + DBusMessage *message, + void *user_data) +{ + struct iwd_network *iwdn; + DBusMessageIter iter; + const char *path, *passwd; + + DBG(""); + + dbus_message_iter_init(message, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) + return get_reply_on_error(message, EINVAL); + + dbus_message_iter_get_basic(&iter, &path); + + iwdn = g_hash_table_lookup(networks, path); + if (!iwdn) + return get_reply_on_error(message, EINVAL); + + passwd = connman_network_get_string(iwdn->network, "WiFi.Passphrase"); + + return g_dbus_create_reply(message, DBUS_TYPE_STRING, &passwd, + DBUS_TYPE_INVALID); +} + +static DBusMessage *agent_cancel(DBusConnection *dbus_conn, + DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + const char *reason; + + dbus_message_iter_init(message, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return get_reply_on_error(message, EINVAL); + + dbus_message_iter_get_basic(&iter, &reason); + + DBG("cancel: %s", reason); + + /* + * We don't have to do anything here, because we asked the + * user upfront for the passphrase. So + * agent_request_passphrase() will always send a passphrase + * immediately. + */ + + return g_dbus_create_reply(message, DBUS_TYPE_INVALID); +} + +static const GDBusMethodTable agent_methods[] = { + { GDBUS_METHOD("Release", NULL, NULL, agent_release_method) }, + { GDBUS_METHOD("RequestPassphrase", + GDBUS_ARGS({ "path", "o" }), + GDBUS_ARGS({ "passphrase", "s" }), + agent_request_passphrase)}, + { GDBUS_METHOD("Cancel", + GDBUS_ARGS({ "reason", "s" }), + NULL, agent_cancel) }, + { }, +}; + +static void agent_register_builder(DBusMessageIter *iter, void *user_data) +{ + const char *path = AGENT_PATH; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, + &path); +} + +static void register_agent(GDBusProxy *proxy) +{ + if (!g_dbus_proxy_method_call(proxy, + "RegisterAgent", + agent_register_builder, + NULL, NULL, NULL)) + return; + + agent_proxy = g_dbus_proxy_ref(proxy); +} + +static void unregister_agent() +{ + if (!agent_proxy) + return; + + g_dbus_proxy_method_call(agent_proxy, + "UnregisterAgent", + agent_register_builder, + NULL, NULL, NULL); + + g_dbus_proxy_unref(agent_proxy); + agent_proxy = NULL; +} + +static void iwd_is_present(DBusConnection *conn, void *user_data) +{ + if (agent_registered) + return; + + if (!g_dbus_register_interface(connection, AGENT_PATH, + IWD_AGENT_INTERFACE, agent_methods, + NULL, NULL, NULL, NULL)) + return; + + agent_registered = true; +} + +static void iwd_is_out(DBusConnection *conn, void *user_data) +{ + if (agent_registered) { + g_dbus_unregister_interface(connection, + AGENT_PATH, IWD_AGENT_INTERFACE); + agent_registered = false; + } +} + +static void create_network(GDBusProxy *proxy) +{ + const char *path = g_dbus_proxy_get_path(proxy); + struct iwd_network *iwdn; + + iwdn = g_try_new0(struct iwd_network, 1); + + if (!iwdn) { + connman_error("Out of memory creating IWD network"); + return; + } + + iwdn->path = g_strdup(path); + g_hash_table_replace(networks, iwdn->path, iwdn); + + iwdn->proxy = g_dbus_proxy_ref(proxy); + + if (!iwdn->proxy) { + connman_error("Cannot create IWD network watcher %s", path); + g_hash_table_remove(networks, path); + return; + } + + iwdn->device = g_strdup(proxy_get_string(proxy, "Device")); + iwdn->name = g_strdup(proxy_get_string(proxy, "Name")); + iwdn->type = g_strdup(proxy_get_string(proxy, "Type")); + iwdn->connected = proxy_get_bool(proxy, "Connected"); + + DBG("device %s name '%s' type %s connected %d", + iwdn->device, + iwdn->name, + iwdn->type, + iwdn->connected); + + g_dbus_proxy_set_property_watch(iwdn->proxy, + network_property_change, NULL); + + add_network(path, iwdn); +} + +static void object_added(GDBusProxy *proxy, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + if (!interface) { + connman_warn("Interface or proxy missing when adding " + "iwd object"); + return; + } + + DBG("%s %s", interface, g_dbus_proxy_get_path(proxy)); + + if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE)) + register_agent(proxy); + else if (!strcmp(interface, IWD_ADAPTER_INTERFACE)) + create_adapter(proxy); + else if (!strcmp(interface, IWD_DEVICE_INTERFACE)) + create_device(proxy); + else if (!strcmp(interface, IWD_NETWORK_INTERFACE)) + create_network(proxy); +} + +static void object_removed(GDBusProxy *proxy, void *user_data) +{ + const char *interface, *path; + + interface = g_dbus_proxy_get_interface(proxy); + if (!interface) { + connman_warn("Interface or proxy missing when removing " + "iwd object"); + return; + } + + path = g_dbus_proxy_get_path(proxy); + DBG("%s %s", interface, path); + + if (!strcmp(interface, IWD_AGENT_MANAGER_INTERFACE)) + unregister_agent(); + if (!strcmp(interface, IWD_ADAPTER_INTERFACE)) + g_hash_table_remove(adapters, path); + else if (!strcmp(interface, IWD_DEVICE_INTERFACE)) + g_hash_table_remove(devices, path); + else if (!strcmp(interface, IWD_NETWORK_INTERFACE)) + g_hash_table_remove(networks, path); +} + +static int iwd_init(void) +{ + connection = connman_dbus_get_connection(); + if (!connection) + goto out; + + adapters = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + adapter_free); + + devices = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + device_free); + + networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + network_free); + + if (connman_technology_driver_register(&tech_driver) < 0) { + connman_warn("Failed to initialize technology for IWD"); + goto out; + } + + if (connman_device_driver_register(&device_driver) < 0) { + connman_warn("Failed to initialize device driver for " + IWD_SERVICE); + connman_technology_driver_unregister(&tech_driver); + goto out; + } + + if (connman_network_driver_register(&network_driver) < 0) { + connman_technology_driver_unregister(&tech_driver); + connman_device_driver_unregister(&device_driver); + goto out; + } + + client = g_dbus_client_new(connection, IWD_SERVICE, IWD_PATH); + if (!client) { + connman_warn("Failed to initialize D-Bus client for " + IWD_SERVICE); + goto out; + } + + g_dbus_client_set_connect_watch(client, iwd_is_present, NULL); + g_dbus_client_set_disconnect_watch(client, iwd_is_out, NULL); + g_dbus_client_set_proxy_handlers(client, object_added, object_removed, + NULL, NULL); + + return 0; + +out: + if (devices) + g_hash_table_destroy(devices); + + if (networks) + g_hash_table_destroy(networks); + + if (adapters) + g_hash_table_destroy(adapters); + + if (connection) + dbus_connection_unref(connection); + + return -EIO; +} + +static void iwd_exit(void) +{ + connman_network_driver_unregister(&network_driver); + connman_device_driver_unregister(&device_driver); + connman_technology_driver_unregister(&tech_driver); + + g_dbus_client_unref(client); + + g_hash_table_destroy(networks); + g_hash_table_destroy(devices); + g_hash_table_destroy(adapters); + + dbus_connection_unref(connection); +} + +CONNMAN_PLUGIN_DEFINE(iwd, "IWD plugin", VERSION, + CONNMAN_PLUGIN_PRIORITY_DEFAULT, iwd_init, iwd_exit) diff --git a/plugins/neard.c b/plugins/neard.c index 1a0fc1cd..69586df6 100755 --- a/plugins/neard.c +++ b/plugins/neard.c @@ -534,10 +534,8 @@ static void register_agent(void) &path, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID); if (!dbus_connection_send_with_reply(connection, message, - ®ister_call, TIMEOUT)) { - dbus_message_unref(message); + ®ister_call, TIMEOUT)) goto out; - } if (!dbus_pending_call_set_notify(register_call, register_agent_cb, NULL, NULL)) diff --git a/plugins/ofono.c b/plugins/ofono.c index 5cd83029..78f8f196 100755 --- a/plugins/ofono.c +++ b/plugins/ofono.c @@ -133,6 +133,7 @@ static GHashTable *context_hash; struct network_context { char *path; int index; + struct connman_network *network; enum connman_ipconfig_method ipv4_method; struct connman_ipaddress *ipv4_address; @@ -141,15 +142,19 @@ struct network_context { enum connman_ipconfig_method ipv6_method; struct connman_ipaddress *ipv6_address; char *ipv6_nameservers; + + int refcount; + + bool active; + bool valid_apn; /* APN is 'valid' if length > 0 */ }; struct modem_data { char *path; struct connman_device *device; - struct connman_network *network; - struct network_context *context; + GSList *context_list; /* Modem Interface */ char *serial; @@ -167,10 +172,6 @@ struct modem_data { bool attached; bool cm_powered; - /* ConnectionContext Interface */ - bool active; - bool valid_apn; /* APN is 'valid' if length > 0 */ - /* SimManager Interface */ char *imsi; @@ -219,6 +220,40 @@ static char *get_ident(const char *path) return pos + 1; } +static struct network_context *get_context_with_path(GSList *context_list, + const gchar *path) +{ + GSList *list; + + DBG("path %s", path); + + for (list = context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (g_strcmp0(context->path, path) == 0) + return context; + } + + return NULL; +} + +static struct network_context *get_context_with_network(GSList *context_list, + const struct connman_network *network) +{ + GSList *list; + + DBG("network %p", network); + + for (list = context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network == network) + return context; + } + + return NULL; +} + static struct network_context *network_context_alloc(const char *path) { struct network_context *context; @@ -238,11 +273,25 @@ static struct network_context *network_context_alloc(const char *path) context->ipv6_address = NULL; context->ipv6_nameservers = NULL; + context->refcount = 1; + return context; } -static void network_context_free(struct network_context *context) +static void network_context_ref(struct network_context *context) +{ + DBG("%p ref %d", context, context->refcount + 1); + + __sync_fetch_and_add(&context->refcount, 1); +} + +static void network_context_unref(struct network_context *context) { + DBG("%p ref %d", context, context->refcount - 1); + + if (__sync_fetch_and_sub(&context->refcount, 1) != 1) + return; + g_free(context->path); connman_ipaddress_free(context->ipv4_address); @@ -251,10 +300,11 @@ static void network_context_free(struct network_context *context) connman_ipaddress_free(context->ipv6_address); g_free(context->ipv6_nameservers); - free(context); + g_free(context); } -static void set_connected(struct modem_data *modem) +static void set_connected(struct modem_data *modem, + struct network_context *context) { struct connman_service *service; bool setip = false; @@ -264,21 +314,21 @@ static void set_connected(struct modem_data *modem) DBG("%s", modem->path); - index = modem->context->index; + index = context->index; - method = modem->context->ipv4_method; - if (index < 0 || (!modem->context->ipv4_address && + method = context->ipv4_method; + if (index < 0 || (!context->ipv4_address && method == CONNMAN_IPCONFIG_METHOD_FIXED)) { connman_error("Invalid index and/or address"); return; } - service = connman_service_lookup_from_network(modem->network); + service = connman_service_lookup_from_network(context->network); if (!service) return; connman_service_create_ip4config(service, index); - connman_network_set_ipv4_method(modem->network, method); + connman_network_set_ipv4_method(context->network, method); if (method == CONNMAN_IPCONFIG_METHOD_FIXED || method == CONNMAN_IPCONFIG_METHOD_DHCP) { @@ -286,69 +336,68 @@ static void set_connected(struct modem_data *modem) } if (method == CONNMAN_IPCONFIG_METHOD_FIXED) { - connman_network_set_ipaddress(modem->network, - modem->context->ipv4_address); + connman_network_set_ipaddress(context->network, + context->ipv4_address); } - method = modem->context->ipv6_method; + method = context->ipv6_method; connman_service_create_ip6config(service, index); - connman_network_set_ipv6_method(modem->network, method); + connman_network_set_ipv6_method(context->network, method); if (method == CONNMAN_IPCONFIG_METHOD_AUTO) { setip = true; } /* Set the nameservers */ - if (modem->context->ipv4_nameservers && - modem->context->ipv6_nameservers) { + if (context->ipv4_nameservers && + context->ipv6_nameservers) { nameservers = g_strdup_printf("%s %s", - modem->context->ipv4_nameservers, - modem->context->ipv6_nameservers); - connman_network_set_nameservers(modem->network, nameservers); + context->ipv4_nameservers, + context->ipv6_nameservers); + connman_network_set_nameservers(context->network, nameservers); g_free(nameservers); - } else if (modem->context->ipv4_nameservers) { - connman_network_set_nameservers(modem->network, - modem->context->ipv4_nameservers); - } else if (modem->context->ipv6_nameservers) { - connman_network_set_nameservers(modem->network, - modem->context->ipv6_nameservers); + } else if (context->ipv4_nameservers) { + connman_network_set_nameservers(context->network, + context->ipv4_nameservers); + } else if (context->ipv6_nameservers) { + connman_network_set_nameservers(context->network, + context->ipv6_nameservers); } if (setip) { - connman_network_set_index(modem->network, index); - connman_network_set_connected(modem->network, true); + connman_network_set_index(context->network, index); + connman_network_set_connected(context->network, true); } } -static void set_disconnected(struct modem_data *modem) +static void set_disconnected(struct network_context *context) { - DBG("%s", modem->path); + DBG("%s", context->path); - if (modem->network) - connman_network_set_connected(modem->network, false); + if (context->network) + connman_network_set_connected(context->network, false); - if (modem->context) { - g_free(modem->context->ipv4_nameservers); - modem->context->ipv4_nameservers = NULL; - if (modem->context->ipv4_method != CONNMAN_IPCONFIG_METHOD_OFF) - modem->context->ipv4_method = - CONNMAN_IPCONFIG_METHOD_UNKNOWN; + g_free(context->ipv4_nameservers); + context->ipv4_nameservers = NULL; + if (context->ipv4_method != CONNMAN_IPCONFIG_METHOD_OFF) + context->ipv4_method = + CONNMAN_IPCONFIG_METHOD_UNKNOWN; - g_free(modem->context->ipv6_nameservers); - modem->context->ipv6_nameservers = NULL; - if (modem->context->ipv6_method != CONNMAN_IPCONFIG_METHOD_OFF) - modem->context->ipv6_method = - CONNMAN_IPCONFIG_METHOD_UNKNOWN; - } + g_free(context->ipv6_nameservers); + context->ipv6_nameservers = NULL; + if (context->ipv6_method != CONNMAN_IPCONFIG_METHOD_OFF) + context->ipv6_method = + CONNMAN_IPCONFIG_METHOD_UNKNOWN; } typedef void (*set_property_cb)(struct modem_data *data, - bool success); + struct network_context *context, bool success); typedef void (*get_properties_cb)(struct modem_data *data, DBusMessageIter *dict); struct property_info { struct modem_data *modem; + struct network_context *context; const char *path; const char *interface; const char *property; @@ -356,6 +405,16 @@ struct property_info { get_properties_cb get_properties_cb; }; +static void free_property_info(void * memory) +{ + struct property_info * info = memory; + + if (info->context) + network_context_unref(info->context); + + g_free(info); +} + static void set_property_reply(DBusPendingCall *call, void *user_data) { struct property_info *info = user_data; @@ -381,7 +440,8 @@ static void set_property_reply(DBusPendingCall *call, void *user_data) } if (info->set_property_cb) - (*info->set_property_cb)(info->modem, success); + (*info->set_property_cb)(info->modem, info->context, + success); dbus_message_unref(reply); @@ -389,6 +449,7 @@ static void set_property_reply(DBusPendingCall *call, void *user_data) } static int set_property(struct modem_data *modem, + struct network_context *context, const char *path, const char *interface, const char *property, int type, void *value, set_property_cb notify) @@ -401,8 +462,8 @@ static int set_property(struct modem_data *modem, if (modem->call_set_property) { DBG("Cancel pending SetProperty"); - dbus_pending_call_cancel(modem->call_set_property); + dbus_pending_call_unref(modem->call_set_property); modem->call_set_property = NULL; } @@ -435,13 +496,17 @@ static int set_property(struct modem_data *modem, } info->modem = modem; + info->context = context; info->path = path; info->interface = interface; info->property = property; info->set_property_cb = notify; + if (info->context) + network_context_ref(info->context); + dbus_pending_call_set_notify(modem->call_set_property, - set_property_reply, info, g_free); + set_property_reply, info, free_property_info); dbus_message_unref(message); @@ -542,9 +607,9 @@ static int get_properties(const char *path, const char *interface, } static void context_set_active_reply(struct modem_data *modem, - bool success) + struct network_context *context, bool success) { - DBG("%s", modem->path); + DBG("%s", context->path); if (success) { /* @@ -561,7 +626,7 @@ static void context_set_active_reply(struct modem_data *modem, * cycle the modem in such cases? */ - if (!modem->network) { + if (!context->network) { /* * In the case where we power down the device * we don't wait for the reply, therefore the network @@ -570,18 +635,19 @@ static void context_set_active_reply(struct modem_data *modem, return; } - connman_network_set_error(modem->network, + connman_network_set_error(context->network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); } static int context_set_active(struct modem_data *modem, - dbus_bool_t active) + struct network_context *context, + dbus_bool_t active) { int err; DBG("%s active %d", modem->path, active); - err = set_property(modem, modem->context->path, + err = set_property(modem, context, context->path, OFONO_CONTEXT_INTERFACE, "Active", DBUS_TYPE_BOOLEAN, &active, @@ -594,9 +660,9 @@ static int context_set_active(struct modem_data *modem, } static void cdma_cm_set_powered_reply(struct modem_data *modem, - bool success) + struct network_context *context, bool success) { - DBG("%s", modem->path); + DBG("%s", context->path); if (success) { /* @@ -613,7 +679,7 @@ static void cdma_cm_set_powered_reply(struct modem_data *modem, * cycle the modem in such cases? */ - if (!modem->network) { + if (!context->network) { /* * In the case where we power down the device * we don't wait for the reply, therefore the network @@ -622,17 +688,24 @@ static void cdma_cm_set_powered_reply(struct modem_data *modem, return; } - connman_network_set_error(modem->network, + connman_network_set_error(context->network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); } static int cdma_cm_set_powered(struct modem_data *modem, dbus_bool_t powered) { int err; + struct network_context *context = NULL; + + if (!modem->context_list) + return -1; DBG("%s powered %d", modem->path, powered); - err = set_property(modem, modem->path, OFONO_CDMA_CM_INTERFACE, + /* In case of CDMA, there is only one context */ + context = modem->context_list->data; + err = set_property(modem, context, modem->path, + OFONO_CDMA_CM_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered, cdma_cm_set_powered_reply); @@ -647,7 +720,7 @@ static int modem_set_online(struct modem_data *modem, dbus_bool_t online) { DBG("%s online %d", modem->path, online); - return set_property(modem, modem->path, + return set_property(modem, NULL, modem->path, OFONO_MODEM_INTERFACE, "Online", DBUS_TYPE_BOOLEAN, &online, @@ -660,7 +733,7 @@ static int cm_set_powered(struct modem_data *modem, dbus_bool_t powered) DBG("%s powered %d", modem->path, powered); - err = set_property(modem, modem->path, + err = set_property(modem, NULL, modem->path, OFONO_CM_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered, @@ -680,7 +753,7 @@ static int modem_set_powered(struct modem_data *modem, dbus_bool_t powered) modem->set_powered = powered; - err = set_property(modem, modem->path, + err = set_property(modem, NULL, modem->path, OFONO_MODEM_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered, @@ -768,7 +841,6 @@ static void extract_ipv4_settings(DBusMessageIter *array, connman_ipaddress_free(context->ipv4_address); context->ipv4_address = NULL; - context->index = -1; if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) return; @@ -871,7 +943,6 @@ static void extract_ipv6_settings(DBusMessageIter *array, connman_ipaddress_free(context->ipv6_address); context->ipv6_address = NULL; - context->index = -1; if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) return; @@ -1017,71 +1088,68 @@ static void destroy_device(struct modem_data *modem) connman_device_set_powered(modem->device, false); - if (modem->network) { - connman_device_remove_network(modem->device, modem->network); - connman_network_unref(modem->network); - modem->network = NULL; - } - connman_device_unregister(modem->device); connman_device_unref(modem->device); modem->device = NULL; } -static void add_network(struct modem_data *modem) +static void add_network(struct modem_data *modem, + struct network_context *context) { const char *group; DBG("%s", modem->path); - if (modem->network) + if (context->network) return; - modem->network = connman_network_create(modem->context->path, - CONNMAN_NETWORK_TYPE_CELLULAR); - if (!modem->network) + context->network = connman_network_create(context->path, + CONNMAN_NETWORK_TYPE_CELLULAR); + if (!context->network) return; - DBG("network %p", modem->network); + DBG("network %p", context->network); - connman_network_set_data(modem->network, modem); + connman_network_set_data(context->network, modem); - connman_network_set_string(modem->network, "Path", - modem->context->path); + connman_network_set_string(context->network, "Path", + context->path); if (modem->name) - connman_network_set_name(modem->network, modem->name); + connman_network_set_name(context->network, modem->name); else - connman_network_set_name(modem->network, ""); + connman_network_set_name(context->network, ""); - connman_network_set_strength(modem->network, modem->strength); + connman_network_set_strength(context->network, modem->strength); - group = get_ident(modem->context->path); - connman_network_set_group(modem->network, group); + group = get_ident(context->path); + connman_network_set_group(context->network, group); - connman_network_set_bool(modem->network, "Roaming", - modem->roaming); + connman_network_set_bool(context->network, "Roaming", + modem->roaming); - if (connman_device_add_network(modem->device, modem->network) < 0) { - connman_network_unref(modem->network); - modem->network = NULL; + if (connman_device_add_network(modem->device, context->network) < 0) { + connman_network_unref(context->network); + context->network = NULL; return; } } -static void remove_network(struct modem_data *modem) +static void remove_network(struct modem_data *modem, + struct network_context *context) { DBG("%s", modem->path); - if (!modem->network) + if (!context || !context->network) return; - DBG("network %p", modem->network); + DBG("network %p", context->network); - connman_device_remove_network(modem->device, modem->network); - connman_network_unref(modem->network); - modem->network = NULL; + if (modem->device) + connman_device_remove_network(modem->device, context->network); + connman_network_unref(context->network); + context->network = NULL; } static int set_context_ipconfig(struct network_context *context, @@ -1134,14 +1202,6 @@ static int add_cm_context(struct modem_data *modem, const char *context_path, DBG("%s context path %s", modem->path, context_path); - if (modem->context) { - /* - * We have already assigned a context to this modem - * and we do only support one Internet context. - */ - return -EALREADY; - } - context = network_context_alloc(context_path); if (!context) return -ENOMEM; @@ -1178,9 +1238,9 @@ static int add_cm_context(struct modem_data *modem, const char *context_path, dbus_message_iter_get_basic(&value, &apn); if (apn && strlen(apn) > 0) - modem->valid_apn = true; + context->valid_apn = true; else - modem->valid_apn = false; + context->valid_apn = false; DBG("%s AccessPointName '%s'", modem->path, apn); } else if (g_str_equal(key, "Protocol") && @@ -1195,51 +1255,77 @@ static int add_cm_context(struct modem_data *modem, const char *context_path, } if (g_strcmp0(context_type, "internet") != 0) { - network_context_free(context); + network_context_unref(context); return -EINVAL; } if (ip_protocol) set_context_ipconfig(context, ip_protocol); - modem->context = context; - modem->active = active; + context->active = active; + modem->context_list = g_slist_prepend(modem->context_list, context); g_hash_table_replace(context_hash, g_strdup(context_path), modem); - if (modem->valid_apn && modem->attached && - has_interface(modem->interfaces, - OFONO_API_NETREG)) { - add_network(modem); - } + if (context->valid_apn && modem->attached && + has_interface(modem->interfaces, OFONO_API_NETREG)) + add_network(modem, context); return 0; } static void remove_cm_context(struct modem_data *modem, - const char *context_path) + struct network_context *context) { - if (!modem->context) + if (!modem->context_list) return; + if (!context) + return; + + g_hash_table_remove(context_hash, context->path); + + if (context->network) + remove_network(modem, context); + modem->context_list = g_slist_remove(modem->context_list, context); + + network_context_unref(context); + context = NULL; +} + +static void remove_all_contexts(struct modem_data *modem) +{ + GSList *list = NULL; - if (modem->network) - remove_network(modem); + DBG(""); + + if (modem->context_list == NULL) + return; + + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; - g_hash_table_remove(context_hash, context_path); + remove_cm_context(modem, context); + } + g_slist_free(modem->context_list); + modem->context_list = NULL; +} - network_context_free(modem->context); - modem->context = NULL; +static void remove_all_networks(struct modem_data *modem) +{ + GSList *list; - modem->valid_apn = false; + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; - if (modem->network) - remove_network(modem); + remove_network(modem, context); + } } static gboolean context_changed(DBusConnection *conn, DBusMessage *message, void *user_data) { + struct network_context *context = NULL; const char *context_path = dbus_message_get_path(message); struct modem_data *modem = NULL; DBusMessageIter iter, value; @@ -1251,6 +1337,10 @@ static gboolean context_changed(DBusConnection *conn, if (!modem) return TRUE; + context = get_context_with_path(modem->context_list, context_path); + if (!context) + return TRUE; + if (!dbus_message_iter_init(message, &iter)) return TRUE; @@ -1267,23 +1357,23 @@ static gboolean context_changed(DBusConnection *conn, if (g_str_equal(key, "Settings")) { DBG("%s Settings", modem->path); - extract_ipv4_settings(&value, modem->context); + extract_ipv4_settings(&value, context); } else if (g_str_equal(key, "IPv6.Settings")) { DBG("%s IPv6.Settings", modem->path); - extract_ipv6_settings(&value, modem->context); + extract_ipv6_settings(&value, context); } else if (g_str_equal(key, "Active")) { dbus_bool_t active; dbus_message_iter_get_basic(&value, &active); - modem->active = active; + context->active = active; - DBG("%s Active %d", modem->path, modem->active); + DBG("%s Active %d", modem->path, context->active); - if (modem->active) - set_connected(modem); + if (context->active) + set_connected(modem, context); else - set_disconnected(modem); + set_disconnected(context); } else if (g_str_equal(key, "AccessPointName")) { const char *apn; @@ -1292,9 +1382,9 @@ static gboolean context_changed(DBusConnection *conn, DBG("%s AccessPointName %s", modem->path, apn); if (apn && strlen(apn) > 0) { - modem->valid_apn = true; + context->valid_apn = true; - if (modem->network) + if (context->network) return TRUE; if (!modem->attached) @@ -1304,17 +1394,17 @@ static gboolean context_changed(DBusConnection *conn, OFONO_API_NETREG)) return TRUE; - add_network(modem); + add_network(modem, context); - if (modem->active) - set_connected(modem); + if (context->active) + set_connected(modem, context); } else { - modem->valid_apn = false; + context->valid_apn = false; - if (!modem->network) + if (!context->network) return TRUE; - remove_network(modem); + remove_network(modem, context); } } else if (g_str_equal(key, "Protocol") && @@ -1323,7 +1413,7 @@ static gboolean context_changed(DBusConnection *conn, dbus_message_iter_get_basic(&value, &ip_protocol); - set_context_ipconfig(modem->context, ip_protocol); + set_context_ipconfig(context, ip_protocol); } return TRUE; @@ -1367,7 +1457,7 @@ static void cm_get_contexts_reply(DBusPendingCall *call, void *user_data) dbus_message_iter_next(&entry); dbus_message_iter_recurse(&entry, &value); - if (add_cm_context(modem, context_path, &value) == 0) + if (add_cm_context(modem, context_path, &value)) break; dbus_message_iter_next(&dict); @@ -1422,7 +1512,7 @@ static gboolean cm_context_added(DBusConnection *conn, const char *path = dbus_message_get_path(message); char *context_path; struct modem_data *modem; - DBusMessageIter iter, properties; + DBusMessageIter iter, properties, dict; DBG("%s", path); @@ -1438,6 +1528,13 @@ static gboolean cm_context_added(DBusConnection *conn, dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &properties); + /* Sometimes, we get an array instead of dict */ + if (dbus_message_iter_get_arg_type(&properties) == DBUS_TYPE_ARRAY) { + /* Must recurse again */ + dbus_message_iter_recurse(&properties, &dict); + if (add_cm_context(modem, context_path, &dict) != 0) + return TRUE; + } if (add_cm_context(modem, context_path, &properties) != 0) return TRUE; @@ -1451,6 +1548,7 @@ static gboolean cm_context_removed(DBusConnection *conn, const char *path = dbus_message_get_path(message); const char *context_path; struct modem_data *modem; + struct network_context *context; DBusMessageIter iter; DBG("context path %s", path); @@ -1464,7 +1562,8 @@ static gboolean cm_context_removed(DBusConnection *conn, if (!modem) return TRUE; - remove_cm_context(modem, context_path); + context = get_context_with_path(modem->context_list, context_path); + remove_cm_context(modem, context); return TRUE; } @@ -1473,6 +1572,7 @@ static void netreg_update_name(struct modem_data *modem, DBusMessageIter* value) { char *name; + GSList *list; dbus_message_iter_get_basic(value, &name); @@ -1481,21 +1581,30 @@ static void netreg_update_name(struct modem_data *modem, g_free(modem->name); modem->name = g_strdup(name); - if (!modem->network) + if (!modem->context_list) return; - connman_network_set_name(modem->network, modem->name); - connman_network_update(modem->network); + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_name(context->network, modem->name); + connman_network_update(context->network); + } + } } static void netreg_update_strength(struct modem_data *modem, DBusMessageIter *value) { + GSList *list; + dbus_message_iter_get_basic(value, &modem->strength); DBG("%s Strength %d", modem->path, modem->strength); - if (!modem->network) + if (!modem->context_list) return; /* @@ -1514,19 +1623,29 @@ static void netreg_update_strength(struct modem_data *modem, if (modem->data_strength != 0) return; - connman_network_set_strength(modem->network, modem->strength); - connman_network_update(modem->network); + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_strength(context->network, + modem->strength); + connman_network_update(context->network); + } + } } /* Retrieve 1xEVDO Data Strength signal */ static void netreg_update_datastrength(struct modem_data *modem, DBusMessageIter *value) { + GSList *list; + dbus_message_iter_get_basic(value, &modem->data_strength); DBG("%s Data Strength %d", modem->path, modem->data_strength); - if (!modem->network) + if (!modem->context_list) return; /* @@ -1537,8 +1656,16 @@ static void netreg_update_datastrength(struct modem_data *modem, if (modem->data_strength == 0) return; - connman_network_set_strength(modem->network, modem->data_strength); - connman_network_update(modem->network); + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_strength(context->network, + modem->data_strength); + connman_network_update(context->network); + } + } } static void netreg_update_status(struct modem_data *modem, @@ -1546,6 +1673,7 @@ static void netreg_update_status(struct modem_data *modem, { char *status; bool roaming; + GSList *list; dbus_message_iter_get_basic(value, &status); @@ -1557,12 +1685,19 @@ static void netreg_update_status(struct modem_data *modem, modem->roaming = roaming; - if (!modem->network) + if (!modem->context_list) return; - connman_network_set_bool(modem->network, + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_bool(context->network, "Roaming", modem->roaming); - connman_network_update(modem->network); + connman_network_update(context->network); + } + } } static void netreg_update_regdom(struct modem_data *modem, @@ -1624,6 +1759,8 @@ static gboolean netreg_changed(DBusConnection *conn, DBusMessage *message, static void netreg_properties_reply(struct modem_data *modem, DBusMessageIter *dict) { + GSList *list = NULL; + DBG("%s", modem->path); while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) { @@ -1648,7 +1785,7 @@ static void netreg_properties_reply(struct modem_data *modem, dbus_message_iter_next(dict); } - if (!modem->context) { + if (!modem->context_list) { /* * netgreg_get_properties() was issued after we got * cm_get_contexts_reply() where we create the @@ -1659,12 +1796,15 @@ static void netreg_properties_reply(struct modem_data *modem, */ return; } + /* Check for all contexts if they are valids and/or actives */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; - if (modem->valid_apn) - add_network(modem); - - if (modem->active) - set_connected(modem); + if (context->valid_apn) + add_network(modem, context); + if (context->active) + set_connected(modem, context); + } } static int netreg_get_properties(struct modem_data *modem) @@ -1675,6 +1815,7 @@ static int netreg_get_properties(struct modem_data *modem) static void add_cdma_network(struct modem_data *modem) { + struct network_context *context = NULL; /* Be sure that device is created before adding CDMA network */ if (!modem->device) return; @@ -1683,16 +1824,20 @@ static void add_cdma_network(struct modem_data *modem) * CDMA modems don't need contexts for data call, however the current * add_network() logic needs one, so we create one to proceed. */ - if (!modem->context) - modem->context = network_context_alloc(modem->path); + if (!modem->context_list) { + context = network_context_alloc(modem->path); + modem->context_list = g_slist_prepend(modem->context_list, + context); + } else + context = modem->context_list->data; if (!modem->name) modem->name = g_strdup("CDMA Network"); - add_network(modem); + add_network(modem, context); if (modem->cdma_cm_powered) - set_connected(modem); + set_connected(modem, context); } static gboolean cdma_netreg_changed(DBusConnection *conn, @@ -1733,7 +1878,7 @@ static gboolean cdma_netreg_changed(DBusConnection *conn, if (modem->registered) add_cdma_network(modem); else - remove_network(modem); + remove_all_networks(modem); return TRUE; } @@ -1768,7 +1913,7 @@ static void cdma_netreg_properties_reply(struct modem_data *modem, if (modem->registered) add_cdma_network(modem); else - remove_network(modem); + remove_all_networks(modem); } static int cdma_netreg_get_properties(struct modem_data *modem) @@ -1788,7 +1933,7 @@ static void cm_update_attached(struct modem_data *modem, DBG("%s Attached %d", modem->path, modem->attached); if (!modem->attached) { - remove_network(modem); + remove_all_networks(modem); return; } @@ -1849,6 +1994,7 @@ static gboolean cm_changed(DBusConnection *conn, DBusMessage *message, static void cdma_cm_update_powered(struct modem_data *modem, DBusMessageIter *value) { + struct network_context *context = NULL; dbus_bool_t cdma_cm_powered; dbus_message_iter_get_basic(value, &cdma_cm_powered); @@ -1856,13 +2002,15 @@ static void cdma_cm_update_powered(struct modem_data *modem, DBG("%s CDMA cm Powered %d", modem->path, modem->cdma_cm_powered); - if (!modem->network) + if (!modem->context_list) return; + /* In case of CDMA, there is only one context */ + context = modem->context_list->data; if (modem->cdma_cm_powered) - set_connected(modem); + set_connected(modem, context); else - set_disconnected(modem); + set_disconnected(context); } static void cdma_cm_update_settings(struct modem_data *modem, @@ -1870,7 +2018,7 @@ static void cdma_cm_update_settings(struct modem_data *modem, { DBG("%s Settings", modem->path); - extract_ipv4_settings(value, modem->context); + extract_ipv4_settings(value, modem->context_list->data); } static gboolean cdma_cm_changed(DBusConnection *conn, @@ -1885,7 +2033,7 @@ static gboolean cdma_cm_changed(DBusConnection *conn, if (!modem) return TRUE; - if (modem->online && !modem->network) + if (modem->online && !modem->context_list) cdma_netreg_get_properties(modem); if (!dbus_message_iter_init(message, &iter)) @@ -2142,17 +2290,24 @@ static void modem_update_interfaces(struct modem_data *modem, if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG)) cdma_netreg_get_properties(modem); - if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM)) - remove_cm_context(modem, modem->context->path); + if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM)) { + if (modem->call_get_contexts) { + DBG("cancelling pending GetContexts call"); + dbus_pending_call_cancel(modem->call_get_contexts); + dbus_pending_call_unref(modem->call_get_contexts); + modem->call_get_contexts = NULL; + } + remove_all_contexts(modem); + } if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_CM)) - remove_cm_context(modem, modem->context->path); + remove_all_contexts(modem); if (api_removed(old_ifaces, new_ifaces, OFONO_API_NETREG)) - remove_network(modem); + remove_all_networks(modem); if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG)) - remove_network(modem); + remove_all_networks(modem); } static gboolean modem_changed(DBusConnection *conn, DBusMessage *message, @@ -2186,8 +2341,8 @@ static gboolean modem_changed(DBusConnection *conn, DBusMessage *message, DBG("%s Powered %d", modem->path, modem->powered); - if (!modem->powered) - modem_set_powered(modem, TRUE); + /* Set the powered according to the value */ + modem_set_powered(modem, powered); } else if (g_str_equal(key, "Online")) { dbus_bool_t online; @@ -2340,21 +2495,31 @@ static void remove_modem(gpointer data) DBG("%s", modem->path); - if (modem->call_set_property) + if (modem->call_set_property) { dbus_pending_call_cancel(modem->call_set_property); + dbus_pending_call_unref(modem->call_set_property); + modem->call_set_property = NULL; + } - if (modem->call_get_properties) + if (modem->call_get_properties) { dbus_pending_call_cancel(modem->call_get_properties); + dbus_pending_call_unref(modem->call_get_properties); + modem->call_get_properties = NULL; + } - if (modem->call_get_contexts) + if (modem->call_get_contexts) { dbus_pending_call_cancel(modem->call_get_contexts); + dbus_pending_call_unref(modem->call_get_contexts); + modem->call_get_contexts = NULL; + } + + /* Must remove the contexts before the device */ + if (modem->context_list) + remove_all_contexts(modem); if (modem->device) destroy_device(modem); - if (modem->context) - remove_cm_context(modem, modem->context->path); - g_free(modem->serial); g_free(modem->name); g_free(modem->imsi); @@ -2530,12 +2695,20 @@ static void network_remove(struct connman_network *network) static int network_connect(struct connman_network *network) { + struct network_context *context; struct modem_data *modem = connman_network_get_data(network); DBG("%s network %p", modem->path, network); + if (!g_hash_table_lookup(modem_hash, modem->path)) + return -ENODEV; + + context = get_context_with_network(modem->context_list, network); + if (!context) + return -ENODEV; + if (has_interface(modem->interfaces, OFONO_API_CM)) - return context_set_active(modem, TRUE); + return context_set_active(modem, context, TRUE); else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM)) return cdma_cm_set_powered(modem, TRUE); @@ -2546,12 +2719,20 @@ static int network_connect(struct connman_network *network) static int network_disconnect(struct connman_network *network) { + struct network_context *context; struct modem_data *modem = connman_network_get_data(network); DBG("%s network %p", modem->path, network); + if (!g_hash_table_lookup(modem_hash, modem->path)) + return -ENODEV; + + context = get_context_with_network(modem->context_list, network); + if (!context) + return -ENODEV; + if (has_interface(modem->interfaces, OFONO_API_CM)) - return context_set_active(modem, FALSE); + return context_set_active(modem, context, FALSE); else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM)) return cdma_cm_set_powered(modem, FALSE); diff --git a/plugins/pacrunner.c b/plugins/pacrunner.c index 850139fd..d2464a5e 100755 --- a/plugins/pacrunner.c +++ b/plugins/pacrunner.c @@ -78,11 +78,6 @@ done: dbus_message_unref(reply); } -static void append_string(DBusMessageIter *iter, void *user_data) -{ - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, user_data); -} - static void append_string_list(DBusMessageIter *iter, void *user_data) { char **list = user_data; @@ -178,11 +173,6 @@ static void create_proxy_configuration(void) g_free(interface); } - str = connman_service_get_domainname(default_service); - if (str) - connman_dbus_dict_append_array(&dict, "Domains", - DBUS_TYPE_STRING, append_string, &str); - str_list = connman_service_get_nameservers(default_service); if (str_list) connman_dbus_dict_append_array(&dict, "Nameservers", diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c index b2369bdc..f003c0e1 100755 --- a/plugins/session_policy_local.c +++ b/plugins/session_policy_local.c @@ -459,6 +459,8 @@ static int load_policy(GKeyFile *keyfile, const char *groupname, str = g_key_file_get_string(keyfile, groupname, "AllowedBearers", NULL); if (str) { + g_slist_free(config->allowed_bearers); + config->allowed_bearers = NULL; tokens = g_strsplit(str, " ", 0); for (i = 0; tokens[i]; i++) { @@ -623,7 +625,7 @@ static int load_file(const char *filename, struct policy_file *file) for (i = 0; groupnames[i]; i++) { group = g_new0(struct policy_group, 1); - group->config = g_new0(struct connman_session_config, 1); + group->config = connman_session_create_default_config(); err = load_policy(keyfile, groupnames[i], group); if (err < 0) { diff --git a/plugins/vpn.c b/plugins/vpn.c index ba5841e1..d3d75b81 100755 --- a/plugins/vpn.c +++ b/plugins/vpn.c @@ -203,7 +203,7 @@ static void resolv_result(GResolvResultStatus status, * We cannot unref the resolver here as resolv struct is manipulated * by gresolv.c after we return from this callback. */ - g_timeout_add_seconds(0, remove_resolv, data); + g_idle_add(remove_resolv, data); data->resolv_id = 0; } @@ -512,26 +512,39 @@ done: dbus_pending_call_unref(call); } -static int connect_provider(struct connection_data *data, void *user_data) +static int connect_provider(struct connection_data *data, void *user_data, + const char *dbus_sender) { DBusPendingCall *call; DBusMessage *message; struct config_create_data *cb_data = user_data; - DBG("data %p user %p path %s", data, cb_data, data->path); + DBG("data %p user %p path %s sender %s", data, cb_data, data->path, + dbus_sender); data->connect_pending = false; +#define VPN_CONNECT2 "Connect2" + + /* We need to pass original dbus sender to connman-vpnd, + * use a Connect2 method for that. + */ message = dbus_message_new_method_call(VPN_SERVICE, data->path, VPN_CONNECTION_INTERFACE, - VPN_CONNECT); + VPN_CONNECT2); if (!message) return -ENOMEM; + if (dbus_sender) + dbus_message_append_args(message, DBUS_TYPE_STRING, + &dbus_sender, NULL); + else + dbus_sender = ""; + if (!dbus_connection_send_with_reply(connection, message, &call, DBUS_TIMEOUT)) { connman_error("Unable to call %s.%s()", - VPN_CONNECTION_INTERFACE, VPN_CONNECT); + VPN_CONNECTION_INTERFACE, VPN_CONNECT2); dbus_message_unref(message); return -EINVAL; } @@ -658,8 +671,15 @@ static void add_connection(const char *path, DBusMessageIter *properties, connman_provider_set_domain(data->provider, data->domain); - if (data->connect_pending) - connect_provider(data, data->cb_data); + if (data->connect_pending) { + const char *dbus_sender = NULL; + + if (data->cb_data && data->cb_data->message) { + dbus_sender = + dbus_message_get_sender(data->cb_data->message); + } + connect_provider(data, data->cb_data, dbus_sender); + } return; @@ -857,7 +877,8 @@ static int provider_remove(struct connman_provider *provider) return 0; } -static int provider_connect(struct connman_provider *provider) +static int provider_connect(struct connman_provider *provider, + const char *dbus_sender) { struct connection_data *data; @@ -865,7 +886,7 @@ static int provider_connect(struct connman_provider *provider) if (!data) return -EINVAL; - return connect_provider(data, NULL); + return connect_provider(data, NULL, dbus_sender); } static void disconnect_reply(DBusPendingCall *call, void *user_data) diff --git a/plugins/wifi.c b/plugins/wifi.c index 0d33f4d0..8bc6307b 100755 --- a/plugins/wifi.c +++ b/plugins/wifi.c @@ -71,14 +71,27 @@ #define P2P_LISTEN_PERIOD 500 #define P2P_LISTEN_INTERVAL 2000 +#define ASSOC_STATUS_NO_CLIENT 17 +#define LOAD_SHAPING_MAX_RETRIES 3 static struct connman_technology *wifi_technology = NULL; static struct connman_technology *p2p_technology = NULL; +enum wifi_ap_capability{ + WIFI_AP_UNKNOWN = 0, + WIFI_AP_SUPPORTED = 1, + WIFI_AP_NOT_SUPPORTED = 2, +}; + struct hidden_params { char ssid[32]; unsigned int ssid_len; char *identity; + char *anonymous_identity; + char *subject_match; + char *altsubject_match; + char *domain_suffix_match; + char *domain_match; char *passphrase; char *security; GSupplicantScanParams *scan_params; @@ -96,6 +109,13 @@ struct autoscan_params { unsigned int timeout; }; +struct wifi_tethering_info { + struct wifi_data *wifi; + struct connman_technology *technology; + char *ifname; + GSupplicantSSID *ssid; +}; + struct wifi_data { char *identifier; struct connman_device *device; @@ -107,6 +127,7 @@ struct wifi_data { bool connected; bool disconnecting; bool tethering; + enum wifi_ap_capability ap_supported; bool bridged; bool interface_ready; const char *bridge; @@ -114,8 +135,10 @@ struct wifi_data { unsigned flags; unsigned int watch; int retries; + int load_shaping_retries; struct hidden_params *hidden; bool postpone_hidden; + struct wifi_tethering_info *tethering_param; /** * autoscan "emulation". */ @@ -125,7 +148,7 @@ struct wifi_data { unsigned int p2p_find_timeout; unsigned int p2p_connection_timeout; struct connman_peer *pending_peer; - GSupplicantPeer *peer; + GSList *peers; bool p2p_connecting; bool p2p_device; int servicing; @@ -158,6 +181,10 @@ bool wfd_service_registered = false; static void start_autoscan(struct connman_device *device); +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" @@ -363,8 +390,6 @@ static void peer_cancel_timeout(struct wifi_data *wifi) connman_peer_unref(wifi->pending_peer); wifi->pending_peer = NULL; } - - wifi->peer = NULL; } static gboolean peer_connect_timeout(gpointer data) @@ -375,8 +400,11 @@ static gboolean peer_connect_timeout(gpointer data) if (wifi->p2p_connecting) { enum connman_peer_state state = CONNMAN_PEER_STATE_FAILURE; + GSupplicantPeer *gs_peer = + g_supplicant_interface_peer_lookup(wifi->interface, + connman_peer_get_identifier(wifi->pending_peer)); - if (g_supplicant_peer_has_requested_connection(wifi->peer)) + if (g_supplicant_peer_has_requested_connection(gs_peer)) state = CONNMAN_PEER_STATE_IDLE; connman_peer_set_state(wifi->pending_peer, state); @@ -427,14 +455,12 @@ static int peer_connect(struct connman_peer *peer, return -ENODEV; wifi = connman_device_get_data(device); - if (!wifi) + if (!wifi || !wifi->interface) return -ENODEV; if (wifi->p2p_connecting) return -EBUSY; - wifi->peer = NULL; - gs_peer = g_supplicant_interface_peer_lookup(wifi->interface, connman_peer_get_identifier(peer)); if (!gs_peer) @@ -473,10 +499,12 @@ static int peer_connect(struct connman_peer *peer, peer_connect_callback, wifi); if (ret == -EINPROGRESS) { wifi->pending_peer = connman_peer_ref(peer); - wifi->peer = gs_peer; wifi->p2p_connecting = true; - } else if (ret < 0) + } else if (ret < 0) { + g_free(peer_params->path); + g_free(peer_params->wps_pin); g_free(peer_params); + } return ret; } @@ -509,8 +537,10 @@ static int peer_disconnect(struct connman_peer *peer) &peer_params); g_free(peer_params.path); - if (ret == -EINPROGRESS) + if (ret == -EINPROGRESS) { peer_cancel_timeout(wifi); + wifi->p2p_device = false; + } return ret; } @@ -879,6 +909,8 @@ static int wifi_probe(struct connman_device *device) return -ENOMEM; wifi->state = G_SUPPLICANT_STATE_INACTIVE; + wifi->ap_supported = WIFI_AP_UNKNOWN; + wifi->tethering_param = NULL; connman_device_set_data(device, wifi); wifi->device = connman_device_ref(device); @@ -912,6 +944,21 @@ static void remove_networks(struct connman_device *device, wifi->networks = NULL; } +static void remove_peers(struct wifi_data *wifi) +{ + GSList *list; + + for (list = wifi->peers; list; list = list->next) { + struct connman_peer *peer = list->data; + + connman_peer_unregister(peer); + connman_peer_unref(peer); + } + + g_slist_free(wifi->peers); + wifi->peers = NULL; +} + static void reset_autoscan(struct connman_device *device) { struct wifi_data *wifi = connman_device_get_data(device); @@ -995,6 +1042,7 @@ static void wifi_remove(struct connman_device *device) g_source_remove(wifi->p2p_connection_timeout); remove_networks(device, wifi); + remove_peers(wifi); connman_device_set_powered(device, false); connman_device_set_data(device, NULL); @@ -1731,6 +1779,7 @@ static int wifi_disable(struct connman_device *device) } remove_networks(device, wifi); + remove_peers(wifi); #if defined TIZEN_EXT wifi->scan_pending_network = NULL; @@ -1894,12 +1943,14 @@ static gboolean p2p_find_stop(gpointer data) DBG(""); - wifi->p2p_find_timeout = 0; + if (wifi) { + wifi->p2p_find_timeout = 0; + + g_supplicant_interface_p2p_stop_find(wifi->interface); + } connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false); - g_supplicant_interface_p2p_stop_find(wifi->interface); - connman_device_unref(device); reset_autoscan(device); @@ -1914,6 +1965,9 @@ static void p2p_find_callback(int result, GSupplicantInterface *interface, DBG("result %d wifi %p", result, wifi); + if (!wifi) + goto error; + if (wifi->p2p_find_timeout) { g_source_remove(wifi->p2p_find_timeout); wifi->p2p_find_timeout = 0; @@ -2117,16 +2171,16 @@ static int wifi_scan(enum connman_service_type type, return -ENODEV; if (wifi->p2p_device) - return 0; + return -EBUSY; + + if (wifi->tethering) + return -EBUSY; if (type == CONNMAN_SERVICE_TYPE_P2P) return p2p_find(device); DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, ssid); - if (wifi->tethering) - return 0; - scanning = connman_device_get_scanning(device); if (!ssid || ssid_len == 0 || ssid_len > 32) { @@ -2419,8 +2473,18 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) ssid->identity = connman_network_get_string(network, "WiFi.AgentIdentity"); + ssid->anonymous_identity = connman_network_get_string(network, + "WiFi.AnonymousIdentity"); ssid->ca_cert_path = connman_network_get_string(network, "WiFi.CACertFile"); + ssid->subject_match = connman_network_get_string(network, + "WiFi.SubjectMatch"); + ssid->altsubject_match = connman_network_get_string(network, + "WiFi.AltSubjectMatch"); + ssid->domain_suffix_match = connman_network_get_string(network, + "WiFi.DomainSuffixMatch"); + ssid->domain_match = connman_network_get_string(network, + "WiFi.DomainMatch"); ssid->client_cert_path = connman_network_get_string(network, "WiFi.ClientCertFile"); ssid->private_key_path = connman_network_get_string(network, @@ -2521,20 +2585,12 @@ found: } if (wifi->network) { - /* - * if result < 0 supplican return an error because - * the network is not current. - * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it - * failed, call connman_network_set_connected to report - * disconnect is completed. - */ - if (result < 0) - connman_network_set_connected(wifi->network, false); + connman_network_set_connected(wifi->network, false); + wifi->network = NULL; } - wifi->network = NULL; - wifi->disconnecting = false; + wifi->connected = false; if (wifi->pending_network) { network_connect(wifi->pending_network); @@ -2625,6 +2681,7 @@ static void interface_added(GSupplicantInterface *interface) if (!wifi) return; + wifi->interface = interface; g_supplicant_interface_set_data(interface, wifi); p2p_iface_list = g_list_append(p2p_iface_list, wifi); wifi->p2p_device = true; @@ -2746,7 +2803,7 @@ static bool handle_wps_completion(GSupplicantInterface *interface, return true; } - ret = send_encryption_request(passphrase, network); + ret = send_encryption_request(passphrase, passphrase); g_free(passphrase); @@ -2766,6 +2823,19 @@ static bool handle_wps_completion(GSupplicantInterface *interface, return true; } +static bool handle_assoc_status_code(GSupplicantInterface *interface, + struct wifi_data *wifi) +{ + if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING && + wifi->assoc_code == ASSOC_STATUS_NO_CLIENT && + wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) { + wifi->load_shaping_retries ++; + return TRUE; + } + wifi->load_shaping_retries = 0; + return FALSE; +} + static bool handle_4way_handshake_failure(GSupplicantInterface *interface, struct connman_network *network, struct wifi_data *wifi) @@ -2864,6 +2934,7 @@ static void interface_state(GSupplicantInterface *interface) struct wifi_data *wifi; GSupplicantState state = g_supplicant_interface_get_state(interface); bool wps; + bool old_connected; wifi = g_supplicant_interface_get_data(interface); @@ -2872,6 +2943,14 @@ static void interface_state(GSupplicantInterface *interface) if (!wifi) return; + if (state == G_SUPPLICANT_STATE_COMPLETED) { + if (wifi->tethering_param) { + g_free(wifi->tethering_param->ssid); + g_free(wifi->tethering_param); + wifi->tethering_param = NULL; + } + } + device = wifi->device; if (!device) return; @@ -2888,6 +2967,9 @@ static void interface_state(GSupplicantInterface *interface) switch (state) { case G_SUPPLICANT_STATE_SCANNING: + if (wifi->connected) + connman_network_set_connected(network, false); + break; case G_SUPPLICANT_STATE_AUTHENTICATING: @@ -2928,8 +3010,10 @@ static void interface_state(GSupplicantInterface *interface) break; connman_network_set_connected(network, true); + wifi->disconnect_code = 0; wifi->assoc_code = 0; + wifi->load_shaping_retries = 0; break; case G_SUPPLICANT_STATE_DISCONNECTED: @@ -2947,6 +3031,9 @@ static void interface_state(GSupplicantInterface *interface) if (is_idle(wifi)) break; + if (handle_assoc_status_code(interface, wifi)) + break; + /* If previous state was 4way-handshake, then * it's either: psk was incorrect and thus we retry * or if we reach the maximum retries we declare the @@ -2969,13 +3056,6 @@ static void interface_state(GSupplicantInterface *interface) break; } - - /* We disable the selected network, if not then - * wpa_supplicant will loop retrying */ - if (g_supplicant_interface_enable_selected_network(interface, - FALSE) != 0) - DBG("Could not disables selected network"); - #if defined TIZEN_EXT int err; @@ -3041,6 +3121,7 @@ static void interface_state(GSupplicantInterface *interface) break; } + old_connected = wifi->connected; wifi->state = state; /* Saving wpa_s state policy: @@ -3052,10 +3133,6 @@ static void interface_state(GSupplicantInterface *interface) * --> We are not connected * */ switch (state) { -#if defined TIZEN_EXT - case G_SUPPLICANT_STATE_SCANNING: - break; -#endif case G_SUPPLICANT_STATE_AUTHENTICATING: case G_SUPPLICANT_STATE_ASSOCIATING: case G_SUPPLICANT_STATE_ASSOCIATED: @@ -3064,8 +3141,12 @@ static void interface_state(GSupplicantInterface *interface) if (wifi->connected) connman_warn("Probably roaming right now!" " Staying connected..."); - else - wifi->connected = false; + break; + case G_SUPPLICANT_STATE_SCANNING: + wifi->connected = false; + + if (old_connected) + start_autoscan(device); break; case G_SUPPLICANT_STATE_COMPLETED: wifi->connected = true; @@ -3106,24 +3187,24 @@ static void interface_removed(GSupplicantInterface *interface) static void set_device_type(const char *type, char dev_type[17]) { const char *oui = "0050F204"; - const char *category = "0100"; + const char *category = "0001"; const char *sub_category = "0000"; if (!g_strcmp0(type, "handset")) { - category = "0A00"; - sub_category = "0500"; + category = "000A"; + sub_category = "0005"; } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container")) - sub_category = "0100"; + sub_category = "0001"; else if (!g_strcmp0(type, "server")) - sub_category = "0200"; + sub_category = "0002"; else if (!g_strcmp0(type, "laptop")) - sub_category = "0500"; + sub_category = "0005"; else if (!g_strcmp0(type, "desktop")) - sub_category = "0600"; + sub_category = "0006"; else if (!g_strcmp0(type, "tablet")) - sub_category = "0900"; + sub_category = "0009"; else if (!g_strcmp0(type, "watch")) - category = "FF00"; + category = "00FF"; snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category); } @@ -3135,6 +3216,9 @@ static void p2p_support(GSupplicantInterface *interface) DBG(""); + if (!interface) + return; + if (!g_supplicant_interface_has_p2p(interface)) return; @@ -3194,6 +3278,36 @@ static void scan_finished(GSupplicantInterface *interface) #endif } +static void ap_create_fail(GSupplicantInterface *interface) +{ + struct wifi_data *wifi = g_supplicant_interface_get_data(interface); + int ret; + + if ((wifi->tethering) && (wifi->tethering_param)) { + DBG("%s create AP fail \n", + g_supplicant_interface_get_ifname(wifi->interface)); + + connman_inet_remove_from_bridge(wifi->index, wifi->bridge); + wifi->ap_supported = WIFI_AP_NOT_SUPPORTED; + wifi->tethering = false; + + ret = tech_set_tethering(wifi->tethering_param->technology, + wifi->tethering_param->ssid->ssid, + wifi->tethering_param->ssid->passphrase, + wifi->bridge, true); + + if ((ret == -EOPNOTSUPP) && (wifi_technology)) { + connman_technology_tethering_notify(wifi_technology,false); + } + + g_free(wifi->tethering_param->ssid); + g_free(wifi->tethering_param); + wifi->tethering_param = NULL; + } + + return; +} + static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network) { unsigned char strength; @@ -3221,7 +3335,8 @@ static void network_added(GSupplicantNetwork *supplicant_network) bool wps_advertizing; #if defined TIZEN_EXT - GSList *vsie_list = NULL; + const char *wifi_vsie; + unsigned int wifi_vsie_len; #endif mode = g_supplicant_network_get_mode(supplicant_network); @@ -3248,6 +3363,9 @@ static void network_added(GSupplicantNetwork *supplicant_network) ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len); +#if defined TIZEN_EXT + wifi_vsie = g_supplicant_network_get_wifi_vsie(supplicant_network, &wifi_vsie_len); +#endif network = connman_device_get_network(wifi->device, identifier); if (!network) { @@ -3272,11 +3390,9 @@ 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"); + if(wifi_vsie_len > 0 && wifi_vsie) + connman_network_set_blob(network, "WiFi.Vsie", + wifi_vsie, wifi_vsie_len); #endif connman_network_set_string(network, "WiFi.Security", security); connman_network_set_strength(network, @@ -3433,6 +3549,57 @@ static void network_changed(GSupplicantNetwork *network, const char *property) #endif } +static void network_associated(GSupplicantNetwork *network) +{ + GSupplicantInterface *interface; + struct wifi_data *wifi; + struct connman_network *connman_network; + const char *identifier; + + DBG(""); + + interface = g_supplicant_network_get_interface(network); + if (!interface) + 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; + + if (wifi->network) { + if (wifi->network == connman_network) + return; + + /* + * This should never happen, we got associated with + * a network different than the one we were expecting. + */ + DBG("Associated to %p while expecting %p", + connman_network, wifi->network); + + connman_network_set_associating(wifi->network, false); + } + + DBG("Reconnecting to previous network %p from wpa_s", connman_network); + + wifi->network = connman_network_ref(connman_network); + wifi->retries = 0; + + /* + * Interface state changes callback (interface_state) is always + * called before network_associated callback thus we need to call + * interface_state again in order to process the new state now that + * we have the network properly set. + */ + interface_state(interface); +} + static void apply_peer_services(GSupplicantPeer *peer, struct connman_peer *connman_peer) { @@ -3489,6 +3656,8 @@ static void peer_found(GSupplicantPeer *peer) ret = connman_peer_register(connman_peer); if (ret < 0 && ret != -EALREADY) connman_peer_unref(connman_peer); + else + wifi->peers = g_slist_prepend(wifi->peers, connman_peer); } static void peer_lost(GSupplicantPeer *peer) @@ -3514,6 +3683,8 @@ static void peer_lost(GSupplicantPeer *peer) connman_peer_unregister(connman_peer); connman_peer_unref(connman_peer); } + + wifi->peers = g_slist_remove(wifi->peers, connman_peer); } static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state) @@ -3533,6 +3704,9 @@ static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state) DBG("ident: %s", identifier); + if (!wifi) + return; + connman_peer = connman_peer_get(wifi->device, identifier); if (!connman_peer) return; @@ -3595,6 +3769,14 @@ static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state) connman_peer_set_as_master(connman_peer, !g_supplicant_peer_is_client(peer)); connman_peer_set_sub_device(connman_peer, g_wifi->device); + + /* + * If wpa_supplicant didn't create a dedicated p2p-group + * interface then mark this interface as p2p_device to avoid + * scan and auto-scan are launched on it while P2P is connected. + */ + if (!g_list_find(p2p_iface_list, g_wifi)) + wifi->p2p_device = true; } connman_peer_set_state(connman_peer, p_state); @@ -3727,6 +3909,7 @@ static void disconnect_reasoncode(GSupplicantInterface *interface, int reasoncode) { struct wifi_data *wifi = g_supplicant_interface_get_data(interface); + if (wifi != NULL) { wifi->disconnect_code = reasoncode; } @@ -3736,18 +3919,8 @@ static void assoc_status_code(GSupplicantInterface *interface, int status_code) { struct wifi_data *wifi = g_supplicant_interface_get_data(interface); -#if defined TIZEN_EXT - struct connman_network *network; -#endif - if (wifi != NULL) { wifi->assoc_code = status_code; - -#if defined TIZEN_EXT - network = wifi->network; - connman_network_set_assoc_status_code(network,status_code); -#endif - } } @@ -3760,9 +3933,11 @@ static const GSupplicantCallbacks callbacks = { .p2p_support = p2p_support, .scan_started = scan_started, .scan_finished = scan_finished, + .ap_create_fail = ap_create_fail, .network_added = network_added, .network_removed = network_removed, .network_changed = network_changed, + .network_associated = network_associated, .add_station = add_station, .remove_station = remove_station, .peer_found = peer_found, @@ -3771,12 +3946,12 @@ static const GSupplicantCallbacks callbacks = { .peer_request = peer_request, #if defined TIZEN_EXT .system_power_off = system_power_off, - .network_merged = network_merged, + .network_merged = network_merged, .assoc_failed = assoc_failed, #endif + .debug = debug, .disconnect_reasoncode = disconnect_reasoncode, .assoc_status_code = assoc_status_code, - .debug = debug, }; @@ -3792,15 +3967,8 @@ static void tech_remove(struct connman_technology *technology) wifi_technology = NULL; } -struct wifi_tethering_info { - struct wifi_data *wifi; - struct connman_technology *technology; - char *ifname; - GSupplicantSSID *ssid; -}; - static GSupplicantSSID *ssid_ap_init(const char *ssid, - const char *passphrase, bool hidden) + const char *passphrase) { GSupplicantSSID *ap; @@ -3825,12 +3993,6 @@ static GSupplicantSSID *ssid_ap_init(const char *ssid, ap->passphrase = passphrase; } - if (hidden) - ap->ignore_broadcast_ssid = - G_SUPPLICANT_AP_HIDDEN_SSID_ZERO_CONTENTS; - else - ap->ignore_broadcast_ssid = G_SUPPLICANT_AP_NO_SSID_HIDING; - return ap; } @@ -3842,10 +4004,16 @@ static void ap_start_callback(int result, GSupplicantInterface *interface, DBG("result %d index %d bridge %s", result, info->wifi->index, info->wifi->bridge); - if (result < 0) { + if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) { connman_inet_remove_from_bridge(info->wifi->index, info->wifi->bridge); - connman_technology_tethering_notify(info->technology, false); + + if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) { + connman_technology_tethering_notify(info->technology, false); + g_free(info->wifi->tethering_param->ssid); + g_free(info->wifi->tethering_param); + info->wifi->tethering_param = NULL; + } } g_free(info->ifname); @@ -3861,10 +4029,17 @@ static void ap_create_callback(int result, DBG("result %d ifname %s", result, g_supplicant_interface_get_ifname(interface)); - if (result < 0) { + if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) { connman_inet_remove_from_bridge(info->wifi->index, info->wifi->bridge); - connman_technology_tethering_notify(info->technology, false); + + if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) { + connman_technology_tethering_notify(info->technology, false); + g_free(info->wifi->tethering_param->ssid); + g_free(info->wifi->tethering_param); + info->wifi->tethering_param = NULL; + + } g_free(info->ifname); g_free(info->ssid); @@ -3891,27 +4066,32 @@ static void sta_remove_callback(int result, DBG("ifname %s result %d ", info->ifname, result); - if (result < 0) { - info->wifi->tethering = true; + if (result < 0 || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) { + info->wifi->tethering = false; + connman_technology_tethering_notify(info->technology, false); g_free(info->ifname); g_free(info->ssid); g_free(info); + + if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) { + g_free(info->wifi->tethering_param->ssid); + g_free(info->wifi->tethering_param); + info->wifi->tethering_param = NULL; + } return; } info->wifi->interface = NULL; - connman_technology_tethering_notify(info->technology, true); - g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge, ap_create_callback, info); } -static int tech_set_tethering(struct connman_technology *technology, - const char *identifier, const char *passphrase, - const char *bridge, bool enabled, bool hidden) +static int enable_wifi_tethering(struct connman_technology *technology, + const char *bridge, const char *identifier, + const char *passphrase, bool available) { GList *list; GSupplicantInterface *interface; @@ -3919,75 +4099,143 @@ static int tech_set_tethering(struct connman_technology *technology, struct wifi_tethering_info *info; const char *ifname; unsigned int mode; - int err; - - DBG(""); - - if (!enabled) { - for (list = iface_list; list; list = list->next) { - wifi = list->data; - - if (wifi->tethering) { - wifi->tethering = false; - - connman_inet_remove_from_bridge(wifi->index, - bridge); - wifi->bridged = false; - } - } - - connman_technology_tethering_notify(technology, false); - - return 0; - } + int err, berr = 0; for (list = iface_list; list; list = list->next) { wifi = list->data; + DBG("wifi %p network %p pending_network %p", wifi, + wifi->network, wifi->pending_network); + interface = wifi->interface; if (!interface) continue; + if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) + continue; + ifname = g_supplicant_interface_get_ifname(wifi->interface); + if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) { + DBG("%s does not support AP mode (detected)", ifname); + continue; + } + mode = g_supplicant_interface_get_mode(interface); if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) { - DBG("%s does not support AP mode", ifname); + wifi->ap_supported = WIFI_AP_NOT_SUPPORTED; + DBG("%s does not support AP mode (capability)", ifname); continue; } + if (wifi->network && available) + continue; + info = g_try_malloc0(sizeof(struct wifi_tethering_info)); if (!info) return -ENOMEM; + wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info)); + if (!wifi->tethering_param) { + g_free(info); + return -ENOMEM; + } + info->wifi = wifi; info->technology = technology; info->wifi->bridge = bridge; - info->ssid = ssid_ap_init(identifier, passphrase, hidden); - if (!info->ssid) { - g_free(info); - continue; - } + info->ssid = ssid_ap_init(identifier, passphrase); + if (!info->ssid) + goto failed; + info->ifname = g_strdup(ifname); - if (!info->ifname) { - g_free(info->ssid); - g_free(info); - continue; - } + if (!info->ifname) + goto failed; + + wifi->tethering_param->technology = technology; + wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase); + if (!wifi->tethering_param->ssid) + goto failed; info->wifi->tethering = true; + info->wifi->ap_supported = WIFI_AP_SUPPORTED; + + berr = connman_technology_tethering_notify(technology, true); + if (berr < 0) + goto failed; err = g_supplicant_interface_remove(interface, sta_remove_callback, info); - if (err == 0) - return err; + if (err >= 0) { + DBG("tethering wifi %p ifname %s", wifi, ifname); + return 0; + } + + failed: + g_free(info->ifname); + g_free(info->ssid); + g_free(info); + g_free(wifi->tethering_param); + wifi->tethering_param = NULL; + + /* + * Remove bridge if it was correctly created but remove + * operation failed. Instead, if bridge creation failed then + * break out and do not try again on another interface, + * bridge set-up does not depend on it. + */ + if (berr == 0) + connman_technology_tethering_notify(technology, false); + else + break; } return -EOPNOTSUPP; } +static int tech_set_tethering(struct connman_technology *technology, + const char *identifier, const char *passphrase, + const char *bridge, bool enabled) +{ + GList *list; + struct wifi_data *wifi; + int err; + + DBG(""); + + if (!enabled) { + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->tethering) { + wifi->tethering = false; + + connman_inet_remove_from_bridge(wifi->index, + bridge); + wifi->bridged = false; + } + } + + connman_technology_tethering_notify(technology, false); + + return 0; + } + + DBG("trying tethering for available devices"); + err = enable_wifi_tethering(technology, bridge, identifier, passphrase, + true); + + if (err < 0) { + DBG("trying tethering for any device"); + err = enable_wifi_tethering(technology, bridge, identifier, + passphrase, false); + } + + return err; +} + static void regdom_callback(int result, const char *alpha2, void *user_data) { DBG(""); |