Merge remote branch 'wireless-next/master' into ath6kl-next
[cascardo/linux.git] / net / mac80211 / rx.c
index 7514091..bcfe8c7 100644 (file)
@@ -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;
                }
        }
@@ -611,7 +613,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
        index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                tid_agg_rx->buf_size;
        if (!tid_agg_rx->reorder_buf[index] &&
-           tid_agg_rx->stored_mpdu_num > 1) {
+           tid_agg_rx->stored_mpdu_num) {
                /*
                 * No buffers ready to be released, but check whether any
                 * frames in the reorder buffer have timed out.
@@ -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))