diff options
author | Niraj Kumar Goit <niraj.g@samsung.com> | 2022-02-15 10:23:07 +0530 |
---|---|---|
committer | Niraj Kumar Goit <niraj.g@samsung.com> | 2022-02-15 10:25:05 +0530 |
commit | f89b473dfd8e916314b534b3397442f8c869c783 (patch) | |
tree | b6f15a191886ac5b78e98b1b2b210adefae69cf2 /plugins | |
parent | dd3cccc5e67548dcc2dd6c6254ed6c97859085d5 (diff) | |
download | connman-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.c | 4 | ||||
-rw-r--r-- | plugins/dundee.c | 2 | ||||
-rw-r--r-- | plugins/ethernet.c | 12 | ||||
-rw-r--r-- | plugins/iwd.c | 310 | ||||
-rw-r--r-- | plugins/neard.c | 2 | ||||
-rw-r--r-- | plugins/ofono.c | 4 | ||||
-rw-r--r-- | plugins/vpn.c | 297 | ||||
-rw-r--r-- | plugins/wifi.c | 117 |
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); |