Send connman mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        https://lists.01.org/mailman/listinfo/connman
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

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


Today's Topics:

   1. Re: Online check fails for working Internet connection
      (Daniel Wagner)
   2. Re: [PATCH] rootnfs: Working rootnfs using connman (Daniel Wagner)
   3. [PATCH] rootnfs: Working rootnfs using connman (Pantelis Antoniou)


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

Message: 1
Date: Wed, 30 Nov 2016 19:46:47 +0100
From: Daniel Wagner <[email protected]>
To: Robert Tiemann <[email protected]>, [email protected]
Subject: Re: Online check fails for working Internet connection
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252

Hi,

On 11/30/2016 10:22 AM, Robert Tiemann wrote:
> I've run into a situation in which ConnMan's online check often fails
> due to a temporary HTTP 404 error. ConnMan remains in ready state and
> never repeats the online check. The connection, however, is actually
> correctly set up and works.
> 
> As I've found out, the 404 error is actually a DNS timeout that is
> reported as 404 by resolv_result(). It happens right after
> establishing a WLAN connection to a slow access point using manual
> IPv4 configuration (no DHCP involved here). Successive DNS queries are
> answered more or less immediately, it's just the first one that is
> always slow, often taking longer than the timeout of 5 seconds. Even
> worse: sometimes the first DNS query is simply dropped by that
> particular access point, so there will never be an answer, no matter
> how long the timeout would be set.
> 
> While I think this problem is clearly caused by the access point and
> ConnMan is not to blame here, repeating the online check would help a
> lot. After all, the connection works well after the initial hiccups. I
> can also dream up dozens of different scenarios that would lead to
> similar temporary failure, and repeating the online check after
> failure would fix these scenarios as well.
> 
> Note that there seems to be no way to fix this situation from external
> applications as there is no way to request to restart the online
> check. It is only possible to disconnect from the service and connect
> again, but it doesn't help here because the DNS timeout problem
> potentially occurs again on each connect.
> 
> Is there a reason to avoid repeating the online check after failure?
> Are there any plans for improving the online check?

My memory is a bit foggy here. IIRC we fixed something similiar with 
IPv4LL and DHCP retries. So in case we fall back to IPv4LL we keep
trying DHCP. So I guess doing the same for online check make sense. 
I can't remember if there was any disagreement why this should be done. 

Anyway, just peeked at the code and there is some retry logic
for IPv6 there:


static gboolean redo_wispr(gpointer user_data)
{
        struct connman_service *service = user_data;
        int refcount = service->refcount - 1;

        connman_service_unref(service);
        if (refcount == 0) {
                DBG("Service %p already removed", service);
                return FALSE;
        }

        __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);

        return FALSE;
}

int __connman_service_online_check_failed(struct connman_service *service,
                                        enum connman_ipconfig_type type)
{
        DBG("service %p type %d count %d", service, type,
                                                service->online_check_count);

        /* currently we only retry IPv6 stuff */
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
                        service->online_check_count != 1) {
                connman_warn("Online check failed for %p %s", service,
                        service->name);
                return 0;
        }

        service->online_check_count = 0;

        /*
         * We set the timeout to 1 sec so that we have a chance to get
         * necessary IPv6 router advertisement messages that might have
         * DNS data etc.
         */
        g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));

        return EAGAIN;
}


So there already some magic involved. A simple approach like in the IPv6
case is to keep rearming the timer (with a backoff) and retry IPv4.

Thoughts?

cheers,
daniel


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

Message: 2
Date: Wed, 30 Nov 2016 19:51:05 +0100
From: Daniel Wagner <[email protected]>
To: Pantelis Antoniou <[email protected]>
Cc: [email protected], Koen Kooi <[email protected]>, Stephane
        Desneux <[email protected]>
Subject: Re: [PATCH] rootnfs: Working rootnfs using connman
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252; format=flowed

On 11/30/2016 07:40 PM, Pantelis Antoniou wrote:
>> Indention looks wrong? There are some more occurrences below. I
>> don't  want to repeat for each line. So just make sure the whitespace
 >> stuff is okay.
>>
>
> Going over fixing this, I see that the file is full of the same
 > indentation problem. That?s why I picked it up on a copy/paste session.

I see, we screwed that up :) If we really get bored we might fixed that 
but I try to avoid unnecessary code churns.

Thanks,
Daniel


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

Message: 3
Date: Wed, 30 Nov 2016 20:59:34 +0200
From: Pantelis Antoniou <[email protected]>
To: [email protected]
Cc: Marcel Holtmann <[email protected]>, Jukka Rissanen
        <[email protected]>, Stephane Desneux
        <[email protected]>, Koen Kooi <[email protected]>, Pantelis
        Antoniou <[email protected]>
Subject: [PATCH] rootnfs: Working rootnfs using connman
Message-ID:
        <[email protected]>

Until now for root NFS you either had to manually blacklist
the interface or disable connman all together

This patch automatically blacklists the interface the NFS server
is reachable from and populates the resolver entries that the
DHCP server provided on startup.

It is now possible to use a vanilla rootfs tarball without
having to manually edit connman configuration entries.
---
 src/connman.h  |   3 +
 src/device.c   |   5 +
 src/inet.c     | 294 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/resolver.c |   8 ++
 4 files changed, 310 insertions(+)

diff --git a/src/connman.h b/src/connman.h
index ce3ef8d..f85d243 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -244,6 +244,9 @@ int __connman_inet_del_default_from_table(uint32_t 
table_id, int ifindex, const
 int __connman_inet_get_address_netmask(int ifindex,
                struct sockaddr_in *address, struct sockaddr_in *netmask);
 
+bool __connman_inet_isrootnfs_device(const char *devname);
+char **__connman_inet_get_pnp_nameservers(const char *pnp_file);
+
 #include <connman/resolver.h>
 
 int __connman_resolver_init(gboolean dnsproxy);
diff --git a/src/device.c b/src/device.c
index 742b3c4..2e1a3cd 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1321,6 +1321,11 @@ nodevice:
        }
 
 list:
+       if (__connman_inet_isrootnfs_device(devname)) {
+               DBG("ignoring device %s (rootnfs)", devname);
+               return true;
+       }
+
        blacklisted_interfaces =
                connman_setting_get_string_list("NetworkInterfaceBlacklist");
        if (!blacklisted_interfaces)
diff --git a/src/inet.c b/src/inet.c
index 803f0e6..0f2151c 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -2964,3 +2964,297 @@ out:
        close(sk);
        return ret;
 }
+
+static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
+                               struct in_addr *addr)
+{
+       char *s, *nfsargs;
+       int len;
+       char addrstr[INET_ADDRSTRLEN];
+       struct in_addr taddr;
+       GError *error = NULL;
+       char *cmdline = NULL;
+       char *pnp = NULL;
+       char **args = NULL;
+       char **pnpent = NULL;
+       char **pp = NULL;
+       int err = -1;
+
+       if (!cmdline_file)
+               cmdline_file = "/proc/cmdline";
+       if (!pnp_file)
+               pnp_file = "/proc/net/pnp";
+       if (!addr)
+               addr = &taddr;
+       addr->s_addr = INADDR_NONE;
+
+       if (!g_file_get_contents(cmdline_file, &cmdline, NULL, &error)) {
+               connman_error("%s: Cannot read %s %s\n", __func__,
+                               cmdline_file, error->message);
+               goto out;
+       }
+
+       if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+               connman_error("%s: Cannot read %s %s\n", __func__,
+                               pnp_file, error->message);
+               goto out;
+       }
+
+       len = strlen(cmdline);
+       if (len <= 1) {
+               /* too short */
+               goto out;
+       }
+       /* remove newline */
+       if (cmdline[len - 1] == '\n')
+               cmdline[--len] = '\0';
+
+       /* split in arguments (seperated by space) */
+       args = g_strsplit(cmdline, " ", 0);
+       if (!args) {
+               connman_error("%s: Cannot split cmdline \"%s\"\n", __func__,
+                               cmdline);
+               goto out;
+       }
+
+       /* split in entries (by newlines) */
+       pnpent = g_strsplit(pnp, "\n", 0);
+       if (!pnpent) {
+               connman_error("%s: Cannot split pnp at file \"%s\"\n", __func__,
+                               pnp_file);
+               goto out;
+       }
+
+       /* first find root argument */
+       for (pp = args; *pp; pp++) {
+               if (!strcmp(*pp, "root=/dev/nfs"))
+                       break;
+       }
+       /* no rootnfs found */
+       if (!*pp)
+               goto out;
+
+       /* locate nfsroot argument */
+       for (pp = args; *pp; pp++) {
+               if (!strncmp(*pp, "nfsroot=", strlen("nfsroot=")))
+                       break;
+       }
+       /* no nfsroot argument found */
+       if (!*pp)
+               goto out;
+
+       /* determine if nfsroot server is provided */
+       nfsargs = strchr(*pp, '=');
+       if (!nfsargs)
+               goto out;
+       nfsargs++;
+
+       /* find whether serverip is present */
+       s = strchr(nfsargs, ':');
+       if (s) {
+               len = s - nfsargs;
+               s = nfsargs;
+       } else {
+               /* no serverip, use bootserver */
+               for (pp = pnpent; *pp; pp++) {
+                       if (!strncmp(*pp, "bootserver ", strlen("bootserver ")))
+                               break;
+               }
+               /* no bootserver found */
+               if (!*pp)
+                       goto out;
+               s = *pp + strlen("bootserver ");
+               len = strlen(s);
+       }
+
+       /* copy to addr string buffer */
+       if (len >= sizeof(addrstr)) {
+               connman_error("%s: Bad server\n", __func__);
+               goto out;
+       }
+       memcpy(addrstr, s, len);
+       addrstr[len] = '\0';
+
+       err = inet_pton(AF_INET, addrstr, addr);
+       if (err <= 0) {
+               connman_error("%s: Cannot convert to numeric addr \"%s\"\n",
+                               __func__, addrstr);
+               err = -1;
+               goto out;
+       }
+
+       /* all done */
+       err = 0;
+out:
+       g_strfreev(pnpent);
+       g_strfreev(args);
+       if (error)
+               g_error_free(error);
+       g_free(pnp);
+       g_free(cmdline);
+
+       return err;
+}
+
+/* get interface out of which peer is reachable (IPv4 only) */
+static int get_peer_iface(struct in_addr *addr, char *ifname)
+{
+       struct ifaddrs *ifaddr, *ifa;
+       struct sockaddr_in saddr, *ifsaddr;
+       socklen_t socklen;
+       int s;
+       int err = -1;
+
+       /* Obtain address(es) matching host/port */
+       err = getifaddrs(&ifaddr);
+       if (err < 0) {
+               connman_error("%s: getifaddrs() failed %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               return -1;
+       }
+
+       s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       if (s < 0) {
+               connman_error("%s: socket() failed %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               return -1;
+       }
+
+       memset(&saddr, 0, sizeof(saddr));
+       saddr.sin_family = AF_INET;
+       saddr.sin_port = 0;     /* any port */
+       saddr.sin_addr = *addr;
+
+       /* no need to bind, connect will select iface */
+       err = connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
+       if (err < 0) {
+               connman_error("%s: connect() failed: %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               goto out;
+       }
+
+       socklen = sizeof(saddr);
+       err = getsockname(s, (struct sockaddr *)&saddr, &socklen);
+       if (err < 0) {
+               connman_error("%s: getsockname() failed: %d (%s)\n",
+                               __func__, errno, strerror(errno));
+               goto out;
+       }
+
+       err = -1;
+       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_addr)
+                       continue;
+
+               /* only IPv4 address */
+               if (ifa->ifa_addr->sa_family != AF_INET)
+                       continue;
+
+               ifsaddr = (struct sockaddr_in *)ifa->ifa_addr;
+
+               /* match address? */
+               if (ifsaddr->sin_addr.s_addr == saddr.sin_addr.s_addr)
+                       break;
+       }
+
+       if (ifa) {
+               err = 0;
+               if (ifname)
+                       strcpy(ifname, ifa->ifa_name);
+       }
+
+out:
+       close(s);
+
+       freeifaddrs(ifaddr);
+
+       return err;
+}
+
+bool __connman_inet_isrootnfs_device(const char *devname)
+{
+       struct in_addr addr;
+       char ifname[IFNAMSIZ];
+
+       return get_nfs_server_ip(NULL, NULL, &addr) == 0 &&
+              get_peer_iface(&addr, ifname) == 0 &&
+              strcmp(devname, ifname) == 0;
+}
+
+char **__connman_inet_get_pnp_nameservers(const char *pnp_file)
+{
+       char **pp;
+       char *s;
+       int pass, count;
+       GError *error = NULL;
+       char *pnp = NULL;
+       char **pnpent = NULL;
+       char **nameservers = NULL;
+
+       if (!pnp_file)
+               pnp_file = "/proc/net/pnp";
+
+       if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+               connman_error("%s: Cannot read %s %s\n", __func__,
+                               pnp_file, error->message);
+               goto out;
+       }
+
+       /* split in entries (by newlines) */
+       pnpent = g_strsplit(pnp, "\n", 0);
+       if (!pnpent) {
+               connman_error("%s: Cannot split pnp \"%s\"\n", __func__,
+                               pnp_file);
+               goto out;
+       }
+
+       /*
+        * Perform two passes to retreive a char ** array of
+        * nameservers that are not 0.0.0.0
+        *
+        * The first pass counts them, the second fills in the
+        * array.
+        */
+       count = 0;
+       nameservers = NULL;
+       for (pass = 1; pass <= 2; pass++) {
+
+               /* at the start of the second pass allocate */
+               if (pass == 2)
+                       nameservers = g_new(char *, count + 1);
+
+               count = 0;
+               for (pp = pnpent; *pp; pp++) {
+                       /* match 'nameserver ' at the start of each line */
+                       if (strncmp(*pp, "nameserver ", strlen("nameserver ")))
+                               continue;
+
+                       /* compare it against 0.0.0.0 */
+                       s = *pp + strlen("nameserver ");
+                       if (!strcmp(s, "0.0.0.0"))
+                               continue;
+
+                       /* on second pass fill in array */
+                       if (pass == 2)
+                               nameservers[count] = g_strdup(s);
+                       count++;
+               }
+
+               /* no nameservers? */
+               if (count == 0)
+                       goto out;
+
+               /* and terminate char ** array with NULL */
+               if (pass == 2)
+                       nameservers[count] = NULL;
+
+       }
+
+out:
+       g_strfreev(pnpent);
+       g_free(pnp);
+       if (error)
+               g_error_free(error);
+
+       return nameservers;
+}
diff --git a/src/resolver.c b/src/resolver.c
index c4adbc6..75ea5ba 100644
--- a/src/resolver.c
+++ b/src/resolver.c
@@ -659,6 +659,14 @@ int __connman_resolver_init(gboolean dnsproxy)
 
        DBG("dnsproxy %d", dnsproxy);
 
+       /* get autoip nameservers */
+       ns = __connman_inet_get_pnp_nameservers(NULL);
+       for (i = 0; ns && ns[i]; i += 1) {
+               DBG("pnp server %s", ns[i]);
+               append_resolver(i, NULL, ns[i], 86400, 0);
+       }
+       g_strfreev(ns);
+
        if (!dnsproxy)
                return 0;
 
-- 
2.1.4



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

Subject: Digest Footer

_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman


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

End of connman Digest, Vol 13, Issue 36
***************************************

Reply via email to