diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/ethernet.c | 8 | ||||
-rw-r--r-- | plugins/iwd.c | 885 | ||||
-rwxr-xr-x | plugins/ofono.c | 6 | ||||
-rwxr-xr-x | plugins/session_policy_local.c | 6 | ||||
-rwxr-xr-x | plugins/tist.c | 2 | ||||
-rwxr-xr-x | plugins/vpn.c | 61 | ||||
-rwxr-xr-x | plugins/wifi.c | 8 |
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; |