From: Jose Blanquicet <jose.blanquicet-melendez(a)magnetimarelli.com>
When DHCP fails and ConnMan obtains an address through IPv4LL, the method
stored/notified for that service must be "auto" instead of "dhcp" as
has
been done so far. This patch aims to fix that misleading.
However, after a disconnection from a service with "auto" as IPv4 method,
ConnMan should use DHCP by first when user tries to reconnects or
auto-connect starts on that service. Same reasoning applies after a
power-cycle, i.e. when ConnMan starts up and reads "auto" as method from
the settings file, it should also use DHCP by first and only if it fails
then IPv4LL should be used.
The IPv4.Configuration is also set to "auto" in order to allow user to ask
ConnMan to try to get an address through DHCP at any time by manually
setting this property to "dhcp". On the other hand, "auto" cannot be
set
by users from D-Bus API, as it has been so far.
---
src/connman.h | 2 ++
src/dhcp.c | 37 ++++++++++++++++++++++++++++++++++++-
src/ipconfig.c | 18 ++++++++++++++----
src/network.c | 13 ++++++++++++-
src/service.c | 9 +++++++++
5 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/src/connman.h b/src/connman.h
index ce4d82e..21b7080 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -680,6 +680,8 @@ struct connman_ipconfig *__connman_service_get_ip6config(
struct connman_service *service);
struct connman_ipconfig *__connman_service_get_ipconfig(
struct connman_service *service, int family);
+void __connman_service_notify_ipv4_configuration(
+ struct connman_service *service);
bool __connman_service_is_connected_state(struct connman_service *service,
enum connman_ipconfig_type type);
const char *__connman_service_get_ident(struct connman_service *service);
diff --git a/src/dhcp.c b/src/dhcp.c
index 54fb64e..e797ae1 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -435,6 +435,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer
user_data)
{
struct connman_dhcp *dhcp = user_data;
GList *option = NULL;
+ enum connman_ipconfig_method old_method;
char *address, *netmask = NULL, *gateway = NULL;
const char *c_address, *c_gateway;
unsigned char prefixlen, c_prefixlen;
@@ -486,8 +487,24 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer
user_data)
} else if (prefixlen != c_prefixlen)
ip_change = true;
+ old_method = __connman_ipconfig_get_method(dhcp->ipconfig);
__connman_ipconfig_set_method(dhcp->ipconfig,
CONNMAN_IPCONFIG_METHOD_DHCP);
+
+ /*
+ * Notify IPv4.Configuration's method moved back to DHCP.
+ *
+ * This is the case ConnMan initially set an address by using
+ * IPv4LL because DHCP failed but now we got an address from DHCP.
+ */
+ if (old_method == CONNMAN_IPCONFIG_METHOD_AUTO) {
+ struct connman_service *service =
+ connman_service_lookup_from_network(dhcp->network);
+
+ if (service)
+ __connman_service_notify_ipv4_configuration(service);
+ }
+
if (ip_change) {
__connman_ipconfig_set_local(dhcp->ipconfig, address);
__connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen);
@@ -509,6 +526,7 @@ done:
static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data)
{
struct connman_dhcp *dhcp = user_data;
+ enum connman_ipconfig_method old_method;
char *address, *netmask;
unsigned char prefixlen;
@@ -519,8 +537,25 @@ static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer
user_data)
prefixlen = connman_ipaddress_calc_netmask_len(netmask);
+ old_method = __connman_ipconfig_get_method(dhcp->ipconfig);
__connman_ipconfig_set_method(dhcp->ipconfig,
- CONNMAN_IPCONFIG_METHOD_DHCP);
+ CONNMAN_IPCONFIG_METHOD_AUTO);
+
+ /*
+ * Notify IPv4.Configuration's method is AUTO now.
+ *
+ * This is the case DHCP failed thus ConnMan used IPv4LL to get an
+ * address. Set IPv4.Configuration method to AUTO allows user to
+ * ask for a DHCP address by setting the method again to DHCP.
+ */
+ if (old_method == CONNMAN_IPCONFIG_METHOD_DHCP) {
+ struct connman_service *service =
+ connman_service_lookup_from_network(dhcp->network);
+
+ if (service)
+ __connman_service_notify_ipv4_configuration(service);
+ }
+
__connman_ipconfig_set_local(dhcp->ipconfig, address);
__connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen);
__connman_ipconfig_set_gateway(dhcp->ipconfig, NULL);
diff --git a/src/ipconfig.c b/src/ipconfig.c
index bae988c..272925a 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -1762,13 +1762,13 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig
*ipconfig,
switch (ipconfig->method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
- case CONNMAN_IPCONFIG_METHOD_AUTO:
return;
case CONNMAN_IPCONFIG_METHOD_FIXED:
append_addr = ipconfig->address;
break;
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
case CONNMAN_IPCONFIG_METHOD_DHCP:
append_addr = ipconfig->system;
@@ -2222,6 +2222,19 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
g_free(key);
break;
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+
+ if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
+ break;
+
+ /*
+ * If the last used method for IPv4 was AUTO then we
+ * try first DHCP. We will try also to use the last
+ * used DHCP address, if exits.
+ */
+ __connman_ipconfig_set_method(ipconfig,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
+
case CONNMAN_IPCONFIG_METHOD_DHCP:
key = g_strdup_printf("%sDHCP.LastAddress", prefix);
@@ -2233,9 +2246,6 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
g_free(key);
break;
-
- case CONNMAN_IPCONFIG_METHOD_AUTO:
- break;
}
return 0;
diff --git a/src/network.c b/src/network.c
index 5b7ef55..a5b7d78 100644
--- a/src/network.c
+++ b/src/network.c
@@ -172,6 +172,8 @@ static void dhcp_success(struct connman_network *network)
if (err < 0)
goto err;
+ __connman_service_save(service);
+
return;
err:
@@ -647,10 +649,19 @@ static void set_disconnected(struct connman_network *network)
switch (ipv4_method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
- case CONNMAN_IPCONFIG_METHOD_AUTO:
case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
break;
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ /*
+ * If the current method is AUTO then next time we
+ * try first DHCP. DHCP also needs to be stopped
+ * in this case because if we fell in AUTO means
+ * that DHCP was launched for IPv4 but it failed.
+ */
+ __connman_ipconfig_set_method(ipconfig_ipv4,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
+ __connman_service_notify_ipv4_configuration(service);
case CONNMAN_IPCONFIG_METHOD_DHCP:
__connman_dhcp_stop(ipconfig_ipv4);
break;
diff --git a/src/service.c b/src/service.c
index d9c1907..73832f8 100644
--- a/src/service.c
+++ b/src/service.c
@@ -1988,6 +1988,15 @@ static void ipv4_configuration_changed(struct connman_service
*service)
service);
}
+void __connman_service_notify_ipv4_configuration(
+ struct connman_service *service)
+{
+ if (!service)
+ return;
+
+ ipv4_configuration_changed(service);
+}
+
static void ipv6_configuration_changed(struct connman_service *service)
{
if (!allow_property_changed(service))
--
1.9.1