mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
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>
This commit is contained in:
parent
5a254ffe3f
commit
85416a4fa1
@ -68,8 +68,36 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
||||
params && params->use_4addr >= 0)
|
||||
sdata->u.mgd.use_4addr = params->use_4addr;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
|
||||
sdata->u.mntr_flags = *flags;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (ieee80211_sdata_running(sdata)) {
|
||||
/*
|
||||
* Prohibit MONITOR_FLAG_COOK_FRAMES to be
|
||||
* changed while the interface is up.
|
||||
* Else we would need to add a lot of cruft
|
||||
* to update everything:
|
||||
* cooked_mntrs, monitor and all fif_* counters
|
||||
* reconfigure hardware
|
||||
*/
|
||||
if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
|
||||
(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
|
||||
return -EBUSY;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
sdata->u.mntr_flags = *flags;
|
||||
ieee80211_adjust_monitor_flags(sdata, 1);
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
} else {
|
||||
/*
|
||||
* Because the interface is down, ieee80211_do_stop
|
||||
* and ieee80211_do_open take care of "everything"
|
||||
* mentioned in the comment above.
|
||||
*/
|
||||
sdata->u.mntr_flags = *flags;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1132,6 +1132,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_remove_interfaces(struct ieee80211_local *local);
|
||||
u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
|
||||
const int offset);
|
||||
|
||||
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
|
@ -148,6 +148,26 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
|
||||
const int offset)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
u32 flags = sdata->u.mntr_flags;
|
||||
|
||||
#define ADJUST(_f, _s) do { \
|
||||
if (flags & MONITOR_FLAG_##_f) \
|
||||
local->fif_##_s += offset; \
|
||||
} while (0)
|
||||
|
||||
ADJUST(FCSFAIL, fcsfail);
|
||||
ADJUST(PLCPFAIL, plcpfail);
|
||||
ADJUST(CONTROL, control);
|
||||
ADJUST(CONTROL, pspoll);
|
||||
ADJUST(OTHER_BSS, other_bss);
|
||||
|
||||
#undef ADJUST
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: Be very careful when changing this function, it must NOT return
|
||||
* 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)
|
||||
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
|
||||
}
|
||||
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
|
||||
local->fif_fcsfail++;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
|
||||
local->fif_plcpfail++;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
|
||||
local->fif_control++;
|
||||
local->fif_pspoll++;
|
||||
}
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
||||
local->fif_other_bss++;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, 1);
|
||||
ieee80211_configure_filter(local);
|
||||
|
||||
netif_carrier_on(dev);
|
||||
@ -477,17 +487,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
|
||||
}
|
||||
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
|
||||
local->fif_fcsfail--;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
|
||||
local->fif_plcpfail--;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
|
||||
local->fif_pspoll--;
|
||||
local->fif_control--;
|
||||
}
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
||||
local->fif_other_bss--;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
ieee80211_configure_filter(local);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
|
Loading…
Reference in New Issue
Block a user