Send connman mailing list submissions to
        connman@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-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 16/27] acd: add handling of received arp packets
      (Christian Spielberger)
   2. [PATCH 21/27] acd: add dbus property for address conflict
      (Christian Spielberger)
   3. [PATCH 22/27] dhcp: add sending of DHCP decline
      (Christian Spielberger)
   4. [PATCH 20/27] network: add ipv4ll as fallback for acd
      (Christian Spielberger)


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

Message: 1
Date: Wed, 11 Apr 2018 16:00:36 +0200
From: Christian Spielberger <christian.spielber...@gmail.com>
To: Daniel Wagner <w...@monom.org>
Cc: connman@lists.01.org, Christian Spielberger
        <christian.spielber...@gmail.com>
Subject: [PATCH 16/27] acd: add handling of received arp packets
Message-ID:
        <1523455247-5877-17-git-send-email-christian.spielber...@gmail.com>

Adds implementation of acd_recv_arp_packet. This is the main logic for ACD. As
long as ACD is activated received ARP packets are checked for potential address
conflicts.
---
 src/acd.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/src/acd.c b/src/acd.c
index 76dbc77..c796f2f 100644
--- a/src/acd.c
+++ b/src/acd.c
@@ -371,4 +371,86 @@ static gboolean acd_announce_timeout(gpointer acd_data)
 }
 
 static int acd_recv_arp_packet(acd_host *acd) {
+       ssize_t cnt;
+       struct ether_arp arp;
+       uint32_t ip_n; /* network byte order */
+       struct in_addr addr;
+       int source_conflict;
+       int target_conflict;
+       bool probe;
+       char* confltxt;
+       uint8_t* mac;
+       uint8_t* omac;
+
+       memset(&arp, 0, sizeof(arp));
+       cnt = read(acd->listener_sockfd, &arp, sizeof(arp));
+       if (cnt != sizeof(arp))
+               return -EINVAL;
+
+       if (arp.arp_op != htons(ARPOP_REPLY) &&
+                       arp.arp_op != htons(ARPOP_REQUEST))
+               return -EINVAL;
+
+       if (memcmp(arp.arp_sha, acd->mac_address, ETH_ALEN) == 0)
+               return 0;
+
+       ip_n = htonl(acd->requested_ip);
+       source_conflict = !memcmp(arp.arp_spa, &ip_n, sizeof(uint32_t));
+       probe = !memcmp(arp.arp_spa, "\0\0\0\0", sizeof(uint32_t));
+       target_conflict = probe &&
+               !memcmp(arp.arp_tpa, &ip_n, sizeof(uint32_t));
+
+       if (!source_conflict && !target_conflict)
+               return 0;
+
+       acd->conflicts++;
+
+       confltxt = target_conflict ? "target" : "source";
+
+       addr.s_addr = ip_n;
+       debug(acd, "IPv4 %d %s conflicts detected for address %s. "
+                       "State=%s", acd->conflicts, confltxt, inet_ntoa(addr),
+                       acd_state_texts[acd->state]);
+       mac = acd->mac_address;
+       omac = arp.arp_sha;
+       debug(acd, "Our MAC: %02x:%02x:%02x:%02x:%02x:%02x"
+                          " other MAC: %02x:%02x:%02x:%02x:%02x:%02x",
+                       mac[0], mac[1], mac[2],mac[3], mac[4], mac[5],
+                       omac[0], omac[1], omac[2],omac[3], omac[4], omac[5]);
+
+       if (acd->state == ACD_MONITOR) {
+               if (!source_conflict)
+                       return 0;
+
+               acd->state = ACD_DEFEND;
+               debug(acd, "DEFEND mode conflicts: %d", acd->conflicts);
+               /* Try to defend with a single announce. */
+               send_announce_packet(acd);
+               return 0;
+       } else if (acd->state == ACD_DEFEND) {
+               if (!source_conflict)
+                       return 0;
+
+               debug(acd, "LOST IPv4 address %s", inet_ntoa(addr));
+               if (acd->ipv4_lost_cb)
+                       acd->ipv4_lost_cb(acd, acd->ipv4_lost_data);
+               return 0;
+       }
+
+       if (acd->conflicts < MAX_CONFLICTS) {
+               acdhost_stop(acd);
+
+               /* we need a new request_ip */
+               if (acd->ipv4_conflict_cb)
+                       acd->ipv4_conflict_cb(acd, acd->ipv4_conflict_data);
+       } else {
+               acdhost_stop(acd);
+
+               /* Here we got a lot of conflicts, RFC3927 and RFC5227 state 
that we
+                * have to wait RATE_LIMIT_INTERVAL before retrying. */
+               if (acd->ipv4_max_conflicts_cb)
+                       acd->ipv4_max_conflicts_cb(acd, 
acd->ipv4_max_conflicts_data);
+       }
+
+       return 0;
 }
-- 
2.7.4



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

Message: 2
Date: Wed, 11 Apr 2018 16:00:41 +0200
From: Christian Spielberger <christian.spielber...@gmail.com>
To: Daniel Wagner <w...@monom.org>
Cc: connman@lists.01.org, Christian Spielberger
        <christian.spielber...@gmail.com>
Subject: [PATCH 21/27] acd: add dbus property for address conflict
Message-ID:
        <1523455247-5877-22-git-send-email-christian.spielber...@gmail.com>

Adds a dbus property called LastAddressConflict and a signal to notify if
the property changes.
---
 doc/service-api.txt | 32 ++++++++++++++++++++
 include/acd.h       |  5 +++-
 include/network.h   |  4 +++
 include/service.h   |  1 +
 src/acd.c           | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/network.c       | 12 +++++++-
 src/service.c       | 11 +++++++
 7 files changed, 146 insertions(+), 3 deletions(-)

diff --git a/doc/service-api.txt b/doc/service-api.txt
index b5b4fab..ac597bc 100644
--- a/doc/service-api.txt
+++ b/doc/service-api.txt
@@ -513,3 +513,35 @@ Properties string State [readonly]
                        Same values as mDNS property. The mDNS
                        represents the actual system configuration
                        while this allows user configuration.
+
+               dict LastAddressConflict [readonly]
+
+                       This property contains information about the previously 
detected
+                       address conflict. If there has been no address conflict 
then
+                       IPv4 Address is "0.0.0.0", Ethernet Address is 
"00:00:00:00:00:00",
+                       Timestamp is zero and Resolved is true.
+
+                       dict IPv4 [readonly]
+
+                               string Address [readonly]
+
+                               The IPv4 address which had a conflict.
+
+                       dict Ethernet [readonly]
+
+                               string Address [readonly]
+
+                               The ethernet device address (MAC address) of 
the conflicting
+                               host.
+
+                       int64 Timestamp [readonly]
+
+                               A timestamp when the conflict was detected in 
microseconds
+                               since January 1, 1970 UTC.
+
+                       bool Resolved [readonly]
+
+                               Set to false when an address conflict occurs.
+                               If a previous conflict could be resolved by 
probing another
+                               IPv4 address (which is not an IPv4LL) then this 
boolean is set
+                               to true.
diff --git a/include/acd.h b/include/acd.h
index dc7e570..69d740d 100644
--- a/include/acd.h
+++ b/include/acd.h
@@ -25,6 +25,7 @@
 
 #include <stdint.h>
 #include <glib.h>
+#include <gdbus.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -34,7 +35,7 @@ struct _acd_host;
 
 typedef struct _acd_host acd_host;
 
-acd_host *acdhost_new(int ifindex);
+acd_host *acdhost_new(int ifindex, const char* path);
 int acdhost_start(acd_host *acd, uint32_t ip);
 void acdhost_stop(acd_host *acd);
 
@@ -52,6 +53,8 @@ void acdhost_register_event(acd_host *acd,
                            ACDHostEventFunc func,
                            gpointer user_data);
 
+void acdhost_append_dbus_property(acd_host *acd, DBusMessageIter *dict);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/network.h b/include/network.h
index 4fc20c1..22463cc 100644
--- a/include/network.h
+++ b/include/network.h
@@ -24,6 +24,7 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <dbus/dbus.h>
 
 #include <connman/device.h>
 #include <connman/ipconfig.h>
@@ -162,6 +163,9 @@ struct connman_network_driver {
 int connman_network_driver_register(struct connman_network_driver *driver);
 void connman_network_driver_unregister(struct connman_network_driver *driver);
 
+void connman_network_append_acddbus(DBusMessageIter *dict,
+               struct connman_network *network);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/service.h b/include/service.h
index 958e7fd..c958375 100644
--- a/include/service.h
+++ b/include/service.h
@@ -117,6 +117,7 @@ enum connman_service_type connman_service_get_type(struct 
connman_service *servi
 char *connman_service_get_interface(struct connman_service *service);
 
 const char *connman_service_get_domainname(struct connman_service *service);
+const char *connman_service_get_dbuspath(struct connman_service *service);
 char **connman_service_get_nameservers(struct connman_service *service);
 char **connman_service_get_timeservers_config(struct connman_service *service);
 char **connman_service_get_timeservers(struct connman_service *service);
diff --git a/src/acd.c b/src/acd.c
index cdd2569..f10e3d7 100644
--- a/src/acd.c
+++ b/src/acd.c
@@ -21,6 +21,7 @@
 #include <connman/log.h>
 #include <connman/inet.h>
 #include <glib.h>
+#include <connman/dbus.h>
 #include "src/shared/arp.h"
 #include "src/shared/random.h"
 #include <errno.h>
@@ -52,6 +53,13 @@ struct _acd_host {
        uint8_t mac_address[6];
        uint32_t requested_ip; /* host byte order */
 
+       /* address conflict fields */
+       uint32_t ac_ip; /* host byte order */
+       uint8_t ac_mac[6];
+       gint64 ac_timestamp;
+       bool ac_resolved;
+       const char *path;
+
        bool listen_on;
        int listener_sockfd;
        unsigned int retry_times;
@@ -80,6 +88,9 @@ static gboolean send_announce_packet(gpointer acd_data);
 static gboolean acd_announce_timeout(gpointer acd_data);
 static gboolean acd_defend_timeout(gpointer acd_data);
 
+/* for DBus property */
+static void report_conflict(acd_host *acd);
+
 static void debug(acd_host *acd, const char *format, ...)
 {
        char str[256];
@@ -93,7 +104,7 @@ static void debug(acd_host *acd, const char *format, ...)
        va_end(ap);
 }
 
-acd_host *acdhost_new(int ifindex)
+acd_host *acdhost_new(int ifindex, const char *path)
 {
        acd_host *acd;
 
@@ -133,6 +144,12 @@ acd_host *acdhost_new(int ifindex)
        acd->ipv4_conflict_cb = NULL;
        acd->ipv4_max_conflicts_cb = NULL;
 
+       acd->ac_ip = 0;
+       memset(acd->ac_mac, 0, sizeof(acd->ac_mac));
+       acd->ac_timestamp = 0;
+       acd->ac_resolved = true;
+       acd->path = path;
+
        return acd;
 
 error:
@@ -346,6 +363,11 @@ static gboolean acd_defend_timeout(gpointer acd_data)
        return FALSE;
 }
 
+static bool is_link_local(uint32_t ip)
+{
+       return (ip & LINKLOCAL_ADDR) == LINKLOCAL_ADDR;
+}
+
 static gboolean acd_announce_timeout(gpointer acd_data)
 {
        acd_host *acd = acd_data;
@@ -362,6 +384,11 @@ static gboolean acd_announce_timeout(gpointer acd_data)
        debug(acd, "switching to monitor mode");
        acd->state = ACD_MONITOR;
 
+       if (!acd->ac_resolved && !is_link_local(acd->requested_ip)) {
+               acd->ac_resolved = true;
+               report_conflict(acd);
+       }
+
        if (acd->ipv4_available_cb)
                acd->ipv4_available_cb(acd,
                                        acd->ipv4_available_data);
@@ -438,6 +465,14 @@ static int acd_recv_arp_packet(acd_host *acd) {
        }
 
        if (acd->conflicts < MAX_CONFLICTS) {
+               if (!is_link_local(acd->requested_ip)) {
+                       acd->ac_ip = acd->requested_ip;
+                       memcpy(acd->ac_mac, arp.arp_sha, sizeof(acd->ac_mac));
+                       acd->ac_timestamp = g_get_real_time();
+                       acd->ac_resolved = false;
+                       report_conflict(acd);
+               }
+
                acdhost_stop(acd);
 
                /* we need a new request_ip */
@@ -483,3 +518,50 @@ void acdhost_register_event(acd_host *acd,
        }
 }
 
+static void append_ac_mac(DBusMessageIter *iter, void *user_data)
+{
+       acd_host *acd = user_data;
+       char mac[32];
+       uint8_t *m = acd->ac_mac;
+       const char *str = mac;
+       snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+                       m[0], m[1], m[2], m[3], m[4], m[5]);
+       connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &str);
+}
+
+static void append_ac_ipv4(DBusMessageIter *iter, void *user_data)
+{
+       acd_host *acd = user_data;
+       struct in_addr addr;
+       char *a;
+
+       addr.s_addr = htonl(acd->ac_ip);
+       a = inet_ntoa(addr);
+       if (!a)
+               a = "";
+       connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &a);
+}
+
+static void append_ac_property(DBusMessageIter *iter, void *user_data)
+{
+       acd_host *acd = user_data;
+
+       connman_dbus_dict_append_dict(iter, "IPv4", append_ac_ipv4, acd);
+       connman_dbus_dict_append_dict(iter, "Ethernet", append_ac_mac, acd);
+       connman_dbus_dict_append_basic(iter, "Timestamp", DBUS_TYPE_INT64,
+                       &acd->ac_timestamp);
+       connman_dbus_dict_append_basic(iter, "Resolved", DBUS_TYPE_BOOLEAN,
+                       &acd->ac_resolved);
+}
+
+void acdhost_append_dbus_property(acd_host *acd, DBusMessageIter *dict)
+{
+       connman_dbus_dict_append_dict(dict, "LastAddressConflict",
+                       append_ac_property, acd);
+}
+
+static void report_conflict(acd_host *acd)
+{
+       connman_dbus_property_changed_dict(acd->path, CONNMAN_SERVICE_INTERFACE,
+                       "LastAddressConflict", append_ac_property, acd);
+}
diff --git a/src/network.c b/src/network.c
index a7d6af4..399a0cd 100644
--- a/src/network.c
+++ b/src/network.c
@@ -158,6 +158,15 @@ static void set_configuration(struct connman_network 
*network,
                                        type);
 }
 
+void connman_network_append_acddbus(DBusMessageIter *dict,
+               struct connman_network *network)
+{
+       if (!network->acdhost)
+               return;
+
+       acdhost_append_dbus_property(network->acdhost, dict);
+}
+
 static int start_acd(struct connman_network *network);
 
 static void remove_ipv4ll_timeout(struct connman_network *network)
@@ -341,7 +350,8 @@ static int start_acd(struct connman_network *network)
                int index;
 
                index = __connman_ipconfig_get_index(ipconfig_ipv4);
-               network->acdhost = acdhost_new(index);
+               network->acdhost = acdhost_new(index,
+                               connman_service_get_dbuspath(service));
                if (!network->acdhost) {
                        connman_error("Could not create ACD data structure");
                        return -EINVAL;
diff --git a/src/service.c b/src/service.c
index ab5b2c6..b16555d 100644
--- a/src/service.c
+++ b/src/service.c
@@ -2524,6 +2524,9 @@ static void append_properties(DBusMessageIter *dict, 
dbus_bool_t limited,
 
        connman_dbus_dict_append_dict(dict, "Provider",
                                                append_provider, service);
+
+       if (service->network)
+               connman_network_append_acddbus(dict, service->network);
 }
 
 static void append_struct_service(DBusMessageIter *iter,
@@ -2655,6 +2658,14 @@ const char *connman_service_get_domainname(struct 
connman_service *service)
                return service->domainname;
 }
 
+const char *connman_service_get_dbuspath(struct connman_service *service)
+{
+       if (!service)
+               return NULL;
+
+       return service->path;
+}
+
 char **connman_service_get_nameservers(struct connman_service *service)
 {
        if (!service)
-- 
2.7.4



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

Message: 3
Date: Wed, 11 Apr 2018 16:00:42 +0200
From: Christian Spielberger <christian.spielber...@gmail.com>
To: Daniel Wagner <w...@monom.org>
Cc: connman@lists.01.org, Christian Spielberger
        <christian.spielber...@gmail.com>
Subject: [PATCH 22/27] dhcp: add sending of DHCP decline
Message-ID:
        <1523455247-5877-23-git-send-email-christian.spielber...@gmail.com>

Add sending of DHCP decline in case of address conflict for a DHCP lease.
---
 gdhcp/client.c | 29 ++++++++++++++++++++++++++++-
 gdhcp/gdhcp.h  |  1 +
 src/connman.h  |  1 +
 src/dhcp.c     | 24 ++++++++++++++++++++++++
 4 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/gdhcp/client.c b/gdhcp/client.c
index 9542eec..d405424 100644
--- a/gdhcp/client.c
+++ b/gdhcp/client.c
@@ -66,6 +66,7 @@ typedef enum _dhcp_client_state {
        REBOOTING,
        REQUESTING,
        BOUND,
+       DECLINED,
        RENEWING,
        REBINDING,
        RELEASED,
@@ -471,6 +472,30 @@ static int send_discover(GDHCPClient *dhcp_client, 
uint32_t requested)
                                dhcp_client->retry_times % 2);
 }
 
+int g_dhcp_client_decline(GDHCPClient *dhcp_client, uint32_t requested)
+{
+       struct dhcp_packet packet;
+
+       dhcp_client->state = DECLINED;
+       dhcp_client->retry_times = 0;
+
+       debug(dhcp_client, "sending DHCP decline");
+
+       init_packet(dhcp_client, &packet, DHCPDECLINE);
+
+       packet.xid = dhcp_client->xid;
+       packet.secs = dhcp_attempt_secs(dhcp_client);
+
+       if (requested)
+               dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP, requested);
+
+       add_send_options(dhcp_client, &packet);
+
+       return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
+                               INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
+                               dhcp_client->ifindex, true);
+}
+
 static int send_request(GDHCPClient *dhcp_client)
 {
        struct dhcp_packet packet;
@@ -2688,6 +2713,7 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const 
char *last_address)
        int re;
        uint32_t addr;
        uint64_t rand;
+       ClientState oldstate = dhcp_client->state;
 
        remove_timeouts(dhcp_client);
 
@@ -2803,7 +2829,7 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const 
char *last_address)
                dhcp_client->start = time(NULL);
        }
 
-       if (!last_address) {
+       if (!last_address || oldstate == DECLINED) {
                addr = 0;
        } else {
                addr = ntohl(inet_addr(last_address));
@@ -3003,6 +3029,7 @@ char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client)
        case REBOOTING:
        case REQUESTING:
        case RELEASED:
+       case DECLINED:
        case IPV4LL_PROBE:
        case IPV4LL_ANNOUNCE:
        case INFORMATION_REQ:
diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h
index 1285431..e3b0131 100644
--- a/gdhcp/gdhcp.h
+++ b/gdhcp/gdhcp.h
@@ -134,6 +134,7 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type, int index,
 
 int g_dhcp_client_start(GDHCPClient *client, const char *last_address);
 void g_dhcp_client_stop(GDHCPClient *client);
+int g_dhcp_client_decline(GDHCPClient *client, uint32_t requested);
 
 GDHCPClient *g_dhcp_client_ref(GDHCPClient *client);
 void g_dhcp_client_unref(GDHCPClient *client);
diff --git a/src/connman.h b/src/connman.h
index 6d1831b..303fddd 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -466,6 +466,7 @@ int __connman_dhcp_start(struct connman_ipconfig *ipconfig,
                        struct connman_network *network, dhcp_cb callback,
                        gpointer user_data);
 void __connman_dhcp_stop(struct connman_ipconfig *ipconfig);
+void __connman_dhcp_decline(struct connman_ipconfig *ipconfig);
 int __connman_dhcp_init(void);
 void __connman_dhcp_cleanup(void);
 int __connman_dhcpv6_init(void);
diff --git a/src/dhcp.c b/src/dhcp.c
index 615ad4a..75e6d85 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -746,6 +746,30 @@ void __connman_dhcp_stop(struct connman_ipconfig *ipconfig)
        }
 }
 
+void __connman_dhcp_decline(struct connman_ipconfig *ipconfig)
+{
+       struct connman_dhcp *dhcp;
+       const char *address;
+       struct in_addr addr;
+
+       DBG("ipconfig_table %p ipconfig %p", ipconfig_table, ipconfig);
+
+       if (!ipconfig_table)
+               return;
+
+       dhcp = g_hash_table_lookup(ipconfig_table, ipconfig);
+       if (dhcp) {
+               address = __connman_ipconfig_get_local(ipconfig);
+               if (!address)
+                       return;
+
+               if (inet_pton(AF_INET, address, &addr) != 1)
+                       connman_error("Could not convert address %s", address);
+
+               g_dhcp_client_decline(dhcp->dhcp_client, htonl(addr.s_addr));
+       }
+}
+
 int __connman_dhcp_init(void)
 {
        DBG("");
-- 
2.7.4



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

Message: 4
Date: Wed, 11 Apr 2018 16:00:40 +0200
From: Christian Spielberger <christian.spielber...@gmail.com>
To: Daniel Wagner <w...@monom.org>
Cc: connman@lists.01.org, Christian Spielberger
        <christian.spielber...@gmail.com>
Subject: [PATCH 20/27] network: add ipv4ll as fallback for acd
Message-ID:
        <1523455247-5877-21-git-send-email-christian.spielber...@gmail.com>

When an address conflict is detected for the static IPv4 configuration a free
IPv4LL address has to be found. This patch adds functions start_ipv4ll for
starting the IPv4LL process, start_ipv4ll_ontimeout for a delayed start of
IPv4LL and remove_ipv4ll_timeout for stopping the delayed start.

For IPv4LL process again we use the new ACD functions.
---
 src/network.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/src/network.c b/src/network.c
index 5b79a2a..a7d6af4 100644
--- a/src/network.c
+++ b/src/network.c
@@ -70,6 +70,7 @@ struct connman_network {
        int router_solicit_count;
        int router_solicit_refresh_count;
        acd_host *acdhost;
+       guint ipv4ll_timeout;
 
        struct connman_network_driver *driver;
        void *driver_data;
@@ -159,6 +160,14 @@ static void set_configuration(struct connman_network 
*network,
 
 static int start_acd(struct connman_network *network);
 
+static void remove_ipv4ll_timeout(struct connman_network *network)
+{
+       if (network->ipv4ll_timeout > 0) {
+               g_source_remove(network->ipv4ll_timeout);
+               network->ipv4ll_timeout = 0;
+       }
+}
+
 static void acdhost_ipv4_available(acd_host *acd, gpointer user_data)
 {
        struct connman_network *network = user_data;
@@ -196,6 +205,51 @@ err:
                                CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
 }
 
+static int start_ipv4ll(struct connman_network *network)
+{
+       struct connman_service *service;
+       struct connman_ipconfig *ipconfig_ipv4;
+       struct in_addr addr;
+       char *address;
+
+       service = connman_service_lookup_from_network(network);
+       if (!service)
+               return -EINVAL;
+
+       ipconfig_ipv4 = __connman_service_get_ip4config(service);
+       if (!ipconfig_ipv4) {
+               connman_error("Service has no IPv4 configuration");
+               return -EINVAL;
+       }
+
+       /* Apply random IPv4 address. */
+       addr.s_addr = htonl(random_ip());
+       address = inet_ntoa(addr);
+       if (!address) {
+               connman_error("Could not convert IPv4LL random address %u",
+                               addr.s_addr);
+               return -EINVAL;
+       }
+       __connman_ipconfig_set_local(ipconfig_ipv4, address);
+
+       connman_info("Probing IPv4LL address %s", address);
+       return start_acd(network);
+}
+
+static gboolean start_ipv4ll_ontimeout(gpointer data)
+{
+       struct connman_network *network = data;
+
+       if (!network)
+               return FALSE;
+
+       /* Start IPv4LL ACD. */
+       if (start_ipv4ll(network) < 0)
+               connman_error("Could not start IPv4LL. No address will be 
assigned");
+
+       return FALSE;
+}
+
 static void acdhost_ipv4_lost(acd_host *acd, gpointer user_data)
 {
        struct connman_network *network = user_data;
@@ -232,6 +286,9 @@ static void acdhost_ipv4_lost(acd_host *acd, gpointer 
user_data)
                        __connman_network_enable_ipconfig(network, 
ipconfig_ipv4);
        } else {
                /* Start IPv4LL ACD. */
+               if (start_ipv4ll(network) < 0)
+                       connman_error("Could not start IPv4LL. "
+                                       "No address will be assigned");
        }
 }
 
@@ -240,15 +297,25 @@ static void acdhost_ipv4_conflict(acd_host *acd, gpointer 
user_data)
        struct connman_network *network = user_data;
 
        /* Start IPv4LL ACD. */
+       if (start_ipv4ll(network) < 0)
+               connman_error("Could not start IPv4LL. "
+                               "No address will be assigned");
 }
 
 static void acdhost_ipv4_maxconflict(acd_host *acd, gpointer user_data)
 {
        struct connman_network *network = user_data;
 
+       remove_ipv4ll_timeout(network);
        connman_info("Had maximum number of conflicts. Next IPv4LL address will 
be "
                        "tried in %d seconds", RATE_LIMIT_INTERVAL);
        /* Wait, then start IPv4LL ACD. */
+       network->ipv4ll_timeout =
+               g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+                               RATE_LIMIT_INTERVAL,
+                               start_ipv4ll_ontimeout,
+                               network,
+                               NULL);
 }
 
 static int start_acd(struct connman_network *network)
@@ -258,6 +325,8 @@ static int start_acd(struct connman_network *network)
        const char* address;
        struct in_addr addr;
 
+       remove_ipv4ll_timeout(network);
+
        service = connman_service_lookup_from_network(network);
        if (!service)
                return -EINVAL;
@@ -1124,6 +1193,7 @@ struct connman_network *connman_network_create(const char 
*identifier,
        network->type       = type;
        network->identifier = ident;
        network->acdhost = NULL;
+       network->ipv4ll_timeout = 0;
 
        network_list = g_slist_prepend(network_list, network);
 
@@ -1668,6 +1738,7 @@ int __connman_network_disconnect(struct connman_network 
*network)
 
        DBG("network %p", network);
 
+       remove_ipv4ll_timeout(network);
        if (network->acdhost)
                acdhost_stop(network->acdhost);
 
-- 
2.7.4



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

Subject: Digest Footer

_______________________________________________
connman mailing list
connman@lists.01.org
https://lists.01.org/mailman/listinfo/connman


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

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

Reply via email to