diff options
author | Eliad Peller <eliad@wizery.com> | 2015-10-25 04:59:36 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-11-03 04:41:12 -0500 |
commit | 968a76cef3d1bb9a3b4d135cd788056e742859f3 (patch) | |
tree | dfe73df7dae4879fe96b045cdffc0d2d64e829be | |
parent | c189a685b83955a39884dc2bdae531bc0adf3b98 (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.c | 44 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 32 | ||||
-rw-r--r-- | net/mac80211/util.c | 3 |
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 | ||
13 | int 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 | |||
35 | void 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 | |||
11 | int drv_add_interface(struct ieee80211_local *local, | 55 | int 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 | ||
69 | static inline int drv_start(struct ieee80211_local *local) | 69 | int drv_start(struct ieee80211_local *local); |
70 | { | 70 | void 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 | |||
83 | static 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 |
101 | static inline int drv_suspend(struct ieee80211_local *local, | 73 | static 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 |