Skip to content

Commit

Permalink
mac80211: fix rx data handling for non-data frames on multiple vifs
Browse files Browse the repository at this point in the history
The loop that passes non-data frames to all relevant vifs inside the
__ieee80211_rx_handle_packet keeps a pointer to the previous sdata to
avoid having to make unnecessary copies of the frame it's handling.
This led to a bug that caused it to apply the ieee80211_rx_data state
to the wrong interface, thereby either missing the rx.sta pointer or
having it assigned where it shouldn't be.
This breaks (among other things) aggregation on some vifs, as action
frame exchages are dropped to the cooked monitor interface due to
rx->sta being NULL.
Fix this by restructuring the loop so that it prepares the rx data just
before making the skb copy and calling the rx handlers.

Cc: stable@kernel.org
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Felix Fietkau authored and John W. Linville committed Jan 22, 2010
1 parent 58da131 commit 4bb29f8
Showing 1 changed file with 28 additions and 17 deletions.
45 changes: 28 additions & 17 deletions net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2348,22 +2348,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;

rx.sta = sta_info_get(sdata, hdr->addr2);

rx.flags |= IEEE80211_RX_RA_MATCH;
prepares = prepare_for_handlers(sdata, &rx, hdr);

if (!prepares)
continue;

if (status->flag & RX_FLAG_MMIC_ERROR) {
rx.sdata = sdata;
if (rx.flags & IEEE80211_RX_RA_MATCH)
ieee80211_rx_michael_mic_report(hdr,
&rx);
continue;
}

/*
* frame is destined for this interface, but if it's
* not also for the previous one we handle that after
Expand All @@ -2375,6 +2359,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
continue;
}

rx.sta = sta_info_get(prev, hdr->addr2);

rx.flags |= IEEE80211_RX_RA_MATCH;
prepares = prepare_for_handlers(prev, &rx, hdr);

if (!prepares)
goto next;

if (status->flag & RX_FLAG_MMIC_ERROR) {
rx.sdata = prev;
if (rx.flags & IEEE80211_RX_RA_MATCH)
ieee80211_rx_michael_mic_report(hdr,
&rx);
goto next;
}

/*
* frame was destined for the previous interface
* so invoke RX handlers for it
Expand All @@ -2387,11 +2387,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
"multicast frame for %s\n",
wiphy_name(local->hw.wiphy),
prev->name);
continue;
goto next;
}
ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
next:
prev = sdata;
}

if (prev) {
rx.sta = sta_info_get(prev, hdr->addr2);

rx.flags |= IEEE80211_RX_RA_MATCH;
prepares = prepare_for_handlers(prev, &rx, hdr);

if (!prepares)
prev = NULL;
}
}
if (prev)
ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
Expand Down

0 comments on commit 4bb29f8

Please sign in to comment.