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