Commit 19d19e96 authored by Johannes Berg's avatar Johannes Berg

mac80211: use driver-indicated transmitter STA only for data frames

When I originally introduced using the driver-indicated station as an
optimisation to avoid the hashtable lookup/iteration, of course it
wasn't intended to really functionally change anything.

I neglected, however, to take into account VLAN interfaces, which have
the property that management and data frames are handled differently:
data frames go directly to the station and the VLAN while management
frames continue to be processed over the underlying/associated AP-type
interface. As a consequence, when a driver used this optimisation for
management frames and the user enabled VLANs, my change broke things
since any management frames, particularly disassoc/deauth, were missed
by hostapd.

Fix this by restoring the original code path for non-data frames, they
aren't critical for performance to begin with.

This fixes https://bugzilla.kernel.org/show_bug.cgi?id=194713.

Big thanks goes to Jarek who bisected the issue and provided a very
detailed bug report, including the crucial information that he was
using VLANs in his configuration.

Cc: stable@vger.kernel.org
Fixes: 771e846bea9e ("mac80211: allow passing transmitter station on RX")
Reported-and-tested-by: default avatarJarek Kamiński <jarek@freeside.be>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ff4dd73d
...@@ -4086,15 +4086,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ...@@ -4086,15 +4086,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
ieee80211_is_beacon(hdr->frame_control))) ieee80211_is_beacon(hdr->frame_control)))
ieee80211_scan_rx(local, skb); ieee80211_scan_rx(local, skb);
if (pubsta) { if (ieee80211_is_data(fc)) {
rx.sta = container_of(pubsta, struct sta_info, sta);
rx.sdata = rx.sta->sdata;
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
return;
goto out;
} else if (ieee80211_is_data(fc)) {
struct sta_info *sta, *prev_sta; struct sta_info *sta, *prev_sta;
if (pubsta) {
rx.sta = container_of(pubsta, struct sta_info, sta);
rx.sdata = rx.sta->sdata;
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
return;
goto out;
}
prev_sta = NULL; prev_sta = NULL;
for_each_sta_info(local, hdr->addr2, sta, tmp) { for_each_sta_info(local, hdr->addr2, sta, tmp) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment