summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorSeonah Moon <seonah1.moon@samsung.com>2018-01-23 14:50:50 +0900
committerSeonah Moon <seonah1.moon@samsung.com>2018-01-23 14:50:55 +0900
commit30602f521a85820a9f6b7ac04876400e00c68b15 (patch)
treef035a4fcc014a034f3b492886d1e8395f327fd25 /plugins
parenta079cfe6f815f8c69055de834d1ccbdf1fd94ba7 (diff)
parent9362752a471a5c892d679548fbf2828d5fc5684b (diff)
downloadconnman-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-xplugins/bluetooth.c28
-rwxr-xr-xplugins/bluetooth_legacy.c1461
-rwxr-xr-xplugins/ethernet.c61
-rwxr-xr-xplugins/gadget.c2
-rw-r--r--plugins/iwd.c1108
-rwxr-xr-xplugins/neard.c4
-rwxr-xr-xplugins/ofono.c561
-rwxr-xr-xplugins/pacrunner.c10
-rwxr-xr-xplugins/session_policy_local.c4
-rwxr-xr-xplugins/vpn.c39
-rwxr-xr-xplugins/wifi.c504
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,
- &register_call, TIMEOUT)) {
- dbus_message_unref(message);
+ &register_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("");