Connman v1.33 with systemd v230 : experiencing delay in IP assignment
by Shrikant Bobade
Hi,
I am using connman v1.33 along with systemd v230 for yocto based project.
Experiencing delay in IP assignment ranging from 20 sec. to 1.5 min.
While used earlier versions previously didn't faced such delays. So by the
time I am finding the exact change in version causing this delay issue.
Just want to check anyone experiencing such delays in IP assignments.
Any suggestions or pointers will be a great help.
Thanks
Shrikant
4 years, 2 months
[PATCH] service: Block wifi autoconnection when hidden connection is in progress
by Saurav Babu
In the following scenario:
1. Device is connected to AP in non hidden mode.
2. Connection is initated to AP in hidden mode.
connman disconnects old service and tries to connect to new service. But
for connecting hidden service it first scans the hidden AP and when
network is added for hidden AP then connection is tried. In the meantime
normal AP got disconnected and was tried to autoconnect even before
hidden AP was scanned successfully.
Ideally non hidden AP should not be autoconnected when hidden AP connection
is in progress.
This patch blocks wifi autoconnection when hidden connection is in
progress and unblocks autoconnection after hidden connection is started
or hidden wifi scan is completed and hidden AP is not found in the scan list.
---
src/connman.h | 2 ++
src/network.c | 4 ++++
src/service.c | 13 ++++++++++++-
3 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/connman.h b/src/connman.h
index ce3ef8d..24461b1 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -796,6 +796,8 @@ void __connman_service_notify(struct connman_service *service,
int __connman_service_counter_register(const char *counter);
void __connman_service_counter_unregister(const char *counter);
+void __connman_set_wifi_autoconnect(bool autoconnect);
+
#include <connman/peer.h>
int __connman_peer_init(void);
diff --git a/src/network.c b/src/network.c
index 2e423bc..eccb2ef 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1370,6 +1370,8 @@ void connman_network_clear_hidden(void *user_data)
DBG("user_data %p", user_data);
+ __connman_set_wifi_autoconnect(true);
+
/*
* Hidden service does not have a connect timeout so
* we do not need to remove it. We can just return
@@ -1389,6 +1391,8 @@ int connman_network_connect_hidden(struct connman_network *network,
DBG("network %p service %p user_data %p", network, service, user_data);
+ __connman_set_wifi_autoconnect(true);
+
if (!service)
return -EINVAL;
diff --git a/src/service.c b/src/service.c
index f6a76f6..5fdff4b 100644
--- a/src/service.c
+++ b/src/service.c
@@ -48,6 +48,7 @@ static unsigned int autoconnect_timeout = 0;
static unsigned int vpn_autoconnect_timeout = 0;
static struct connman_service *current_default = NULL;
static bool services_dirty = false;
+static bool wifi_autoconnect = true;
struct connman_stats {
bool valid;
@@ -3764,6 +3765,9 @@ static bool auto_connect_service(GList *services,
ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
+ if (!wifi_autoconnect)
+ ignore[CONNMAN_SERVICE_TYPE_WIFI] = true;
+
for (list = services; list; list = list->next) {
service = list->data;
@@ -5921,12 +5925,19 @@ static void prepare_8021x(struct connman_service *service)
service->phase2);
}
+void __connman_set_wifi_autoconnect(bool autoconnect)
+{
+ wifi_autoconnect = autoconnect;
+}
+
static int service_connect(struct connman_service *service)
{
int err;
- if (service->hidden)
+ if (service->hidden) {
+ wifi_autoconnect = false;
return -EPERM;
+ }
switch (service->type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
--
1.9.1
4 years, 3 months
Using connman with multiple active interfaces
by Lukasz Nowak
Hi,
We are building a system which has 4 network interfaces: ethernet (private), ethernet (public), wifi, cellular.
We need to keep multiple of them (ideally all, if available) on-line, and allow the applications to select which one they want to use on a per-socket basis. This includes access to internet, so we would need a default route established on every interface.
Also, there will be a management application, which will select the preferred interface, which should be used by all other "normal" applications.
As far as I can see, there are two potential options to do that:
1. Add multiple default routes to the main routing table, with different metrics. In that case to select an interface an application should call setsockopt(SO_BINDTODEVICE). Example: ping -I eth1
2. Create multiple routing tables with iproute2, and rules filtering based on source address. Application uses bind(adapter ip address) before connect(). Example: ping -I 10.20.30.40
Our primary use case is Mosquitto, an MQTT client. It only currently implements option 2, although option 1 could be ported into it easily enough.
As far as I can see, currently, neither option is implemented in Connman. There is only one on-line interface at a time.
The session API, and per-application routing, seems to be the closest thing, but it still does not allow the application to freely chose which interface it wants to use.
There was a discussion here, in March, about something very similar to what we are trying to do:
https://lists.01.org/pipermail/connman/2016-March/000532.html
https://endocode.com/blog/2016/03/22/multipathtcp-support-for-connman/
https://github.com/endocode/connman
Is that something that can be integrated into Connman?
Alternatively, is there any other way of achieving our requirement of keeping multiple on-line interfaces at the same time with Connman?
We have some development time allocated to this feature, so we could work on providing it upstream, if it could be accepted in one form or another.
Thanks for help with this.
Kind Regards,
Lukasz Nowak
4 years, 4 months
Online check fails for working Internet connection
by Robert Tiemann
Hi,
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?
Best regards,
Robert Tiemann
4 years, 4 months
Re: Tethering - using different subnets
by Usman S
Hi Daniel,
Thanks for the response!! I was using v1.25 and the patch has been
integrated in v1.31 and I will update to a newer version. As mentioned
in the patch, the same block will be only offered if it was not
allocated for any other device. Should we think of a way where we
maintain the offered blocks for a particular device so that next time
the same is offered or more freedom to the application in choosing its
subnet?
Best Regards,
Usman
On 28 November 2016 at 21:00, <connman-request(a)lists.01.org> wrote:
> Send connman mailing list submissions to
> connman(a)lists.01.org
>
> 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
> connman-request(a)lists.01.org
>
> You can reach the person managing the list at
> connman-owner(a)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. Re: Tethering - using different subnets (Daniel Wagner)
>
>
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Mon, 28 Nov 2016 08:33:43 +0100
> From: Daniel Wagner <wagi(a)monom.org>
> To: Usman S <usmanabu314(a)gmail.com>
> Cc: connman(a)lists.01.org
> Subject: Re: Tethering - using different subnets
> Message-ID: <e03fa9f2-8b29-1ef8-c4da-35babe706afd(a)monom.org>
> Content-Type: text/plain; charset=windows-1252; format=flowed
>
> Hi,
>
> On 11/26/2016 10:44 PM, Usman S wrote:
>> Could you please help me understand the below behavior from ConnMan.
>> Why does connman uses a different subnet for its DHCP sever whenever
>> tethering is disabled and enabled back again. Isnt that it extends the
>> DHCP handshake for the remembered device? Maybe a dbus API for the
>> clients to decide on the subnet for their operation?
>
> This should be addressed by 09963fa93f0b ("ippool: Try to assign the
> same subnet while tethering"). Which version of ConnMan are you using?
>
> cheers,
> daniel
>
>
> ------------------------------
>
> Subject: Digest Footer
>
> _______________________________________________
> connman mailing list
> connman(a)lists.01.org
> https://lists.01.org/mailman/listinfo/connman
>
>
> ------------------------------
>
> End of connman Digest, Vol 13, Issue 32
> ***************************************
4 years, 4 months
[PATCH 0/2] DHCPv6 infinite expiry times
by Patrik Flykt
Hi,
This patch set is heavily influenced by the patch set from
wangfe(a)nestlabs.com. The difference is that T1, T2 and expiry
timeouts are all set to 0xffffffff (infinite) when the expiry
time is infinite. With this it is believed any further changes
will be much smaller, as the code already checks for T1 and
T2 being unequal to 0xffffffff.
Wang Feng, does this work with your setup?
Cheers,
Patrik
Patrik Flykt (2):
dhcpv6: Return -EISCONN when the expiry time is inifinite
gdhcp: Set T1 and T2 to infinite if expiry time is infinite
gdhcp/client.c | 9 ++++++---
src/dhcpv6.c | 5 +++++
2 files changed, 11 insertions(+), 3 deletions(-)
--
2.8.1
4 years, 4 months
[PATCH] rootnfs: Working rootnfs using connman
by Pantelis Antoniou
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
4 years, 4 months
[PATCH] rootnfs: Working rootnfs using connman
by Pantelis Antoniou
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.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou(a)konsulko.com>
---
src/connman.h | 3 +
src/device.c | 8 +-
src/inet.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/resolver.c | 8 ++
4 files changed, 299 insertions(+), 1 deletion(-)
diff --git a/src/connman.h b/src/connman.h
index ce3ef8d..1a76dc2 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);
+gchar **__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..3bcf5ab 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1324,7 +1324,7 @@ list:
blacklisted_interfaces =
connman_setting_get_string_list("NetworkInterfaceBlacklist");
if (!blacklisted_interfaces)
- return false;
+ goto rootnfs;
for (pattern = blacklisted_interfaces; *pattern; pattern++) {
if (g_str_has_prefix(devname, *pattern)) {
@@ -1333,6 +1333,12 @@ list:
}
}
+rootnfs:
+ if (__connman_inet_isrootnfs_device(devname)) {
+ DBG("ignoring device %s (rootnfs)", devname);
+ return true;
+ }
+
return false;
}
diff --git a/src/inet.c b/src/inet.c
index 803f0e6..6733bfa 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -2964,3 +2964,284 @@ out:
close(sk);
return ret;
}
+
+static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
+ struct in_addr *addr)
+{
+ GError *error = NULL;
+ gchar *cmdline = NULL;
+ gchar *pnp = NULL;
+ gchar **args = NULL;
+ gchar **pnpent = NULL;
+ gchar **pp = NULL;
+ gchar *s, *nfsargs;
+ int ret, len, err;
+ char addrstr[INET_ADDRSTRLEN];
+ struct in_addr taddr;
+
+ ret = -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)) {
+ g_printerr("Cannot read %s %s\n", cmdline_file, error->message);
+ goto out;
+ }
+
+ if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+ g_printerr("Cannot read %s %s\n", 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';
+
+ /* g_print("cmdline=%s\n", cmdline); */
+
+ /* split in arguments (seperated by space) */
+ args = g_strsplit(cmdline, " ", 0);
+ if (!args) {
+ g_printerr("Cannot split cmdline \"%s\"\n", cmdline);
+ goto out;
+ }
+
+ /* split in entries (by newlines) */
+ pnpent = g_strsplit(pnp, "\n", 0);
+ if (!pnpent) {
+ g_printerr("Cannot split pnp\n");
+ 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;
+
+ /* g_print("root argument: %s\n", *pp); */
+
+ /* locate nfsroot argument */
+ for (pp = args; *pp; pp++) {
+ if (!strncmp(*pp, "nfsroot=", strlen("nfsroot=")))
+ break;
+ }
+ /* no nfsroot argument found */
+ if (!*pp)
+ goto out;
+
+ /* g_print("nfsroot argument: %s\n", *pp); */
+
+ /* 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)) {
+ g_printerr("Bad server\n");
+ goto out;
+ }
+ memcpy(addrstr, s, len);
+ addrstr[len] = '\0';
+
+ /* g_print("using server addr: %s\n", addrstr); */
+
+ err = inet_pton(AF_INET, addrstr, addr);
+ if (err <= 0) {
+ g_printerr("Cannot convert to numeric addr \"%s\"\n",
+ addrstr);
+ goto out;
+ }
+ /* all done */
+ ret = 0;
+out:
+ g_strfreev(pnpent);
+ g_strfreev(args);
+ if (error)
+ g_error_free(error);
+ g_free(pnp);
+ g_free(cmdline);
+
+ return ret;
+}
+
+/* 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;
+ int ret = -1, s;
+ socklen_t socklen;
+ struct sockaddr_in saddr, *ifsaddr;
+
+ /* Obtain address(es) matching host/port */
+ ret = getifaddrs(&ifaddr);
+ if (ret == -1) {
+ fprintf(stderr, "getifaddrs() failed %d (%s)\n",
+ errno, strerror(errno));
+ return -1;
+ }
+
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
+ fprintf(stderr, "socket() failed %d (%s)\n",
+ 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 */
+ ret = connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
+ if (ret == -1) {
+ fprintf(stderr, "connect() failed: %d (%s)\n",
+ errno, strerror(errno));
+ goto do_close;
+ }
+
+ socklen = sizeof(saddr);
+ ret = getsockname(s, (struct sockaddr *)&saddr, &socklen);
+ if (ret == -1) {
+ fprintf(stderr, "getsockname() failed: %d (%s)\n",
+ errno, strerror(errno));
+ goto do_close;
+ }
+
+ ret = -1;
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ 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) {
+ ret = 0;
+ if (ifname)
+ strcpy(ifname, ifa->ifa_name);
+ }
+
+do_close:
+ close(s);
+
+ freeifaddrs(ifaddr);
+
+ return ret;
+}
+
+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;
+}
+
+gchar **__connman_inet_get_pnp_nameservers(const char *pnp_file)
+{
+ GError *error = NULL;
+ gchar *pnp = NULL;
+ gchar **pnpent = NULL;
+ gchar **nameservers = NULL;
+ gchar **pp;
+ char *s;
+ int pass, count;
+
+ if (!pnp_file)
+ pnp_file = "/proc/net/pnp";
+
+ if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+ g_printerr("Cannot read %s %s\n", pnp_file, error->message);
+ goto out;
+ }
+
+ /* split in entries (by newlines) */
+ pnpent = g_strsplit(pnp, "\n", 0);
+ if (!pnpent) {
+ g_printerr("Cannot split pnp\n");
+ goto out;
+ }
+
+ count = 0;
+ nameservers = NULL;
+ for (pass = 1; pass <= 2; pass++) {
+
+ if (pass == 2)
+ nameservers = g_new(gchar *, count + 1);
+
+ count = 0;
+ for (pp = pnpent; *pp; pp++) {
+ if (strncmp(*pp, "nameserver ", strlen("nameserver ")))
+ continue;
+ s = *pp + strlen("nameserver ");
+ if (!strcmp(s, "0.0.0.0"))
+ continue;
+
+ if (pass == 2)
+ nameservers[count] = g_strdup(s);
+ count++;
+ }
+
+ /* no nameservers? */
+ if (count == 0)
+ goto out;
+
+ 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
4 years, 4 months
Tethering - using different subnets
by Usman S
Hi,
Could you please help me understand the below behavior from ConnMan.
Why does connman uses a different subnet for its DHCP sever whenever
tethering is disabled and enabled back again. Isnt that it extends the
DHCP handshake for the remembered device? Maybe a dbus API for the
clients to decide on the subnet for their operation?
Please correct me if I am wrong.
Thanks and Regards,
Usman
4 years, 4 months