I was trying to use the latest connman and I found that it was crashing
during the very first wifi scan and is to do with newly introduced
functions *wifi_data_ref* and *wifi_data_unref*. This is the scenario:
After wpa_supplicant has created the interface it is gonna call connman
supplied callback "interface_create_callback". In this function connman is
going to initiate the device scan. This is the sequence of call that would
happen:
interface_create_callback --> finalize_interface_creation -->
connman_device_set_powered -->device->driver->scan (which is a function
defined in wifi_plugins) (Function called would be wifi_scan).
As a result of this scan operation the wifi_data_ref count would go up to
2 (the initial value of the ref count is 1 when wifi struct got allocated
as a part of wifi_probe). The problem is that after starting the scan when
finalize_intreface_creation returns, it is gonna decrement the ref count by
1 (which is wrong) because when scan_callback_done is called it will again
try to decrement it by 1 and then the value would be 0 causing wifi memory
to be freed.
This is the piece of code that I am talking about:
static void interface_create_callback(int result,
GSupplicantInterface *interface,
void *user_data)
{
struct wifi_data *wifi = user_data;
DBG("result %d ifname %s, wifi %p", result,
g_supplicant_interface_get_ifname(interface),
wifi);
if (result < 0 || wifi_link_removed(wifi))
goto done;
wifi->interface = interface;
g_supplicant_interface_set_data(interface, wifi);
if (g_supplicant_interface_get_ready(interface)) {
wifi->interface_ready = true;
finalize_interface_creation(wifi);
}
done:
if (wifi != NULL) {
DBG("calling unref 6");
/* Remove ref added in wifi_enable */
wifi_data_unref(wifi); ==> *This code would decrement the count
even in the successful case*
}
}
I suggest to make following change:
static void interface_create_callback(int result,
GSupplicantInterface *interface,
void *user_data)
{
static void interface_create_callback(int result,
GSupplicantInterface *interface,
void *user_data)
{
struct wifi_data *wifi = user_data;
DBG("result %d ifname %s, wifi %p", result,
g_supplicant_interface_get_ifname(interface),
wifi);
if (result < 0 || wifi_link_removed(wifi))
goto done;
wifi->interface = interface;
g_supplicant_interface_set_data(interface, wifi);
if (g_supplicant_interface_get_ready(interface)) {
wifi->interface_ready = true;
finalize_interface_creation(wifi);
wifi = NULL;
}
done:
if (wifi != NULL) {
DBG("calling unref 6");
/* Remove ref added in wifi_enable */
wifi_data_unref(wifi);
}
}
if (g_supplicant_interface_get_ready(interface)) {
wifi->interface_ready = true;
finalize_interface_creation(wifi);
*wifi = NULL; ==> make wifi as NULL again so that we can
distinguish b/w failure and successful case.*
}
done:
if (wifi != NULL) {
DBG("calling unref 6");
/* Remove ref added in wifi_enable */
wifi_data_unref(wifi);
}
}
Regards
Naveen
_______________________________________________
connman mailing list
[email protected]
https://lists.connman.net/mailman/listinfo/connman