frame-xchg: Cancel NL80211_CMD_FRAME commands when interrupted

The callback for the FRAME command was causing a crash in
wiphy_radio_work_done when not cancelled when the wiphy was being
removed from the system.  This was likely to happen if this radio work
item was waiting for another item to finish.  When the first one was
being cancelled due to the wiphy being removed, this one would be
started and immediately stopped by the radio work queue.

Now this crash could be fixed by dropping all frame exchange instances
on an interface that is being removed which is easy to do, but properly
cancelling the commands saves us the headache of analysing whether
there's a race condition in other situations where a frame exchange is
being aborted.
This commit is contained in:
Andrew Zaborowski 2020-09-29 18:37:05 +02:00 committed by Denis Kenzior
parent 3de345e903
commit fab764967b
1 changed files with 14 additions and 3 deletions

View File

@ -116,6 +116,7 @@ struct frame_xchg_data {
unsigned int retries_on_ack;
struct wiphy_radio_work_item work;
bool no_cck_rates;
unsigned int tx_cmd_id;
};
struct frame_xchg_watch_data {
@ -772,6 +773,9 @@ static void frame_xchg_reset(struct frame_xchg_data *fx)
if (fx->timeout)
l_timeout_remove(fx->timeout);
if (fx->tx_cmd_id)
l_genl_family_cancel(nl80211, fx->tx_cmd_id);
l_free(fx->early_frame.mpdu);
fx->early_frame.mpdu = NULL;
l_queue_destroy(fx->rx_watches, l_free);
@ -930,12 +934,18 @@ error:
frame_xchg_done(fx, error);
}
static void frame_xchg_tx_destroy(void *user_data)
{
struct frame_xchg_data *fx = user_data;
fx->tx_cmd_id = 0;
}
static bool frame_xchg_tx_retry(struct wiphy_radio_work_item *item)
{
struct frame_xchg_data *fx = l_container_of(item,
struct frame_xchg_data, work);
struct l_genl_msg *msg;
uint32_t cmd_id;
uint32_t duration = fx->resp_timeout;
/*
@ -963,8 +973,9 @@ static bool frame_xchg_tx_retry(struct wiphy_radio_work_item *item)
l_genl_msg_append_attr(msg, NL80211_ATTR_DURATION, 4,
&duration);
cmd_id = l_genl_family_send(nl80211, msg, frame_xchg_tx_cb, fx, NULL);
if (!cmd_id) {
fx->tx_cmd_id = l_genl_family_send(nl80211, msg, frame_xchg_tx_cb, fx,
frame_xchg_tx_destroy);
if (!fx->tx_cmd_id) {
l_error("Error sending frame");
l_genl_msg_unref(msg);
frame_xchg_done(fx, -EIO);