aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@googlemail.com>2010-10-02 07:17:07 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-05 13:35:21 -0400
commit85416a4fa193754ef36e12b20bb02fe661cb7f17 (patch)
tree45228e888bd76a5f1251c55ea28377ddedfe2914 /net
parent5a254ffe3ffdfa84fe076009bd8e88da412180d2 (diff)
mac80211: fix rx monitor filter refcounters
This patch fixes an refcounting bug. Previously it was possible to corrupt the per-device recv. filter and monitor management counters when: iw dev wlanX set monitor [new flags] was issued on an active monitor interface. Acked-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c32
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/iface.c44
3 files changed, 54 insertions, 24 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c981604b71e6..9e63fc28f859 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -68,8 +68,36 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
68 params && params->use_4addr >= 0) 68 params && params->use_4addr >= 0)
69 sdata->u.mgd.use_4addr = params->use_4addr; 69 sdata->u.mgd.use_4addr = params->use_4addr;
70 70
71 if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) 71 if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
72 sdata->u.mntr_flags = *flags; 72 struct ieee80211_local *local = sdata->local;
73
74 if (ieee80211_sdata_running(sdata)) {
75 /*
76 * Prohibit MONITOR_FLAG_COOK_FRAMES to be
77 * changed while the interface is up.
78 * Else we would need to add a lot of cruft
79 * to update everything:
80 * cooked_mntrs, monitor and all fif_* counters
81 * reconfigure hardware
82 */
83 if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
84 (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
85 return -EBUSY;
86
87 ieee80211_adjust_monitor_flags(sdata, -1);
88 sdata->u.mntr_flags = *flags;
89 ieee80211_adjust_monitor_flags(sdata, 1);
90
91 ieee80211_configure_filter(local);
92 } else {
93 /*
94 * Because the interface is down, ieee80211_do_stop
95 * and ieee80211_do_open take care of "everything"
96 * mentioned in the comment above.
97 */
98 sdata->u.mntr_flags = *flags;
99 }
100 }
73 101
74 return 0; 102 return 0;
75} 103}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 945fbf29719d..f6a6d78efcf0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1132,6 +1132,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
1132void ieee80211_remove_interfaces(struct ieee80211_local *local); 1132void ieee80211_remove_interfaces(struct ieee80211_local *local);
1133u32 __ieee80211_recalc_idle(struct ieee80211_local *local); 1133u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
1134void ieee80211_recalc_idle(struct ieee80211_local *local); 1134void ieee80211_recalc_idle(struct ieee80211_local *local);
1135void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
1136 const int offset);
1135 1137
1136static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) 1138static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
1137{ 1139{
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 66785739dad3..1300e8859ea7 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -148,6 +148,26 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
148 return 0; 148 return 0;
149} 149}
150 150
151void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
152 const int offset)
153{
154 struct ieee80211_local *local = sdata->local;
155 u32 flags = sdata->u.mntr_flags;
156
157#define ADJUST(_f, _s) do { \
158 if (flags & MONITOR_FLAG_##_f) \
159 local->fif_##_s += offset; \
160 } while (0)
161
162 ADJUST(FCSFAIL, fcsfail);
163 ADJUST(PLCPFAIL, plcpfail);
164 ADJUST(CONTROL, control);
165 ADJUST(CONTROL, pspoll);
166 ADJUST(OTHER_BSS, other_bss);
167
168#undef ADJUST
169}
170
151/* 171/*
152 * NOTE: Be very careful when changing this function, it must NOT return 172 * NOTE: Be very careful when changing this function, it must NOT return
153 * an error on interface type changes that have been pre-checked, so most 173 * an error on interface type changes that have been pre-checked, so most
@@ -240,17 +260,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
240 hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; 260 hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
241 } 261 }
242 262
243 if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) 263 ieee80211_adjust_monitor_flags(sdata, 1);
244 local->fif_fcsfail++;
245 if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
246 local->fif_plcpfail++;
247 if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
248 local->fif_control++;
249 local->fif_pspoll++;
250 }
251 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
252 local->fif_other_bss++;
253
254 ieee80211_configure_filter(local); 264 ieee80211_configure_filter(local);
255 265
256 netif_carrier_on(dev); 266 netif_carrier_on(dev);
@@ -477,17 +487,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
477 hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; 487 hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
478 } 488 }
479 489
480 if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) 490 ieee80211_adjust_monitor_flags(sdata, -1);
481 local->fif_fcsfail--;
482 if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
483 local->fif_plcpfail--;
484 if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
485 local->fif_pspoll--;
486 local->fif_control--;
487 }
488 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
489 local->fif_other_bss--;
490
491 ieee80211_configure_filter(local); 491 ieee80211_configure_filter(local);
492 break; 492 break;
493 case NL80211_IFTYPE_MESH_POINT: 493 case NL80211_IFTYPE_MESH_POINT: