From d7d49eb1d5a7d30c3415b6b569f7b5e1e2a480da Mon Sep 17 00:00:00 2001 From: Jimmy Gysens Date: Tue, 19 Nov 2019 10:53:20 +0000 Subject: [PATCH] huawei: Fix infinite loop on modem removal After unplugging a Huawei USB dongle, the 'atoms' in oFono are removed via 'flush_atoms'. Every atom has a destruct function pointer, used as destructor. This includes the gprs_context atom that is currently active. The function calls are: flush_atoms -> destruct -> gprs_context_remove -> at_gprs_context_remove -> modem_disconnect Because the device is physically removed, the IO channel for the AT port is gone. In 'at_gprs_context_remove', there is an attempt to resume communication over that AT port, but that is not possible. This is detected, and 'io_disconnect' (pointer to 'modem_disconnect') is called. 'modem_disconnect' has the same atom and tries to remove it again, so it calls the same destructor. This continues infinitely. This patch moves the GPRS context removal so that it only happens if the modem port could be re-opened successfully. If the port cannot be re-opened (in the case of modem removal), the atom is already in the process of being removed by the process kicked off in flush_atoms. This fix is limited to Huawei devices and has been tested using the following devices: - E3531i-2 - E3372 - E3531s-2 - E369 - E1552 --- plugins/huawei.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/huawei.c b/plugins/huawei.c index bdf7bc39..bb876701 100644 --- a/plugins/huawei.c +++ b/plugins/huawei.c @@ -583,9 +583,6 @@ static void modem_disconnect(gpointer user_data) g_at_chat_unref(data->modem); data->modem = NULL; - /* close gprs context driver */ - ofono_gprs_context_remove(data->gc); - /* reopen modem channel */ data->modem = open_device(modem, "Modem", "Modem: "); @@ -594,6 +591,10 @@ static void modem_disconnect(gpointer user_data) return; } + /* close previous gprs context driver */ + if (data->gc) + ofono_gprs_context_remove(data->gc); + /* configure modem channel */ g_at_chat_set_disconnect_function(data->modem, modem_disconnect, modem); g_at_chat_set_slave(data->modem, data->pcui);