aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2015-10-25 04:59:36 -0400
committerJohannes Berg <johannes.berg@intel.com>2015-11-03 04:41:12 -0500
commit968a76cef3d1bb9a3b4d135cd788056e742859f3 (patch)
treedfe73df7dae4879fe96b045cdffc0d2d64e829be
parentc189a685b83955a39884dc2bdae531bc0adf3b98 (diff)
mac80211: call drv_stop only if driver is started
If drv_start() fails during hw_restart, all the running interfaces are being closed/stopped, which results in drv_stop() being called, although the driver was never started successfully. This might cause drivers to perform operations on uninitialized memory (as they assume it was initialized on drv_start) Consider the local->started flag, and call the driver's stop() op only if drv_start() succeeded before. Move drv_start() and drv_stop() to driver-ops.c, as they are no longer simple wrappers. Signed-off-by: Eliad Peller <eliadx.peller@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/driver-ops.c44
-rw-r--r--net/mac80211/driver-ops.h32
-rw-r--r--net/mac80211/util.c3
3 files changed, 48 insertions, 31 deletions
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
index a1d54318f16c..9f97343f13fd 100644
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -1,4 +1,6 @@
1/* 1/*
2 * Copyright 2015 Intel Deutschland GmbH
3 *
2 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
@@ -8,6 +10,48 @@
8#include "trace.h" 10#include "trace.h"
9#include "driver-ops.h" 11#include "driver-ops.h"
10 12
13int drv_start(struct ieee80211_local *local)
14{
15 int ret;
16
17 might_sleep();
18
19 if (WARN_ON(local->started))
20 return -EALREADY;
21
22 trace_drv_start(local);
23 local->started = true;
24 /* allow rx frames */
25 smp_mb();
26 ret = local->ops->start(&local->hw);
27 trace_drv_return_int(local, ret);
28
29 if (ret)
30 local->started = false;
31
32 return ret;
33}
34
35void drv_stop(struct ieee80211_local *local)
36{
37 might_sleep();
38
39 if (WARN_ON(!local->started))
40 return;
41
42 trace_drv_stop(local);
43 local->ops->stop(&local->hw);
44 trace_drv_return_void(local);
45
46 /* sync away all work on the tasklet before clearing started */
47 tasklet_disable(&local->tasklet);
48 tasklet_enable(&local->tasklet);
49
50 barrier();
51
52 local->started = false;
53}
54
11int drv_add_interface(struct ieee80211_local *local, 55int drv_add_interface(struct ieee80211_local *local,
12 struct ieee80211_sub_if_data *sdata) 56 struct ieee80211_sub_if_data *sdata)
13{ 57{
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 30987099eb8f..f82cfab615f2 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -66,36 +66,8 @@ static inline int drv_get_et_sset_count(struct ieee80211_sub_if_data *sdata,
66 return rv; 66 return rv;
67} 67}
68 68
69static inline int drv_start(struct ieee80211_local *local) 69int drv_start(struct ieee80211_local *local);
70{ 70void drv_stop(struct ieee80211_local *local);
71 int ret;
72
73 might_sleep();
74
75 trace_drv_start(local);
76 local->started = true;
77 smp_mb();
78 ret = local->ops->start(&local->hw);
79 trace_drv_return_int(local, ret);
80 return ret;
81}
82
83static inline void drv_stop(struct ieee80211_local *local)
84{
85 might_sleep();
86
87 trace_drv_stop(local);
88 local->ops->stop(&local->hw);
89 trace_drv_return_void(local);
90
91 /* sync away all work on the tasklet before clearing started */
92 tasklet_disable(&local->tasklet);
93 tasklet_enable(&local->tasklet);
94
95 barrier();
96
97 local->started = false;
98}
99 71
100#ifdef CONFIG_PM 72#ifdef CONFIG_PM
101static inline int drv_suspend(struct ieee80211_local *local, 73static inline int drv_suspend(struct ieee80211_local *local,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index b0e3a4248bd5..551164dabbaf 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1665,7 +1665,6 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
1665 1665
1666 local->resuming = false; 1666 local->resuming = false;
1667 local->suspended = false; 1667 local->suspended = false;
1668 local->started = false;
1669 local->in_reconfig = false; 1668 local->in_reconfig = false;
1670 1669
1671 /* scheduled scan clearly can't be running any more, but tell 1670 /* scheduled scan clearly can't be running any more, but tell
@@ -1764,6 +1763,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1764 if (suspended && local->in_reconfig && !reconfig_due_to_wowlan) 1763 if (suspended && local->in_reconfig && !reconfig_due_to_wowlan)
1765 cancel_work_sync(&local->restart_work); 1764 cancel_work_sync(&local->restart_work);
1766 1765
1766 local->started = false;
1767
1767 /* 1768 /*
1768 * Upon resume hardware can sometimes be goofy due to 1769 * Upon resume hardware can sometimes be goofy due to
1769 * various platform / driver / bus issues, so restarting 1770 * various platform / driver / bus issues, so restarting