aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/driver-ops.h14
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/iface.c9
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/rx.c9
5 files changed, 26 insertions, 11 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d231c93..020a94a 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -12,7 +12,11 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
static inline int drv_start(struct ieee80211_local *local)
{
- int ret = local->ops->start(&local->hw);
+ int ret;
+
+ local->started = true;
+ smp_mb();
+ ret = local->ops->start(&local->hw);
trace_drv_start(local, ret);
return ret;
}
@@ -21,6 +25,14 @@ static inline void drv_stop(struct ieee80211_local *local)
{
local->ops->stop(&local->hw);
trace_drv_stop(local);
+
+ /* sync away all work on the tasklet before clearing started */
+ tasklet_disable(&local->tasklet);
+ tasklet_enable(&local->tasklet);
+
+ barrier();
+
+ local->started = false;
}
static inline int drv_add_interface(struct ieee80211_local *local,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index fa930e0..dbd8411 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -667,6 +667,9 @@ struct ieee80211_local {
*/
bool quiescing;
+ /* device is started */
+ bool started;
+
int tx_headroom; /* required headroom for hardware/radiotap */
/* Tasklet and skb queue to process calls from IRQ mode. All frames
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 5940e69..d134bd7 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -277,11 +277,6 @@ static int ieee80211_open(struct net_device *dev)
}
}
- if (local->open_count == 0) {
- tasklet_enable(&local->tx_pending_tasklet);
- tasklet_enable(&local->tasklet);
- }
-
/*
* set_multicast_list will be invoked by the networking core
* which will check whether any increments here were done in
@@ -552,11 +547,9 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) {
+ ieee80211_clear_tx_pending(local);
ieee80211_stop_device(local);
- tasklet_disable(&local->tx_pending_tasklet);
- tasklet_disable(&local->tasklet);
-
/* no reconfiguring after stop! */
hw_reconf_flags = 0;
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index dd3b081..797f539 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -715,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
skb_queue_head_init(&local->pending[i]);
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
(unsigned long)local);
- tasklet_disable(&local->tx_pending_tasklet);
tasklet_init(&local->tasklet,
ieee80211_tasklet_handler,
(unsigned long) local);
- tasklet_disable(&local->tasklet);
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index dff2239..b98f1af 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2471,6 +2471,15 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
return;
}
+ /*
+ * The same happens when we're not even started,
+ * but that's worth a warning.
+ */
+ if (WARN_ON(!local->started)) {
+ kfree_skb(skb);
+ return;
+ }
+
if (status->flag & RX_FLAG_HT) {
/* rate_idx is MCS index */
if (WARN_ON(status->rate_idx < 0 ||