3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-12-23 06:02:37 +01:00

scan: Cancel CMD_TRIGGER_SCAN when removing scan context

Save the ids of the netlink trigger scan commands that we send and
cancel them in scan_ifindex_remove to fix a race leading to a
segfault.  The segfault would happen every time if scan_ifindex_remove
was called in the same main loop iteration in which we sent the
command, on shutdown:

^CTerminate
src/netdev.c:netdev_free() Freeing netdev wlan3[6]
src/device.c:device_disassociated() 6
src/device.c:device_enter_state() Old State: connected, new state:
disconnected
src/device.c:device_enter_state() Old State: disconnected, new state:
autoconnect
src/scan.c:scan_periodic_start() Starting periodic scan for ifindex: 6
src/device.c:device_free()
src/device.c:bss_free() Freeing BSS 02:00:00:00:00:00
src/device.c:bss_free() Freeing BSS 02:00:00:00:01:00
Removing scan context for ifindex: 6
src/scan.c:scan_context_free() sc: 0x5555557ca290
src/scan.c:scan_notify() Scan notification 33
src/netdev.c:netdev_operstate_down_cb() netdev: 6, success: 1
src/scan.c:scan_periodic_done()
src/scan.c:scan_periodic_done() Periodic scan triggered for ifindex:
1434209520

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000064 in ?? ()
(gdb) bt
 #0  0x0000000000000064 in ?? ()
 #1  0x0000555555583560 in process_unicast (nlmsg=0x7fffffffc1a0,
     genl=0x5555557c1d60) at ell/genl.c:390
 #2  received_data (io=<optimized out>, user_data=0x5555557c1d60)
     at ell/genl.c:506
 #3  0x0000555555580d45 in io_callback (fd=<optimized out>,
     events=1, user_data=0x5555557c1e60) at ell/io.c:120
 #4  0x000055555558005f in l_main_run () at ell/main.c:381
 #5  0x00005555555599c1 in main (argc=<optimized out>, argv=<optimized out>)
     at src/main.c:259
This commit is contained in:
Andrew Zaborowski 2017-02-01 11:58:42 +01:00 committed by Denis Kenzior
parent 701e5dabb9
commit 4e9dc77b2d

View File

@ -74,6 +74,7 @@ struct scan_context {
enum scan_state state;
struct scan_periodic sp;
struct l_queue *requests;
unsigned int start_cmd_id;
};
struct scan_results {
@ -160,25 +161,27 @@ bool scan_ifindex_remove(uint32_t ifindex)
if (!sc)
return false;
if (sc->start_cmd_id)
l_genl_family_cancel(nl80211, sc->start_cmd_id);
l_info("Removing scan context for ifindex: %u", ifindex);
scan_context_free(sc);
return true;
}
static bool scan_send_start(struct l_genl_msg **msg,
static unsigned int scan_send_start(struct l_genl_msg **msg,
scan_func_t callback, void *user_data)
{
if (!l_genl_family_send(nl80211, *msg, callback,
user_data, NULL)) {
unsigned int id = l_genl_family_send(nl80211, *msg, callback,
user_data, NULL);
if (id)
*msg = NULL;
else
l_error("Sending NL80211_CMD_TRIGGER_SCAN failed");
return false;
}
*msg = NULL;
return true;
return id;
}
static void start_next_scan_request(void *userdata)
@ -195,7 +198,9 @@ static void start_next_scan_request(void *userdata)
sr = l_queue_peek_head(sc->requests);
if (!scan_send_start(&sr->start_cmd, scan_done, sc)) {
sc->start_cmd_id = scan_send_start(&sr->start_cmd, scan_done, sc);
if (!sc->start_cmd_id) {
if (sr->destroy)
sr->destroy(sr->userdata);
@ -216,6 +221,8 @@ static void scan_done(struct l_genl_msg *msg, void *userdata)
l_debug("");
sc->start_cmd_id = 0;
err = l_genl_msg_get_error(msg);
if (err < 0) {
/* Scan in progress, defer */
@ -352,7 +359,8 @@ static uint32_t scan_common(uint32_t ifindex, bool passive,
if (sc->state != SCAN_STATE_NOT_RUNNING)
goto done;
if (scan_send_start(&sr->start_cmd, scan_done, sc))
sc->start_cmd_id = scan_send_start(&sr->start_cmd, scan_done, sc);
if (!sc->start_cmd_id)
goto done;
error:
@ -457,6 +465,8 @@ static void scan_periodic_done(struct l_genl_msg *msg, void *user_data)
l_debug("");
sc->sp.rearm = true;
sc->start_cmd_id = 0;
err = l_genl_msg_get_error(msg);
if (err < 0) {
/* Scan already in progress */
@ -485,7 +495,8 @@ static bool scan_periodic_send_start(struct scan_context *sc)
if (!msg)
return false;
if (!scan_send_start(&msg, scan_periodic_done, sc)) {
sc->start_cmd_id = scan_send_start(&msg, scan_periodic_done, sc);
if (!sc->start_cmd_id) {
l_genl_msg_unref(msg);
return false;
}