|
@@ -297,10 +297,13 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
|
|
|
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free)
|
|
|
{
|
|
|
struct ieee80211_roc_work *dep, *tmp;
|
|
|
|
|
|
+ if (WARN_ON(roc->to_be_freed))
|
|
|
+ return;
|
|
|
+
|
|
|
/* was never transmitted */
|
|
|
if (roc->frame) {
|
|
|
cfg80211_mgmt_tx_status(&roc->sdata->wdev,
|
|
@@ -316,9 +319,12 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
|
|
|
GFP_KERNEL);
|
|
|
|
|
|
list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
|
|
|
- ieee80211_roc_notify_destroy(dep);
|
|
|
+ ieee80211_roc_notify_destroy(dep, true);
|
|
|
|
|
|
- kfree(roc);
|
|
|
+ if (free)
|
|
|
+ kfree(roc);
|
|
|
+ else
|
|
|
+ roc->to_be_freed = true;
|
|
|
}
|
|
|
|
|
|
void ieee80211_sw_roc_work(struct work_struct *work)
|
|
@@ -331,6 +337,9 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
|
|
|
|
|
mutex_lock(&local->mtx);
|
|
|
|
|
|
+ if (roc->to_be_freed)
|
|
|
+ goto out_unlock;
|
|
|
+
|
|
|
if (roc->abort)
|
|
|
goto finish;
|
|
|
|
|
@@ -370,7 +379,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
|
|
finish:
|
|
|
list_del(&roc->list);
|
|
|
started = roc->started;
|
|
|
- ieee80211_roc_notify_destroy(roc);
|
|
|
+ ieee80211_roc_notify_destroy(roc, !roc->abort);
|
|
|
|
|
|
if (started) {
|
|
|
drv_flush(local, false);
|
|
@@ -410,7 +419,7 @@ static void ieee80211_hw_roc_done(struct work_struct *work)
|
|
|
|
|
|
list_del(&roc->list);
|
|
|
|
|
|
- ieee80211_roc_notify_destroy(roc);
|
|
|
+ ieee80211_roc_notify_destroy(roc, true);
|
|
|
|
|
|
/* if there's another roc, start it now */
|
|
|
ieee80211_start_next_roc(local);
|
|
@@ -460,12 +469,14 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
|
|
|
list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
|
|
|
if (local->ops->remain_on_channel) {
|
|
|
list_del(&roc->list);
|
|
|
- ieee80211_roc_notify_destroy(roc);
|
|
|
+ ieee80211_roc_notify_destroy(roc, true);
|
|
|
} else {
|
|
|
ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
|
|
|
|
|
|
/* work will clean up etc */
|
|
|
flush_delayed_work(&roc->work);
|
|
|
+ WARN_ON(!roc->to_be_freed);
|
|
|
+ kfree(roc);
|
|
|
}
|
|
|
}
|
|
|
|