|
@@ -25,6 +25,207 @@
|
|
#include "tkip.h"
|
|
#include "tkip.h"
|
|
#include "wme.h"
|
|
#include "wme.h"
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * monitor mode reception
|
|
|
|
+ *
|
|
|
|
+ * This function cleans up the SKB, i.e. it removes all the stuff
|
|
|
|
+ * only useful for monitoring.
|
|
|
|
+ */
|
|
|
|
+static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
|
|
|
|
+ struct sk_buff *skb,
|
|
|
|
+ int rtap_len)
|
|
|
|
+{
|
|
|
|
+ skb_pull(skb, rtap_len);
|
|
|
|
+
|
|
|
|
+ if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
|
|
|
|
+ if (likely(skb->len > FCS_LEN))
|
|
|
|
+ skb_trim(skb, skb->len - FCS_LEN);
|
|
|
|
+ else {
|
|
|
|
+ /* driver bug */
|
|
|
|
+ WARN_ON(1);
|
|
|
|
+ dev_kfree_skb(skb);
|
|
|
|
+ skb = NULL;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return skb;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline int should_drop_frame(struct ieee80211_rx_status *status,
|
|
|
|
+ struct sk_buff *skb,
|
|
|
|
+ int present_fcs_len,
|
|
|
|
+ int radiotap_len)
|
|
|
|
+{
|
|
|
|
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
|
|
|
+
|
|
|
|
+ if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
|
|
|
+ return 1;
|
|
|
|
+ if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len))
|
|
|
|
+ return 1;
|
|
|
|
+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==
|
|
|
|
+ cpu_to_le16(IEEE80211_FTYPE_CTL))
|
|
|
|
+ return 1;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * This function copies a received frame to all monitor interfaces and
|
|
|
|
+ * returns a cleaned-up SKB that no longer includes the FCS nor the
|
|
|
|
+ * radiotap header the driver might have added.
|
|
|
|
+ */
|
|
|
|
+static struct sk_buff *
|
|
|
|
+ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
|
|
|
+ struct ieee80211_rx_status *status)
|
|
|
|
+{
|
|
|
|
+ struct ieee80211_sub_if_data *sdata;
|
|
|
|
+ struct ieee80211_rate *rate;
|
|
|
|
+ int needed_headroom = 0;
|
|
|
|
+ struct ieee80211_rtap_hdr {
|
|
|
|
+ struct ieee80211_radiotap_header hdr;
|
|
|
|
+ u8 flags;
|
|
|
|
+ u8 rate;
|
|
|
|
+ __le16 chan_freq;
|
|
|
|
+ __le16 chan_flags;
|
|
|
|
+ u8 antsignal;
|
|
|
|
+ u8 padding_for_rxflags;
|
|
|
|
+ __le16 rx_flags;
|
|
|
|
+ } __attribute__ ((packed)) *rthdr;
|
|
|
|
+ struct sk_buff *skb, *skb2;
|
|
|
|
+ struct net_device *prev_dev = NULL;
|
|
|
|
+ int present_fcs_len = 0;
|
|
|
|
+ int rtap_len = 0;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * First, we may need to make a copy of the skb because
|
|
|
|
+ * (1) we need to modify it for radiotap (if not present), and
|
|
|
|
+ * (2) the other RX handlers will modify the skb we got.
|
|
|
|
+ *
|
|
|
|
+ * We don't need to, of course, if we aren't going to return
|
|
|
|
+ * the SKB because it has a bad FCS/PLCP checksum.
|
|
|
|
+ */
|
|
|
|
+ if (status->flag & RX_FLAG_RADIOTAP)
|
|
|
|
+ rtap_len = ieee80211_get_radiotap_len(origskb->data);
|
|
|
|
+ else
|
|
|
|
+ needed_headroom = sizeof(*rthdr);
|
|
|
|
+
|
|
|
|
+ if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
|
|
|
|
+ present_fcs_len = FCS_LEN;
|
|
|
|
+
|
|
|
|
+ if (!local->monitors) {
|
|
|
|
+ if (should_drop_frame(status, origskb, present_fcs_len,
|
|
|
|
+ rtap_len)) {
|
|
|
|
+ dev_kfree_skb(origskb);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return remove_monitor_info(local, origskb, rtap_len);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) {
|
|
|
|
+ /* only need to expand headroom if necessary */
|
|
|
|
+ skb = origskb;
|
|
|
|
+ origskb = NULL;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * This shouldn't trigger often because most devices have an
|
|
|
|
+ * RX header they pull before we get here, and that should
|
|
|
|
+ * be big enough for our radiotap information. We should
|
|
|
|
+ * probably export the length to drivers so that we can have
|
|
|
|
+ * them allocate enough headroom to start with.
|
|
|
|
+ */
|
|
|
|
+ if (skb_headroom(skb) < needed_headroom &&
|
|
|
|
+ pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
|
|
|
|
+ dev_kfree_skb(skb);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * Need to make a copy and possibly remove radiotap header
|
|
|
|
+ * and FCS from the original.
|
|
|
|
+ */
|
|
|
|
+ skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC);
|
|
|
|
+
|
|
|
|
+ origskb = remove_monitor_info(local, origskb, rtap_len);
|
|
|
|
+
|
|
|
|
+ if (!skb)
|
|
|
|
+ return origskb;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* if necessary, prepend radiotap information */
|
|
|
|
+ if (!(status->flag & RX_FLAG_RADIOTAP)) {
|
|
|
|
+ rthdr = (void *) skb_push(skb, sizeof(*rthdr));
|
|
|
|
+ memset(rthdr, 0, sizeof(*rthdr));
|
|
|
|
+ rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
|
|
|
|
+ rthdr->hdr.it_present =
|
|
|
|
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
|
|
|
|
+ (1 << IEEE80211_RADIOTAP_RATE) |
|
|
|
|
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
|
|
|
|
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
|
|
|
|
+ (1 << IEEE80211_RADIOTAP_RX_FLAGS));
|
|
|
|
+ rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
|
|
|
|
+ IEEE80211_RADIOTAP_F_FCS : 0;
|
|
|
|
+
|
|
|
|
+ /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
|
|
|
|
+ rthdr->rx_flags = 0;
|
|
|
|
+ if (status->flag &
|
|
|
|
+ (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
|
|
|
+ rthdr->rx_flags |=
|
|
|
|
+ cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
|
|
|
|
+
|
|
|
|
+ rate = ieee80211_get_rate(local, status->phymode,
|
|
|
|
+ status->rate);
|
|
|
|
+ if (rate)
|
|
|
|
+ rthdr->rate = rate->rate / 5;
|
|
|
|
+
|
|
|
|
+ rthdr->chan_freq = cpu_to_le16(status->freq);
|
|
|
|
+
|
|
|
|
+ if (status->phymode == MODE_IEEE80211A)
|
|
|
|
+ rthdr->chan_flags =
|
|
|
|
+ cpu_to_le16(IEEE80211_CHAN_OFDM |
|
|
|
|
+ IEEE80211_CHAN_5GHZ);
|
|
|
|
+ else
|
|
|
|
+ rthdr->chan_flags =
|
|
|
|
+ cpu_to_le16(IEEE80211_CHAN_DYN |
|
|
|
|
+ IEEE80211_CHAN_2GHZ);
|
|
|
|
+
|
|
|
|
+ rthdr->antsignal = status->ssi;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ skb_set_mac_header(skb, 0);
|
|
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
+ skb->pkt_type = PACKET_OTHERHOST;
|
|
|
|
+ skb->protocol = htons(ETH_P_802_2);
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
|
|
|
+ if (!netif_running(sdata->dev))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (sdata->type != IEEE80211_IF_TYPE_MNTR)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (prev_dev) {
|
|
|
|
+ skb2 = skb_clone(skb, GFP_ATOMIC);
|
|
|
|
+ if (skb2) {
|
|
|
|
+ skb2->dev = prev_dev;
|
|
|
|
+ netif_rx(skb2);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ prev_dev = sdata->dev;
|
|
|
|
+ sdata->dev->stats.rx_packets++;
|
|
|
|
+ sdata->dev->stats.rx_bytes += skb->len;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (prev_dev) {
|
|
|
|
+ skb->dev = prev_dev;
|
|
|
|
+ netif_rx(skb);
|
|
|
|
+ } else
|
|
|
|
+ dev_kfree_skb(skb);
|
|
|
|
+
|
|
|
|
+ return origskb;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
/* pre-rx handlers
|
|
/* pre-rx handlers
|
|
*
|
|
*
|
|
* these don't have dev/sdata fields in the rx data
|
|
* these don't have dev/sdata fields in the rx data
|
|
@@ -132,100 +333,6 @@ ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
|
|
return TXRX_CONTINUE;
|
|
return TXRX_CONTINUE;
|
|
}
|
|
}
|
|
|
|
|
|
-static void
|
|
|
|
-ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb,
|
|
|
|
- struct ieee80211_rx_status *status)
|
|
|
|
-{
|
|
|
|
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
|
|
|
- struct ieee80211_rate *rate;
|
|
|
|
- struct ieee80211_rtap_hdr {
|
|
|
|
- struct ieee80211_radiotap_header hdr;
|
|
|
|
- u8 flags;
|
|
|
|
- u8 rate;
|
|
|
|
- __le16 chan_freq;
|
|
|
|
- __le16 chan_flags;
|
|
|
|
- u8 antsignal;
|
|
|
|
- u8 padding_for_rxflags;
|
|
|
|
- __le16 rx_flags;
|
|
|
|
- } __attribute__ ((packed)) *rthdr;
|
|
|
|
-
|
|
|
|
- skb->dev = dev;
|
|
|
|
-
|
|
|
|
- if (status->flag & RX_FLAG_RADIOTAP)
|
|
|
|
- goto out;
|
|
|
|
-
|
|
|
|
- if (skb_headroom(skb) < sizeof(*rthdr)) {
|
|
|
|
- I802_DEBUG_INC(local->rx_expand_skb_head);
|
|
|
|
- if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
|
|
|
|
- dev_kfree_skb(skb);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr));
|
|
|
|
- memset(rthdr, 0, sizeof(*rthdr));
|
|
|
|
- rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
|
|
|
|
- rthdr->hdr.it_present =
|
|
|
|
- cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
|
|
|
|
- (1 << IEEE80211_RADIOTAP_RATE) |
|
|
|
|
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
|
|
|
|
- (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
|
|
|
|
- (1 << IEEE80211_RADIOTAP_RX_FLAGS));
|
|
|
|
- rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
|
|
|
|
- IEEE80211_RADIOTAP_F_FCS : 0;
|
|
|
|
-
|
|
|
|
- /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
|
|
|
|
- rthdr->rx_flags = 0;
|
|
|
|
- if (status->flag &
|
|
|
|
- (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
|
|
|
- rthdr->rx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
|
|
|
|
-
|
|
|
|
- rate = ieee80211_get_rate(local, status->phymode, status->rate);
|
|
|
|
- if (rate)
|
|
|
|
- rthdr->rate = rate->rate / 5;
|
|
|
|
-
|
|
|
|
- rthdr->chan_freq = cpu_to_le16(status->freq);
|
|
|
|
- rthdr->chan_flags =
|
|
|
|
- status->phymode == MODE_IEEE80211A ?
|
|
|
|
- cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) :
|
|
|
|
- cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ);
|
|
|
|
- rthdr->antsignal = status->ssi;
|
|
|
|
-
|
|
|
|
- out:
|
|
|
|
- dev->stats.rx_packets++;
|
|
|
|
- dev->stats.rx_bytes += skb->len;
|
|
|
|
-
|
|
|
|
- skb_set_mac_header(skb, 0);
|
|
|
|
- skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
- skb->pkt_type = PACKET_OTHERHOST;
|
|
|
|
- skb->protocol = htons(ETH_P_802_2);
|
|
|
|
- memset(skb->cb, 0, sizeof(skb->cb));
|
|
|
|
- netif_rx(skb);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static ieee80211_txrx_result
|
|
|
|
-ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx)
|
|
|
|
-{
|
|
|
|
- if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) {
|
|
|
|
- ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status);
|
|
|
|
- return TXRX_QUEUED;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Drop frames with failed FCS/PLCP checksums here, they are only
|
|
|
|
- * relevant for monitor mode, the rest of the stack should never
|
|
|
|
- * see them.
|
|
|
|
- */
|
|
|
|
- if (rx->u.rx.status->flag &
|
|
|
|
- (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
|
|
|
|
- return TXRX_DROP;
|
|
|
|
-
|
|
|
|
- if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP)
|
|
|
|
- skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb->data));
|
|
|
|
-
|
|
|
|
- return TXRX_CONTINUE;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static ieee80211_txrx_result
|
|
static ieee80211_txrx_result
|
|
ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
|
|
ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
|
|
{
|
|
{
|
|
@@ -266,10 +373,6 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
|
|
rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
|
|
rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
|
|
}
|
|
}
|
|
|
|
|
|
- if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) &&
|
|
|
|
- rx->skb->len > FCS_LEN)
|
|
|
|
- skb_trim(rx->skb, rx->skb->len - FCS_LEN);
|
|
|
|
-
|
|
|
|
if (unlikely(rx->skb->len < 16)) {
|
|
if (unlikely(rx->skb->len < 16)) {
|
|
I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
|
|
I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
|
|
return TXRX_DROP;
|
|
return TXRX_DROP;
|
|
@@ -1264,7 +1367,6 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
|
|
ieee80211_rx_handler ieee80211_rx_handlers[] =
|
|
ieee80211_rx_handler ieee80211_rx_handlers[] =
|
|
{
|
|
{
|
|
ieee80211_rx_h_if_stats,
|
|
ieee80211_rx_h_if_stats,
|
|
- ieee80211_rx_h_monitor,
|
|
|
|
ieee80211_rx_h_passive_scan,
|
|
ieee80211_rx_h_passive_scan,
|
|
ieee80211_rx_h_check,
|
|
ieee80211_rx_h_check,
|
|
ieee80211_rx_h_load_key,
|
|
ieee80211_rx_h_load_key,
|
|
@@ -1371,16 +1473,10 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|
struct ieee80211_hdr *hdr;
|
|
struct ieee80211_hdr *hdr;
|
|
struct ieee80211_txrx_data rx;
|
|
struct ieee80211_txrx_data rx;
|
|
u16 type;
|
|
u16 type;
|
|
- int radiotap_len = 0, prepres;
|
|
|
|
|
|
+ int prepres;
|
|
struct ieee80211_sub_if_data *prev = NULL;
|
|
struct ieee80211_sub_if_data *prev = NULL;
|
|
struct sk_buff *skb_new;
|
|
struct sk_buff *skb_new;
|
|
u8 *bssid;
|
|
u8 *bssid;
|
|
- int bogon;
|
|
|
|
-
|
|
|
|
- if (status->flag & RX_FLAG_RADIOTAP) {
|
|
|
|
- radiotap_len = ieee80211_get_radiotap_len(skb->data);
|
|
|
|
- skb_pull(skb, radiotap_len);
|
|
|
|
- }
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* key references and virtual interfaces are protected using RCU
|
|
* key references and virtual interfaces are protected using RCU
|
|
@@ -1389,30 +1485,35 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|
*/
|
|
*/
|
|
rcu_read_lock();
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Frames with failed FCS/PLCP checksum are not returned,
|
|
|
|
+ * all other frames are returned without radiotap header
|
|
|
|
+ * if it was previously present.
|
|
|
|
+ * Also, frames with less than 16 bytes are dropped.
|
|
|
|
+ */
|
|
|
|
+ skb = ieee80211_rx_monitor(local, skb, status);
|
|
|
|
+ if (!skb) {
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
hdr = (struct ieee80211_hdr *) skb->data;
|
|
hdr = (struct ieee80211_hdr *) skb->data;
|
|
memset(&rx, 0, sizeof(rx));
|
|
memset(&rx, 0, sizeof(rx));
|
|
rx.skb = skb;
|
|
rx.skb = skb;
|
|
rx.local = local;
|
|
rx.local = local;
|
|
|
|
|
|
rx.u.rx.status = status;
|
|
rx.u.rx.status = status;
|
|
- rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0;
|
|
|
|
|
|
+ rx.fc = le16_to_cpu(hdr->frame_control);
|
|
type = rx.fc & IEEE80211_FCTL_FTYPE;
|
|
type = rx.fc & IEEE80211_FCTL_FTYPE;
|
|
|
|
|
|
- bogon = status->flag & (RX_FLAG_FAILED_FCS_CRC |
|
|
|
|
- RX_FLAG_FAILED_PLCP_CRC);
|
|
|
|
-
|
|
|
|
- if (!bogon && (type == IEEE80211_FTYPE_DATA ||
|
|
|
|
- type == IEEE80211_FTYPE_MGMT))
|
|
|
|
|
|
+ if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
|
|
local->dot11ReceivedFragmentCount++;
|
|
local->dot11ReceivedFragmentCount++;
|
|
|
|
|
|
- if (!bogon && skb->len >= 16) {
|
|
|
|
- sta = rx.sta = sta_info_get(local, hdr->addr2);
|
|
|
|
- if (sta) {
|
|
|
|
- rx.dev = rx.sta->dev;
|
|
|
|
- rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
|
|
|
|
- }
|
|
|
|
- } else
|
|
|
|
- sta = rx.sta = NULL;
|
|
|
|
|
|
+ sta = rx.sta = sta_info_get(local, hdr->addr2);
|
|
|
|
+ if (sta) {
|
|
|
|
+ rx.dev = rx.sta->dev;
|
|
|
|
+ rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
|
|
|
|
+ }
|
|
|
|
|
|
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
|
|
if ((status->flag & RX_FLAG_MMIC_ERROR)) {
|
|
ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
|
|
ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
|
|
@@ -1427,7 +1528,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|
goto end;
|
|
goto end;
|
|
skb = rx.skb;
|
|
skb = rx.skb;
|
|
|
|
|
|
- skb_push(skb, radiotap_len);
|
|
|
|
if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
|
|
if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
|
|
!local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) {
|
|
!local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) {
|
|
rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
|
|
rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
|
|
@@ -1438,14 +1538,16 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
|
|
|
|
|
|
+ bssid = ieee80211_get_bssid(hdr, skb->len);
|
|
|
|
|
|
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
|
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
|
- rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
|
|
|
|
-
|
|
|
|
if (!netif_running(sdata->dev))
|
|
if (!netif_running(sdata->dev))
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
|
|
prepres = prepare_for_handlers(sdata, bssid, &rx, hdr);
|
|
prepres = prepare_for_handlers(sdata, bssid, &rx, hdr);
|
|
/* prepare_for_handlers can change sta */
|
|
/* prepare_for_handlers can change sta */
|
|
sta = rx.sta;
|
|
sta = rx.sta;
|