summaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-04-14 13:18:27 +0200
committerIngo Molnar <mingo@kernel.org>2012-04-14 13:19:04 +0200
commit6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch)
tree021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /net/mac80211/rx.c
parent682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff)
parenta385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff)
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree), to prepare for tooling changes, and also to pick up v3.4 MM changes that the uprobes code needs to take care of. Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c123
1 files changed, 53 insertions, 70 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5a5e504a8ff..bcfe8c77c83 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -19,6 +19,7 @@
#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"
@@ -176,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);
@@ -226,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;
@@ -488,12 +490,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;
}
}
@@ -859,7 +861,12 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
- if (rx->sta && rx->sta->dummy &&
+ /*
+ * 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)) {
u16 ethertype;
u8 *payload;
@@ -1056,20 +1063,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
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:
@@ -1089,6 +1085,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;
@@ -1145,19 +1143,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_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;
}
@@ -1307,8 +1301,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
@@ -1955,6 +1951,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
}
+ if (!ifmsh->mshcfg.dot11MeshForwarding)
+ goto out;
+
fwd_skb = skb_copy(skb, GFP_ATOMIC);
if (!fwd_skb) {
if (net_ratelimit())
@@ -2180,12 +2179,14 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
ieee80211_is_beacon(mgmt->frame_control) &&
!(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
- struct ieee80211_rx_status *status;
+ int sig = 0;
+
+ if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ sig = status->signal;
- status = IEEE80211_SKB_RXCB(rx->skb);
cfg80211_report_obss_beacon(rx->local->hw.wiphy,
rx->skb->data, rx->skb->len,
- status->freq, GFP_ATOMIC);
+ status->freq, sig, GFP_ATOMIC);
rx->flags |= IEEE80211_RX_BEACON_REPORTED;
}
@@ -2268,9 +2269,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sband = rx->local->hw.wiphy->bands[status->band];
- rate_control_rate_update(local, sband, rx->sta,
- IEEE80211_RC_SMPS_CHANGED,
- local->_oper_channel_type);
+ 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:
@@ -2337,7 +2340,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;
@@ -2409,6 +2412,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)
@@ -2421,7 +2425,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)
@@ -2486,14 +2493,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) &&
@@ -2502,10 +2504,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) &&
@@ -2517,7 +2522,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;
@@ -2542,16 +2546,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
@@ -2565,30 +2563,15 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
if (!local->cooked_mntrs)
goto out_free_skb;
- if (skb_headroom(skb) < sizeof(*rthdr) &&
- pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
- 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);
skb_set_mac_header(skb, 0);
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2956,7 +2939,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (ieee80211_is_data(fc)) {
prev_sta = NULL;
- for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
+ for_each_sta_info(local, hdr->addr2, sta, tmp) {
if (!prev_sta) {
prev_sta = sta;
continue;
@@ -3000,7 +2983,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
continue;
}
- rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
rx.sdata = prev;
ieee80211_prepare_and_rx_handle(&rx, skb, false);
@@ -3008,7 +2991,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if (prev) {
- rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
+ rx.sta = sta_info_get_bss(prev, hdr->addr2);
rx.sdata = prev;
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))