In order to recover from a lost lease, gdhcp will restart the address
acquisition process. As the dhcp structures are removed from the hash
and freed in dhcp_invalidate() without notifying gdhcp, the following
crash can happen:

connmand[28337]: DHCP index 3: lease expired
connmand[28337]: DHCP index 3: restart DHCP (retries 0)
connmand[28337]: DHCP index 3: DHCP client start with state init_reboot
connmand[28337]: DHCP index 3: sending DHCP request
connmand[28337]: src/dhcp.c:lease_lost_cb() Lease lost
connmand[28337]: src/dhcp.c:dhcp_invalidate() dhcp 0xb958a0 callback 1
connmand[28337]: src/dhcp.c:dhcp_invalidate() last address 10.0.0.18
connmand[28337]: src/dhcp.c:__connman_dhcp_stop() network_table 0xb94c60 
network 0xb9b500
connmand[28337]: wlan0 {del} address 10.0.0.18/20 label wlan0
connmand[28337]: wlan0 {del} route 10.0.0.0 gw 0.0.0.0 scope 253 <LINK>
connmand[28337]: DHCP index 3: received DHCP packet xid 0x0000 (current state 1)
connmand[28337]: DHCP index 3: switch listening mode (1 ==> 0)
connmand[28337]: src/dhcp.c:lease_available_cb() Lease available
connmand[28337]: Aborting (signal 11) [src/connmand]
connmand[28337]: ++++++++ backtrace ++++++++
connmand[28337]: #0  0x7f1890e98420 in /lib/x86_64-linux-gnu/libc.so.6
connmand[28337]: #1  0x439580 in connman_device_get_ident() at src/device.c:555
connmand[28337]: #2  0x448041 in connman_service_lookup_from_network() at 
src/service.c:6483
connmand[28337]: #3  0x459d97 in lease_available_cb() at src/dhcp.c:331
connmand[28337]: #4  0x4122b1 in start_bound() at gdhcp/client.c:1740
connmand[28337]: #5  0x7f1891f8a526 in /lib/x86_64-linux-gnu/libglib-2.0.so.0
connmand[28337]: #6  0x7f1891f8a878 in /lib/x86_64-linux-gnu/libglib-2.0.so.0
connmand[28337]: #7  0x7f1891f8ab3a in /lib/x86_64-linux-gnu/libglib-2.0.so.0
connmand[28337]: #8  0x40f902 in main() at src/main.c:690
connmand[28337]: #9  0x7f1890e84b45 in /lib/x86_64-linux-gnu/libc.so.6
connmand[28337]: +++++++++++++++++++++++++++

Fix this by freeing and removing the dhcp structure only when explicitely
calling __connman_dhcp_stop() and modify dhcp_invalidate() so that it
will only reset IP configuration data for the service.
---
 src/dhcp.c | 22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/src/dhcp.c b/src/dhcp.c
index e4bac67..03200f1 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -86,7 +86,6 @@ static void dhcp_invalidate(struct connman_dhcp *dhcp, bool 
callback)
 {
        struct connman_service *service;
        struct connman_ipconfig *ipconfig;
-       bool network_removed = false;
        int i;
 
        DBG("dhcp %p callback %u", dhcp, callback);
@@ -96,11 +95,11 @@ static void dhcp_invalidate(struct connman_dhcp *dhcp, bool 
callback)
 
        service = connman_service_lookup_from_network(dhcp->network);
        if (!service)
-               goto out;
+               return;
 
        ipconfig = __connman_service_get_ip4config(service);
        if (!ipconfig)
-               goto out;
+               return;
 
        __connman_6to4_remove(ipconfig);
 
@@ -132,18 +131,8 @@ static void dhcp_invalidate(struct connman_dhcp *dhcp, 
bool callback)
        __connman_ipconfig_set_gateway(ipconfig, NULL);
        __connman_ipconfig_set_prefixlen(ipconfig, 0);
 
-       if (dhcp->callback && callback) {
-               g_hash_table_remove(network_table, dhcp->network);
-               network_removed = true;
+       if (dhcp->callback && callback)
                dhcp->callback(dhcp->network, false, NULL);
-       }
-
-out:
-       if (!network_removed)
-               g_hash_table_remove(network_table, dhcp->network);
-
-       connman_network_unref(dhcp->network);
-       dhcp_free(dhcp);
 }
 
 static void dhcp_valid(struct connman_dhcp *dhcp)
@@ -622,11 +611,12 @@ void __connman_dhcp_stop(struct connman_network *network)
                return;
 
        dhcp = g_hash_table_lookup(network_table, network);
-       g_hash_table_remove(network_table, network);
-
        if (dhcp) {
+               g_hash_table_remove(network_table, network);
+               connman_network_unref(network);
                dhcp_release(dhcp);
                dhcp_invalidate(dhcp, false);
+               dhcp_free(dhcp);
        }
 }
 
-- 
1.9.1

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

Reply via email to