Skip to content

Commit

Permalink
provider: Reformat IPv6 toggle function to use service.c functionality
Browse files Browse the repository at this point in the history
[provider] Reformat IPv6 toggle function to use service.c funct. JB#53542

Moved the IPv6 toggling functionality for the most part to service.c and
this change adapts to the change. Only the VPN service checks are kept
in provider.c and IPv6 is disabled for all connected services instead of
using transport only and disabling IPv6 on system level. Current VPN and
transport services are passed to the service.c functionality to exclude
VPN service and always include transport service in IPv6 changes.

Changed to use "enable" to be in line with rest of the code. This
removes the need to use a lot of negations and perhaps it is easier to
understand the code as well.

Allow to change IPv6 only for VPNs that are connected (ready, as VPNs
cannot reach online state).

Prevent running the function as a loop within loop. This might happen
when current transport service is disconnected that in turn causes the
VPN to be disconnected as well. Then while looping through the services
another disconnect on the transport will get provider_indicate_state()
called again.

When re-enabling IPv6 enable the internal IPv6 suppor prior to resuming
IPv6 functionality on service basis. When disabling IPv6 do the internal
disabling after the services are handled. This is due to the changes
that were required for network.c to get new connections enabled but IPv6
disabled if IPv6 is internally disabled.
  • Loading branch information
LaakkonenJussi committed Apr 27, 2021
1 parent 36674c8 commit c4edf1a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 107 deletions.
5 changes: 3 additions & 2 deletions connman/src/connman.h
Expand Up @@ -781,8 +781,9 @@ int __connman_provider_indicate_error(struct connman_provider *provider,
int __connman_provider_connect(struct connman_provider *provider,
const char *dbus_sender);
int __connman_provider_remove_by_path(const char *path);
int __connman_provider_toggle_transport_ipv6(struct connman_provider *provider,
bool disable);
int __connman_provider_set_ipv6_for_connected(
struct connman_provider *provider,
bool enable);
void __connman_provider_cleanup(void);
int __connman_provider_init(void);

Expand Down
164 changes: 59 additions & 105 deletions connman/src/provider.c
Expand Up @@ -47,7 +47,6 @@ struct connman_provider {
int family;
struct connman_provider_driver *driver;
void *driver_data;
enum connman_ipconfig_method transport_ipv6_method;
};

void __connman_provider_append_properties(struct connman_provider *provider,
Expand Down Expand Up @@ -122,132 +121,86 @@ void connman_provider_unref_debug(struct connman_provider *provider,
provider_destruct(provider);
}

int __connman_provider_toggle_transport_ipv6(struct connman_provider *provider,
bool disable)
static bool ipv6_change_running = false;

int __connman_provider_set_ipv6_for_connected(
struct connman_provider *provider, bool enable)
{
struct connman_service *service;
struct connman_service *transport;
struct connman_network *network;
struct connman_ipconfig *service_ipv6config;
struct connman_ipconfig *transport_ipv6config;
struct connman_ipconfig *ipconfig;
enum connman_service_state state;
const char *transport_ident;
bool single_connected_tech;

if (ipv6_change_running)
return -EALREADY;

if (!provider)
return -EINVAL;

DBG("provider %p %s", provider, !disable ? "enable" : "disable");
DBG("provider %p %s", provider, enable ? "enable" : "disable");

service = provider->vpn_service;
if (!service)
return -EINVAL;

/*
* Allow only when the VPN service is in ready state, service state
* is changed to ready before provider when connecting and changed
* away from ready after provider state is changed.
*/
state = connman_service_get_state(service);
if (state != CONNMAN_SERVICE_STATE_READY)
return 0;

/*
* If a VPN changes from non-split routed to split routed then IPv6 on
* the transport must be re-enabled.
*/
if (__connman_service_is_split_routing(service) && disable)
goto out;
if (__connman_service_is_split_routing(service) && !enable)
return 0;

service_ipv6config = __connman_service_get_ip6config(service);
if (service_ipv6config &&
__connman_ipconfig_ipv6_is_enabled(service_ipv6config))
ipconfig = __connman_service_get_ip6config(service);
if (__connman_ipconfig_ipv6_is_enabled(ipconfig))
return 0;

/*
* Set system IPv6 status if multiple connected technologies are used
* in order to avoid leaking DNS/data to any IPv6 network. That may
* happen when DNS server returns also AAAA record for a request.
single_connected_tech =
connman_setting_get_bool("SingleConnectedTechnology");

/* If re-enabling IPv6 set the internal status prior to enabling IPv6
* for connected servises to allow the IPv6 ipconfig enabled check to
* return correct value.
*/
if (!connman_setting_get_bool("SingleConnectedTechnology")) {
if (!__connman_ipconfig_set_ipv6_support(!disable))
connman_warn("cannot disable IPv6 support for "
"provider %p", provider);
}
if (enable && !single_connected_tech)
__connman_ipconfig_set_ipv6_support(enable);

transport_ident = __connman_provider_get_transport_ident(provider);
transport = connman_service_lookup_from_identifier(transport_ident);
if (!transport) {
DBG("no transport for %p transport ident %s", service,
transport_ident);
return -ENODEV;
}

DBG("transport %p", transport);

network = __connman_service_get_network(transport);
if (!network) {
DBG("no network for transport %p", transport);
return -ENODEV;
}

transport_ipv6config = __connman_service_get_ip6config(transport);
if (!transport_ipv6config) {
DBG("no ipv6config on transport %p", transport);
return 0; // Not enabled?
}

if (disable) {
if (!__connman_ipconfig_ipv6_is_enabled(transport_ipv6config))
return 0;

provider->transport_ipv6_method =
__connman_ipconfig_get_method(
transport_ipv6config);
DBG("set IPv6 ipconfig %p off (old %d)", transport,
provider->transport_ipv6_method);

__connman_network_clear_ipconfig(network,
transport_ipv6config);
__connman_ipconfig_gateway_remove(transport_ipv6config);

__connman_service_ipconfig_indicate_state(transport,
CONNMAN_SERVICE_STATE_DISCONNECT,
CONNMAN_IPCONFIG_TYPE_IPV6);
__connman_ipconfig_address_unset(transport_ipv6config);

/*
* Disables IPv6 on ipconfig and sets the force_disabled
* as true.
*/
connman_network_set_ipv6_method(network,
CONNMAN_IPCONFIG_METHOD_OFF);
__connman_network_enable_ipconfig(network,
transport_ipv6config, true);

__connman_service_ipconfig_indicate_state(transport,
CONNMAN_SERVICE_STATE_IDLE,
CONNMAN_IPCONFIG_TYPE_IPV6);
} else {
if (__connman_ipconfig_ipv6_is_enabled(transport_ipv6config))
return 0;

switch (provider->transport_ipv6_method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
DBG("IPv6 previously disabled on %p", transport);
goto out;
case CONNMAN_IPCONFIG_METHOD_MANUAL:
case CONNMAN_IPCONFIG_METHOD_AUTO:
case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_DHCP:
break;
}

DBG("set IPv6 method %d", provider->transport_ipv6_method);

connman_network_set_ipv6_method(network,
provider->transport_ipv6_method);
__connman_network_enable_ipconfig(network,
transport_ipv6config, true);
}
/* In case a sevice of same type that the current transport is changed
* to use another, e.g., WiFi AP, then the service is first
* disconnected which in turn calls provider_indicate_state() when
* provider is being disconnected and this function gets called. In
* such case another call to provider_indicate_state() can be made
* while traversing through the services list with
* __connman_service_set_ipv6_for_connected() to disconnect this
* provider. Therefore, using this boolean can prevent a loop within
* loop from being executed.
*/
ipv6_change_running = true;

/* Set IPv6 for connected, excluding VPN and include transport. */
__connman_service_set_ipv6_for_connected(service, transport, enable);

__connman_service_notify_ipv6_configuration(transport);
__connman_notifier_ipconfig_changed(transport, transport_ipv6config);
/*
* Disable internal IPv6 use after disabling IPv6 for the connected
* services to allow IPv6 enabled check to work.
*/
if (!enable && !single_connected_tech)
__connman_ipconfig_set_ipv6_support(enable);

out:
if (!disable)
provider->transport_ipv6_method =
CONNMAN_IPCONFIG_METHOD_UNKNOWN;
ipv6_change_running = false;

return 0;
}
Expand All @@ -270,8 +223,9 @@ static int provider_indicate_state(struct connman_provider *provider,
if (provider->family != AF_INET)
break;

err = __connman_provider_toggle_transport_ipv6(provider, true);
if (err)
err = __connman_provider_set_ipv6_for_connected(provider,
false);
if (err && err != -EALREADY)
DBG("cannot disable IPv6 on provider %p transport",
provider);
break;
Expand All @@ -280,9 +234,9 @@ static int provider_indicate_state(struct connman_provider *provider,
if (provider->family != AF_INET)
break;

err = __connman_provider_toggle_transport_ipv6(provider,
false);
if (err)
err = __connman_provider_set_ipv6_for_connected(provider,
true);
if (err && err != -EALREADY)
DBG("cannot enable IPv6 on provider %p transport",
provider);

Expand Down

0 comments on commit c4edf1a

Please sign in to comment.