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 02/15] inet: Add function for detecting a default route
      (Jussi Laakkonen)
   2. [PATCH 00/15] Support SplitRouting on vpnd, drop vpnd route management
      (Jussi Laakkonen)
   3. [PATCH 01/15] connection: Add getter for the phy index of a VPN transport 
service
      (Jussi Laakkonen)
   4. [PATCH 03/15] inet: Refactor with getifaddrs() and add network route 
getter function
      (Jussi Laakkonen)


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

Date: Tue,  8 Dec 2020 12:17:48 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: [PATCH 02/15] inet: Add function for detecting a default
        route
To: connman@lists.01.org
Message-ID: <20201208101801.26715-3-jussi.laakko...@jolla.com>

Support checking of network route being as default route. If host and
netmask are set as INADDR_ANY then the route is a default route. Gateway
can be unset (NULL) or pointing directly to the gateway IP. Check for
this is, however, omitted because it would need ipconfig to get the set
IP for comparison and ipconfig is different for connmand and vpnd.
---
 include/inet.h |  2 ++
 src/inet.c     | 15 +++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/include/inet.h b/include/inet.h
index fdc2155f..5ac9a474 100644
--- a/include/inet.h
+++ b/include/inet.h
@@ -78,6 +78,8 @@ int connman_inet_ipv6_get_dest_addr(int index, char **dest);
 int connman_inet_check_ipaddress(const char *host);
 bool connman_inet_check_hostname(const char *ptr, size_t len);
 bool connman_inet_is_ipv6_supported();
+bool connman_inet_is_default_route(int family, const char *host,
+                               const char *gateway, const char *netmask);
 
 #ifdef __cplusplus
 }
diff --git a/src/inet.c b/src/inet.c
index 4c341438..a537db90 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -2835,6 +2835,21 @@ bool connman_inet_is_ipv6_supported()
        return true;
 }
 
+/*
+ * Omits checking of the gateway matching the actual gateway IP since both
+ * connmand and vpnd use inet.c, getting the route is via ipconfig and ipconfig
+ * is different for both. Gateway is left here for possible future use.
+ *
+ * Gateway can be NULL and connection.c then assigns 0.0.0.0 address or ::,
+ * depending on IP family.
+ */
+bool connman_inet_is_default_route(int family, const char *host,
+                               const char *gateway, const char *netmask)
+{
+       return __connman_inet_is_any_addr(host, family) &&
+                               __connman_inet_is_any_addr(netmask, family);
+}
+
 int __connman_inet_get_interface_address(int index, int family, void *address)
 {
        struct ifaddrs *ifaddr, *ifa;
-- 
2.20.1

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

Date: Tue,  8 Dec 2020 12:17:46 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: [PATCH 00/15] Support SplitRouting on vpnd, drop vpnd route
        management
To: connman@lists.01.org
Message-ID: <20201208101801.26715-1-jussi.laakko...@jolla.com>

SplitRouting is a VPN only setting that was managed by connmand and is also
saved along the vpn_*/settings. This change exposes SplitRouting value also to
vpnd, making it accessible over VPN D-Bus API as well. This allows to control
the split routing value also on VPNs that are not connected yet. And being a
VPN only value it seems natural to have it controllable over VPN D-Bus API.
This does not affect the service moving, but extends it for internal use.

In order to make this happen a lot of changes were required. First of all it
is required to have synchronization of the value changes between connmand and
vpnd. This is achieved by using service specific property changed signals sent
always when the value changes, or is being set (e.g., loading the service), on
both sides. This will result in vpnd informing about the change twice when the
SplitRouting value is changed over VPN D-Bus API. This happens because VPN
changes to connmand are propagated using property changed signals and after
connmand has processed the SplitRouting signal connmand will notify the value
again with a property changed signal to keep vpnd in sync in case of an error,
for instance.

Since service moving is utilized here for making the SplitRouting value changes
on a connected VPN the route checks in plugins/vpn.c is enhanced to handle the
routes better. If a VPN that is being set as a split routed does not have any
other than the default route a network route will be attempted to be added. If
that fails an error is printed and the resulting property changed signal will
contain the current, not affected value of SplitRouting But if a VPN has a
default route configured it will be prevented for SplitRouted VPNs. Also to
make sure that a non-SplitRouted VPN will have a default route set it will be
added if missing.

And to make this happen inet.c was amended with new functionality to get route
addresses. This resulted in some other changes to clean up the code and fix
the issue of getifaddrs() not being able to interpret the destination address
if the P-t-P connection has broadcast address also set. Combined many different
getifaddrs() uses behind one function to have it a multi-purpose function for
different uses. The added, inet.c internal get_interface_addresses() uses
struct interface_address that allows AF specific addresses to be retrieved to
their respective by copying the struct ifaddrs content that matches the given
criteria.

Also some minor change to service.c was required in order to propagate the
SplitRouting value at all times. When loading a service it is imperative to
apply the service settings after registering the D-Bus service because
otherwise any signals cannot be sent about the loaded settings, if needed. This
boils down to the fact that the internal gdbus implementation does not allow
signals to be sent if the path given is not registered.

Route management is also dropped from vpnd as a separate commit so it may be
reverted easily if need arises. This was deemed to be unnecessary and confusing
in discussions with Daniel Wagner on the ConnMan mailing list.

Jussi Laakkonen (15):
  connection: Add getter for the phy index of a VPN transport service
  inet: Add function for detecting a default route
  inet: Refactor with getifaddrs() and add network route getter function
  inet: Do not add broadcast address for P2P/VPNs
  dbus: Report back the return value of g_dbus_send_message()
  service: Split service move functionality for internal use
  service: Expose set_split_routing() for internal use
  service: Add property changed signal for SplitRouting value
  service: Load and apply service settings after D-Bus registration
  provider: Add support for managing SplitRouting
  vpn: Support SplitRouting in D-Bus variables, improve route code
  vpn-config: Implement function to get boolean from keyfile
  vpn-provider: Drop route management from vpnd
  vpn-provider: Support SplitRouting option from connmand
  doc: Document VPN connection SplitRouting boolean

 doc/connman-vpn.8.in       |   4 -
 doc/vpn-connection-api.txt |   9 +-
 include/inet.h             |  10 +-
 include/ipaddress.h        |   4 +
 include/provider.h         |   4 +
 plugins/dundee.c           |   2 +-
 plugins/ofono.c            |   4 +-
 plugins/vpn.c              | 228 +++++++++++--
 src/bridge.c               |   3 +-
 src/connection.c           |  23 ++
 src/connman.h              |  10 +-
 src/dbus.c                 |  24 +-
 src/inet.c                 | 642 ++++++++++++++++++++++---------------
 src/ipaddress.c            |  10 +
 src/ipconfig.c             |  42 ++-
 src/peer.c                 |   2 +-
 src/provider.c             | 101 ++++++
 src/service.c              | 113 +++++--
 src/tethering.c            |   3 +-
 vpn/main.c                 |   5 +-
 vpn/plugins/l2tp.c         |   2 +
 vpn/plugins/openconnect.c  |   2 +
 vpn/plugins/openvpn.c      |   1 +
 vpn/plugins/pptp.c         |   1 +
 vpn/plugins/vpnc.c         |   1 +
 vpn/plugins/wireguard.c    |   2 +
 vpn/vpn-config.c           |  15 +
 vpn/vpn-ipconfig.c         |   8 +-
 vpn/vpn-provider.c         | 276 +++++++++-------
 vpn/vpn-provider.h         |   3 +
 vpn/vpn.h                  |  12 +-
 31 files changed, 1096 insertions(+), 470 deletions(-)

-- 
2.20.1

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

Date: Tue,  8 Dec 2020 12:17:47 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: [PATCH 01/15] connection: Add getter for the phy index of a
        VPN transport service
To: connman@lists.01.org
Message-ID: <20201208101801.26715-2-jussi.laakko...@jolla.com>

Use same approach as in __connman_connection_get_vpn_index() to get the
exact opposite, the physical index of the transport medium used to
connect the VPN with the given index.
---
 src/connection.c | 23 +++++++++++++++++++++++
 src/connman.h    |  1 +
 2 files changed, 24 insertions(+)

diff --git a/src/connection.c b/src/connection.c
index 303e9922..9d2c6961 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -1066,6 +1066,29 @@ int __connman_connection_get_vpn_index(int phy_index)
        return -1;
 }
 
+int __connman_connection_get_vpn_phy_index(int vpn_index)
+{
+       GHashTableIter iter;
+       gpointer value, key;
+
+       g_hash_table_iter_init(&iter, gateway_hash);
+
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               struct gateway_data *data = value;
+
+               if (data->index != vpn_index)
+                       continue;
+
+               if (data->ipv4_gateway)
+                       return data->ipv4_gateway->vpn_phy_index;
+
+               if (data->ipv6_gateway)
+                       return data->ipv6_gateway->vpn_phy_index;
+       }
+
+       return -1;
+}
+
 int __connman_connection_init(void)
 {
        int err;
diff --git a/src/connman.h b/src/connman.h
index 3bdc0dc7..560ef46c 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -502,6 +502,7 @@ int __connman_connection_gateway_add(struct connman_service 
*service,
 void __connman_connection_gateway_remove(struct connman_service *service,
                                        enum connman_ipconfig_type type);
 int __connman_connection_get_vpn_index(int phy_index);
+int __connman_connection_get_vpn_phy_index(int vpn_index);
 
 bool __connman_connection_update_gateway(void);
 
-- 
2.20.1

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

Date: Tue,  8 Dec 2020 12:17:49 +0200
From: Jussi Laakkonen <jussi.laakko...@jolla.com>
Subject: [PATCH 03/15] inet: Refactor with getifaddrs() and add
        network route getter function
To: connman@lists.01.org
Message-ID: <20201208101801.26715-4-jussi.laakko...@jolla.com>

Create new internal get_interface_addresses() function that utilizes
simple structure to get the IP address, netmask, broadcast address
and/or P-t-P address using getifaddrs() in a single run. This allows to
define whether to accept unspecified addresses (checked with
is_addr_unspec()) and to require the IP address to be link local address
(checked with is_addr_ll(), in which use htonl() for the constant to get
network order for comparison).

If the set requirements for unspec/link local are not met, -ENOENT is
returned as error and all the pointers in the struct interface_address
are NULL. With invalid address family, or missing struct -EINVAL is
returned. Or the error of getifaddrs() is returned if the call fails.

When get_interface_addressses() is used directly, the pointer array in
struct interface_address must have struct in_addr* for AF_INET and
struct in6_addr* for AF_INET6 set as family. The types defined in enum
ipaddr_type are to be used as a position for the different addresses
requested.

Cleaned up a lot of existing code to have only one use of getifaddrs()
via the get_interface_addresses() by just filling in the structure with
the required parameters.

Created new functions connman_inet_get_route_addresses() and
connman_inet_ipv6_get_route_addresses() for getting the string
representation of all the required address for a route. Parameter
destination (for P-t-P) is optional.
---
 include/inet.h |   6 +
 src/inet.c     | 563 ++++++++++++++++++++++++++++---------------------
 2 files changed, 326 insertions(+), 243 deletions(-)

diff --git a/include/inet.h b/include/inet.h
index 5ac9a474..c76e487d 100644
--- a/include/inet.h
+++ b/include/inet.h
@@ -81,6 +81,12 @@ bool connman_inet_is_ipv6_supported();
 bool connman_inet_is_default_route(int family, const char *host,
                                const char *gateway, const char *netmask);
 
+int connman_inet_get_route_addresses(int index, char **network, char **netmask,
+                                                       char **destination);
+int connman_inet_ipv6_get_route_addresses(int index, char **network,
+                                                       char **netmask,
+                                                       char **destination);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/inet.c b/src/inet.c
index a537db90..8cbc3e46 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -189,13 +189,46 @@ done:
        return err;
 }
 
+static bool is_addr_unspec(int family, struct sockaddr *addr)
+{
+       struct sockaddr_in *in4;
+       struct sockaddr_in6 *in6;
+
+       switch (family) {
+       case AF_INET:
+               in4 = (struct sockaddr_in*) addr;
+               return in4->sin_addr.s_addr == INADDR_ANY;
+       case AF_INET6:
+               in6 = (struct sockaddr_in6*) addr;
+               return IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr);
+       default:
+               return false;
+       }
+}
+
+static bool is_addr_ll(int family, struct sockaddr *addr)
+{
+       struct sockaddr_in *in4;
+       struct sockaddr_in6 *in6;
+
+       switch (family) {
+       case AF_INET:
+               in4 = (struct sockaddr_in*) addr;
+               return (in4->sin_addr.s_addr & IN_CLASSB_NET) ==
+                                       ((in_addr_t) htonl(0xa9fe0000));
+       case AF_INET6:
+               in6 = (struct sockaddr_in6*) addr;
+               return IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr);
+       default:
+               return false;
+       }
+}
+
 bool __connman_inet_is_any_addr(const char *address, int family)
 {
        bool ret = false;
        struct addrinfo hints;
        struct addrinfo *result = NULL;
-       struct sockaddr_in6 *in6 = NULL;
-       struct sockaddr_in *in4 = NULL;
 
        if (!address || !*address)
                goto out;
@@ -208,14 +241,7 @@ bool __connman_inet_is_any_addr(const char *address, int 
family)
                goto out;
 
        if (result) {
-               if (result->ai_family == AF_INET6) {
-                       in6 = (struct sockaddr_in6*)result->ai_addr;
-                       ret = IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr);
-               } else if (result->ai_family == AF_INET) {
-                       in4 = (struct sockaddr_in*)result->ai_addr;
-                       ret = in4->sin_addr.s_addr == INADDR_ANY;
-               }
-
+               ret = is_addr_unspec(result->ai_family, result->ai_addr);
                freeaddrinfo(result);
        }
 
@@ -1066,54 +1092,161 @@ out:
        return err;
 }
 
-bool connman_inet_compare_subnet(int index, const char *host)
+#define ADDR_TYPE_MAX 4
+
+struct interface_address {
+       int index;
+       int family;
+       bool allow_unspec;
+        /* Applies only to ADDR_TYPE_IPADDR in ipaddrs */
+       bool require_ll;
+       /* Real types must be in_addr for AF_INET and in6_addr for AF_INET6 */
+       void *ipaddrs[ADDR_TYPE_MAX];
+};
+
+enum ipaddr_type {
+       ADDR_TYPE_IPADDR = 0,
+       ADDR_TYPE_NETMASK,
+       ADDR_TYPE_BRDADDR,
+       ADDR_TYPE_DSTADDR
+};
+
+static int get_interface_addresses(struct interface_address *if_addr)
 {
-       struct ifreq ifr;
-       struct in_addr _host_addr;
-       in_addr_t host_addr, netmask_addr, if_addr;
-       struct sockaddr_in *netmask, *addr;
-       int sk;
+       struct ifaddrs *ifaddr;
+       struct ifaddrs *ifa;
+       struct sockaddr *addrs[ADDR_TYPE_MAX] = { 0 };
+       struct sockaddr_in *addr_in;
+       struct sockaddr_in6 *addr_in6;
+       char name[IF_NAMESIZE] = { 0 };
+       size_t len;
+       int err = -ENOENT;
+       int i;
 
-       DBG("host %s", host);
+       if (!if_addr)
+               return -EINVAL;
 
-       if (!host)
-               return false;
+       if (!if_indextoname(if_addr->index, name))
+               return -EINVAL;
 
-       if (inet_aton(host, &_host_addr) == 0)
-               return false;
-       host_addr = _host_addr.s_addr;
+       DBG("index %d interface %s", if_addr->index, name);
 
-       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return false;
+       if (getifaddrs(&ifaddr) < 0) {
+               connman_error("Cannot get addresses err %d/%s", errno,
+                                                       strerror(errno));
+               return -errno;
+       }
 
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = index;
+       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_addr)
+                       continue;
 
-       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
-               close(sk);
-               return false;
+               if (g_strcmp0(ifa->ifa_name, name) ||
+                                       ifa->ifa_addr->sa_family !=
+                                               if_addr->family)
+                       continue;
+
+
+               if (if_addr->ipaddrs[ADDR_TYPE_IPADDR]) {
+                       if (!if_addr->allow_unspec && is_addr_unspec(
+                                               if_addr->family,
+                                               ifa->ifa_addr))
+                               continue;
+
+                       if (if_addr->require_ll && !is_addr_ll(if_addr->family,
+                                               ifa->ifa_addr))
+                               continue;
+
+                       addrs[ADDR_TYPE_IPADDR] = ifa->ifa_addr;
+               }
+
+               if (if_addr->ipaddrs[ADDR_TYPE_NETMASK]) {
+                       if (!if_addr->allow_unspec && is_addr_unspec(
+                                               if_addr->family,
+                                               ifa->ifa_netmask))
+                               continue;
+
+                       addrs[ADDR_TYPE_NETMASK] = ifa->ifa_netmask;
+               }
+
+               if (if_addr->ipaddrs[ADDR_TYPE_BRDADDR] &&
+                                       (ifa->ifa_flags & IFF_BROADCAST)) {
+                       if (!if_addr->allow_unspec && is_addr_unspec(
+                                               if_addr->family,
+                                               ifa->ifa_ifu.ifu_broadaddr))
+                               continue;
+
+                       addrs[ADDR_TYPE_BRDADDR] = ifa->ifa_ifu.ifu_broadaddr;
+               }
+
+               if (if_addr->ipaddrs[ADDR_TYPE_DSTADDR] &&
+                                       (ifa->ifa_flags & IFF_POINTOPOINT)) {
+                       if (!if_addr->allow_unspec && is_addr_unspec(
+                                               if_addr->family,
+                                               ifa->ifa_ifu.ifu_dstaddr))
+                               continue;
+
+                       addrs[ADDR_TYPE_DSTADDR] = ifa->ifa_ifu.ifu_dstaddr;
+               }
+
+               err = 0;
+
+               break;
        }
 
-       if (ioctl(sk, SIOCGIFNETMASK, &ifr) < 0) {
-               close(sk);
-               return false;
+       if (err)
+               goto out;
+
+       for (i = 0; i < ADDR_TYPE_MAX; i++) {
+               if (!addrs[i])
+                       continue;
+
+               switch (if_addr->family) {
+               case AF_INET:
+                       len = sizeof(struct in_addr);
+                       addr_in = (struct sockaddr_in*) addrs[i];
+                       memcpy(if_addr->ipaddrs[i], &addr_in->sin_addr, len);
+                       break;
+               case AF_INET6:
+                       len = sizeof(struct in6_addr);
+                       addr_in6 = (struct sockaddr_in6*) addrs[i];
+                       memcpy(if_addr->ipaddrs[i], &addr_in6->sin6_addr, len);
+                       break;
+               default:
+                       err = -EINVAL;
+                       break;
+               }
        }
 
-       netmask = (struct sockaddr_in *)&ifr.ifr_netmask;
-       netmask_addr = netmask->sin_addr.s_addr;
+out:
+       freeifaddrs(ifaddr);
+       return err;
+}
 
-       if (ioctl(sk, SIOCGIFADDR, &ifr) < 0) {
-               close(sk);
+bool connman_inet_compare_subnet(int index, const char *host)
+{
+       struct interface_address if_addr = { 0 };
+       struct in_addr iaddr = { 0 };
+       struct in_addr imask = { 0 };
+       struct in_addr haddr = { 0 };
+
+       DBG("host %s", host);
+
+       if (!host)
                return false;
-       }
 
-       close(sk);
+       if (inet_pton(AF_INET, host, &haddr) <= 0)
+               return false;
+
+       if_addr.index = index;
+       if_addr.family = AF_INET;
+       if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &iaddr;
+       if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &imask;
 
-       addr = (struct sockaddr_in *)&ifr.ifr_addr;
-       if_addr = addr->sin_addr.s_addr;
+       if (get_interface_addresses(&if_addr))
+               return false;
 
-       return ((if_addr & netmask_addr) == (host_addr & netmask_addr));
+       return (iaddr.s_addr & imask.s_addr) == (haddr.s_addr & imask.s_addr);
 }
 
 static bool mem_mask_equal(const void *a, const void *b,
@@ -1134,47 +1267,23 @@ static bool mem_mask_equal(const void *a, const void *b,
 
 bool connman_inet_compare_ipv6_subnet(int index, const char *host)
 {
-       struct ifaddrs *ifaddr, *ifa;
-       bool rv = false;
-       char name[IF_NAMESIZE];
-       struct in6_addr haddr;
+       struct interface_address addr = { 0 };
+       struct in6_addr iaddr = { 0 };
+       struct in6_addr imask = { 0 };
+       struct in6_addr haddr = { 0 };
 
        if (inet_pton(AF_INET6, host, &haddr) <= 0)
                return false;
 
-       if (!if_indextoname(index, name))
-               return false;
-
-       DBG("index %d interface %s", index, name);
+       addr.index = index;
+       addr.family = AF_INET6;
+       addr.ipaddrs[ADDR_TYPE_IPADDR] = &iaddr;
+       addr.ipaddrs[ADDR_TYPE_NETMASK] = &imask;
 
-       if (getifaddrs(&ifaddr) < 0) {
-               DBG("Cannot get addresses err %d/%s", errno, strerror(errno));
+       if (get_interface_addresses(&addr))
                return false;
-       }
 
-       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
-               struct sockaddr_in6 *iaddr;
-               struct sockaddr_in6 *imask;
-
-               if (!ifa->ifa_addr)
-                       continue;
-
-               if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) != 0 ||
-                                       ifa->ifa_addr->sa_family != AF_INET6)
-                       continue;
-
-               iaddr = (struct sockaddr_in6 *)ifa->ifa_addr;
-               imask = (struct sockaddr_in6 *)ifa->ifa_netmask;
-
-               rv = mem_mask_equal(&iaddr->sin6_addr, &haddr,
-                                       &imask->sin6_addr,
-                                       sizeof(haddr));
-               goto out;
-       }
-
-out:
-       freeifaddrs(ifaddr);
-       return rv;
+       return mem_mask_equal(&iaddr, &haddr, &imask, sizeof(haddr));
 }
 
 int connman_inet_remove_from_bridge(int index, const char *bridge)
@@ -2147,98 +2256,156 @@ GSList *__connman_inet_ipv6_get_prefixes(struct 
nd_router_advert *hdr,
        return prefixes;
 }
 
-static int get_dest_addr(int family, int index, char *buf, int len)
+int connman_inet_get_dest_addr(int index, char **dest)
 {
-       struct ifreq ifr;
-       void *addr;
-       int sk;
+       struct interface_address if_addr = { 0 };
+       struct in_addr dstaddr = { 0 };
+       char buf[INET_ADDRSTRLEN] = { 0 };
+       int err;
 
-       sk = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-       if (sk < 0)
-               return -errno;
+       if (!dest)
+               return -EINVAL;
 
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_ifindex = index;
+       if_addr.index = index;
+       if_addr.family = AF_INET;
+       if_addr.allow_unspec = true;
+       if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dstaddr;
 
-       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
-               DBG("SIOCGIFNAME (%d/%s)", errno, strerror(errno));
-               close(sk);
-               return -errno;
-       }
+       err = get_interface_addresses(&if_addr);
+       if (err)
+               return err;
 
-       if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
-               DBG("SIOCGIFFLAGS (%d/%s)", errno, strerror(errno));
-               close(sk);
-               return -errno;
-       }
+       if (inet_ntop(AF_INET, &dstaddr, buf, INET_ADDRSTRLEN))
+               *dest = g_strdup(buf);
 
-       if ((ifr.ifr_flags & IFF_POINTOPOINT) == 0) {
-               close(sk);
-               errno = EINVAL;
-               return -errno;
-       }
+       DBG("destination %s", *dest);
 
-       DBG("index %d %s", index, ifr.ifr_name);
+       return *dest && **dest ? 0 : -ENOENT;
+}
 
-       if (ioctl(sk, SIOCGIFDSTADDR, &ifr) < 0) {
-               connman_error("Get destination address failed (%s)",
-                                                       strerror(errno));
-               close(sk);
-               return -errno;
-       }
+int connman_inet_ipv6_get_dest_addr(int index, char **dest)
+{
+       struct interface_address if_addr = { 0 };
+       struct in_addr dstaddr = { 0 };
+       char buf[INET6_ADDRSTRLEN] = { 0 };
+       int err;
 
-       close(sk);
+       if (!dest)
+               return -EINVAL;
 
-       switch (family) {
-       case AF_INET:
-               addr = &((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr;
-               break;
-       case AF_INET6:
-               addr = &((struct sockaddr_in6 *)&ifr.ifr_dstaddr)->sin6_addr;
-               break;
-       default:
-               errno = EINVAL;
-               return -errno;
-       }
+       if_addr.index = index;
+       if_addr.family = AF_INET6;
+       if_addr.allow_unspec = true;
+       if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dstaddr;
 
-       if (!inet_ntop(family, addr, buf, len)) {
-               DBG("error %d/%s", errno, strerror(errno));
-               return -errno;
-       }
+       err = get_interface_addresses(&if_addr);
+       if (err)
+               return err;
 
-       return 0;
+       if (inet_ntop(AF_INET6, &dstaddr, buf, INET6_ADDRSTRLEN))
+               *dest = g_strdup(buf);
+
+       DBG("destination %s", *dest);
+
+       return *dest && **dest ? 0 : -ENOENT;
 }
 
-int connman_inet_get_dest_addr(int index, char **dest)
+/* destination is optional */
+int connman_inet_get_route_addresses(int index, char **network, char **netmask,
+                                                       char **destination)
 {
-       char addr[INET_ADDRSTRLEN];
-       int ret;
+       struct interface_address if_addr = { 0 };
+       struct in_addr addr = { 0 };
+       struct in_addr mask = { 0 };
+       struct in_addr dest = { 0 };
+       struct in_addr nw_addr = { 0 };
+       char buf[INET_ADDRSTRLEN] = { 0 };
+       int err;
 
-       ret = get_dest_addr(PF_INET, index, addr, INET_ADDRSTRLEN);
-       if (ret < 0)
-               return ret;
+       if (!network || !netmask)
+               return -EINVAL;
 
-       *dest = g_strdup(addr);
+       if_addr.index = index;
+       if_addr.family = AF_INET;
+       if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &addr;
+       if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &mask;
+       if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dest;
 
-       DBG("destination %s", *dest);
+       err = get_interface_addresses(&if_addr);
+       if (err)
+               return err;
 
-       return 0;
+       nw_addr.s_addr = (addr.s_addr & mask.s_addr);
+
+       if (inet_ntop(AF_INET, &nw_addr, buf, INET_ADDRSTRLEN))
+               *network = g_strdup(buf);
+
+       memset(&buf, 0, INET_ADDRSTRLEN);
+
+       if (inet_ntop(AF_INET, &mask, buf, INET_ADDRSTRLEN))
+               *netmask = g_strdup(buf);
+
+       if (destination) {
+               memset(&buf, 0, INET_ADDRSTRLEN);
+
+               if (inet_ntop(AF_INET, &dest, buf, INET_ADDRSTRLEN))
+                       *destination = g_strdup(buf);
+       }
+
+       DBG("network %s netmask %s destination %s", *network, *netmask,
+                               destination ? *destination : NULL);
+
+       return *network && **network && *netmask && **netmask ? 0 : -ENOENT;
 }
 
-int connman_inet_ipv6_get_dest_addr(int index, char **dest)
+int connman_inet_ipv6_get_route_addresses(int index, char **network,
+                                       char **netmask, char **destination)
 {
-       char addr[INET6_ADDRSTRLEN];
-       int ret;
+       struct interface_address if_addr = { 0 };
+       struct in6_addr addr = { 0 };
+       struct in6_addr mask = { 0 };
+       struct in6_addr dest = { 0 };
+       struct in6_addr nw_addr  = { 0 };
+       char buf[INET6_ADDRSTRLEN] = { 0 };
+       int err;
 
-       ret = get_dest_addr(PF_INET6, index, addr, INET6_ADDRSTRLEN);
-       if (ret < 0)
-               return ret;
+       if (!network)
+               return -EINVAL;
 
-       *dest = g_strdup(addr);
+       if_addr.index = index;
+       if_addr.family = AF_INET6;
+       if_addr.ipaddrs[ADDR_TYPE_IPADDR] = &addr;
+       if_addr.ipaddrs[ADDR_TYPE_NETMASK] = &mask;
+       if_addr.ipaddrs[ADDR_TYPE_DSTADDR] = &dest;
 
-       DBG("destination %s", *dest);
+       err = get_interface_addresses(&if_addr);
+       if (err)
+               return err;
 
-       return 0;
+       ipv6_addr_set(&nw_addr, addr.s6_addr32[0] & mask.s6_addr32[0],
+                               addr.s6_addr32[1] & mask.s6_addr32[1],
+                               addr.s6_addr32[2] & mask.s6_addr32[2],
+                               addr.s6_addr32[3] & mask.s6_addr32[3]);
+
+       if (inet_ntop(AF_INET6, &nw_addr, buf, INET6_ADDRSTRLEN))
+               *network = g_strdup(buf);
+
+       memset(&buf, 0, INET6_ADDRSTRLEN);
+
+       if (inet_ntop(AF_INET6, &mask, buf, INET6_ADDRSTRLEN))
+               *netmask = g_strdup(buf);
+
+       if (destination) {
+               memset(&buf, 0, INET6_ADDRSTRLEN);
+
+               if (inet_ntop(AF_INET6, &dest, buf, INET6_ADDRSTRLEN))
+                       *destination = g_strdup(buf);
+       }
+
+       DBG("network %s netmask %s destination %s", *network, *netmask,
+                               destination ? *destination : NULL);
+
+       return *network && **network && *netmask && **netmask ? 0 : -ENOENT;
 }
 
 int __connman_inet_rtnl_open(struct __connman_inet_rtnl_handle *rth)
@@ -2852,56 +3019,13 @@ bool connman_inet_is_default_route(int family, const 
char *host,
 
 int __connman_inet_get_interface_address(int index, int family, void *address)
 {
-       struct ifaddrs *ifaddr, *ifa;
-       int err = -ENOENT;
-       char name[IF_NAMESIZE];
-
-       if (!if_indextoname(index, name))
-               return -EINVAL;
-
-       DBG("index %d interface %s", index, name);
-
-       if (getifaddrs(&ifaddr) < 0) {
-               err = -errno;
-               DBG("Cannot get addresses err %d/%s", err, strerror(-err));
-               return err;
-       }
+       struct interface_address if_addr = { 0 };
 
-       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
-               if (!ifa->ifa_addr)
-                       continue;
+       if_addr.index = index;
+       if_addr.family = family;
+       if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address;
 
-               if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 &&
-                                       ifa->ifa_addr->sa_family == family) {
-                       if (family == AF_INET) {
-                               struct sockaddr_in *in4 = (struct sockaddr_in *)
-                                       ifa->ifa_addr;
-                               if (in4->sin_addr.s_addr == INADDR_ANY)
-                                       continue;
-                               memcpy(address, &in4->sin_addr,
-                                                       sizeof(struct in_addr));
-                       } else if (family == AF_INET6) {
-                               struct sockaddr_in6 *in6 =
-                                       (struct sockaddr_in6 *)ifa->ifa_addr;
-                               if (memcmp(&in6->sin6_addr, &in6addr_any,
-                                               sizeof(struct in6_addr)) == 0)
-                                       continue;
-                               memcpy(address, &in6->sin6_addr,
-                                               sizeof(struct in6_addr));
-
-                       } else {
-                               err = -EINVAL;
-                               goto out;
-                       }
-
-                       err = 0;
-                       break;
-               }
-       }
-
-out:
-       freeifaddrs(ifaddr);
-       return err;
+       return get_interface_addresses(&if_addr);
 }
 
 int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address)
@@ -3110,61 +3234,14 @@ int __connman_inet_del_subnet_from_table(uint32_t 
table_id, int ifindex,
 int __connman_inet_get_interface_ll_address(int index, int family,
                                                                void *address)
 {
-       struct ifaddrs *ifaddr, *ifa;
-       int err = -ENOENT;
-       char name[IF_NAMESIZE];
-
-       if (!if_indextoname(index, name))
-               return -EINVAL;
+       struct interface_address if_addr = { 0 };
 
-       DBG("index %d interface %s", index, name);
+       if_addr.index = index;
+       if_addr.family = family;
+       if_addr.require_ll = true;
+       if_addr.ipaddrs[ADDR_TYPE_IPADDR] = address;
 
-       if (getifaddrs(&ifaddr) < 0) {
-               err = -errno;
-               DBG("Cannot get addresses err %d/%s", err, strerror(-err));
-               return err;
-       }
-
-       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
-               if (!ifa->ifa_addr)
-                       continue;
-
-               if (strncmp(ifa->ifa_name, name, IF_NAMESIZE) == 0 &&
-                                       ifa->ifa_addr->sa_family == family) {
-                       if (family == AF_INET) {
-                               struct sockaddr_in *in4 = (struct sockaddr_in *)
-                                       ifa->ifa_addr;
-                               if (in4->sin_addr.s_addr == INADDR_ANY)
-                                       continue;
-                               if ((in4->sin_addr.s_addr & IN_CLASSB_NET) !=
-                                               ((in_addr_t) 0xa9fe0000))
-                                       continue;
-                               memcpy(address, &in4->sin_addr,
-                                                       sizeof(struct in_addr));
-                       } else if (family == AF_INET6) {
-                               struct sockaddr_in6 *in6 =
-                                       (struct sockaddr_in6 *)ifa->ifa_addr;
-                               if (memcmp(&in6->sin6_addr, &in6addr_any,
-                                               sizeof(struct in6_addr)) == 0)
-                                       continue;
-                               if (!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
-                                       continue;
-
-                               memcpy(address, &in6->sin6_addr,
-                                               sizeof(struct in6_addr));
-                       } else {
-                               err = -EINVAL;
-                               goto out;
-                       }
-
-                       err = 0;
-                       break;
-               }
-       }
-
-out:
-       freeifaddrs(ifaddr);
-       return err;
+       return get_interface_addresses(&if_addr);
 }
 
 int __connman_inet_get_address_netmask(int ifindex,
-- 
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 62, Issue 8
**************************************

Reply via email to