Send connman mailing list submissions to
        connman@lists.01.org

To subscribe or unsubscribe via email, send a message with subject or
body 'help' to
        connman-requ...@lists.01.org

You can reach the person managing the list at
        connman-ow...@lists.01.org

When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."

Today's Topics:

   1. [PATCH] dnsproxy: Enable DNS servers on connected VPN if split routing 
changes
      (Jussi Laakkonen)
   2. Re: [PATCH] service: Allow only user connection after WiFi failure
      (Jussi Laakkonen)
   3. [RFC 0/8] Prevent IPv4 VPN data/DNS leak to IPv6 network(s)
      (Jussi Laakkonen)
   4. [RFC 1/8] ipconfig: Add disabling of IPv6, support method restore and 
refactor
      (Jussi Laakkonen)


----------------------------------------------------------------------

Date: Fri, 26 Mar 2021 14:45:53 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: [PATCH] dnsproxy: Enable DNS servers on connected VPN if
        split routing changes
To: connman@lists.01.org
Message-ID: <20210326124553.5851-1-jussi.laakko...@jolla.com>

If split routing is enabled on a connected VPN the DNS servers of the
VPN should be enabled as well when the default service is switched to be
the transport service.
---
 src/dnsproxy.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index 4f5c897f..de52df5a 100644
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -2885,6 +2885,7 @@ static void dnsproxy_default_changed(struct 
connman_service *service)
        bool server_enabled = false;
        GSList *list;
        int index;
+       int vpn_index;
 
        DBG("service %p", service);
 
@@ -2901,6 +2902,13 @@ static void dnsproxy_default_changed(struct 
connman_service *service)
        if (index < 0)
                return;
 
+       /*
+        * In case non-split-routed VPN is set as split routed the DNS servers
+        * the VPN must be enabled as well, when the transport becomes the
+        * default service.
+        */
+       vpn_index = __connman_connection_get_vpn_index(index);
+
        for (list = server_list; list; list = list->next) {
                struct server_data *data = list->data;
 
@@ -2908,6 +2916,9 @@ static void dnsproxy_default_changed(struct 
connman_service *service)
                        DBG("Enabling DNS server %s", data->server);
                        data->enabled = true;
                        server_enabled = true;
+               } else if (data->index == vpn_index) {
+                       DBG("Enabling DNS server of VPN %s", data->server);
+                       data->enabled = true;
                } else {
                        DBG("Disabling DNS server %s", data->server);
                        data->enabled = false;
-- 
2.20.1

------------------------------

Date: Fri, 26 Mar 2021 17:25:15 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: Re: [PATCH] service: Allow only user connection after WiFi
        failure
To: "VAUTRIN Emmanuel (Canal Plus Prestataire)"
        <emmanuel.vaut...@cpexterne.org>, "connman@lists.01.org"
        <connman@lists.01.org>
Message-ID: <b6bbb4f0-ab67-0e71-e43e-887de3e84...@jolla.com>
Content-Type: text/plain; charset=utf-8; format=flowed

Hi Emmanuel,

On 3/11/21 3:06 PM, VAUTRIN Emmanuel (Canal Plus Prestataire) wrote:
> The failure state may not always result from a bad connection.
> For security matter, as a password renewal, the AP may disconnect the
> station, and finally completely block it, after several inappropriate
> retries, due to auto connection with former password.
> ---
>   src/service.c | 14 ++++++++++----
>   1 file changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/src/service.c b/src/service.c
> index a24dea729545..cd939320d3d5 100644
> --- a/src/service.c
> +++ b/src/service.c
> @@ -3447,16 +3447,22 @@ static void do_auto_connect(struct connman_service 
> *service,
>                               reason == CONNMAN_SERVICE_CONNECT_REASON_NONE))
>               return;
>   
> +     /*
> +      * Only user interaction should get VPN or WIFI connected in failure
> +      * state.
> +      */
> +     if (service->state == CONNMAN_SERVICE_STATE_FAILURE &&
> +                             reason != CONNMAN_SERVICE_CONNECT_REASON_USER &&
> +                             (service->type == CONNMAN_SERVICE_TYPE_VPN ||
> +                             service->type == CONNMAN_SERVICE_TYPE_WIFI))

Could this be treated in some other manner as I suspect (I haven't 
tested this at all yet) that in mobile environment when AP is shut down, 
lost or it simply crashes and does not get up instantly (put down for 
maintenance) the service may end up in failure state? In that case user 
interaction would not be required for re-connecting and autoconnect 
should handle that case. But I understand your point here that 
repeatedly re-connecting has its downsides as well.

We have our own implementation of the WiFi plugin and I haven't tried 
with the plugin upstream has so this is just a guess/concern from my part.

So, if the WiFi plugin can in the cases I described result in failure 
state this may need some re-thinking. If not, please ignore this :)

> +             return;
> +
>       /*
>        * Run service auto connect for other than VPN services. Afterwards
>        * start also VPN auto connect process.
>        */
>       if (service->type != CONNMAN_SERVICE_TYPE_VPN)
>               __connman_service_auto_connect(reason);
> -     /* Only user interaction should get VPN connected in failure state. */
> -     else if (service->state == CONNMAN_SERVICE_STATE_FAILURE &&
> -                             reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
> -             return;
>   
>       vpn_auto_connect();
>   }
> 

Sincerely,
  Jussi Laakkonen

------------------------------

Date: Fri, 26 Mar 2021 17:58:17 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: [RFC 0/8] Prevent IPv4 VPN data/DNS leak to IPv6 network(s)
To: connman@lists.01.org
Message-ID: <20210326155825.3938-1-jussi.laakko...@jolla.com>

This change is quite big, touching many places around the codebase and may
have still some quirks to be polished out and therefore this is sent as an
RFC first. The core idea of this is to prevent leaking of any data to an IPv6
network when an IPv4 VPN is used with dual-stack transport or when there are
other connected IPv6 cabable technologies. Leak can happen when the DNS server
of the VPN responds also to AAAA requests providing an IPv6 address as well. In
that case IPv6 of the transport/other connected service will be used and
traffic bypasses VPN.

Prevention of data leak is achieved by disabling IPv6 on adapter basis with
disable_ipv6 and autoconf values. It was not seen reasonable to disable IPv6
on system basis as there may be other interfaces that are not managed by
ConnMan (blacklisted) which may require IPv6 to function properly.

Therefore, this simply does disable IPv6 on all connected services when the
IPv4 VPN is connected with the help of changes done to ipconfig.c. Setting the
internal value to block IPv6 use within ConnMan is utilized only when there can
be multiple connected technologies as otherwise the transport will get replaced
and VPN is re-connected using the new transport.

If multiple connected technologies is enabled and a new service connects then
in this case it cannot first establish an IPv6 connection at all but if the
particular service then ranks over the current service the VPN will be
disconnected, IPv6 is re-enabled and the new service starts to establish an
IPv6 connection. Otherwise the new service remains with IPv4
connectivity only - but if it is IPv6 only the service cannot connect and this
is expected (might it be good to have this feature as a configurable option?).

To be future-proof it may be better to have the new services to have their IPv6
network not enabled but forcefully disabled in case at the time of connection
an IPv4 VPN is connected. Not only due to the fact that an IPv6 address is not
attempted to be retrieved with the current approach for a newly connected
network. Alternative would be to call
__connman_provider_set_ipv6_for_connected() in case the default service is an
IPv4 VPN to get the service list traversed. But in that case IPv6 connectivity
may have been established and there might be a small timeframe for leaking
traffic.

It was also considered and prototyped to do this with DNS filtering but that
did prove to be a bit problematic, hence the added delays in some cases to DNS
requests and respective responses. Also disabling only the routes was
considered but since it depends on the IPv6 network type and autoconfiguration
of the interface it seemed to be safer and more consistent to do the change
like this.

But being a RFC any opinnion and comment is welcome. We have done some testing
and in those this seems to work well. One thing to consider is whether to
always set the autoconf value for an IPv6 enabled network interface or not, or
to save it along other IPv6 values to be able to restore the previous value in
case ConnMan crashes when the VPN is connected and IPv6 is disabled.


Jussi Laakkonen (8):
  ipconfig: Add disabling of IPv6, support method restore and refactor
  network: Support ipconfig.c changes for IPv6 force option
  network: Prevent enabling IPv6 for network if internally disabled
  service: Support IPv6 enable/disable for connected services
  provider: Toggle IPv6 on the transport of IPv4 VPN connection
  vpn: Return transport ident with get_property()
  provider: Add function to get transport ident from VPN
  service: Sort VPNs using the transport service if connected

 plugins/vpn.c  |   2 +
 src/connman.h  |  20 +++-
 src/ipconfig.c | 290 +++++++++++++++++++++++++++++++++----------------
 src/network.c  |  61 ++++++++---
 src/provider.c | 130 ++++++++++++++++++++++
 src/service.c  | 203 ++++++++++++++++++++++++++++++++--
 6 files changed, 583 insertions(+), 123 deletions(-)

-- 
2.20.1

------------------------------

Date: Fri, 26 Mar 2021 17:58:18 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: [RFC 1/8] ipconfig: Add disabling of IPv6, support method
        restore and refactor
To: connman@lists.01.org
Message-ID: <20210326155825.3938-2-jussi.laakko...@jolla.com>

Support complete disabling of IPv6 on both system and interface levels.
Disabling of IPv6 completely albeit temporarily is required when there
can be multiple connected technologies and a VPN is connected over IPv4
using an dual-stack transport and/or there is another technology with
dual-stack or only IPv6 in use. This approach effectively ensures that
no data from an IPv4 VPN leaks to any other interface. A DNS server
returning replies to AAAA requests may return an IPv6 address, which
could be then used over IPv6 routing on another technolology that is not
acting as the transport of the VPN.

Add getter and setter for the internal IPv6 status. When enabling check
the status with connman_inet_is_ipv6_supported(). It is not the
intention to disable IPv6 system-wide since there may be interfaces that
should not be managed by ConnMan and are handled for other OS needs
where IPv6 is required, e.g., VoLTE may be one of them.

Add a "ipv6_force_disabled" toggle to indicate that the particular
device tied to ipconfig should not have IPv6 enabled. This toggle is to
be used in scenarios where IPv6 should be prevented from reinstating
unless forcefully enabled. The __connman_ipconfig_{enable,disable}_ipv6()
now have additional boolean to control this behavior, and the enabling
function returns either -EINVAL or -EOPNOTSUPP for errors and 0 when
success.

When checking IPv6 enabled state return false if ipv6_force_disabled is
set as that is the real status of IPv6. The /proc disable_ipv6 can
change when kernel processes ICMPv6 (RA/RS) packets and brings the IPv6
interface up so using only the disable_ipv6 value is not consistent
enough in case when IPv6 has been forcefully disabled.

This change will prevent from changing the IPv6 status until it has
it has been forcefully enabled. The most prominent use case for this
is to prevent data as well as DNS leak to IPv6 when IPv4 only VPN is
connected over a transport supporting both IPv4 and IPv6 connectivity.

In addition to changing disable_ipv6 value also the autoconf option is
managed. This is done in order to control the address setup for the
interface. It is worthy to note that disable_ipv6 may be temporarily
set to 0 by the kernel. This can happen when LL address is temporarily
set as a typical behavior of IPv6 on some configurations to handle
ICMPv6. After a while the value of disable_ipv6 as well as LL address
are reset/removed by kernel.

Also refactor getting and setting the proc conf values, have read and
write in their own respective general functions. If write/read is
issued without interface name (NULL) then "all" section is used to
follow the old behavior.

Add functions to save and restore old IPv6 method. This is useful when
IPv6 is disabled termporarily for the time IPv4 VPN is used. First save
the IPv6 method before disabling and call restore when IPv6 needs to be
set up again using the old method.
---
 src/connman.h  |  10 +-
 src/ipconfig.c | 290 +++++++++++++++++++++++++++++++++----------------
 2 files changed, 203 insertions(+), 97 deletions(-)

diff --git a/src/connman.h b/src/connman.h
index a43a6b8b..1ffce3e1 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -340,8 +340,12 @@ void __connman_ipconfig_set_ops(struct connman_ipconfig 
*ipconfig,
                                const struct connman_ipconfig_ops *ops);
 int __connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
                                        enum connman_ipconfig_method method);
-void __connman_ipconfig_disable_ipv6(struct connman_ipconfig *ipconfig);
-void __connman_ipconfig_enable_ipv6(struct connman_ipconfig *ipconfig);
+void __connman_ipconfig_disable_ipv6(struct connman_ipconfig *ipconfig,
+                                                               bool forced);
+int __connman_ipconfig_enable_ipv6(struct connman_ipconfig *ipconfig,
+                                                               bool forced);
+int __connman_ipconfig_set_ipv6_support(bool enable);
+bool __connman_ipconfig_get_ipv6_support();
 
 int __connman_ipconfig_init(void);
 void __connman_ipconfig_cleanup(void);
@@ -406,6 +410,8 @@ void __connman_ipconfig_append_ethernet(struct 
connman_ipconfig *ipconfig,
                                                        DBusMessageIter *iter);
 enum connman_ipconfig_method __connman_ipconfig_get_method(
                                struct connman_ipconfig *ipconfig);
+void __connman_ipconfig_ipv6_method_save(struct connman_ipconfig *ipconfig);
+void __connman_ipconfig_ipv6_method_restore(struct connman_ipconfig *ipconfig);
 
 int __connman_ipconfig_address_add(struct connman_ipconfig *ipconfig);
 int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig);
diff --git a/src/ipconfig.c b/src/ipconfig.c
index 2bfeefd4..737e69bc 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -49,12 +49,15 @@ struct connman_ipconfig {
        void *ops_data;
 
        enum connman_ipconfig_method method;
+       enum connman_ipconfig_method saved_method;
        struct connman_ipaddress *address;
        struct connman_ipaddress *system;
 
        int ipv6_privacy_config;
        char *last_dhcp_address;
        char **last_dhcpv6_prefixes;
+
+       bool ipv6_force_disabled;
 };
 
 struct connman_ipdevice {
@@ -258,153 +261,174 @@ static const char *scope2str(unsigned char scope)
        return "";
 }
 
-static bool get_ipv6_state(gchar *ifname)
+#define PROC_IPV4_CONF_PREFIX "/proc/sys/net/ipv4/conf"
+#define PROC_IPV6_CONF_PREFIX "/proc/sys/net/ipv6/conf"
+
+static int read_conf_value(const char *prefix, const char *ifname,
+                                       const char *suffix, int *value)
 {
-       int disabled;
        gchar *path;
        FILE *f;
-       bool enabled = false;
-
-       if (!ifname)
-               path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
-       else
-               path = g_strdup_printf(
-                       "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
+       int err;
 
+       path = g_build_filename(prefix, ifname ? ifname : "all", suffix, NULL);
        if (!path)
-               return enabled;
+               return -ENOMEM;
 
+       errno = 0;
        f = fopen(path, "r");
+       if (!f) {
+               err = -errno;
+       } else {
+               errno = 0; /* Avoid stale errno values with fscanf */
 
-       g_free(path);
+               err = fscanf(f, "%d", value);
+               if (err <= 0 && errno)
+                       err = -errno;
 
-       if (f) {
-               if (fscanf(f, "%d", &disabled) > 0)
-                       enabled = !disabled;
                fclose(f);
        }
 
-       return enabled;
+       if (err <= 0)
+               connman_error("failed to read %s", path);
+
+       g_free(path);
+
+       return err;
 }
 
-static void set_ipv6_state(gchar *ifname, bool enable)
+static int read_ipv4_conf_value(const char *ifname, const char *suffix,
+                                                               int *value)
 {
+       return read_conf_value(PROC_IPV4_CONF_PREFIX, ifname, suffix, value);
+}
+
+static int read_ipv6_conf_value(const char *ifname, const char *suffix,
+                                                               int *value)
+{
+       return read_conf_value(PROC_IPV6_CONF_PREFIX, ifname, suffix, value);
+}
+
+static int write_conf_value(const char *prefix, const char *ifname,
+                                       const char *suffix, int value) {
        gchar *path;
        FILE *f;
+       int rval;
 
-       if (!ifname)
-               path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
-       else
-               path = g_strdup_printf(
-                       "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
-
+       path = g_build_filename(prefix, ifname ? ifname : "all", suffix, NULL);
        if (!path)
-               return;
+               return -ENOMEM;
 
        f = fopen(path, "r+");
+       if (!f) {
+               rval = -errno;
+       } else {
+               rval = fprintf(f, "%d", value);
+               fclose(f);
+       }
+
+       if (rval <= 0)
+               connman_error("failed to set %s value %d", path, value);
 
        g_free(path);
 
-       if (!f)
-               return;
+       return rval;
+}
 
-       if (!enable)
-               fprintf(f, "1");
-       else
-               fprintf(f, "0");
+static int write_ipv4_conf_value(const char *ifname, const char *suffix,
+                                                               int value)
+{
+       return write_conf_value(PROC_IPV4_CONF_PREFIX, ifname, suffix, value);
+}
 
-       fclose(f);
+static int write_ipv6_conf_value(const char *ifname, const char *suffix,
+                                                               int value)
+{
+       return write_conf_value(PROC_IPV6_CONF_PREFIX, ifname, suffix, value);
 }
 
-static int get_ipv6_privacy(gchar *ifname)
+static bool get_ipv6_state(gchar *ifname)
 {
-       gchar *path;
-       FILE *f;
-       int value;
+       int disabled;
+       bool enabled = false;
 
-       if (!ifname)
-               return 0;
+       if (read_ipv6_conf_value(ifname, "disable_ipv6", &disabled) > 0)
+               enabled = !disabled;
 
-       path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
-                                                               ifname);
+       return enabled;
+}
 
-       if (!path)
-               return 0;
+static int set_ipv6_state(gchar *ifname, bool enable)
+{
+       int disabled = enable ? 0 : 1;
 
-       f = fopen(path, "r");
+       DBG("%s %d", ifname, disabled);
 
-       g_free(path);
+       return write_ipv6_conf_value(ifname, "disable_ipv6", disabled);
+}
 
-       if (!f)
+static int get_ipv6_privacy(gchar *ifname)
+{
+       int value;
+
+       if (!ifname)
                return 0;
 
-       if (fscanf(f, "%d", &value) <= 0)
+       if (read_ipv6_conf_value(ifname, "use_tempaddr", &value) < 0)
                value = 0;
 
-       fclose(f);
-
        return value;
 }
 
 /* Enable the IPv6 privacy extension for stateless address autoconfiguration.
  * The privacy extension is described in RFC 3041 and RFC 4941
  */
-static void set_ipv6_privacy(gchar *ifname, int value)
+static int set_ipv6_privacy(gchar *ifname, int value)
 {
-       gchar *path;
-       FILE *f;
-
        if (!ifname)
-               return;
-
-       path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
-                                                               ifname);
-
-       if (!path)
-               return;
+               return -EINVAL;
 
        if (value < 0)
                value = 0;
 
-       f = fopen(path, "r+");
+       return write_ipv6_conf_value(ifname, "use_tempaddr", value);
+}
 
-       g_free(path);
+static int set_ipv6_autoconf(gchar *ifname, bool enable)
+{
+       int value = enable ? 1 : 0;
 
-       if (!f)
-               return;
+       DBG("%s %d", ifname, enable);
 
-       fprintf(f, "%d", value);
-       fclose(f);
+       return write_ipv6_conf_value(ifname, "autoconf", value);
 }
 
 static int get_rp_filter(void)
 {
-       FILE *f;
-       int value = -EINVAL, tmp;
-
-       f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r");
+       int value;
 
-       if (f) {
-               if (fscanf(f, "%d", &tmp) == 1)
-                       value = tmp;
-               fclose(f);
-       }
+       if (read_ipv4_conf_value(NULL, "rp_filter", &value) < 0)
+               value = -EINVAL;
 
        return value;
 }
 
-static void set_rp_filter(int value)
+static int set_rp_filter(int value)
 {
-       FILE *f;
-
-       f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r+");
-
-       if (!f)
-               return;
-
-       fprintf(f, "%d", value);
+       /* 0 = no validation, 1 = strict mode, 2 = loose mode */
+       switch (value) {
+       case -1:
+               value = 0;
+               /* fall through */
+       case 0:
+       case 1:
+       case 2:
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       fclose(f);
+       return write_ipv4_conf_value(NULL, "rp_filter", value);
 }
 
 int __connman_ipconfig_set_rp_filter()
@@ -448,6 +472,13 @@ bool __connman_ipconfig_ipv6_is_enabled(struct 
connman_ipconfig *ipconfig)
        if (!ipconfig)
                return false;
 
+       /*
+        * Return forced value since kernel can enable LL address for IPv6
+        * for handling ICMPv6.
+        */
+       if (ipconfig->ipv6_force_disabled)
+               return false;
+
        ipdevice = g_hash_table_lookup(ipdevice_hash,
                                        GINT_TO_POINTER(ipconfig->index));
        if (!ipdevice)
@@ -1236,6 +1267,8 @@ static struct connman_ipconfig *create_ipv6config(int 
index)
        else
                ipv6config->method = CONNMAN_IPCONFIG_METHOD_AUTO;
 
+       ipv6config->saved_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
+
        ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
        if (ipdevice)
                ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy;
@@ -1421,6 +1454,33 @@ enum connman_ipconfig_method 
__connman_ipconfig_get_method(
        return ipconfig->method;
 }
 
+void __connman_ipconfig_ipv6_method_save(struct connman_ipconfig *ipconfig)
+{
+       if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
+               return;
+
+       DBG("%p method %d", ipconfig, ipconfig->method);
+
+       ipconfig->saved_method = ipconfig->method;
+}
+
+void __connman_ipconfig_ipv6_method_restore(struct connman_ipconfig *ipconfig)
+{
+       if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
+               return;
+
+       /* If not previously set, default to AUTO */
+       if (ipconfig->saved_method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
+               ipconfig->method = CONNMAN_IPCONFIG_METHOD_AUTO;
+       else
+               ipconfig->method = ipconfig->saved_method;
+
+       DBG("%p saved method %d set method %d", ipconfig,
+                               ipconfig->saved_method, ipconfig->method);
+
+       ipconfig->saved_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
+}
+
 int __connman_ipconfig_address_add(struct connman_ipconfig *ipconfig)
 {
        switch (ipconfig->method) {
@@ -1567,7 +1627,7 @@ char **__connman_ipconfig_get_dhcpv6_prefixes(struct 
connman_ipconfig *ipconfig)
        return ipconfig->last_dhcpv6_prefixes;
 }
 
-static void disable_ipv6(struct connman_ipconfig *ipconfig)
+static int disable_ipv6(struct connman_ipconfig *ipconfig, bool forced)
 {
        struct connman_ipdevice *ipdevice;
        char *ifname;
@@ -1577,16 +1637,26 @@ static void disable_ipv6(struct connman_ipconfig 
*ipconfig)
        ipdevice = g_hash_table_lookup(ipdevice_hash,
                                        GINT_TO_POINTER(ipconfig->index));
        if (!ipdevice)
-               return;
+               return -EINVAL;
+
+       DBG("%p forced %s force_disabled %s", ipconfig, forced ? "yes" : "no",
+                               ipconfig->ipv6_force_disabled ? "yes" : "no");
 
        ifname = connman_inet_ifname(ipconfig->index);
 
        set_ipv6_state(ifname, false);
 
+       if (forced) {
+               set_ipv6_autoconf(ifname, false);
+               ipconfig->ipv6_force_disabled = true;
+       }
+
        g_free(ifname);
+
+       return 0;
 }
 
-static void enable_ipv6(struct connman_ipconfig *ipconfig)
+static int enable_ipv6(struct connman_ipconfig *ipconfig, bool forced)
 {
        struct connman_ipdevice *ipdevice;
        char *ifname;
@@ -1596,7 +1666,17 @@ static void enable_ipv6(struct connman_ipconfig 
*ipconfig)
        ipdevice = g_hash_table_lookup(ipdevice_hash,
                                        GINT_TO_POINTER(ipconfig->index));
        if (!ipdevice)
-               return;
+               return -EINVAL;
+
+       DBG("IPv6 %s %p forced %s force_disabled %s",
+                               is_ipv6_supported ? "on" : "off", ipconfig,
+                               forced ? "yes" : "no",
+                               ipconfig->ipv6_force_disabled ? "yes" : "no");
+
+       if ((!is_ipv6_supported || ipconfig->ipv6_force_disabled) && !forced)
+               return -EOPNOTSUPP;
+
+       ipconfig->ipv6_force_disabled = false;
 
        ifname = connman_inet_ifname(ipconfig->index);
 
@@ -1605,23 +1685,42 @@ static void enable_ipv6(struct connman_ipconfig 
*ipconfig)
 
        set_ipv6_state(ifname, true);
 
+       if (forced)
+               set_ipv6_autoconf(ifname, true);
+
        g_free(ifname);
+
+       return 0;
 }
 
-void __connman_ipconfig_enable_ipv6(struct connman_ipconfig *ipconfig)
+int __connman_ipconfig_enable_ipv6(struct connman_ipconfig *ipconfig,
+                                                       bool forced)
 {
        if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
-               return;
+               return -EINVAL;
 
-       enable_ipv6(ipconfig);
+       return enable_ipv6(ipconfig, forced);
 }
 
-void __connman_ipconfig_disable_ipv6(struct connman_ipconfig *ipconfig)
+void __connman_ipconfig_disable_ipv6(struct connman_ipconfig *ipconfig,
+                                                       bool forced)
 {
        if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
                return;
 
-       disable_ipv6(ipconfig);
+       disable_ipv6(ipconfig, forced);
+}
+
+int __connman_ipconfig_set_ipv6_support(bool enable)
+{
+       is_ipv6_supported = enable ? connman_inet_is_ipv6_supported() : false;
+
+       return 0;
+}
+
+bool __connman_ipconfig_get_ipv6_support()
+{
+       return is_ipv6_supported;
 }
 
 bool __connman_ipconfig_is_usable(struct connman_ipconfig *ipconfig)
@@ -1650,6 +1749,7 @@ int __connman_ipconfig_enable(struct connman_ipconfig 
*ipconfig)
        bool lower_up = false, lower_down = false;
        enum connman_ipconfig_type type;
        char *ifname;
+       int err;
 
        DBG("ipconfig %p", ipconfig);
 
@@ -1703,7 +1803,9 @@ int __connman_ipconfig_enable(struct connman_ipconfig 
*ipconfig)
        else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
                ipdevice->config_ipv6 = __connman_ipconfig_ref(ipconfig);
 
-               enable_ipv6(ipdevice->config_ipv6);
+               err = enable_ipv6(ipdevice->config_ipv6, false);
+               if (err)
+                       return err;
        }
        ipconfig_list = g_list_append(ipconfig_list, ipconfig);
 
@@ -1872,9 +1974,7 @@ int __connman_ipconfig_ipv6_set_privacy(struct 
connman_ipconfig *ipconfig,
 
        ipconfig->ipv6_privacy_config = privacy;
 
-       enable_ipv6(ipconfig);
-
-       return 0;
+       return enable_ipv6(ipconfig, false);
 }
 
 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
-- 
2.20.1

------------------------------

Subject: Digest Footer

_______________________________________________
connman mailing list -- connman@lists.01.org
To unsubscribe send an email to connman-le...@lists.01.org


------------------------------

End of connman Digest, Vol 65, Issue 7
**************************************

Reply via email to