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
connman@connman.net
https://lists.connman.net/mailman/listinfo/connman

Reply via email to