3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-26 10:39:23 +01:00

netdev: use l_idle_create for disconnect idle

The chances were extremely low, but using l_idle_oneshot
could end up causing a invalid memory access if the netdev
went down while waiting for the disconnect idle callback.

Instead netdev can keep track of the idle with l_idle_create
and remove it if the netdev goes down prior to the idle callback.
This commit is contained in:
James Prestwood 2021-04-06 09:58:26 -07:00 committed by Denis Kenzior
parent 51fc2453ba
commit 6c9f72380d

View File

@ -148,6 +148,8 @@ struct netdev {
void *get_station_data; void *get_station_data;
netdev_destroy_func_t get_station_destroy; netdev_destroy_func_t get_station_destroy;
struct l_idle *disconnect_idle;
struct watchlist station_watches; struct watchlist station_watches;
struct l_io *pae_io; /* for drivers without EAPoL over NL80211 */ struct l_io *pae_io; /* for drivers without EAPoL over NL80211 */
@ -811,6 +813,11 @@ static void netdev_free(void *data)
if (netdev->fw_roam_bss) if (netdev->fw_roam_bss)
scan_bss_free(netdev->fw_roam_bss); scan_bss_free(netdev->fw_roam_bss);
if (netdev->disconnect_idle) {
l_idle_remove(netdev->disconnect_idle);
netdev->disconnect_idle = NULL;
}
if (netdev->events_ready) if (netdev->events_ready)
WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t, WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
netdev, NETDEV_WATCH_EVENT_DEL); netdev, NETDEV_WATCH_EVENT_DEL);
@ -3182,10 +3189,13 @@ build_cmd_connect:
event_filter, cb, user_data); event_filter, cb, user_data);
} }
static void disconnect_idle(void *user_data) static void disconnect_idle(struct l_idle *idle, void *user_data)
{ {
struct netdev *netdev = user_data; struct netdev *netdev = user_data;
l_idle_remove(idle);
netdev->disconnect_idle = NULL;
netdev->disconnect_cb(netdev, true, netdev->user_data); netdev->disconnect_cb(netdev, true, netdev->user_data);
} }
@ -3249,8 +3259,8 @@ int netdev_disconnect(struct netdev *netdev,
} else if (cb) { } else if (cb) {
netdev->disconnect_cb = cb; netdev->disconnect_cb = cb;
netdev->user_data = user_data; netdev->user_data = user_data;
netdev->disconnect_idle = l_idle_create(disconnect_idle,
l_idle_oneshot(disconnect_idle, netdev, NULL); netdev, NULL);
} }
return 0; return 0;