summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorNiraj Kumar Goit <niraj.g@samsung.com>2022-02-15 10:23:07 +0530
committerNiraj Kumar Goit <niraj.g@samsung.com>2022-02-15 10:25:05 +0530
commitf89b473dfd8e916314b534b3397442f8c869c783 (patch)
treeb6f15a191886ac5b78e98b1b2b210adefae69cf2 /plugins
parentdd3cccc5e67548dcc2dd6c6254ed6c97859085d5 (diff)
downloadconnman-f89b473dfd8e916314b534b3397442f8c869c783.tar.gz
connman-f89b473dfd8e916314b534b3397442f8c869c783.tar.bz2
connman-f89b473dfd8e916314b534b3397442f8c869c783.zip
Imported Upstream version 1.40upstream/1.40
Change-Id: Id3e405d088ee3fb19fd0ca049e1cb7f812b40fca Signed-off-by: Niraj Kumar Goit <niraj.g@samsung.com>
Diffstat (limited to 'plugins')
-rw-r--r--plugins/bluetooth.c4
-rw-r--r--plugins/dundee.c2
-rw-r--r--plugins/ethernet.c12
-rw-r--r--plugins/iwd.c310
-rw-r--r--plugins/neard.c2
-rw-r--r--plugins/ofono.c4
-rw-r--r--plugins/vpn.c297
-rw-r--r--plugins/wifi.c117
8 files changed, 575 insertions, 173 deletions
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index f759a902..53361034 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -717,8 +717,6 @@ static bool tethering_create(const char *path,
const char *method;
bool result;
- DBG("path %s bridge %s", path, bridge);
-
if (!bridge) {
g_free(tethering);
return false;
@@ -730,6 +728,8 @@ static bool tethering_create(const char *path,
return false;
}
+ DBG("path %s bridge %s", path, bridge);
+
tethering->technology = technology;
tethering->bridge = g_strdup(bridge);
tethering->enable = enabled;
diff --git a/plugins/dundee.c b/plugins/dundee.c
index b5420acf..57571ec3 100644
--- a/plugins/dundee.c
+++ b/plugins/dundee.c
@@ -488,7 +488,7 @@ static void extract_settings(DBusMessageIter *array,
if (index < 0)
goto out;
- info->address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
+ info->address = connman_ipaddress_alloc(AF_INET);
if (!info->address)
goto out;
diff --git a/plugins/ethernet.c b/plugins/ethernet.c
index ed4208ad..6146b1c0 100644
--- a/plugins/ethernet.c
+++ b/plugins/ethernet.c
@@ -73,7 +73,7 @@ static int get_vlan_vid(const char *ifname)
return -errno;
vifr.cmd = GET_VLAN_VID_CMD;
- stpncpy(vifr.device1, ifname, sizeof(vifr.device1));
+ stpncpy(vifr.device1, ifname, sizeof(vifr.device1) - 1);
if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
vid = vifr.u.VID;
@@ -99,14 +99,16 @@ static int get_dsa_port(const char *ifname)
return -errno;
memset(&ifr, 0, sizeof(ifr));
- stpncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ stpncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
/* check if it is a vlan and get physical interface name*/
vifr.cmd = GET_VLAN_REALDEV_NAME_CMD;
- stpncpy(vifr.device1, ifname, sizeof(vifr.device1));
+ stpncpy(vifr.device1, ifname, sizeof(vifr.device1) - 1);
- if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
- stpncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name));
+ if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0) {
+ stpncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+ }
/* get driver info */
drvinfocmd.cmd = ETHTOOL_GDRVINFO;
diff --git a/plugins/iwd.c b/plugins/iwd.c
index bf6a2c26..4ba107f3 100644
--- a/plugins/iwd.c
+++ b/plugins/iwd.c
@@ -95,6 +95,8 @@ struct iwd_network {
struct iwd_device *iwdd;
struct connman_network *network;
+ /* service's autoconnect */
+ bool autoconnect;
};
struct iwd_known_network {
@@ -106,6 +108,9 @@ struct iwd_known_network {
char *last_connected_time;
bool auto_connect;
int auto_connect_id;
+
+ /* service's autoconnect */
+ bool autoconnect;
};
struct iwd_station {
@@ -244,7 +249,7 @@ static void cm_network_connect_cb(DBusMessage *message, void *user_data)
if (!strcmp(dbus_error, "net.connman.iwd.Failed"))
connman_network_set_error(iwdn->network,
CONNMAN_NETWORK_ERROR_INVALID_KEY);
- else
+ else if (!iwdn->autoconnect)
connman_network_set_error(iwdn->network,
CONNMAN_NETWORK_ERROR_CONNECT_FAIL);
return;
@@ -318,12 +323,157 @@ static int cm_network_disconnect(struct connman_network *network)
return -EINPROGRESS;
}
+struct auto_connect_cb_data {
+ char *path;
+ bool auto_connect;
+};
+
+static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
+{
+ g_free(cbd->path);
+ g_free(cbd);
+}
+
+static void auto_connect_cb(const DBusError *error, void *user_data)
+{
+ struct auto_connect_cb_data *cbd = user_data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, cbd->path);
+ if (!iwdkn)
+ goto out;
+
+ if (dbus_error_is_set(error))
+ connman_warn("WiFi known network %s property auto connect %s",
+ cbd->path, error->message);
+
+ /* property is updated via watch known_network_property_change() */
+out:
+ auto_connect_cb_free(cbd);
+}
+
+static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
+{
+ dbus_bool_t dbus_auto_connect = auto_connect;
+ struct auto_connect_cb_data *cbd;
+
+ if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
+ return -EALREADY;
+
+ cbd = g_new(struct auto_connect_cb_data, 1);
+ cbd->path = g_strdup(iwdkn->path);
+ cbd->auto_connect = auto_connect;
+
+ if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
+ DBUS_TYPE_BOOLEAN,
+ &dbus_auto_connect,
+ auto_connect_cb, cbd, NULL)) {
+ auto_connect_cb_free(cbd);
+ return -EIO;
+ }
+
+ return -EINPROGRESS;
+}
+
+static gboolean disable_auto_connect_cb(gpointer data)
+{
+ char *path = data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return FALSE;
+
+ if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
+ connman_warn("Failed to disable auto connect");
+
+ iwdkn->auto_connect_id = 0;
+ return FALSE;
+}
+
+static int disable_auto_connect(struct iwd_known_network *iwdkn)
+{
+ if (iwdkn->auto_connect_id)
+ return -EBUSY;
+
+ iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ 0,
+ disable_auto_connect_cb,
+ g_strdup(iwdkn->path),
+ g_free);
+ return 0;
+}
+
+static gboolean enable_auto_connect_cb(gpointer data)
+{
+ char *path = data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return FALSE;
+
+ if (set_auto_connect(iwdkn, true) != -EINPROGRESS)
+ connman_warn("Failed to enable auto connect");
+
+ iwdkn->auto_connect_id = 0;
+ return FALSE;
+}
+
+static int enable_auto_connect(struct iwd_known_network *iwdkn)
+{
+ if (iwdkn->auto_connect_id)
+ return -EBUSY;
+
+ iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ 0,
+ enable_auto_connect_cb,
+ g_strdup(iwdkn->path),
+ g_free);
+ return 0;
+}
+
+static int update_auto_connect(struct iwd_known_network *iwdkn)
+{
+ DBG("auto_connect %d autoconnect %d", iwdkn->auto_connect, iwdkn->autoconnect);
+
+ if (iwdkn->auto_connect == iwdkn->autoconnect)
+ return -EALREADY;
+
+ if (iwdkn->autoconnect)
+ return enable_auto_connect(iwdkn);
+ return disable_auto_connect(iwdkn);
+}
+
+static int cm_network_set_autoconnect(struct connman_network *network,
+ bool autoconnect)
+{
+ struct iwd_network *iwdn = connman_network_get_data(network);
+ struct iwd_known_network *iwdkn;
+
+ DBG("autoconnect %d", autoconnect);
+
+ iwdn->autoconnect = autoconnect;
+
+ if (!iwdn->known_network)
+ return -ENOENT;
+
+ iwdkn = g_hash_table_lookup(known_networks, iwdn->known_network);
+ if (!iwdkn)
+ return -ENOENT;
+
+ iwdkn->autoconnect = autoconnect;
+
+ return update_auto_connect(iwdkn);
+}
+
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,
+ .name = "iwd",
+ .type = CONNMAN_NETWORK_TYPE_WIFI,
+ .probe = cm_network_probe,
+ .connect = cm_network_connect,
+ .disconnect = cm_network_disconnect,
+ .set_autoconnect = cm_network_set_autoconnect,
};
static int cm_device_probe(struct connman_device *device)
@@ -535,7 +685,7 @@ static void tech_enable_tethering_cb(const DBusError *error, void *user_data)
{
struct tech_cb_data *cbd = user_data;
struct iwd_device *iwdd;
- struct iwd_ap *iwdap;
+ struct iwd_ap *iwdap = NULL;
DBG("");
@@ -616,7 +766,7 @@ static void tech_disable_tethering_cb(const DBusError *error, void *user_data)
if (!g_dbus_proxy_method_call(iwdap->proxy, "Stop",
NULL, tech_ap_stop_cb, cbd, NULL)) {
- connman_warn("iwd ap %s could not start AccessPoint mode: %s",
+ connman_warn("iwd ap %s could not stop AccessPoint mode: %s",
cbd->path, error->message);
goto out;
}
@@ -923,6 +1073,7 @@ static void network_property_change(GDBusProxy *proxy, const char *name,
DBusMessageIter *iter, void *user_data)
{
struct iwd_network *iwdn;
+ struct iwd_known_network *iwdkn;
const char *path;
path = g_dbus_proxy_get_path(proxy);
@@ -942,6 +1093,17 @@ static void network_property_change(GDBusProxy *proxy, const char *name,
update_network_connected(iwdn);
else
update_network_disconnected(iwdn);
+ } else if (!strcmp(name, "KnownNetwork")) {
+ g_free(iwdn->known_network);
+ iwdn->known_network =
+ g_strdup(proxy_get_string(proxy, "KnownNetwork"));
+ if (!iwdn->known_network)
+ return;
+
+ iwdkn = g_hash_table_lookup(known_networks,
+ iwdn->known_network);
+ if (iwdkn)
+ update_auto_connect(iwdkn);
}
}
@@ -972,12 +1134,15 @@ static void _update_signal_strength(const char *path, int16_t signal_strength)
connman_network_set_strength(iwdn->network,
calculate_strength(signal_strength));
+ connman_network_set_available(iwdn->network, true);
connman_network_update(iwdn->network);
}
static void ordered_networks_cb(DBusMessage *message, void *user_data)
{
DBusMessageIter array, entry;
+ struct iwd_device *iwdd;
+ char *path = user_data;
DBG("");
@@ -1005,6 +1170,11 @@ static void ordered_networks_cb(DBusMessage *message, void *user_data)
dbus_message_iter_next(&entry);
}
+
+ iwdd = g_hash_table_lookup(devices, path);
+ if (iwdd)
+ connman_device_set_scanning(iwdd->device,
+ CONNMAN_SERVICE_TYPE_WIFI, false);
}
static void update_signal_strength(struct iwd_station *iwds)
@@ -1012,7 +1182,7 @@ static void update_signal_strength(struct iwd_station *iwds)
if (!g_dbus_proxy_method_call(iwds->proxy,
"GetOrderedNetworks",
NULL, ordered_networks_cb,
- NULL, NULL))
+ g_strdup(iwds->path), g_free))
DBG("GetOrderedNetworks() failed");
}
@@ -1020,6 +1190,7 @@ static void station_property_change(GDBusProxy *proxy, const char *name,
DBusMessageIter *iter, void *user_data)
{
struct iwd_station *iwds;
+ struct iwd_device *iwdd;
const char *path;
path = g_dbus_proxy_get_path(proxy);
@@ -1053,8 +1224,15 @@ static void station_property_change(GDBusProxy *proxy, const char *name,
dbus_message_iter_get_basic(iter, &scanning);
iwds->scanning = scanning;
- if (!iwds->scanning)
+ if (iwds->scanning) {
+ iwdd = g_hash_table_lookup(devices, path);
+ if (iwdd)
+ connman_device_set_scanning(iwdd->device,
+ CONNMAN_SERVICE_TYPE_WIFI, true);
+ } else {
update_signal_strength(iwds);
+ }
+
DBG("%s scanning %d", path, iwds->scanning);
}
@@ -1452,86 +1630,6 @@ static void create_network(GDBusProxy *proxy)
add_network(path, iwdn);
}
-struct auto_connect_cb_data {
- char *path;
- bool auto_connect;
-};
-
-static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
-{
- g_free(cbd->path);
- g_free(cbd);
-}
-
-static void auto_connect_cb(const DBusError *error, void *user_data)
-{
- struct auto_connect_cb_data *cbd = user_data;
- struct iwd_known_network *iwdkn;
-
- iwdkn = g_hash_table_lookup(known_networks, cbd->path);
- if (!iwdkn)
- goto out;
-
- if (dbus_error_is_set(error))
- connman_warn("WiFi known network %s property auto connect %s",
- cbd->path, error->message);
-
- /* property is updated via watch known_network_property_change() */
-out:
- auto_connect_cb_free(cbd);
-}
-
-static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
-{
- dbus_bool_t dbus_auto_connect = auto_connect;
- struct auto_connect_cb_data *cbd;
-
- if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
- return -EALREADY;
-
- cbd = g_new(struct auto_connect_cb_data, 1);
- cbd->path = g_strdup(iwdkn->path);
- cbd->auto_connect = auto_connect;
-
- if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
- DBUS_TYPE_BOOLEAN,
- &dbus_auto_connect,
- auto_connect_cb, cbd, NULL)) {
- auto_connect_cb_free(cbd);
- return -EIO;
- }
-
- return -EINPROGRESS;
-}
-
-static gboolean disable_auto_connect_cb(gpointer data)
-{
- char *path = data;
- struct iwd_known_network *iwdkn;
-
- iwdkn = g_hash_table_lookup(known_networks, path);
- if (!iwdkn)
- return FALSE;
-
- if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
- connman_warn("Failed to disable auto connect");
-
- iwdkn->auto_connect_id = 0;
- return FALSE;
-}
-
-static void disable_auto_connect(struct iwd_known_network *iwdkn)
-{
- if (iwdkn->auto_connect_id)
- return;
-
- iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
- 0,
- disable_auto_connect_cb,
- g_strdup(iwdkn->path),
- g_free);
-}
-
static void known_network_property_change(GDBusProxy *proxy, const char *name,
DBusMessageIter *iter, void *user_data)
{
@@ -1551,8 +1649,31 @@ static void known_network_property_change(GDBusProxy *proxy, const char *name,
DBG("%p auto_connect %d", path, iwdkn->auto_connect);
- if (iwdkn->auto_connect)
- disable_auto_connect(iwdkn);
+ update_auto_connect(iwdkn);
+ }
+}
+
+static void init_auto_connect(struct iwd_known_network *iwdkn)
+{
+ 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;
+ struct iwd_known_network *kn;
+
+ if (!iwdn->known_network)
+ continue;
+
+ kn = g_hash_table_lookup(known_networks, iwdn->known_network);
+ if (iwdkn != kn)
+ continue;
+
+ iwdkn->autoconnect = iwdn->autoconnect;
+ update_auto_connect(iwdkn);
+ return;
}
}
@@ -1589,11 +1710,10 @@ static void create_know_network(GDBusProxy *proxy)
iwdkn->name, iwdkn->type, iwdkn->hidden,
iwdkn->last_connected_time, iwdkn->auto_connect);
+ init_auto_connect(iwdkn);
+
g_dbus_proxy_set_property_watch(iwdkn->proxy,
known_network_property_change, NULL);
-
- if (iwdkn->auto_connect)
- disable_auto_connect(iwdkn);
}
static void create_station(GDBusProxy *proxy)
diff --git a/plugins/neard.c b/plugins/neard.c
index 69586df6..45effd44 100644
--- a/plugins/neard.c
+++ b/plugins/neard.c
@@ -499,7 +499,7 @@ static void register_agent_cb(DBusPendingCall *pending, void *user_data)
DBusMessage *reply;
if (!dbus_pending_call_get_completed(pending))
- return;
+ goto out;
register_call = NULL;
diff --git a/plugins/ofono.c b/plugins/ofono.c
index 36873d5a..f0bd3c5d 100644
--- a/plugins/ofono.c
+++ b/plugins/ofono.c
@@ -910,7 +910,7 @@ static void extract_ipv4_settings(DBusMessageIter *array,
if (context->ipv4_method != CONNMAN_IPCONFIG_METHOD_FIXED)
goto out;
- context->ipv4_address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
+ context->ipv4_address = connman_ipaddress_alloc(AF_INET);
if (!context->ipv4_address) {
context->index = -1;
goto out;
@@ -998,7 +998,7 @@ static void extract_ipv6_settings(DBusMessageIter *array,
context->ipv6_method = CONNMAN_IPCONFIG_METHOD_AUTO;
context->ipv6_address =
- connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
+ connman_ipaddress_alloc(AF_INET6);
if (!context->ipv6_address)
goto out;
diff --git a/plugins/vpn.c b/plugins/vpn.c
index 5668c004..d708d1ff 100644
--- a/plugins/vpn.c
+++ b/plugins/vpn.c
@@ -85,6 +85,7 @@ struct connection_data {
char *domain;
char **nameservers;
bool immutable;
+ bool default_route_set;
GHashTable *server_routes;
GHashTable *user_routes;
@@ -94,6 +95,7 @@ struct connection_data {
GResolv *resolv;
guint resolv_id;
+ guint remove_resolv_id;
};
static int set_string(struct connman_provider *provider,
@@ -151,6 +153,8 @@ static const char *get_string(struct connman_provider *provider,
return data->host_ip[0];
} else if (g_str_equal(key, "VPN.Domain"))
return data->domain;
+ else if (g_str_equal(key, "Transport"))
+ return data->service_ident;
return g_hash_table_lookup(data->setting_strings, key);
}
@@ -171,10 +175,15 @@ static char *get_ident(const char *path)
static void cancel_host_resolv(struct connection_data *data)
{
- if (data->resolv_id != 0)
+
+ if (data->remove_resolv_id)
+ g_source_remove(data->remove_resolv_id);
+
+ if (data->resolv && data->resolv_id)
g_resolv_cancel_lookup(data->resolv, data->resolv_id);
data->resolv_id = 0;
+ data->remove_resolv_id = 0;
g_resolv_unref(data->resolv);
data->resolv = NULL;
@@ -206,7 +215,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_idle_add(remove_resolv, data);
+ data->remove_resolv_id = g_idle_add(remove_resolv, data);
data->resolv_id = 0;
}
@@ -261,14 +270,12 @@ static bool provider_is_connected(struct connection_data *data)
static void set_provider_state(struct connection_data *data)
{
enum connman_provider_state state = CONNMAN_PROVIDER_STATE_UNKNOWN;
+ bool connected;
int err = 0;
DBG("provider %p new state %s", data->provider, data->state);
- if (!provider_is_connected(data)) {
- g_free(data->service_ident);
- data->service_ident = NULL;
- }
+ connected = provider_is_connected(data);
if (g_str_equal(data->state, "ready")) {
state = CONNMAN_PROVIDER_STATE_READY;
@@ -288,7 +295,7 @@ static void set_provider_state(struct connection_data *data)
}
connman_provider_set_state(data->provider, state);
- return;
+ goto free;
set:
if (data->cb_data)
@@ -299,6 +306,12 @@ set:
free_config_cb_data(data->cb_data);
data->cb_data = NULL;
+
+free:
+ if (!connected) {
+ g_free(data->service_ident);
+ data->service_ident = NULL;
+ }
}
static int create_provider(struct connection_data *data, void *user_data)
@@ -431,6 +444,7 @@ static int extract_ip(DBusMessageIter *array, int family,
}
connman_ipaddress_set_peer(data->ip, peer);
+ connman_ipaddress_set_p2p(data->ip, true);
return 0;
}
@@ -490,8 +504,12 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
struct connection_data *data = user_data;
struct config_create_data *cb_data = data->cb_data;
- if (!dbus_pending_call_get_completed(call))
- return;
+ DBG("");
+
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("vpn connect reply pending call incomplete");
+ goto out;
+ }
if (call != data->call) {
connman_error("invalid call %p to VPN connect_reply data %p "
@@ -769,12 +787,16 @@ static void get_connections_reply(DBusPendingCall *call, void *user_data)
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
DBUS_STRUCT_END_CHAR_AS_STRING;
- if (!dbus_pending_call_get_completed(call))
- return;
-
DBG("");
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("get connections reply pending call incomplete");
+ goto out;
+ }
+
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
@@ -814,6 +836,7 @@ static void get_connections_reply(DBusPendingCall *call, void *user_data)
done:
dbus_message_unref(reply);
+out:
dbus_pending_call_unref(call);
}
@@ -861,12 +884,16 @@ static void remove_connection_reply(DBusPendingCall *call, void *user_data)
DBusMessage *reply;
DBusError error;
- if (!dbus_pending_call_get_completed(call))
- return;
-
DBG("");
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("remove connection reply pending call incomplete");
+ goto out;
+ }
+
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
@@ -884,6 +911,7 @@ static void remove_connection_reply(DBusPendingCall *call, void *user_data)
dbus_message_unref(reply);
+out:
dbus_pending_call_unref(call);
}
@@ -1010,11 +1038,14 @@ static int disconnect_provider(struct connection_data *data)
dbus_pending_call_set_notify(data->disconnect_call, disconnect_reply,
data, NULL);
- g_free(data->service_ident);
- data->service_ident = NULL;
+ data->default_route_set = false;
connman_provider_set_state(data->provider,
CONNMAN_PROVIDER_STATE_DISCONNECT);
+
+ g_free(data->service_ident);
+ data->service_ident = NULL;
+
return -EINPROGRESS;
}
@@ -1055,12 +1086,16 @@ static void configuration_create_reply(DBusPendingCall *call, void *user_data)
struct connection_data *data;
struct config_create_data *cb_data = user_data;
- if (!dbus_pending_call_get_completed(call))
- return;
-
DBG("user %p", cb_data);
+ if (!dbus_pending_call_get_completed(call)) {
+ connman_warn("configuration create reply pending call incomplete");
+ goto out;
+ }
+
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
@@ -1114,6 +1149,7 @@ static void configuration_create_reply(DBusPendingCall *call, void *user_data)
done:
dbus_message_unref(reply);
+out:
dbus_pending_call_unref(call);
}
@@ -1461,6 +1497,17 @@ static void set_route(struct connection_data *data, struct vpn_route *route)
return;
}
+ DBG("set route provider %p %s/%s/%s", data->provider,
+ route->network, route->gateway,
+ route->netmask);
+
+ /* Do not add default route for split routed VPNs.*/
+ if (connman_provider_is_split_routing(data->provider) &&
+ connman_inet_is_default_route(route->family,
+ route->network, route->gateway,
+ route->netmask))
+ return;
+
if (route->family == AF_INET6) {
unsigned char prefix_len = atoi(route->netmask);
@@ -1473,6 +1520,126 @@ static void set_route(struct connection_data *data, struct vpn_route *route)
route->gateway,
route->netmask);
}
+
+ if (connman_inet_is_default_route(route->family, route->network,
+ route->gateway, route->netmask))
+ data->default_route_set = true;
+}
+
+static int save_route(GHashTable *routes, int family, const char *network,
+ const char *netmask, const char *gateway);
+
+static int add_network_route(struct connection_data *data)
+{
+ struct vpn_route rt = { 0, };
+ int err;
+
+ if (!data)
+ return -EINVAL;
+
+ rt.family = connman_provider_get_family(data->provider);
+ switch (rt.family) {
+ case PF_INET:
+ err = connman_inet_get_route_addresses(data->index,
+ &rt.network, &rt.netmask, &rt.gateway);
+ break;
+ case PF_INET6:
+ err = connman_inet_ipv6_get_route_addresses(data->index,
+ &rt.network, &rt.netmask, &rt.gateway);
+ break;
+ default:
+ connman_error("invalid protocol family %d", rt.family);
+ return -EINVAL;
+ }
+
+ DBG("network %s gateway %s netmask %s for provider %p",
+ rt.network, rt.gateway, rt.netmask,
+ data->provider);
+
+ if (err) {
+ connman_error("cannot get network/gateway/netmask for %p",
+ data->provider);
+ goto out;
+ }
+
+ err = save_route(data->server_routes, rt.family, rt.network, rt.netmask,
+ rt.gateway);
+ if (err) {
+ connman_warn("failed to add network route for provider"
+ "%p", data->provider);
+ goto out;
+ }
+
+ set_route(data, &rt);
+
+out:
+ g_free(rt.network);
+ g_free(rt.netmask);
+ g_free(rt.gateway);
+
+ return 0;
+}
+
+static bool is_valid_route_table(struct connman_provider *provider,
+ GHashTable *table)
+{
+ GHashTableIter iter;
+ gpointer value, key;
+ struct vpn_route *route;
+ size_t table_size;
+
+ if (!table)
+ return false;
+
+ table_size = g_hash_table_size(table);
+
+ /* Non-split routed may have only the default route */
+ if (table_size > 0 && !connman_provider_is_split_routing(provider))
+ return true;
+
+ /* Split routed has more than the default route */
+ if (table_size > 1)
+ return true;
+
+ /*
+ * Only one route for split routed VPN, which should not be the
+ * default route.
+ */
+ g_hash_table_iter_init(&iter, table);
+ if (!g_hash_table_iter_next(&iter, &key, &value)) /* First and only */
+ return false;
+
+ route = value;
+ if (!route)
+ return false;
+
+ DBG("check route %d %s/%s/%s", route->family, route->network,
+ route->gateway, route->netmask);
+
+ if (!connman_inet_is_default_route(route->family, route->network,
+ route->gateway, route->netmask))
+ return true;
+
+ return false;
+}
+
+static bool check_routes(struct connman_provider *provider)
+{
+ struct connection_data *data;;
+
+ DBG("provider %p", provider);
+
+ data = connman_provider_get_data(provider);
+ if (!data)
+ return false;
+
+ if (is_valid_route_table(provider, data->user_routes))
+ return true;
+
+ if (is_valid_route_table(provider, data->server_routes))
+ return true;
+
+ return false;
}
static int set_routes(struct connman_provider *provider,
@@ -1504,28 +1671,30 @@ static int set_routes(struct connman_provider *provider,
set_route(data, value);
}
- return 0;
-}
-
-static bool check_routes(struct connman_provider *provider)
-{
- struct connection_data *data;
-
- DBG("provider %p", provider);
+ /* If non-split routed VPN does not have a default route, add it */
+ if (!connman_provider_is_split_routing(provider) &&
+ !data->default_route_set) {
+ int family = connman_provider_get_family(provider);
+ const char *ipaddr_any = family == AF_INET6 ?
+ "::" : "0.0.0.0";
+ struct vpn_route def_route = {family, (char*) ipaddr_any,
+ (char*) ipaddr_any, NULL};
- data = connman_provider_get_data(provider);
- if (!data)
- return false;
-
- if (data->user_routes &&
- g_hash_table_size(data->user_routes) > 0)
- return true;
+ set_route(data, &def_route);
+ }
- if (data->server_routes &&
- g_hash_table_size(data->server_routes) > 0)
- return true;
+ /* Split routed VPN must have at least one route to the network */
+ if (connman_provider_is_split_routing(provider) &&
+ !check_routes(provider)) {
+ int err = add_network_route(data);
+ if (err) {
+ connman_warn("cannot add network route provider %p",
+ provider);
+ return err;
+ }
+ }
- return false;
+ return 0;
}
static struct connman_provider_driver provider_driver = {
@@ -1694,12 +1863,52 @@ static int save_route(GHashTable *routes, int family, const char *network,
route->gateway = g_strdup(gateway);
g_hash_table_replace(routes, key, route);
- } else
+ } else {
g_free(key);
+ return -EALREADY;
+ }
return 0;
}
+static void change_provider_split_routing(struct connman_provider *provider,
+ bool split_routing)
+{
+ struct connection_data *data;
+ int err;
+
+ if (!provider)
+ return;
+
+ if (connman_provider_is_split_routing(provider) == split_routing)
+ return;
+
+ data = connman_provider_get_data(provider);
+ if (split_routing && data && provider_is_connected(data) &&
+ !check_routes(provider)) {
+ err = add_network_route(data);
+ if (err) {
+ connman_warn("cannot add network route provider %p",
+ provider);
+ return;
+ }
+ }
+
+ err = connman_provider_set_split_routing(provider, split_routing);
+ switch (err) {
+ case 0:
+ /* fall through */
+ case -EALREADY:
+ break;
+ case -EINVAL:
+ /* fall through */
+ case -EOPNOTSUPP:
+ connman_warn("cannot change split routing %d", err);
+ default:
+ break;
+ }
+}
+
static int read_route_dict(GHashTable *routes, DBusMessageIter *dicts)
{
DBusMessageIter dict;
@@ -1876,6 +2085,10 @@ static gboolean property_changed(DBusConnection *conn,
g_free(data->domain);
data->domain = g_strdup(str);
connman_provider_set_domain(data->provider, data->domain);
+ } else if (g_str_equal(key, "SplitRouting")) {
+ dbus_bool_t split_routing;
+ dbus_message_iter_get_basic(&value, &split_routing);
+ change_provider_split_routing(data->provider, split_routing);
}
if (ip_set && err == 0) {
@@ -1964,6 +2177,10 @@ static void vpn_disconnect_check_provider(struct connection_data *data)
if (!vpn_is_valid_transport(service)) {
connman_provider_disconnect(data->provider);
}
+
+ /* VPN moved to be split routed, default route is not set */
+ if (connman_provider_is_split_routing(data->provider))
+ data->default_route_set = false;
}
}
diff --git a/plugins/wifi.c b/plugins/wifi.c
index fc304e3b..e7014510 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -49,7 +49,6 @@
#include <connman/service.h>
#include <connman/peer.h>
#include <connman/log.h>
-#include <connman/option.h>
#include <connman/storage.h>
#include <include/setting.h>
#include <connman/provision.h>
@@ -68,12 +67,14 @@
#define BGSCAN_DEFAULT "simple:30:-65:300"
#define AUTOSCAN_EXPONENTIAL "exponential:3:300"
#define AUTOSCAN_SINGLE "single:3"
+#define SCAN_MAX_DURATION 10
#define P2P_FIND_TIMEOUT 30
#define P2P_CONNECTION_TIMEOUT 100
#define P2P_LISTEN_PERIOD 500
#define P2P_LISTEN_INTERVAL 2000
+#define ASSOC_STATUS_AUTH_TIMEOUT 16
#define ASSOC_STATUS_NO_CLIENT 17
#define LOAD_SHAPING_MAX_RETRIES 3
@@ -165,6 +166,11 @@ struct wifi_data {
int assoc_code;
};
+struct disconnect_data {
+ struct wifi_data *wifi;
+ struct connman_network *network;
+};
+
static GList *iface_list = NULL;
static GList *pending_wifi_device = NULL;
@@ -477,15 +483,23 @@ static GSupplicantP2PServiceParams *fill_in_peer_service_params(
if (version > 0) {
params->version = version;
- params->service = g_memdup(spec, spec_length);
+ if (spec_length > 0) {
+ params->service = g_malloc(spec_length);
+ memcpy(params->service, spec, spec_length);
+ }
} else if (query_length > 0 && spec_length > 0) {
- params->query = g_memdup(query, query_length);
+ params->query = g_malloc(query_length);
+ memcpy(params->query, query, query_length);
params->query_length = query_length;
- params->response = g_memdup(spec, spec_length);
+ params->response = g_malloc(spec_length);
+ memcpy(params->response, spec, spec_length);
params->response_length = spec_length;
} else {
- params->wfd_ies = g_memdup(spec, spec_length);
+ if (spec_length > 0) {
+ params->wfd_ies = g_malloc(spec_length);
+ memcpy(params->wfd_ies, spec, spec_length);
+ }
params->wfd_ies_length = spec_length;
}
@@ -752,14 +766,15 @@ static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
}
if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
- if (flags & IFF_LOWER_UP) {
+ if (flags & IFF_LOWER_UP)
DBG("carrier on");
-
- handle_tethering(wifi);
- } else
+ else
DBG("carrier off");
}
+ if (flags & IFF_LOWER_UP)
+ handle_tethering(wifi);
+
wifi->flags = flags;
}
@@ -1178,11 +1193,14 @@ static int get_hidden_connections_params(struct wifi_data *wifi,
scan_params->num_ssids = i;
scan_params->ssids = g_slist_reverse(scan_params->ssids);
- scan_params->freqs = g_memdup(orig_params->freqs,
- sizeof(uint16_t) * orig_params->num_freqs);
- if (!scan_params->freqs)
+ if (orig_params->num_freqs <= 0)
goto err;
+ scan_params->freqs =
+ g_malloc(sizeof(uint16_t) * orig_params->num_freqs);
+ memcpy(scan_params->freqs, orig_params->freqs,
+ sizeof(uint16_t) *orig_params->num_freqs);
+
scan_params->num_freqs = orig_params->num_freqs;
} else
@@ -1524,6 +1542,8 @@ static void interface_create_callback(int result,
void *user_data)
{
struct wifi_data *wifi = user_data;
+ char *bgscan_range_max;
+ long value;
DBG("result %d ifname %s, wifi %p", result,
g_supplicant_interface_get_ifname(interface),
@@ -1539,6 +1559,24 @@ static void interface_create_callback(int result,
wifi->interface_ready = true;
finalize_interface_creation(wifi);
}
+
+ /*
+ * Set the BSS expiration age to match the long scanning
+ * interval to avoid the loss of unconnected networks between
+ * two scans.
+ */
+ bgscan_range_max = strrchr(BGSCAN_DEFAULT, ':');
+ if (!bgscan_range_max || strlen(bgscan_range_max) < 1)
+ return;
+
+ value = strtol(bgscan_range_max + 1, NULL, 10);
+ if (value <= 0 || errno == ERANGE)
+ return;
+
+ if (g_supplicant_interface_set_bss_expiration_age(interface,
+ value + SCAN_MAX_DURATION) < 0) {
+ connman_warn("Failed to set bss expiration age");
+ }
}
static int wifi_enable(struct connman_device *device)
@@ -1546,7 +1584,7 @@ static int wifi_enable(struct connman_device *device)
struct wifi_data *wifi = connman_device_get_data(device);
int index;
char *interface;
- const char *driver = connman_option_get_string("wifi");
+ const char *driver = connman_setting_get_string("wifi");
int ret;
DBG("device %p %p", device, wifi);
@@ -2220,21 +2258,35 @@ static int network_connect(struct connman_network *network)
static void disconnect_callback(int result, GSupplicantInterface *interface,
void *user_data)
{
- struct wifi_data *wifi = user_data;
+ struct disconnect_data *dd = user_data;
+ struct connman_network *network = dd->network;
+ struct wifi_data *wifi = dd->wifi;
- DBG("result %d supplicant interface %p wifi %p",
- result, interface, wifi);
+ g_free(dd);
+
+ DBG("result %d supplicant interface %p wifi %p networks: current %p "
+ "pending %p disconnected %p", result, interface, wifi,
+ wifi->network, wifi->pending_network, network);
if (result == -ECONNABORTED) {
DBG("wifi interface no longer available");
return;
}
- if (wifi->network && wifi->network != wifi->pending_network)
- connman_network_set_connected(wifi->network, false);
- wifi->network = NULL;
+ if (g_slist_find(wifi->networks, network))
+ connman_network_set_connected(network, false);
wifi->disconnecting = false;
+
+ if (network != wifi->network) {
+ if (network == wifi->pending_network)
+ wifi->pending_network = NULL;
+ DBG("current wifi network has changed since disconnection");
+ return;
+ }
+
+ wifi->network = NULL;
+
wifi->connected = false;
if (wifi->pending_network) {
@@ -2248,6 +2300,7 @@ static void disconnect_callback(int result, GSupplicantInterface *interface,
static int network_disconnect(struct connman_network *network)
{
struct connman_device *device = connman_network_get_device(network);
+ struct disconnect_data *dd;
struct wifi_data *wifi;
int err;
@@ -2264,10 +2317,16 @@ static int network_disconnect(struct connman_network *network)
wifi->disconnecting = true;
+ dd = g_malloc0(sizeof(*dd));
+ dd->wifi = wifi;
+ dd->network = network;
+
err = g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, wifi);
- if (err < 0)
+ disconnect_callback, dd);
+ if (err < 0) {
wifi->disconnecting = false;
+ g_free(dd);
+ }
return err;
}
@@ -2375,6 +2434,7 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
if (wps) {
const unsigned char *ssid, *wps_ssid;
unsigned int ssid_len, wps_ssid_len;
+ struct disconnect_data *dd;
const char *wps_key;
/* Checking if we got associated with requested
@@ -2387,9 +2447,13 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
if (!wps_ssid || wps_ssid_len != ssid_len ||
memcmp(ssid, wps_ssid, ssid_len) != 0) {
+ dd = g_malloc0(sizeof(*dd));
+ dd->wifi = wifi;
+ dd->network = network;
+
connman_network_set_associating(network, false);
g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, wifi);
+ disconnect_callback, dd);
return false;
}
@@ -2422,7 +2486,9 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
{
struct connman_service *service;
- if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
+ if ((wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) &&
+ !((wifi->state == G_SUPPLICANT_STATE_ASSOCIATING) &&
+ (wifi->assoc_code == ASSOC_STATUS_AUTH_TIMEOUT)))
return false;
if (wifi->connected)
@@ -2544,9 +2610,6 @@ static void interface_state(GSupplicantInterface *interface)
/* See table 8-36 Reason codes in IEEE Std 802.11 */
switch (wifi->disconnect_code) {
- case 1: /* Unspecified reason */
- /* Let's assume it's because we got blocked */
-
case 6: /* Class 2 frame received from nonauthenticated STA */
connman_network_set_error(network,
CONNMAN_NETWORK_ERROR_BLOCKED);
@@ -3350,7 +3413,7 @@ static void sta_remove_callback(int result,
void *user_data)
{
struct wifi_tethering_info *info = user_data;
- const char *driver = connman_option_get_string("wifi");
+ const char *driver = connman_setting_get_string("wifi");
DBG("ifname %s result %d ", info->ifname, result);