|
@@ -315,6 +315,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
|
|
static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
|
|
{
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
int tid;
|
|
|
|
|
|
/* does the frame have a qos control field? */
|
|
@@ -323,9 +324,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
|
|
/* frame has qos control */
|
|
|
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
|
|
|
- rx->flags |= IEEE80211_RX_AMSDU;
|
|
|
- else
|
|
|
- rx->flags &= ~IEEE80211_RX_AMSDU;
|
|
|
+ status->rx_flags |= IEEE80211_RX_AMSDU;
|
|
|
} else {
|
|
|
/*
|
|
|
* IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
|
|
@@ -387,26 +386,25 @@ static ieee80211_rx_result debug_noinline
|
|
|
ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
|
|
|
{
|
|
|
struct ieee80211_local *local = rx->local;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
struct sk_buff *skb = rx->skb;
|
|
|
|
|
|
- if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning)))
|
|
|
+ if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
|
|
|
+ return RX_CONTINUE;
|
|
|
+
|
|
|
+ if (test_bit(SCAN_HW_SCANNING, &local->scanning))
|
|
|
return ieee80211_scan_rx(rx->sdata, skb);
|
|
|
|
|
|
- if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) &&
|
|
|
- (rx->flags & IEEE80211_RX_IN_SCAN))) {
|
|
|
+ if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
|
|
|
/* drop all the other packets during a software scan anyway */
|
|
|
if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
|
|
|
dev_kfree_skb(skb);
|
|
|
return RX_QUEUED;
|
|
|
}
|
|
|
|
|
|
- if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) {
|
|
|
- /* scanning finished during invoking of handlers */
|
|
|
- I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
|
|
|
- return RX_DROP_UNUSABLE;
|
|
|
- }
|
|
|
-
|
|
|
- return RX_CONTINUE;
|
|
|
+ /* scanning finished during invoking of handlers */
|
|
|
+ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
|
|
|
+ return RX_DROP_UNUSABLE;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -785,13 +783,14 @@ static ieee80211_rx_result debug_noinline
|
|
|
ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
|
|
{
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
|
|
|
if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
|
|
|
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
|
|
|
rx->sta->last_seq_ctrl[rx->queue] ==
|
|
|
hdr->seq_ctrl)) {
|
|
|
- if (rx->flags & IEEE80211_RX_RA_MATCH) {
|
|
|
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
|
|
|
rx->local->dot11FrameDuplicateCount++;
|
|
|
rx->sta->num_duplicates++;
|
|
|
}
|
|
@@ -824,7 +823,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
|
|
if ((!ieee80211_has_fromds(hdr->frame_control) &&
|
|
|
!ieee80211_has_tods(hdr->frame_control) &&
|
|
|
ieee80211_is_data(hdr->frame_control)) ||
|
|
|
- !(rx->flags & IEEE80211_RX_RA_MATCH)) {
|
|
|
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH)) {
|
|
|
/* Drop IBSS frames and frames for other hosts
|
|
|
* silently. */
|
|
|
return RX_DROP_MONITOR;
|
|
@@ -881,7 +880,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|
|
* No point in finding a key and decrypting if the frame is neither
|
|
|
* addressed to us nor a multicast frame.
|
|
|
*/
|
|
|
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
|
|
return RX_CONTINUE;
|
|
|
|
|
|
/* start without a key */
|
|
@@ -1114,7 +1113,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
|
|
sta->last_rx = jiffies;
|
|
|
}
|
|
|
|
|
|
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
|
|
return RX_CONTINUE;
|
|
|
|
|
|
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
|
|
@@ -1271,6 +1270,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
|
|
unsigned int frag, seq;
|
|
|
struct ieee80211_fragment_entry *entry;
|
|
|
struct sk_buff *skb;
|
|
|
+ struct ieee80211_rx_status *status;
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *)rx->skb->data;
|
|
|
fc = hdr->frame_control;
|
|
@@ -1370,7 +1370,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
|
|
}
|
|
|
|
|
|
/* Complete frame has been reassembled - process it now */
|
|
|
- rx->flags |= IEEE80211_RX_FRAGMENTED;
|
|
|
+ status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
+ status->rx_flags |= IEEE80211_RX_FRAGMENTED;
|
|
|
|
|
|
out:
|
|
|
if (rx->sta)
|
|
@@ -1387,9 +1388,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
|
|
|
{
|
|
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
|
|
__le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
|
|
|
- !(rx->flags & IEEE80211_RX_RA_MATCH)))
|
|
|
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH)))
|
|
|
return RX_CONTINUE;
|
|
|
|
|
|
if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
|
|
@@ -1550,6 +1552,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
|
|
struct sk_buff *skb, *xmit_skb;
|
|
|
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
|
|
|
struct sta_info *dsta;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
skb = rx->skb;
|
|
|
xmit_skb = NULL;
|
|
@@ -1557,7 +1560,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
|
|
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
|
|
|
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
|
|
|
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
|
|
|
- (rx->flags & IEEE80211_RX_RA_MATCH) &&
|
|
|
+ (status->rx_flags & IEEE80211_RX_RA_MATCH) &&
|
|
|
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
|
|
|
if (is_multicast_ether_addr(ehdr->h_dest)) {
|
|
|
/*
|
|
@@ -1634,6 +1637,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
__le16 fc = hdr->frame_control;
|
|
|
struct sk_buff_head frame_list;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
if (unlikely(!ieee80211_is_data(fc)))
|
|
|
return RX_CONTINUE;
|
|
@@ -1641,7 +1645,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
|
|
if (unlikely(!ieee80211_is_data_present(fc)))
|
|
|
return RX_DROP_MONITOR;
|
|
|
|
|
|
- if (!(rx->flags & IEEE80211_RX_AMSDU))
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_AMSDU))
|
|
|
return RX_CONTINUE;
|
|
|
|
|
|
if (ieee80211_has_a4(hdr->frame_control) &&
|
|
@@ -1692,6 +1696,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
|
|
struct sk_buff *skb = rx->skb, *fwd_skb;
|
|
|
struct ieee80211_local *local = rx->local;
|
|
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *) skb->data;
|
|
|
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
|
@@ -1737,7 +1742,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
|
|
|
|
|
mesh_hdr->ttl--;
|
|
|
|
|
|
- if (rx->flags & IEEE80211_RX_RA_MATCH) {
|
|
|
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
|
|
|
if (!mesh_hdr->ttl)
|
|
|
IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
|
|
|
dropped_frames_ttl);
|
|
@@ -1947,6 +1952,7 @@ static ieee80211_rx_result debug_noinline
|
|
|
ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
|
|
|
{
|
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
/*
|
|
|
* From here on, look only at management frames.
|
|
@@ -1959,7 +1965,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
|
|
|
if (!ieee80211_is_mgmt(mgmt->frame_control))
|
|
|
return RX_DROP_MONITOR;
|
|
|
|
|
|
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
|
|
return RX_DROP_MONITOR;
|
|
|
|
|
|
if (ieee80211_drop_unencrypted_mgmt(rx))
|
|
@@ -1974,6 +1980,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|
|
struct ieee80211_local *local = rx->local;
|
|
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
int len = rx->skb->len;
|
|
|
|
|
|
if (!ieee80211_is_action(mgmt->frame_control))
|
|
@@ -1986,7 +1993,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|
|
if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
|
|
|
return RX_DROP_UNUSABLE;
|
|
|
|
|
|
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
|
|
return RX_DROP_UNUSABLE;
|
|
|
|
|
|
switch (mgmt->u.action.category) {
|
|
@@ -2082,7 +2089,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|
|
return RX_CONTINUE;
|
|
|
|
|
|
invalid:
|
|
|
- rx->flags |= IEEE80211_MALFORMED_ACTION_FRM;
|
|
|
+ status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM;
|
|
|
/* will return in the next handlers */
|
|
|
return RX_CONTINUE;
|
|
|
|
|
@@ -2104,10 +2111,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|
|
static ieee80211_rx_result debug_noinline
|
|
|
ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
|
|
|
{
|
|
|
- struct ieee80211_rx_status *status;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
/* skip known-bad action frames and return them in the next handler */
|
|
|
- if (rx->flags & IEEE80211_MALFORMED_ACTION_FRM)
|
|
|
+ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
|
|
|
return RX_CONTINUE;
|
|
|
|
|
|
/*
|
|
@@ -2116,7 +2123,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
|
|
|
* so userspace can register for those to know whether ones
|
|
|
* it transmitted were processed or returned.
|
|
|
*/
|
|
|
- status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
|
|
|
rx->skb->data, rx->skb->len,
|
|
@@ -2138,6 +2144,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
|
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
|
|
|
struct sk_buff *nskb;
|
|
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
|
|
|
|
|
if (!ieee80211_is_action(mgmt->frame_control))
|
|
|
return RX_CONTINUE;
|
|
@@ -2152,7 +2159,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
|
|
|
* registration mechanisms, but older ones still use cooked
|
|
|
* monitor interfaces so push all frames there.
|
|
|
*/
|
|
|
- if (!(rx->flags & IEEE80211_MALFORMED_ACTION_FRM) &&
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
|
|
|
(sdata->vif.type == NL80211_IFTYPE_AP ||
|
|
|
sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
|
|
|
return RX_DROP_MONITOR;
|
|
@@ -2286,8 +2293,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
|
|
|
struct net_device *prev_dev = NULL;
|
|
|
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
|
|
|
|
|
- if (status->flag & RX_FLAG_INTERNAL_CMTR)
|
|
|
+ /*
|
|
|
+ * If cooked monitor has been processed already, then
|
|
|
+ * don't do it again. If not, set the flag.
|
|
|
+ */
|
|
|
+ if (rx->flags & IEEE80211_RX_CMNTR)
|
|
|
goto out_free_skb;
|
|
|
+ rx->flags |= IEEE80211_RX_CMNTR;
|
|
|
|
|
|
if (skb_headroom(skb) < sizeof(*rthdr) &&
|
|
|
pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
|
|
@@ -2343,12 +2355,8 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
|
|
|
if (prev_dev) {
|
|
|
skb->dev = prev_dev;
|
|
|
netif_receive_skb(skb);
|
|
|
- skb = NULL;
|
|
|
- } else
|
|
|
- goto out_free_skb;
|
|
|
-
|
|
|
- status->flag |= RX_FLAG_INTERNAL_CMTR;
|
|
|
- return;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
out_free_skb:
|
|
|
dev_kfree_skb(skb);
|
|
@@ -2409,6 +2417,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
|
|
|
* same TID from the same station
|
|
|
*/
|
|
|
rx->skb = skb;
|
|
|
+ rx->flags = 0;
|
|
|
|
|
|
CALL_RXH(ieee80211_rx_h_decrypt)
|
|
|
CALL_RXH(ieee80211_rx_h_check_more_data)
|
|
@@ -2443,18 +2452,13 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
- struct ieee80211_rx_data *rx,
|
|
|
- struct sk_buff *skb)
|
|
|
+static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
|
|
|
{
|
|
|
struct sk_buff_head reorder_release;
|
|
|
ieee80211_rx_result res = RX_DROP_MONITOR;
|
|
|
|
|
|
__skb_queue_head_init(&reorder_release);
|
|
|
|
|
|
- rx->skb = skb;
|
|
|
- rx->sdata = sdata;
|
|
|
-
|
|
|
#define CALL_RXH(rxh) \
|
|
|
do { \
|
|
|
res = rxh(rx); \
|
|
@@ -2484,7 +2488,12 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
|
|
{
|
|
|
struct sk_buff_head frames;
|
|
|
- struct ieee80211_rx_data rx = { };
|
|
|
+ struct ieee80211_rx_data rx = {
|
|
|
+ .sta = sta,
|
|
|
+ .sdata = sta->sdata,
|
|
|
+ .local = sta->local,
|
|
|
+ .queue = tid,
|
|
|
+ };
|
|
|
struct tid_ampdu_rx *tid_agg_rx;
|
|
|
|
|
|
tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
|
|
@@ -2493,17 +2502,6 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
|
|
|
|
|
__skb_queue_head_init(&frames);
|
|
|
|
|
|
- /* construct rx struct */
|
|
|
- rx.sta = sta;
|
|
|
- rx.sdata = sta->sdata;
|
|
|
- rx.local = sta->local;
|
|
|
- rx.queue = tid;
|
|
|
- rx.flags |= IEEE80211_RX_RA_MATCH;
|
|
|
-
|
|
|
- if (unlikely(test_bit(SCAN_HW_SCANNING, &sta->local->scanning) ||
|
|
|
- test_bit(SCAN_OFF_CHANNEL, &sta->local->scanning)))
|
|
|
- rx.flags |= IEEE80211_RX_IN_SCAN;
|
|
|
-
|
|
|
spin_lock(&tid_agg_rx->reorder_lock);
|
|
|
ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames);
|
|
|
spin_unlock(&tid_agg_rx->reorder_lock);
|
|
@@ -2513,10 +2511,10 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
|
|
|
|
|
/* main receive path */
|
|
|
|
|
|
-static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
- struct ieee80211_rx_data *rx,
|
|
|
+static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
|
|
struct ieee80211_hdr *hdr)
|
|
|
{
|
|
|
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
|
|
|
struct sk_buff *skb = rx->skb;
|
|
|
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
|
|
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
|
|
@@ -2530,7 +2528,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
|
|
|
if (!(sdata->dev->flags & IFF_PROMISC))
|
|
|
return 0;
|
|
|
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
}
|
|
|
break;
|
|
|
case NL80211_IFTYPE_ADHOC:
|
|
@@ -2540,15 +2538,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
return 1;
|
|
|
}
|
|
|
else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
|
|
|
- if (!(rx->flags & IEEE80211_RX_IN_SCAN))
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
|
|
|
return 0;
|
|
|
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
} else if (!multicast &&
|
|
|
compare_ether_addr(sdata->vif.addr,
|
|
|
hdr->addr1) != 0) {
|
|
|
if (!(sdata->dev->flags & IFF_PROMISC))
|
|
|
return 0;
|
|
|
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
} else if (!rx->sta) {
|
|
|
int rate_idx;
|
|
|
if (status->flag & RX_FLAG_HT)
|
|
@@ -2566,7 +2564,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
if (!(sdata->dev->flags & IFF_PROMISC))
|
|
|
return 0;
|
|
|
|
|
|
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
}
|
|
|
break;
|
|
|
case NL80211_IFTYPE_AP_VLAN:
|
|
@@ -2577,9 +2575,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
return 0;
|
|
|
} else if (!ieee80211_bssid_match(bssid,
|
|
|
sdata->vif.addr)) {
|
|
|
- if (!(rx->flags & IEEE80211_RX_IN_SCAN))
|
|
|
+ if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
|
|
|
return 0;
|
|
|
- rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
|
|
}
|
|
|
break;
|
|
|
case NL80211_IFTYPE_WDS:
|
|
@@ -2597,6 +2595,51 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This function returns whether or not the SKB
|
|
|
+ * was destined for RX processing or not, which,
|
|
|
+ * if consume is true, is equivalent to whether
|
|
|
+ * or not the skb was consumed.
|
|
|
+ */
|
|
|
+static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
|
|
+ struct sk_buff *skb, bool consume)
|
|
|
+{
|
|
|
+ struct ieee80211_local *local = rx->local;
|
|
|
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
|
|
|
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
|
|
+ struct ieee80211_hdr *hdr = (void *)skb->data;
|
|
|
+ int prepares;
|
|
|
+
|
|
|
+ rx->skb = skb;
|
|
|
+ status->rx_flags |= IEEE80211_RX_RA_MATCH;
|
|
|
+ prepares = prepare_for_handlers(rx, hdr);
|
|
|
+
|
|
|
+ if (!prepares)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (status->flag & RX_FLAG_MMIC_ERROR) {
|
|
|
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH)
|
|
|
+ ieee80211_rx_michael_mic_report(hdr, rx);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!consume) {
|
|
|
+ skb = skb_copy(skb, GFP_ATOMIC);
|
|
|
+ if (!skb) {
|
|
|
+ if (net_ratelimit())
|
|
|
+ wiphy_debug(local->hw.wiphy,
|
|
|
+ "failed to copy multicast frame for %s\n",
|
|
|
+ sdata->name);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ rx->skb = skb;
|
|
|
+ }
|
|
|
+
|
|
|
+ ieee80211_invoke_rx_handlers(rx);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This is the actual Rx frames handler. as it blongs to Rx path it must
|
|
|
* be called with rcu_read_lock protection.
|
|
@@ -2610,11 +2653,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_hdr *hdr;
|
|
|
__le16 fc;
|
|
|
struct ieee80211_rx_data rx;
|
|
|
- int prepares;
|
|
|
- struct ieee80211_sub_if_data *prev = NULL;
|
|
|
- struct sk_buff *skb_new;
|
|
|
- struct sta_info *sta, *tmp;
|
|
|
- bool found_sta = false;
|
|
|
+ struct ieee80211_sub_if_data *prev;
|
|
|
+ struct sta_info *sta, *tmp, *prev_sta;
|
|
|
int err = 0;
|
|
|
|
|
|
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
|
|
@@ -2627,7 +2667,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|
|
|
|
|
if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
|
|
|
test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
|
|
|
- rx.flags |= IEEE80211_RX_IN_SCAN;
|
|
|
+ status->rx_flags |= IEEE80211_RX_IN_SCAN;
|
|
|
|
|
|
if (ieee80211_is_mgmt(fc))
|
|
|
err = skb_linearize(skb);
|
|
@@ -2644,90 +2684,67 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|
|
ieee80211_verify_alignment(&rx);
|
|
|
|
|
|
if (ieee80211_is_data(fc)) {
|
|
|
+ prev_sta = NULL;
|
|
|
+
|
|
|
for_each_sta_info(local, hdr->addr2, sta, tmp) {
|
|
|
- rx.sta = sta;
|
|
|
- found_sta = true;
|
|
|
- rx.sdata = sta->sdata;
|
|
|
-
|
|
|
- rx.flags |= IEEE80211_RX_RA_MATCH;
|
|
|
- prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
|
|
|
- if (prepares) {
|
|
|
- if (status->flag & RX_FLAG_MMIC_ERROR) {
|
|
|
- if (rx.flags & IEEE80211_RX_RA_MATCH)
|
|
|
- ieee80211_rx_michael_mic_report(hdr, &rx);
|
|
|
- } else
|
|
|
- prev = rx.sdata;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (!found_sta) {
|
|
|
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
|
|
- if (!ieee80211_sdata_running(sdata))
|
|
|
+ if (!prev_sta) {
|
|
|
+ prev_sta = sta;
|
|
|
continue;
|
|
|
+ }
|
|
|
|
|
|
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
|
|
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
|
|
- continue;
|
|
|
+ rx.sta = prev_sta;
|
|
|
+ rx.sdata = prev_sta->sdata;
|
|
|
+ ieee80211_prepare_and_rx_handle(&rx, skb, false);
|
|
|
|
|
|
- /*
|
|
|
- * frame is destined for this interface, but if it's
|
|
|
- * not also for the previous one we handle that after
|
|
|
- * the loop to avoid copying the SKB once too much
|
|
|
- */
|
|
|
+ prev_sta = sta;
|
|
|
+ }
|
|
|
|
|
|
- if (!prev) {
|
|
|
- prev = sdata;
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (prev_sta) {
|
|
|
+ rx.sta = prev_sta;
|
|
|
+ rx.sdata = prev_sta->sdata;
|
|
|
|
|
|
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
|
|
|
+ if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- rx.flags |= IEEE80211_RX_RA_MATCH;
|
|
|
- prepares = prepare_for_handlers(prev, &rx, hdr);
|
|
|
+ prev = NULL;
|
|
|
|
|
|
- if (!prepares)
|
|
|
- goto next;
|
|
|
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
|
|
+ if (!ieee80211_sdata_running(sdata))
|
|
|
+ continue;
|
|
|
|
|
|
- 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;
|
|
|
- }
|
|
|
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
|
|
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
|
|
+ continue;
|
|
|
|
|
|
- /*
|
|
|
- * frame was destined for the previous interface
|
|
|
- * so invoke RX handlers for it
|
|
|
- */
|
|
|
+ /*
|
|
|
+ * frame is destined for this interface, but if it's
|
|
|
+ * not also for the previous one we handle that after
|
|
|
+ * the loop to avoid copying the SKB once too much
|
|
|
+ */
|
|
|
|
|
|
- skb_new = skb_copy(skb, GFP_ATOMIC);
|
|
|
- if (!skb_new) {
|
|
|
- if (net_ratelimit())
|
|
|
- wiphy_debug(local->hw.wiphy,
|
|
|
- "failed to copy multicast frame for %s\n",
|
|
|
- prev->name);
|
|
|
- goto next;
|
|
|
- }
|
|
|
- ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
|
|
|
-next:
|
|
|
+ if (!prev) {
|
|
|
prev = sdata;
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- if (prev) {
|
|
|
- rx.sta = sta_info_get_bss(prev, hdr->addr2);
|
|
|
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
|
|
|
+ rx.sdata = prev;
|
|
|
+ ieee80211_prepare_and_rx_handle(&rx, skb, false);
|
|
|
|
|
|
- rx.flags |= IEEE80211_RX_RA_MATCH;
|
|
|
- prepares = prepare_for_handlers(prev, &rx, hdr);
|
|
|
+ prev = sdata;
|
|
|
+ }
|
|
|
|
|
|
- if (!prepares)
|
|
|
- prev = NULL;
|
|
|
- }
|
|
|
+ if (prev) {
|
|
|
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
|
|
|
+ rx.sdata = prev;
|
|
|
+
|
|
|
+ if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
|
|
|
+ return;
|
|
|
}
|
|
|
- if (prev)
|
|
|
- ieee80211_invoke_rx_handlers(prev, &rx, skb);
|
|
|
- else
|
|
|
- dev_kfree_skb(skb);
|
|
|
+
|
|
|
+ dev_kfree_skb(skb);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2801,6 +2818,8 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ status->rx_flags = 0;
|
|
|
+
|
|
|
/*
|
|
|
* key references and virtual interfaces are protected using RCU
|
|
|
* and this requires that we are in a read-side RCU section during
|