aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c654
1 files changed, 426 insertions, 228 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 10e88423ff4..6202d050412 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -16,8 +16,10 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/rcupdate.h>
+#include <linux/export.h>
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
+#include <asm/unaligned.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
@@ -27,6 +29,7 @@
#include "wpa.h"
#include "tkip.h"
#include "wme.h"
+#include "rate.h"
/*
* monitor mode reception
@@ -100,7 +103,7 @@ static void
ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
struct sk_buff *skb,
struct ieee80211_rate *rate,
- int rtap_len)
+ int rtap_len, bool has_fcs)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_radiotap_header *rthdr;
@@ -131,7 +134,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
}
/* IEEE80211_RADIOTAP_FLAGS */
- if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+ if (has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))
*pos |= IEEE80211_RADIOTAP_F_FCS;
if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
*pos |= IEEE80211_RADIOTAP_F_BADFCS;
@@ -174,7 +177,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
pos += 2;
/* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
- if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM &&
+ !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
*pos = status->signal;
rthdr->it_present |=
cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
@@ -224,7 +228,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
struct ieee80211_sub_if_data *sdata;
- int needed_headroom = 0;
+ int needed_headroom;
struct sk_buff *skb, *skb2;
struct net_device *prev_dev = NULL;
int present_fcs_len = 0;
@@ -290,7 +294,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
}
/* prepend radiotap information */
- ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom);
+ ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
+ true);
skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -334,15 +339,18 @@ 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;
+ int tid, seqno_idx, security_idx;
/* does the frame have a qos control field? */
if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *qc = ieee80211_get_qos_ctl(hdr);
/* frame has qos control */
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
- if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+ if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
status->rx_flags |= IEEE80211_RX_AMSDU;
+
+ seqno_idx = tid;
+ security_idx = tid;
} else {
/*
* IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
@@ -355,10 +363,15 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
*
* We also use that counter for non-QoS STAs.
*/
- tid = NUM_RX_DATA_QUEUES - 1;
+ seqno_idx = NUM_RX_DATA_QUEUES;
+ security_idx = 0;
+ if (ieee80211_is_mgmt(hdr->frame_control))
+ security_idx = NUM_RX_DATA_QUEUES;
+ tid = 0;
}
- rx->queue = tid;
+ rx->seqno_idx = seqno_idx;
+ rx->security_idx = security_idx;
/* Set skb->priority to 1d tag if highest order bit of TID is not set.
* For now, set skb->priority to 0 for other cases. */
rx->skb->priority = (tid > 7) ? 0 : tid;
@@ -471,7 +484,6 @@ static ieee80211_rx_result
ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
- unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
char *dev_addr = rx->sdata->vif.addr;
if (ieee80211_is_data(hdr->frame_control)) {
@@ -479,12 +491,12 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
if (ieee80211_has_tods(hdr->frame_control) ||
!ieee80211_has_fromds(hdr->frame_control))
return RX_DROP_MONITOR;
- if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0)
+ if (compare_ether_addr(hdr->addr3, dev_addr) == 0)
return RX_DROP_MONITOR;
} else {
if (!ieee80211_has_a4(hdr->frame_control))
return RX_DROP_MONITOR;
- if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0)
+ if (compare_ether_addr(hdr->addr4, dev_addr) == 0)
return RX_DROP_MONITOR;
}
}
@@ -501,6 +513,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
if (ieee80211_is_action(hdr->frame_control)) {
u8 category;
+
+ /* make sure category field is present */
+ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
+ return RX_DROP_MONITOR;
+
mgmt = (struct ieee80211_mgmt *)hdr;
category = mgmt->u.action.category;
if (category != WLAN_CATEGORY_MESH_ACTION &&
@@ -519,14 +536,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
}
-#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
-
- if (ieee80211_is_data(hdr->frame_control) &&
- is_multicast_ether_addr(hdr->addr1) &&
- mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
- return RX_DROP_MONITOR;
-#undef msh_h_get
-
return RX_CONTINUE;
}
@@ -659,9 +668,10 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
set_release_timer:
- mod_timer(&tid_agg_rx->reorder_timer,
- tid_agg_rx->reorder_time[j] + 1 +
- HT_RX_REORDER_BUF_TIMEOUT);
+ if (!tid_agg_rx->removed)
+ mod_timer(&tid_agg_rx->reorder_timer,
+ tid_agg_rx->reorder_time[j] + 1 +
+ HT_RX_REORDER_BUF_TIMEOUT);
} else {
del_timer(&tid_agg_rx->reorder_timer);
}
@@ -748,12 +758,14 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct sta_info *sta = rx->sta;
struct tid_ampdu_rx *tid_agg_rx;
u16 sc;
- int tid;
+ u8 tid, ack_policy;
- if (!ieee80211_is_data_qos(hdr->frame_control))
+ if (!ieee80211_is_data_qos(hdr->frame_control) ||
+ is_multicast_ether_addr(hdr->addr1))
goto dont_reorder;
/*
@@ -764,6 +776,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
if (!sta)
goto dont_reorder;
+ ack_policy = *ieee80211_get_qos_ctl(hdr) &
+ IEEE80211_QOS_CTL_ACK_POLICY_MASK;
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -774,6 +788,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
goto dont_reorder;
+ /* not part of a BA session */
+ if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+ ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+ goto dont_reorder;
+
+ /* not actually part of this BA session */
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+ goto dont_reorder;
+
/* new, potentially un-ordered, ampdu frame - process it */
/* reset session timer */
@@ -819,7 +842,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
!ieee80211_is_qos_nullfunc(hdr->frame_control) &&
!is_multicast_ether_addr(hdr->addr1)) {
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
- rx->sta->last_seq_ctrl[rx->queue] ==
+ rx->sta->last_seq_ctrl[rx->seqno_idx] ==
hdr->seq_ctrl)) {
if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
rx->local->dot11FrameDuplicateCount++;
@@ -827,7 +850,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
}
return RX_DROP_UNUSABLE;
} else
- rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
+ rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
}
if (unlikely(rx->skb->len < 16)) {
@@ -851,8 +874,35 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
ieee80211_is_pspoll(hdr->frame_control)) &&
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
- (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC))))
+ (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
+ /*
+ * accept port control frames from the AP even when it's not
+ * yet marked ASSOC to prevent a race where we don't set the
+ * assoc bit quickly enough before it sends the first frame
+ */
+ if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+ ieee80211_is_data_present(hdr->frame_control)) {
+ unsigned int hdrlen;
+ __be16 ethertype;
+
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ if (rx->skb->len < hdrlen + 8)
+ return RX_DROP_MONITOR;
+
+ skb_copy_bits(rx->skb, hdrlen + 6, &ethertype, 2);
+ if (ethertype == rx->sdata->control_port_protocol)
+ return RX_CONTINUE;
+ }
+
+ if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+ cfg80211_rx_spurious_frame(rx->sdata->dev,
+ hdr->addr2,
+ GFP_ATOMIC))
+ return RX_DROP_UNUSABLE;
+
return RX_DROP_MONITOR;
+ }
return RX_CONTINUE;
}
@@ -1020,26 +1070,18 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
}
if (rx->key) {
+ if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
+ return RX_DROP_MONITOR;
+
rx->key->tx_rx_count++;
/* TODO: add threshold stuff again */
} else {
return RX_DROP_MONITOR;
}
- if (skb_linearize(rx->skb))
- return RX_DROP_UNUSABLE;
- /* the hdr variable is invalid now! */
-
switch (rx->key->conf.cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
- /* Check for weak IVs if possible */
- if (rx->sta && ieee80211_is_data(fc) &&
- (!(status->flag & RX_FLAG_IV_STRIPPED) ||
- !(status->flag & RX_FLAG_DECRYPTED)) &&
- ieee80211_wep_is_weak_iv(rx->skb, rx->key))
- rx->sta->wep_weak_iv_count++;
-
result = ieee80211_crypto_wep_decrypt(rx);
break;
case WLAN_CIPHER_SUITE_TKIP:
@@ -1059,6 +1101,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
}
+ /* the hdr variable is invalid after the decrypt handlers */
+
/* either the frame has been decrypted or will be dropped */
status->flag |= RX_FLAG_DECRYPTED;
@@ -1104,7 +1148,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
struct ieee80211_local *local = sdata->local;
atomic_inc(&sdata->bss->num_sta_ps);
- set_sta_flags(sta, WLAN_STA_PS_STA);
+ set_sta_flag(sta, WLAN_STA_PS_STA);
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -1115,19 +1159,15 @@ static void ap_sta_ps_start(struct sta_info *sta)
static void ap_sta_ps_end(struct sta_info *sta)
{
- struct ieee80211_sub_if_data *sdata = sta->sdata;
-
- atomic_dec(&sdata->bss->num_sta_ps);
-
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
- sdata->name, sta->sta.addr, sta->sta.aid);
+ sta->sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
+ if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
- sdata->name, sta->sta.addr, sta->sta.aid);
+ sta->sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
return;
}
@@ -1143,7 +1183,7 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS));
/* Don't let the same PS state be set twice */
- in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA);
+ in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA);
if ((start && in_ps) || (!start && !in_ps))
return -EINVAL;
@@ -1157,6 +1197,81 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
EXPORT_SYMBOL(ieee80211_sta_ps_transition);
static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_hdr *hdr = (void *)rx->skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+ int tid, ac;
+
+ if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH))
+ return RX_CONTINUE;
+
+ if (sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+ return RX_CONTINUE;
+
+ /*
+ * The device handles station powersave, so don't do anything about
+ * uAPSD and PS-Poll frames (the latter shouldn't even come up from
+ * it to mac80211 since they're handled.)
+ */
+ if (sdata->local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+ return RX_CONTINUE;
+
+ /*
+ * Don't do anything if the station isn't already asleep. In
+ * the uAPSD case, the station will probably be marked asleep,
+ * in the PS-Poll case the station must be confused ...
+ */
+ if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA))
+ return RX_CONTINUE;
+
+ if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
+ if (!test_sta_flag(rx->sta, WLAN_STA_SP)) {
+ if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+ ieee80211_sta_ps_deliver_poll_response(rx->sta);
+ else
+ set_sta_flag(rx->sta, WLAN_STA_PSPOLL);
+ }
+
+ /* Free PS Poll skb here instead of returning RX_DROP that would
+ * count as an dropped frame. */
+ dev_kfree_skb(rx->skb);
+
+ return RX_QUEUED;
+ } else if (!ieee80211_has_morefrags(hdr->frame_control) &&
+ !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
+ ieee80211_has_pm(hdr->frame_control) &&
+ (ieee80211_is_data_qos(hdr->frame_control) ||
+ ieee80211_is_qos_nullfunc(hdr->frame_control))) {
+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+ ac = ieee802_1d_to_ac[tid & 7];
+
+ /*
+ * If this AC is not trigger-enabled do nothing.
+ *
+ * NB: This could/should check a separate bitmap of trigger-
+ * enabled queues, but for now we only implement uAPSD w/o
+ * TSPEC changes to the ACs, so they're always the same.
+ */
+ if (!(rx->sta->sta.uapsd_queues & BIT(ac)))
+ return RX_CONTINUE;
+
+ /* if we are in a service period, do nothing */
+ if (test_sta_flag(rx->sta, WLAN_STA_SP))
+ return RX_CONTINUE;
+
+ if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+ ieee80211_sta_ps_deliver_uapsd(rx->sta);
+ else
+ set_sta_flag(rx->sta, WLAN_STA_UAPSD);
+ }
+
+ return RX_CONTINUE;
+}
+
+static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{
struct sta_info *sta = rx->sta;
@@ -1202,8 +1317,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
- sta->last_signal = status->signal;
- ewma_add(&sta->avg_signal, -status->signal);
+ if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
+ sta->last_signal = status->signal;
+ ewma_add(&sta->avg_signal, -status->signal);
+ }
/*
* Change STA power saving mode only at the end of a frame
@@ -1214,7 +1331,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
!(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
(rx->sdata->vif.type == NL80211_IFTYPE_AP ||
rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
- if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
+ if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
/*
* Ignore doze->wake transitions that are
* indicated by non-data frames, the standard
@@ -1242,15 +1359,20 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
/*
* If we receive a 4-addr nullfunc frame from a STA
- * that was not moved to a 4-addr STA vlan yet, drop
- * the frame to the monitor interface, to make sure
- * that hostapd sees it
+ * that was not moved to a 4-addr STA vlan yet send
+ * the event to userspace and for older hostapd drop
+ * the frame to the monitor interface.
*/
if (ieee80211_has_a4(hdr->frame_control) &&
(rx->sdata->vif.type == NL80211_IFTYPE_AP ||
(rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
- !rx->sdata->u.vlan.sta)))
+ !rx->sdata->u.vlan.sta))) {
+ if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
+ cfg80211_rx_unexpected_4addr_frame(
+ rx->sdata->dev, sta->sta.addr,
+ GFP_ATOMIC);
return RX_DROP_MONITOR;
+ }
/*
* Update counter and free packet here to avoid
* counting this as a dropped packed.
@@ -1365,11 +1487,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
sc = le16_to_cpu(hdr->seq_ctrl);
frag = sc & IEEE80211_SCTL_FRAG;
- if (likely((!ieee80211_has_morefrags(fc) && frag == 0) ||
- is_multicast_ether_addr(hdr->addr1))) {
- /* not fragmented */
- goto out;
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ rx->local->dot11MulticastReceivedFrameCount++;
+ goto out_no_led;
}
+
+ if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
+ goto out;
+
I802_DEBUG_INC(rx->local->rx_handlers_fragments);
if (skb_linearize(rx->skb))
@@ -1386,11 +1511,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
if (frag == 0) {
/* This is the first fragment of a new frame. */
entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
- rx->queue, &(rx->skb));
+ rx->seqno_idx, &(rx->skb));
if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP &&
ieee80211_has_protected(fc)) {
- int queue = ieee80211_is_mgmt(fc) ?
- NUM_RX_DATA_QUEUES : rx->queue;
+ int queue = rx->security_idx;
/* Store CCMP PN so that we can verify that the next
* fragment has a sequential PN value. */
entry->ccmp = 1;
@@ -1404,7 +1528,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
/* This is a fragment for a frame that should already be pending in
* fragment cache. Add this fragment to the end of the pending entry.
*/
- entry = ieee80211_reassemble_find(rx->sdata, frag, seq, rx->queue, hdr);
+ entry = ieee80211_reassemble_find(rx->sdata, frag, seq,
+ rx->seqno_idx, hdr);
if (!entry) {
I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
return RX_DROP_MONITOR;
@@ -1424,8 +1549,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
if (pn[i])
break;
}
- queue = ieee80211_is_mgmt(fc) ?
- NUM_RX_DATA_QUEUES : rx->queue;
+ queue = rx->security_idx;
rpn = rx->key->u.ccmp.rx_pn[queue];
if (memcmp(pn, rpn, CCMP_PN_LEN))
return RX_DROP_UNUSABLE;
@@ -1461,58 +1585,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
status->rx_flags |= IEEE80211_RX_FRAGMENTED;
out:
+ ieee80211_led_rx(rx->local);
+ out_no_led:
if (rx->sta)
rx->sta->rx_packets++;
- if (is_multicast_ether_addr(hdr->addr1))
- rx->local->dot11MulticastReceivedFrameCount++;
- else
- ieee80211_led_rx(rx->local);
- return RX_CONTINUE;
-}
-
-static ieee80211_rx_result debug_noinline
-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) ||
- !(status->rx_flags & IEEE80211_RX_RA_MATCH)))
- return RX_CONTINUE;
-
- if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
- (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
- return RX_DROP_UNUSABLE;
-
- if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
- ieee80211_sta_ps_deliver_poll_response(rx->sta);
- else
- set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
-
- /* Free PS Poll skb here instead of returning RX_DROP that would
- * count as an dropped frame. */
- dev_kfree_skb(rx->skb);
-
- return RX_QUEUED;
-}
-
-static ieee80211_rx_result debug_noinline
-ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
-{
- u8 *data = rx->skb->data;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
-
- if (!ieee80211_is_data_qos(hdr->frame_control))
- return RX_CONTINUE;
-
- /* remove the qos control field, update frame type and meta-data */
- memmove(data + IEEE80211_QOS_CTL_LEN, data,
- ieee80211_hdrlen(hdr->frame_control) - IEEE80211_QOS_CTL_LEN);
- hdr = (struct ieee80211_hdr *)skb_pull(rx->skb, IEEE80211_QOS_CTL_LEN);
- /* change frame type to non QOS */
- hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
-
return RX_CONTINUE;
}
@@ -1520,7 +1596,7 @@ static int
ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
{
if (unlikely(!rx->sta ||
- !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED)))
+ !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
return -EACCES;
return 0;
@@ -1563,7 +1639,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_DECRYPTED)
return 0;
- if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
+ if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {
if (unlikely(!ieee80211_has_protected(fc) &&
ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
rx->key)) {
@@ -1748,7 +1824,12 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
}
if (xmit_skb) {
- /* send to wireless media */
+ /*
+ * Send to wireless media and increase priority by 256 to
+ * keep the received priority instead of reclassifying
+ * the frame (see cfg80211_classify8021d).
+ */
+ xmit_skb->priority += 256;
xmit_skb->protocol = htons(ETH_P_802_3);
skb_reset_network_header(xmit_skb);
skb_reset_mac_header(xmit_skb);
@@ -1817,23 +1898,49 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
static ieee80211_rx_result
ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
{
- struct ieee80211_hdr *hdr;
+ struct ieee80211_hdr *fwd_hdr, *hdr;
+ struct ieee80211_tx_info *info;
struct ieee80211s_hdr *mesh_hdr;
- unsigned int hdrlen;
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);
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
+ u16 q, hdrlen;
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+ /* make sure fixed part of mesh header is there, also checks skb len */
+ if (!pskb_may_pull(rx->skb, hdrlen + 6))
+ return RX_DROP_MONITOR;
+
mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
- if (!ieee80211_is_data(hdr->frame_control))
+ /* make sure full mesh header is there, also checks skb len */
+ if (!pskb_may_pull(rx->skb,
+ hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
+ return RX_DROP_MONITOR;
+
+ /* reload pointers */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+
+ if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
+ return RX_DROP_MONITOR;
+
+ /* frame is in RMC, don't forward */
+ if (ieee80211_is_data(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr1) &&
+ mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
+ return RX_DROP_MONITOR;
+
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;
if (!mesh_hdr->ttl)
- /* illegal frame */
return RX_DROP_MONITOR;
if (mesh_hdr->flags & MESH_FLAGS_AE) {
@@ -1844,9 +1951,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
if (is_multicast_ether_addr(hdr->addr1)) {
mpp_addr = hdr->addr3;
proxied_addr = mesh_hdr->eaddr1;
- } else {
+ } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) {
+ /* has_a4 already checked in ieee80211_rx_mesh_check */
mpp_addr = hdr->addr4;
proxied_addr = mesh_hdr->eaddr2;
+ } else {
+ return RX_DROP_MONITOR;
}
rcu_read_lock();
@@ -1867,60 +1977,51 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
return RX_CONTINUE;
- mesh_hdr->ttl--;
+ q = ieee80211_select_queue_80211(local, skb, hdr);
+ if (ieee80211_queue_stopped(&local->hw, q)) {
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
+ return RX_DROP_MONITOR;
+ }
+ skb_set_queue_mapping(skb, q);
- if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
- if (!mesh_hdr->ttl)
- IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
- dropped_frames_ttl);
- else {
- struct ieee80211_hdr *fwd_hdr;
- struct ieee80211_tx_info *info;
-
- fwd_skb = skb_copy(skb, GFP_ATOMIC);
-
- if (!fwd_skb && net_ratelimit())
- printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
- sdata->name);
- if (!fwd_skb)
- goto out;
-
- fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
- memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
- info = IEEE80211_SKB_CB(fwd_skb);
- memset(info, 0, sizeof(*info));
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
- info->control.vif = &rx->sdata->vif;
- skb_set_queue_mapping(skb,
- ieee80211_select_queue(rx->sdata, fwd_skb));
- ieee80211_set_qos_hdr(local, skb);
- if (is_multicast_ether_addr(fwd_hdr->addr1))
- IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
- fwded_mcast);
- else {
- int err;
- /*
- * Save TA to addr1 to send TA a path error if a
- * suitable next hop is not found
- */
- memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
- ETH_ALEN);
- err = mesh_nexthop_lookup(fwd_skb, sdata);
- /* Failed to immediately resolve next hop:
- * fwded frame was dropped or will be added
- * later to the pending skb queue. */
- if (err)
- return RX_DROP_MONITOR;
-
- IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
- fwded_unicast);
- }
- IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
- fwded_frames);
- ieee80211_add_pending_skb(local, fwd_skb);
- }
+ if (!--mesh_hdr->ttl) {
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
+ return RX_DROP_MONITOR;
+ }
+
+ if (!ifmsh->mshcfg.dot11MeshForwarding)
+ goto out;
+
+ fwd_skb = skb_copy(skb, GFP_ATOMIC);
+ if (!fwd_skb) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
+ sdata->name);
+ goto out;
+ }
+
+ fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
+ info = IEEE80211_SKB_CB(fwd_skb);
+ memset(info, 0, sizeof(*info));
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.vif = &rx->sdata->vif;
+ info->control.jiffies = jiffies;
+ if (is_multicast_ether_addr(fwd_hdr->addr1)) {
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
+ memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
+ } else if (!mesh_nexthop_lookup(fwd_skb, sdata)) {
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
+ } else {
+ /* unable to resolve next hop */
+ mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
+ 0, reason, fwd_hdr->addr2, sdata);
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
+ kfree_skb(fwd_skb);
+ return RX_DROP_MONITOR;
}
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
+ ieee80211_add_pending_skb(local, fwd_skb);
out:
if (is_multicast_ether_addr(hdr->addr1) ||
sdata->dev->flags & IFF_PROMISC)
@@ -1948,12 +2049,17 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
/*
- * Allow the cooked monitor interface of an AP to see 4-addr frames so
- * that a 4-addr station can be detected and moved into a separate VLAN
+ * Send unexpected-4addr-frame event to hostapd. For older versions,
+ * also drop the frame to cooked monitor interfaces.
*/
if (ieee80211_has_a4(hdr->frame_control) &&
- sdata->vif.type == NL80211_IFTYPE_AP)
+ sdata->vif.type == NL80211_IFTYPE_AP) {
+ if (rx->sta &&
+ !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
+ cfg80211_rx_unexpected_4addr_frame(
+ rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
return RX_DROP_MONITOR;
+ }
err = __ieee80211_data_to_8023(rx, &port_control);
if (unlikely(err))
@@ -2108,6 +2214,20 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
if (!ieee80211_is_mgmt(mgmt->frame_control))
return RX_DROP_MONITOR;
+ if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+ ieee80211_is_beacon(mgmt->frame_control) &&
+ !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+ int sig = 0;
+
+ if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ sig = status->signal;
+
+ cfg80211_report_obss_beacon(rx->local->hw.wiphy,
+ rx->skb->data, rx->skb->len,
+ status->freq, sig, GFP_ATOMIC);
+ rx->flags |= IEEE80211_RX_BEACON_REPORTED;
+ }
+
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_MONITOR;
@@ -2140,16 +2260,71 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
switch (mgmt->u.action.category) {
+ case WLAN_CATEGORY_HT:
+ /* reject HT action frames from stations not supporting HT */
+ if (!rx->sta->sta.ht_cap.ht_supported)
+ goto invalid;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ break;
+
+ /* verify action & smps_control are present */
+ if (len < IEEE80211_MIN_ACTION_SIZE + 2)
+ goto invalid;
+
+ switch (mgmt->u.action.u.ht_smps.action) {
+ case WLAN_HT_ACTION_SMPS: {
+ struct ieee80211_supported_band *sband;
+ u8 smps;
+
+ /* convert to HT capability */
+ switch (mgmt->u.action.u.ht_smps.smps_control) {
+ case WLAN_HT_SMPS_CONTROL_DISABLED:
+ smps = WLAN_HT_CAP_SM_PS_DISABLED;
+ break;
+ case WLAN_HT_SMPS_CONTROL_STATIC:
+ smps = WLAN_HT_CAP_SM_PS_STATIC;
+ break;
+ case WLAN_HT_SMPS_CONTROL_DYNAMIC:
+ smps = WLAN_HT_CAP_SM_PS_DYNAMIC;
+ break;
+ default:
+ goto invalid;
+ }
+ smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+ /* if no change do nothing */
+ if ((rx->sta->sta.ht_cap.cap &
+ IEEE80211_HT_CAP_SM_PS) == smps)
+ goto handled;
+
+ rx->sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS;
+ rx->sta->sta.ht_cap.cap |= smps;
+
+ sband = rx->local->hw.wiphy->bands[status->band];
+
+ rate_control_rate_update(
+ local, sband, rx->sta,
+ IEEE80211_RC_SMPS_CHANGED,
+ ieee80211_get_tx_channel_type(
+ local, local->_oper_channel_type));
+ goto handled;
+ }
+ default:
+ goto invalid;
+ }
+
+ break;
case WLAN_CATEGORY_BACK:
- /*
- * The aggregation code is not prepared to handle
- * anything but STA/AP due to the BSSID handling;
- * IBSS could work in the code but isn't supported
- * by drivers or the standard.
- */
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- sdata->vif.type != NL80211_IFTYPE_AP)
+ sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
break;
/* verify action_code is present */
@@ -2203,7 +2378,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
- if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
+ if (compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid))
break;
goto queue;
@@ -2222,12 +2397,37 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto handled;
}
break;
+ case WLAN_CATEGORY_SELF_PROTECTED:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.self_prot.action_code)))
+ break;
+
+ switch (mgmt->u.action.u.self_prot.action_code) {
+ case WLAN_SP_MESH_PEERING_OPEN:
+ case WLAN_SP_MESH_PEERING_CLOSE:
+ case WLAN_SP_MESH_PEERING_CONFIRM:
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ goto invalid;
+ if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+ /* userspace handles this frame */
+ break;
+ goto queue;
+ case WLAN_SP_MGK_INFORM:
+ case WLAN_SP_MGK_ACK:
+ if (!ieee80211_vif_is_mesh(&sdata->vif))
+ goto invalid;
+ break;
+ }
+ break;
case WLAN_CATEGORY_MESH_ACTION:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.mesh_action.action_code)))
+ break;
+
if (!ieee80211_vif_is_mesh(&sdata->vif))
break;
- goto queue;
- case WLAN_CATEGORY_MESH_PATH_SEL:
- if (!mesh_path_sel_is_hwmp(sdata))
+ if (mesh_action_is_path_sel(mgmt) &&
+ (!mesh_path_sel_is_hwmp(sdata)))
break;
goto queue;
}
@@ -2258,6 +2458,7 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+ int sig = 0;
/* skip known-bad action frames and return them in the next handler */
if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
@@ -2270,7 +2471,10 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
* it transmitted were processed or returned.
*/
- if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
+ if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ sig = status->signal;
+
+ if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig,
rx->skb->data, rx->skb->len,
GFP_ATOMIC)) {
if (rx->sta)
@@ -2338,14 +2542,9 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
- ieee80211_rx_result rxs;
struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
__le16 stype;
- rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
- if (rxs != RX_CONTINUE)
- return rxs;
-
stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
@@ -2354,10 +2553,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
switch (stype) {
+ case cpu_to_le16(IEEE80211_STYPE_AUTH):
case cpu_to_le16(IEEE80211_STYPE_BEACON):
case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
/* process for all: mesh, mlme, ibss */
break;
+ case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+ case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
if (is_multicast_ether_addr(mgmt->da) &&
@@ -2369,7 +2571,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
break;
case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
- case cpu_to_le16(IEEE80211_STYPE_AUTH):
/* process only for ibss */
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
return RX_DROP_MONITOR;
@@ -2394,16 +2595,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local = rx->local;
- struct ieee80211_rtap_hdr {
- struct ieee80211_radiotap_header hdr;
- u8 flags;
- u8 rate_or_pad;
- __le16 chan_freq;
- __le16 chan_flags;
- } __packed *rthdr;
struct sk_buff *skb = rx->skb, *skb2;
struct net_device *prev_dev = NULL;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ int needed_headroom;
/*
* If cooked monitor has been processed already, then
@@ -2413,30 +2608,20 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
goto out_free_skb;
rx->flags |= IEEE80211_RX_CMNTR;
- if (skb_headroom(skb) < sizeof(*rthdr) &&
- pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
+ /* If there are no cooked monitor interfaces, just free the SKB */
+ if (!local->cooked_mntrs)
goto out_free_skb;
- 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_CHANNEL));
+ /* room for the radiotap header based on driver features */
+ needed_headroom = ieee80211_rx_radiotap_len(local, status);
- if (rate) {
- rthdr->rate_or_pad = rate->bitrate / 5;
- rthdr->hdr.it_present |=
- cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
- }
- rthdr->chan_freq = cpu_to_le16(status->freq);
+ if (skb_headroom(skb) < needed_headroom &&
+ pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
+ goto out_free_skb;
- if (status->band == IEEE80211_BAND_5GHZ)
- 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);
+ /* prepend radiotap information */
+ ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
+ false);
skb_set_mac_header(skb, 0);
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2539,17 +2724,16 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
+ CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)
CALL_RXH(ieee80211_rx_h_sta_process)
CALL_RXH(ieee80211_rx_h_defragment)
- CALL_RXH(ieee80211_rx_h_ps_poll)
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
- CALL_RXH(ieee80211_rx_h_remove_qos_control)
- CALL_RXH(ieee80211_rx_h_amsdu)
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
+ CALL_RXH(ieee80211_rx_h_amsdu)
CALL_RXH(ieee80211_rx_h_data)
CALL_RXH(ieee80211_rx_h_ctrl);
CALL_RXH(ieee80211_rx_h_mgmt_check)
@@ -2605,7 +2789,9 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
.sta = sta,
.sdata = sta->sdata,
.local = sta->local,
- .queue = tid,
+ /* This is OK -- must be QoS data frame */
+ .security_idx = tid,
+ .seqno_idx = tid,
.flags = 0,
};
struct tid_ampdu_rx *tid_agg_rx;
@@ -2647,6 +2833,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
case NL80211_IFTYPE_ADHOC:
if (!bssid)
return 0;
+ if (compare_ether_addr(sdata->vif.addr, hdr->addr2) == 0 ||
+ compare_ether_addr(sdata->u.ibss.bssid, hdr->addr2) == 0)
+ return 0;
if (ieee80211_is_beacon(hdr->frame_control)) {
return 1;
}
@@ -2666,8 +2855,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
rate_idx = 0; /* TODO: HT rates */
else
rate_idx = status->rate_idx;
- rx->sta = ieee80211_ibss_add_sta(sdata, bssid,
- hdr->addr2, BIT(rate_idx), GFP_ATOMIC);
+ ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
+ BIT(rate_idx));
}
break;
case NL80211_IFTYPE_MESH_POINT:
@@ -2688,6 +2877,15 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
return 0;
} else if (!ieee80211_bssid_match(bssid,
sdata->vif.addr)) {
+ /*
+ * Accept public action frames even when the
+ * BSSID doesn't match, this is used for P2P
+ * and location updates. Note that mac80211
+ * itself never looks at these frames.
+ */
+ if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
+ ieee80211_is_public_action(hdr, skb->len))
+ return 1;
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
!ieee80211_is_beacon(hdr->frame_control))
return 0;