summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/ethernet.c8
-rw-r--r--plugins/iwd.c885
-rwxr-xr-xplugins/ofono.c6
-rwxr-xr-xplugins/session_policy_local.c6
-rwxr-xr-xplugins/tist.c2
-rwxr-xr-xplugins/vpn.c61
-rwxr-xr-xplugins/wifi.c8
7 files changed, 875 insertions, 101 deletions
diff --git a/plugins/ethernet.c b/plugins/ethernet.c
index b0031cbe..ad2ab6e1 100644
--- a/plugins/ethernet.c
+++ b/plugins/ethernet.c
@@ -84,7 +84,7 @@ static int get_vlan_vid(const char *ifname)
return -errno;
vifr.cmd = GET_VLAN_VID_CMD;
- strncpy(vifr.device1, ifname, sizeof(vifr.device1));
+ stpncpy(vifr.device1, ifname, sizeof(vifr.device1));
if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
vid = vifr.u.VID;
@@ -110,14 +110,14 @@ static int get_dsa_port(const char *ifname)
return -errno;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ stpncpy(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));
+ stpncpy(vifr.device1, ifname, sizeof(vifr.device1));
if(ioctl(sk, SIOCSIFVLAN, &vifr) >= 0)
- strncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name));
+ stpncpy(ifr.ifr_name, vifr.u.device2, sizeof(ifr.ifr_name));
/* get driver info */
drvinfocmd.cmd = ETHTOOL_GDRVINFO;
diff --git a/plugins/iwd.c b/plugins/iwd.c
index ddc9201d..bf6a2c26 100644
--- a/plugins/iwd.c
+++ b/plugins/iwd.c
@@ -42,6 +42,9 @@ static GDBusProxy *agent_proxy;
static GHashTable *adapters;
static GHashTable *devices;
static GHashTable *networks;
+static GHashTable *known_networks;
+static GHashTable *stations;
+static GHashTable *access_points;
static bool agent_registered;
#define IWD_SERVICE "net.connman.iwd"
@@ -50,6 +53,9 @@ static bool agent_registered;
#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_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork"
+#define IWD_STATION_INTERFACE "net.connman.iwd.Station"
+#define IWD_AP_INTERFACE "net.connman.iwd.AccessPoint"
#define IWD_AGENT_INTERFACE "net.connman.iwd.Agent"
#define IWD_AGENT_ERROR_INTERFACE "net.connman.iwd.Agent.Error"
@@ -61,6 +67,9 @@ struct iwd_adapter {
char *vendor;
char *model;
bool powered;
+ bool ad_hoc;
+ bool station;
+ bool ap;
};
struct iwd_device {
@@ -70,7 +79,7 @@ struct iwd_device {
char *name;
char *address;
bool powered;
- bool scanning;
+ char *mode;
struct connman_device *device;
};
@@ -82,11 +91,41 @@ struct iwd_network {
char *name;
char *type;
bool connected;
+ char *known_network;
struct iwd_device *iwdd;
struct connman_network *network;
};
+struct iwd_known_network {
+ GDBusProxy *proxy;
+ char *path;
+ char *name;
+ char *type;
+ bool hidden;
+ char *last_connected_time;
+ bool auto_connect;
+ int auto_connect_id;
+};
+
+struct iwd_station {
+ GDBusProxy *proxy;
+ char *path;
+ char *state;
+ char *connected_network;
+ bool scanning;
+};
+
+struct iwd_ap {
+ GDBusProxy *proxy;
+ char *path;
+ bool started;
+
+ int index;
+ char *bridge;
+ struct connman_technology *tech;
+};
+
static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
{
DBusMessageIter iter;
@@ -100,6 +139,27 @@ static const char *proxy_get_string(GDBusProxy *proxy, const char *property)
return str;
}
+static GSList *proxy_get_strings(GDBusProxy *proxy, const char *property)
+{
+ DBusMessageIter array, entry;
+ GSList *list = NULL;
+
+ if (!g_dbus_proxy_get_property(proxy, property, &array))
+ return NULL;
+
+ dbus_message_iter_recurse(&array, &entry);
+
+ while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING){
+ const char *val;
+
+ dbus_message_iter_get_basic(&entry, &val);
+ list = g_slist_prepend(list, g_strdup(val));
+ dbus_message_iter_next(&entry);
+ }
+
+ return list;
+}
+
static bool proxy_get_bool(GDBusProxy *proxy, const char *property)
{
DBusMessageIter iter;
@@ -181,7 +241,11 @@ static void cm_network_connect_cb(DBusMessage *message, void *user_data)
return;
DBG("%s connect failed: %s", path, dbus_error);
- connman_network_set_error(iwdn->network,
+ if (!strcmp(dbus_error, "net.connman.iwd.Failed"))
+ connman_network_set_error(iwdn->network,
+ CONNMAN_NETWORK_ERROR_INVALID_KEY);
+ else
+ connman_network_set_error(iwdn->network,
CONNMAN_NETWORK_ERROR_CONNECT_FAIL);
return;
}
@@ -238,16 +302,16 @@ static void cm_network_disconnect_cb(DBusMessage *message, void *user_data)
static int cm_network_disconnect(struct connman_network *network)
{
struct iwd_network *iwdn = connman_network_get_data(network);
- struct iwd_device *iwdd;
+ struct iwd_station *iwds;
- if (!iwdn)
+ if (!iwdn && !iwdn->iwdd)
return -EINVAL;
- iwdd = g_hash_table_lookup(devices, iwdn->device);
- if (!iwdd)
+ iwds = g_hash_table_lookup(stations, iwdn->iwdd->path);
+ if (!iwds)
return -EIO;
- if (!g_dbus_proxy_method_call(iwdd->proxy, "Disconnect",
+ if (!g_dbus_proxy_method_call(iwds->proxy, "Disconnect",
NULL, cm_network_disconnect_cb, g_strdup(iwdn->path), g_free))
return -EIO;
@@ -339,6 +403,42 @@ static int cm_device_disable(struct connman_device *device)
return set_device_powered(device, false);
}
+static void cm_device_scan_cb(DBusMessage *message, void *user_data)
+{
+ const char *path = user_data;
+ struct iwd_station *iwds;
+
+ iwds = g_hash_table_lookup(networks, path);
+ if (!iwds)
+ return;
+
+ if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
+ const char *dbus_error = dbus_message_get_error_name(message);
+
+ DBG("%s scan failed: %s", path, dbus_error);
+ }
+}
+
+static int cm_device_scan(struct connman_device *device,
+ struct connman_device_scan_params *params)
+{
+ struct iwd_device *iwdd = connman_device_get_data(device);
+ struct iwd_station *iwds;
+
+ if (strcmp(iwdd->mode, "station"))
+ return -EINVAL;
+
+ iwds = g_hash_table_lookup(stations, iwdd->path);
+ if (!iwds)
+ return -EIO;
+
+ if (!g_dbus_proxy_method_call(iwds->proxy, "Scan",
+ NULL, cm_device_scan_cb, g_strdup(iwds->path), g_free))
+ return -EIO;
+
+ return -EINPROGRESS;
+}
+
static struct connman_device_driver device_driver = {
.name = "iwd",
.type = CONNMAN_DEVICE_TYPE_WIFI,
@@ -346,6 +446,7 @@ static struct connman_device_driver device_driver = {
.remove = cm_device_remove,
.enable = cm_device_enable,
.disable = cm_device_disable,
+ .scan = cm_device_scan,
};
static int cm_tech_probe(struct connman_technology *technology)
@@ -357,92 +458,269 @@ 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,
+struct tech_cb_data {
+ struct iwd_device *iwdd;
+ char *path;
+ char *ssid;
+ char *passphrase;
+ char *bridge;
+ int index;
+ struct connman_technology *tech;
};
-static unsigned char calculate_strength(int strength)
+static void tech_cb_free(struct tech_cb_data *cbd)
{
- unsigned char res;
+ g_free(cbd->path);
+ g_free(cbd->ssid);
+ g_free(cbd->passphrase);
+ g_free(cbd->bridge);
+ g_free(cbd);
+}
- /*
- * 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);
+static int cm_change_tethering(struct iwd_device *iwdd,
+ struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+ const char *bridge, bool enabled);
- return res;
+static void tech_ap_start_cb(DBusMessage *message, void *user_data)
+{
+
+ struct tech_cb_data *cbd = user_data;
+
+ if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
+ const char *dbus_error = dbus_message_get_error_name(message);
+
+ connman_warn("iwd device %s could not enable AccessPoint mode: %s",
+ cbd->path, dbus_error);
+ goto out;
+ }
+
+ /* wait for 'Started' signal */
+ return;
+out:
+ cm_change_tethering(cbd->iwdd, cbd->tech,
+ cbd->ssid, cbd->passphrase, cbd->bridge, false);
+ tech_cb_free(cbd);
}
-static void _update_signal_strength(const char *path, int16_t signal_strength)
+static void tech_ap_stop_cb(DBusMessage *message, void *user_data)
{
- struct iwd_network *iwdn;
+ struct tech_cb_data *cbd = user_data;
- 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 (!iwdn->network)
- return;
+ connman_warn("iwd device %s could not disable AccessPoint mode: %s",
+ cbd->path, dbus_error);
+ goto out;
+ }
- connman_network_set_strength(iwdn->network,
- calculate_strength(signal_strength));
+ return;
+out:
+ tech_cb_free(cbd);
}
-static void ordered_networks_cb(DBusMessage *message, void *user_data)
+static void ap_start_append(DBusMessageIter *iter, void *user_data)
{
- DBusMessageIter array, entry;
+ struct tech_cb_data *cbd = user_data;
+
+ DBG("ssid %s", cbd->ssid);
+ DBG("passphrase %s", cbd->passphrase);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->ssid);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cbd->passphrase);
+}
+
+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;
DBG("");
- if (!dbus_message_iter_init(message, &array))
- return;
+ iwdd = g_hash_table_lookup(devices, cbd->path);
+ if (!iwdd) {
+ DBG("device already removed");
+ goto out;
+ }
- if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
- return;
+ if (dbus_error_is_set(error)) {
+ connman_warn("iwd device %s could not enable AcessPoint mode: %s",
+ cbd->path, error->message);
+ goto out;
+ }
- 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;
+ iwdap = g_hash_table_lookup(access_points, iwdd->path);
+ if (!iwdap) {
+ DBG("%s no ap object found", iwdd->path);
+ goto out;
+ }
+ iwdap->index = cbd->index;
+ iwdap->bridge = g_strdup(cbd->bridge);
+ iwdap->tech = cbd->tech;
- dbus_message_iter_recurse(&entry, &value);
+ if (!g_dbus_proxy_method_call(iwdap->proxy, "Start",
+ ap_start_append, tech_ap_start_cb, cbd, NULL)) {
+ connman_warn("iwd ap %s could not start AccessPoint mode: %s",
+ cbd->path, error->message);
+ goto out;
+ }
- dbus_message_iter_get_basic(&value, &path);
+ return;
+out:
+ if (iwdap) {
+ iwdap->index = -1;
+ g_free(iwdap->bridge);
+ iwdap->bridge = NULL;
+ }
+ tech_cb_free(cbd);
+}
- dbus_message_iter_next(&value);
- dbus_message_iter_get_basic(&value, &name);
+static void tech_disable_tethering_cb(const DBusError *error, void *user_data)
+{
+ struct tech_cb_data *cbd = user_data;
+ struct iwd_device *iwdd;
+ struct iwd_ap *iwdap;
- dbus_message_iter_next(&value);
- dbus_message_iter_get_basic(&value, &signal_strength);
+ DBG("");
- dbus_message_iter_next(&value);
- dbus_message_iter_get_basic(&value, &type);
+ iwdd = g_hash_table_lookup(devices, cbd->path);
+ if (!iwdd) {
+ DBG("device already removed");
+ goto out;
+ }
- _update_signal_strength(path, signal_strength);
+ if (dbus_error_is_set(error)) {
+ connman_warn("iwd device %s could not enable Station mode: %s",
+ cbd->path, error->message);
+ goto out;
+ }
- dbus_message_iter_next(&entry);
+ iwdap = g_hash_table_lookup(access_points, iwdd->path);
+ if (!iwdap) {
+ DBG("%s no ap object found", iwdd->path);
+ goto out;
+ }
+
+ g_free(iwdap->bridge);
+ iwdap->index = -1;
+ iwdap->bridge = NULL;
+ iwdap->tech = NULL;
+
+ if (!connman_inet_remove_from_bridge(cbd->index, cbd->bridge))
+ goto out;
+
+ connman_technology_tethering_notify(cbd->tech, false);
+
+ 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",
+ cbd->path, error->message);
+ goto out;
+ }
+
+ return;
+out:
+ tech_cb_free(cbd);
+}
+
+static int cm_change_tethering(struct iwd_device *iwdd,
+ struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+ const char *bridge, bool enabled)
+{
+ struct tech_cb_data *cbd;
+ int index;
+ const char *mode;
+ GDBusResultFunction cb;
+
+ index = connman_inet_ifindex(iwdd->name);
+ if (index < 0)
+ return -ENODEV;
+
+ cbd = g_new(struct tech_cb_data, 1);
+ cbd->iwdd = iwdd;
+ cbd->path = g_strdup(iwdd->path);
+ cbd->ssid = g_strdup(identifier);
+ cbd->passphrase = g_strdup(passphrase);
+ cbd->bridge = g_strdup(bridge);
+ cbd->tech = technology;
+ cbd->index = index;
+
+ if (enabled) {
+ mode = "ap";
+ cb = tech_enable_tethering_cb;
+ } else {
+ mode = "station";
+ cb = tech_disable_tethering_cb;
+ }
+
+ if (!g_dbus_proxy_set_property_basic(iwdd->proxy,
+ "Mode", DBUS_TYPE_STRING, &mode,
+ cb, cbd, NULL)) {
+ tech_cb_free(cbd);
+ return -EIO;
}
+
+ return 0;
}
-static void update_signal_strength(struct iwd_device *iwdd)
+static int cm_tech_tethering(struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+ const char *bridge, bool enabled)
{
- if (!g_dbus_proxy_method_call(iwdd->proxy,
- "GetOrderedNetworks",
- NULL, ordered_networks_cb,
- NULL, NULL))
- DBG("GetOrderedNetworks() failed");
+ GHashTableIter iter;
+ gpointer key, value;
+ int err = 0, res;
+
+ g_hash_table_iter_init(&iter, devices);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ struct iwd_device *iwdd = value;
+ struct iwd_adapter *iwda;
+
+ iwda = g_hash_table_lookup(adapters, iwdd->adapter);
+ if (!iwda)
+ continue;
+
+ if (!iwda->station || !iwda->ap )
+ /* No support for Station and AccessPoint mode */
+ continue;
+
+ if (!enabled && !g_strcmp0("ap", iwdd->mode)) {
+ res = cm_change_tethering(iwdd, technology, identifier,
+ passphrase, bridge, enabled);
+ if (res)
+ connman_warn("%s switching to Station mode failed",
+ iwdd->path);
+ if (!err)
+ err = res;
+ continue;
+ }
+
+ if (enabled && !g_strcmp0("station", iwdd->mode)) {
+ err = cm_change_tethering(iwdd, technology, identifier,
+ passphrase, bridge, enabled);
+ if (err)
+ connman_warn("%s switching to AccessPoint mode failed",
+ iwdd->path);
+ break;
+ }
+ }
+
+ return err;
}
+static struct connman_technology_driver tech_driver = {
+ .name = "iwd",
+ .type = CONNMAN_SERVICE_TYPE_WIFI,
+ .probe = cm_tech_probe,
+ .remove = cm_tech_remove,
+ .set_tethering = cm_tech_tethering,
+};
+
static const char *security_remap(const char *security)
{
if (!g_strcmp0(security, "open"))
@@ -498,7 +776,7 @@ static void add_network(const char *path, struct iwd_network *iwdn)
connman_network_set_blob(iwdn->network, "WiFi.SSID", iwdn->name,
strlen(iwdn->name));
connman_network_set_string(iwdn->network, "WiFi.Security",
- iwdn->type);
+ security_remap(iwdn->type));
connman_network_set_string(iwdn->network, "WiFi.Mode", "managed");
if (connman_device_add_network(iwdd->device, iwdn->network) < 0) {
@@ -630,17 +908,14 @@ static void device_property_change(GDBusProxy *proxy, const char *name,
iwdd->powered = powered;
DBG("%s powered %d", path, iwdd->powered);
- } else if (!strcmp(name, "Scanning")) {
- dbus_bool_t scanning;
+ } else if (!strcmp(name, "Mode")) {
+ const char *mode;
- dbus_message_iter_get_basic(iter, &scanning);
- iwdd->scanning = scanning;
-
- DBG("%s scanning %d", path, iwdd->scanning);
-
- if (!iwdd->scanning)
- update_signal_strength(iwdd);
+ dbus_message_iter_get_basic(iter, &mode);
+ g_free(iwdd->mode);
+ iwdd->mode = g_strdup(mode);
+ DBG("%s mode %s", path, iwdd->mode);
}
}
@@ -670,6 +945,153 @@ static void network_property_change(GDBusProxy *proxy, const char *name,
}
}
+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;
+
+ connman_network_set_strength(iwdn->network,
+ calculate_strength(signal_strength));
+ connman_network_update(iwdn->network);
+}
+
+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;
+ 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, &signal_strength);
+
+ _update_signal_strength(path, signal_strength);
+
+ dbus_message_iter_next(&entry);
+ }
+}
+
+static void update_signal_strength(struct iwd_station *iwds)
+{
+ if (!g_dbus_proxy_method_call(iwds->proxy,
+ "GetOrderedNetworks",
+ NULL, ordered_networks_cb,
+ NULL, NULL))
+ DBG("GetOrderedNetworks() failed");
+}
+
+static void station_property_change(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct iwd_station *iwds;
+ const char *path;
+
+ path = g_dbus_proxy_get_path(proxy);
+ iwds = g_hash_table_lookup(stations, path);
+ if (!iwds)
+ return;
+
+ if (!strcmp(name, "State")) {
+ const char *state;
+
+ dbus_message_iter_get_basic(iter, &state);
+ g_free(iwds->state);
+ iwds->state = g_strdup(state);
+
+ DBG("%s state %s", path, iwds->state);
+ } else if (!strcmp(name, "ConnectedNetwork")) {
+ const char *connected_network;
+
+ g_free(iwds->connected_network);
+ if (iter) {
+ dbus_message_iter_get_basic(iter, &connected_network);
+ iwds->connected_network = g_strdup(connected_network);
+ } else {
+ iwds->connected_network = NULL;
+ }
+
+ DBG("%s connected_network %s", path, iwds->connected_network);
+ } else if (!strcmp(name, "Scanning")) {
+ dbus_bool_t scanning;
+
+ dbus_message_iter_get_basic(iter, &scanning);
+ iwds->scanning = scanning;
+
+ if (!iwds->scanning)
+ update_signal_strength(iwds);
+
+ DBG("%s scanning %d", path, iwds->scanning);
+ }
+}
+
+static void ap_property_change(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct iwd_ap *iwdap;
+ const char *path;
+ int err;
+
+ path = g_dbus_proxy_get_path(proxy);
+ iwdap = g_hash_table_lookup(access_points, path);
+ if (!iwdap)
+ return;
+
+ if (!strcmp(name, "Started")) {
+ dbus_bool_t started;
+
+ dbus_message_iter_get_basic(iter, &started);
+ iwdap->started = started;
+
+ DBG("%s started %d", path, iwdap->started);
+
+ if (iwdap->started && iwdap->index != -1) {
+ DBG("index %d bridge %s", iwdap->index, iwdap->bridge);
+ err = connman_technology_tethering_notify(
+ iwdap->tech, true);
+ if (err)
+ return;
+ err = connman_inet_add_to_bridge(
+ iwdap->index, iwdap->bridge);
+ }
+ }
+}
+
static void adapter_free(gpointer data)
{
struct iwd_adapter *iwda = data;
@@ -718,13 +1140,59 @@ static void network_free(gpointer data)
g_free(iwdn->device);
g_free(iwdn->name);
g_free(iwdn->type);
+ g_free(iwdn->known_network);
g_free(iwdn);
}
+static void known_network_free(gpointer data)
+{
+ struct iwd_known_network *iwdkn = data;
+
+ if (iwdkn->proxy) {
+ g_dbus_proxy_unref(iwdkn->proxy);
+ iwdkn->proxy = NULL;
+ }
+
+ if (iwdkn->auto_connect_id)
+ g_source_remove(iwdkn->auto_connect_id);
+
+ g_free(iwdkn->path);
+ g_free(iwdkn->name);
+ g_free(iwdkn->type);
+ g_free(iwdkn->last_connected_time);
+ g_free(iwdkn);
+}
+
+static void station_free(gpointer data)
+{
+ struct iwd_station *iwds = data;
+
+ if (iwds->proxy) {
+ g_dbus_proxy_unref(iwds->proxy);
+ iwds->proxy = NULL;
+ }
+ g_free(iwds->path);
+ g_free(iwds->connected_network);
+ g_free(iwds);
+}
+
+static void ap_free(gpointer data)
+{
+ struct iwd_ap *iwdap = data;
+
+ if (iwdap->proxy) {
+ g_dbus_proxy_unref(iwdap->proxy);
+ iwdap->proxy = NULL;
+ }
+ g_free(iwdap->bridge);
+ g_free(iwdap);
+}
+
static void create_adapter(GDBusProxy *proxy)
{
const char *path = g_dbus_proxy_get_path(proxy);
struct iwd_adapter *iwda;
+ GSList *modes, *list;
iwda = g_try_new0(struct iwd_adapter, 1);
@@ -748,8 +1216,25 @@ static void create_adapter(GDBusProxy *proxy)
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);
+ modes = proxy_get_strings(proxy, "SupportedModes");
+ for (list = modes; list; list = list->next) {
+ char *m = list->data;
+
+ if (!m)
+ continue;
+
+ if (!strcmp(m, "ad-hoc"))
+ iwda->ad_hoc = true;
+ else if (!strcmp(m, "station"))
+ iwda->station = true;
+ else if (!strcmp(m, "ap"))
+ iwda->ap = true;
+ }
+ g_slist_free_full(modes, g_free);
+
+ DBG("%s vendor '%s' model '%s' powered %d ad-hoc %d station %d ap %d",
+ path, iwda->vendor, iwda->model, iwda->powered,
+ iwda->ad_hoc, iwda->station, iwda->ap);
g_dbus_proxy_set_property_watch(iwda->proxy,
adapter_property_change, NULL);
@@ -782,11 +1267,11 @@ static void create_device(GDBusProxy *proxy)
iwdd->name = g_strdup(proxy_get_string(proxy, "Name"));
iwdd->address = g_strdup(proxy_get_string(proxy, "Address"));
iwdd->powered = proxy_get_bool(proxy, "Powered");
- iwdd->scanning = proxy_get_bool(proxy, "Scanning");
+ iwdd->mode = g_strdup(proxy_get_string(proxy, "Mode"));
- DBG("adapter %s name %s address %s powered %d scanning %d",
+ DBG("adapter %s name %s address %s powered %d mode %s",
iwdd->adapter, iwdd->name, iwdd->address,
- iwdd->powered, iwdd->scanning);
+ iwdd->powered, iwdd->mode);
g_dbus_proxy_set_property_watch(iwdd->proxy,
device_property_change, NULL);
@@ -955,12 +1440,11 @@ static void create_network(GDBusProxy *proxy)
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");
+ iwdn->known_network = g_strdup(proxy_get_string(proxy, "KnownNetwork"));
- DBG("device %s name '%s' type %s connected %d",
- iwdn->device,
- iwdn->name,
- iwdn->type,
- iwdn->connected);
+ DBG("device %s name '%s' type %s connected %d known_network %s",
+ iwdn->device, iwdn->name, iwdn->type, iwdn->connected,
+ iwdn->known_network);
g_dbus_proxy_set_property_watch(iwdn->proxy,
network_property_change, NULL);
@@ -968,6 +1452,214 @@ 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)
+{
+ struct iwd_known_network *iwdkn;
+ const char *path;
+
+ path = g_dbus_proxy_get_path(proxy);
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return;
+
+ if (!strcmp(name, "AutoConnect")) {
+ dbus_bool_t auto_connect;
+
+ dbus_message_iter_get_basic(iter, &auto_connect);
+ iwdkn->auto_connect = auto_connect;
+
+ DBG("%p auto_connect %d", path, iwdkn->auto_connect);
+
+ if (iwdkn->auto_connect)
+ disable_auto_connect(iwdkn);
+ }
+}
+
+static void create_know_network(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_try_new0(struct iwd_known_network, 1);
+ if (!iwdkn) {
+ connman_error("Out of memory creating IWD known network");
+ return;
+ }
+
+ iwdkn->path = g_strdup(path);
+ g_hash_table_replace(known_networks, iwdkn->path, iwdkn);
+
+ iwdkn->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwdkn->proxy) {
+ connman_error("Cannot create IWD known network watcher %s", path);
+ g_hash_table_remove(known_networks, path);
+ return;
+ }
+
+ iwdkn->name = g_strdup(proxy_get_string(proxy, "Name"));
+ iwdkn->type = g_strdup(proxy_get_string(proxy, "Type"));
+ iwdkn->hidden = proxy_get_bool(proxy, "Hidden");
+ iwdkn->last_connected_time =
+ g_strdup(proxy_get_string(proxy, "LastConnectedTime"));
+ iwdkn->auto_connect = proxy_get_bool(proxy, "AutoConnect");
+
+ DBG("name '%s' type %s hidden %d, last_connection_time %s auto_connect %d",
+ iwdkn->name, iwdkn->type, iwdkn->hidden,
+ iwdkn->last_connected_time, iwdkn->auto_connect);
+
+ 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)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_station *iwds;
+
+ iwds = g_try_new0(struct iwd_station, 1);
+ if (!iwds) {
+ connman_error("Out of memory creating IWD station");
+ return;
+ }
+
+ iwds->path = g_strdup(path);
+ g_hash_table_replace(stations, iwds->path, iwds);
+
+ iwds->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwds->proxy) {
+ connman_error("Cannot create IWD station watcher %s", path);
+ g_hash_table_remove(stations, path);
+ return;
+ }
+
+ iwds->state = g_strdup(proxy_get_string(proxy, "State"));
+ iwds->connected_network = g_strdup(proxy_get_string(proxy, "ConnectedNetwork"));
+ iwds->scanning = proxy_get_bool(proxy, "Scanning");
+
+ DBG("state '%s' connected_network %s scanning %d",
+ iwds->state, iwds->connected_network, iwds->scanning);
+
+ g_dbus_proxy_set_property_watch(iwds->proxy,
+ station_property_change, NULL);
+}
+
+static void create_ap(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_ap *iwdap;
+
+ iwdap = g_try_new0(struct iwd_ap, 1);
+ if (!iwdap) {
+ connman_error("Out of memory creating IWD access point");
+ return;
+ }
+ iwdap->index = -1;
+
+ iwdap->path = g_strdup(path);
+ g_hash_table_replace(access_points, iwdap->path, iwdap);
+
+ iwdap->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwdap->proxy) {
+ connman_error("Cannot create IWD access point watcher %s", path);
+ g_hash_table_remove(access_points, path);
+ return;
+ }
+
+ iwdap->started = proxy_get_bool(proxy, "Started");
+
+ DBG("started %d", iwdap->started);
+
+ g_dbus_proxy_set_property_watch(iwdap->proxy,
+ ap_property_change, NULL);
+}
+
static void object_added(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -989,6 +1681,12 @@ static void object_added(GDBusProxy *proxy, void *user_data)
create_device(proxy);
else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
create_network(proxy);
+ else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
+ create_know_network(proxy);
+ else if (!strcmp(interface, IWD_STATION_INTERFACE))
+ create_station(proxy);
+ else if (!strcmp(interface, IWD_AP_INTERFACE))
+ create_ap(proxy);
}
static void object_removed(GDBusProxy *proxy, void *user_data)
@@ -1013,6 +1711,12 @@ static void object_removed(GDBusProxy *proxy, void *user_data)
g_hash_table_remove(devices, path);
else if (!strcmp(interface, IWD_NETWORK_INTERFACE))
g_hash_table_remove(networks, path);
+ else if (!strcmp(interface, IWD_KNOWN_NETWORK_INTERFACE))
+ g_hash_table_remove(known_networks, path);
+ else if (!strcmp(interface, IWD_STATION_INTERFACE))
+ g_hash_table_remove(stations, path);
+ else if (!strcmp(interface, IWD_AP_INTERFACE))
+ g_hash_table_remove(access_points, path);
}
static int iwd_init(void)
@@ -1030,6 +1734,15 @@ static int iwd_init(void)
networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
network_free);
+ known_networks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ known_network_free);
+
+ stations = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ station_free);
+
+ access_points = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ ap_free);
+
if (connman_technology_driver_register(&tech_driver) < 0) {
connman_warn("Failed to initialize technology for IWD");
goto out;
@@ -1069,6 +1782,15 @@ out:
if (networks)
g_hash_table_destroy(networks);
+ if (known_networks)
+ g_hash_table_destroy(known_networks);
+
+ if (stations)
+ g_hash_table_destroy(stations);
+
+ if (access_points)
+ g_hash_table_destroy(access_points);
+
if (adapters)
g_hash_table_destroy(adapters);
@@ -1086,6 +1808,9 @@ static void iwd_exit(void)
g_dbus_client_unref(client);
+ g_hash_table_destroy(access_points);
+ g_hash_table_destroy(stations);
+ g_hash_table_destroy(known_networks);
g_hash_table_destroy(networks);
g_hash_table_destroy(devices);
g_hash_table_destroy(adapters);
diff --git a/plugins/ofono.c b/plugins/ofono.c
index 82413b6e..36873d5a 100755
--- a/plugins/ofono.c
+++ b/plugins/ofono.c
@@ -614,7 +614,7 @@ static void context_set_active_reply(struct modem_data *modem,
if (success) {
/*
* Don't handle do anything on success here. oFono will send
- * the change via PropertyChanged singal.
+ * the change via PropertyChanged signal.
*/
return;
}
@@ -667,7 +667,7 @@ static void cdma_cm_set_powered_reply(struct modem_data *modem,
if (success) {
/*
* Don't handle do anything on success here. oFono will send
- * the change via PropertyChanged singal.
+ * the change via PropertyChanged signal.
*/
return;
}
@@ -2968,7 +2968,7 @@ static void ofono_exit(void)
if (modem_hash) {
/*
- * We should propably wait for the SetProperty() reply
+ * We should probably wait for the SetProperty() reply
* message, because ...
*/
g_hash_table_foreach(modem_hash, modem_power_down, NULL);
diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c
index 9beb0980..32b9c697 100755
--- a/plugins/session_policy_local.c
+++ b/plugins/session_policy_local.c
@@ -66,7 +66,7 @@ static GHashTable *gid_hash; /* (gid, policy_group) */
struct policy_file {
/*
* A valid file is a keyfile with one ore more groups. All
- * groups are keept in this list.
+ * groups are kept in this list.
*/
GSList *groups;
};
@@ -134,7 +134,7 @@ static char *parse_selinux_type(const char *context)
/*
* SELinux combines Role-Based Access Control (RBAC), Type
- * Enforcment (TE) and optionally Multi-Level Security (MLS).
+ * Enforcement (TE) and optionally Multi-Level Security (MLS).
*
* When SELinux is enabled all processes and files are labeled
* with a contex that contains information such as user, role
@@ -145,7 +145,7 @@ static char *parse_selinux_type(const char *context)
*
* For identifyng application we (ab)using the type
* information. In the above example the haifux_exec_t type
- * will be transfered to haifux_t as defined in the domain
+ * will be transferred to haifux_t as defined in the domain
* transition and thus we are able to identify the application
* as haifux_t.
*/
diff --git a/plugins/tist.c b/plugins/tist.c
index cc2800a1..c3a5e694 100755
--- a/plugins/tist.c
+++ b/plugins/tist.c
@@ -578,7 +578,7 @@ static int tist_init(void)
err = install_ldisc(install_channel, true);
if (err < 0) {
- connman_error("ldisc installtion failed");
+ connman_error("ldisc installation failed");
return err;
}
}
diff --git a/plugins/vpn.c b/plugins/vpn.c
index 11bab154..5668c004 100755
--- a/plugins/vpn.c
+++ b/plugins/vpn.c
@@ -477,6 +477,9 @@ static int errorstr2val(const char *error) {
if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".AlreadyConnected") == 0)
return -EISCONN;
+ if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".OperationCanceled") == 0)
+ return -ECANCELED;
+
return -ECONNREFUSED;
}
@@ -490,16 +493,34 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
if (!dbus_pending_call_get_completed(call))
return;
+ if (call != data->call) {
+ connman_error("invalid call %p to VPN connect_reply data %p "
+ " call %p ", call, data, data->call);
+ dbus_pending_call_unref(call);
+ return;
+ }
+
DBG("user_data %p path %s", user_data, cb_data ? cb_data->path : NULL);
reply = dbus_pending_call_steal_reply(call);
+ if (!reply)
+ goto out;
dbus_error_init(&error);
if (dbus_set_error_from_message(&error, reply)) {
int err = errorstr2val(error.name);
- if (err != -EINPROGRESS) {
+ /*
+ * ECANCELED means that user has canceled authentication
+ * dialog. That's not really an error, it's part of a normal
+ * workflow. We also take it as a request to turn autoconnect
+ * off, in case if it was on.
+ */
+ if (err == -ECANCELED) {
+ DBG("%s connect canceled", data->path);
+ connman_provider_set_autoconnect(data->provider, false);
+ } else if (err != -EINPROGRESS) {
connman_error("Connect reply: %s (%s)", error.message,
error.name);
DBG("data %p cb_data %p", data, cb_data);
@@ -522,7 +543,11 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
dbus_message_unref(reply);
- dbus_pending_call_unref(call);
+out:
+ dbus_pending_call_unref(data->call);
+
+ data->call = NULL;
+ data->connect_pending = false;
}
static int connect_provider(struct connection_data *data, void *user_data,
@@ -541,7 +566,10 @@ static int connect_provider(struct connection_data *data, void *user_data,
return -EINVAL;
}
- data->connect_pending = false;
+ if (data->connect_pending && data->call) {
+ connman_info("connect already pending");
+ return -EALREADY;
+ }
/* We need to pass original dbus sender to connman-vpnd,
* use a Connect2 method for that if the original dbus sender is set.
@@ -575,6 +603,14 @@ static int connect_provider(struct connection_data *data, void *user_data,
return -EINVAL;
}
+ if (data->call) {
+ dbus_pending_call_cancel(data->call);
+ dbus_pending_call_unref(data->call);
+ }
+
+ data->call = call;
+ data->connect_pending = true;
+
if (cb_data) {
g_free(cb_data->path);
cb_data->path = g_strdup(data->path);
@@ -984,6 +1020,8 @@ static int disconnect_provider(struct connection_data *data)
static int provider_disconnect(struct connman_provider *provider)
{
+ int err = 0;
+
struct connection_data *data;
DBG("provider %p", provider);
@@ -993,9 +1031,17 @@ static int provider_disconnect(struct connman_provider *provider)
return -EINVAL;
if (provider_is_connected(data))
- return disconnect_provider(data);
+ err = disconnect_provider(data);
- return 0;
+ if (data->call) {
+ dbus_pending_call_cancel(data->call);
+ dbus_pending_call_unref(data->call);
+ data->call = NULL;
+ }
+
+ data->connect_pending = false;
+
+ return err;
}
static void configuration_create_reply(DBusPendingCall *call, void *user_data)
@@ -1909,13 +1955,14 @@ static bool vpn_is_valid_transport(struct connman_service *transport)
static void vpn_disconnect_check_provider(struct connection_data *data)
{
- if (data->service_ident && provider_is_connected(data)) {
+ if (provider_is_connected(data)) {
+ /* With NULL service ident NULL is returned immediately */
struct connman_service *service =
connman_service_lookup_from_identifier
(data->service_ident);
if (!vpn_is_valid_transport(service)) {
- disconnect_provider(data);
+ connman_provider_disconnect(data->provider);
}
}
}
diff --git a/plugins/wifi.c b/plugins/wifi.c
index 6672f0dd..f80cbd17 100755
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -59,11 +59,13 @@
#include <gsupplicant/gsupplicant.h>
+#include "src/shared/util.h"
+
#define CLEANUP_TIMEOUT 8 /* in seconds */
#define INACTIVE_TIMEOUT 12 /* in seconds */
#define FAVORITE_MAXIMUM_RETRIES 2
-#define BGSCAN_DEFAULT "simple:30:-45:300"
+#define BGSCAN_DEFAULT "simple:30:-65:300"
#define AUTOSCAN_EXPONENTIAL "exponential:3:300"
#define AUTOSCAN_SINGLE "single:3"
@@ -2618,7 +2620,7 @@ static int get_latest_connections(int max_ssids,
g_key_file_free(keyfile);
continue;
}
- g_time_val_from_iso8601(str, &modified);
+ util_iso8601_to_timeval(str, &modified);
g_free(str);
ssid = g_key_file_get_string(keyfile,
@@ -3707,7 +3709,7 @@ found:
return;
}
- if (wifi->network != wifi->pending_network)
+ if (wifi->network && wifi->network != wifi->pending_network)
connman_network_set_connected(wifi->network, false);
wifi->network = NULL;