]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/mac80211/rx.c
mac80211: pass in PS_POLL frames
[mv-sheeva.git] / net / mac80211 / rx.c
index 7cd185e9dde4a70871755801489ed8054d7517a7..e65da5780cd38780ed6eccd2876b93077ccfbbfc 100644 (file)
@@ -61,8 +61,10 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
                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))
+       if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==
+                       cpu_to_le16(IEEE80211_FTYPE_CTL)) &&
+           ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
+                       cpu_to_le16(IEEE80211_STYPE_PSPOLL)))
                return 1;
        return 0;
 }
@@ -79,8 +81,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_rate *rate;
        int needed_headroom = 0;
-       struct ieee80211_rtap_hdr {
-               struct ieee80211_radiotap_header hdr;
+       struct ieee80211_radiotap_header *rthdr;
+       __le64 *rttsft = NULL;
+       struct ieee80211_rtap_fixed_data {
                u8 flags;
                u8 rate;
                __le16 chan_freq;
@@ -88,7 +91,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                u8 antsignal;
                u8 padding_for_rxflags;
                __le16 rx_flags;
-       } __attribute__ ((packed)) *rthdr;
+       } __attribute__ ((packed)) *rtfixed;
        struct sk_buff *skb, *skb2;
        struct net_device *prev_dev = NULL;
        int present_fcs_len = 0;
@@ -105,7 +108,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        if (status->flag & RX_FLAG_RADIOTAP)
                rtap_len = ieee80211_get_radiotap_len(origskb->data);
        else
-               needed_headroom = sizeof(*rthdr);
+               /* room for radiotap header, always present fields and TSFT */
+               needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8;
 
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
@@ -133,7 +137,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                 * them allocate enough headroom to start with.
                 */
                if (skb_headroom(skb) < needed_headroom &&
-                   pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+                   pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) {
                        dev_kfree_skb(skb);
                        return NULL;
                }
@@ -152,42 +156,56 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 
        /* if necessary, prepend radiotap information */
        if (!(status->flag & RX_FLAG_RADIOTAP)) {
+               rtfixed = (void *) skb_push(skb, sizeof(*rtfixed));
+               rtap_len = sizeof(*rthdr) + sizeof(*rtfixed);
+               if (status->flag & RX_FLAG_TSFT) {
+                       rttsft = (void *) skb_push(skb, sizeof(*rttsft));
+                       rtap_len += 8;
+               }
                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 =
+               memset(rtfixed, 0, sizeof(*rtfixed));
+               rthdr->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;
+               rtfixed->flags = 0;
+               if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+                       rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS;
+
+               if (rttsft) {
+                       *rttsft = cpu_to_le64(status->mactime);
+                       rthdr->it_present |=
+                               cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+               }
 
                /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
-               rthdr->rx_flags = 0;
+               rtfixed->rx_flags = 0;
                if (status->flag &
                    (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
-                       rthdr->rx_flags |=
+                       rtfixed->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;
+                       rtfixed->rate = rate->rate / 5;
 
-               rthdr->chan_freq = cpu_to_le16(status->freq);
+               rtfixed->chan_freq = cpu_to_le16(status->freq);
 
                if (status->phymode == MODE_IEEE80211A)
-                       rthdr->chan_flags =
+                       rtfixed->chan_flags =
                                cpu_to_le16(IEEE80211_CHAN_OFDM |
                                            IEEE80211_CHAN_5GHZ);
                else
-                       rthdr->chan_flags =
+                       rtfixed->chan_flags =
                                cpu_to_le16(IEEE80211_CHAN_DYN |
                                            IEEE80211_CHAN_2GHZ);
 
-               rthdr->antsignal = status->ssi;
+               rtfixed->antsignal = status->ssi;
+               rthdr->it_len = cpu_to_le16(rtap_len);
        }
 
        skb_set_mac_header(skb, 0);
@@ -243,6 +261,10 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
                u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
                /* frame has qos control */
                tid = qc[0] & QOS_CONTROL_TID_MASK;
+               if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+                       rx->flags |= IEEE80211_TXRXD_RX_AMSDU;
+               else
+                       rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU;
        } else {
                if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
                        /* Separate TID for management frames */
@@ -338,8 +360,14 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct sk_buff *skb = rx->skb;
 
-       if (unlikely(local->sta_scanning != 0)) {
-               ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+       if (unlikely(local->sta_hw_scanning))
+               return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+
+       if (unlikely(local->sta_sw_scanning)) {
+               /* drop all the other packets during a software scan anyway */
+               if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
+                   != TXRX_QUEUED)
+                       dev_kfree_skb(skb);
                return TXRX_QUEUED;
        }
 
@@ -419,11 +447,12 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 
 
 static ieee80211_txrx_result
-ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
        int keyidx;
        int hdrlen;
+       ieee80211_txrx_result result = TXRX_DROP;
        struct ieee80211_key *stakey = NULL;
 
        /*
@@ -456,7 +485,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
                return TXRX_CONTINUE;
 
        /*
-        * No point in finding a key if the frame is neither
+        * No point in finding a key and decrypting if the frame is neither
         * addressed to us nor a multicast frame.
         */
        if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
@@ -507,9 +536,39 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
        if (rx->key) {
                rx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
+       } else {
+#ifdef CONFIG_MAC80211_DEBUG
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "%s: RX protected frame,"
+                              " but have no key\n", rx->dev->name);
+#endif /* CONFIG_MAC80211_DEBUG */
+               return TXRX_DROP;
        }
 
-       return TXRX_CONTINUE;
+       /* Check for weak IVs if possible */
+       if (rx->sta && rx->key->conf.alg == ALG_WEP &&
+           ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+           (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||
+            !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) &&
+           ieee80211_wep_is_weak_iv(rx->skb, rx->key))
+               rx->sta->wep_weak_iv_count++;
+
+       switch (rx->key->conf.alg) {
+       case ALG_WEP:
+               result = ieee80211_crypto_wep_decrypt(rx);
+               break;
+       case ALG_TKIP:
+               result = ieee80211_crypto_tkip_decrypt(rx);
+               break;
+       case ALG_CCMP:
+               result = ieee80211_crypto_ccmp_decrypt(rx);
+               break;
+       }
+
+       /* either the frame has been decrypted or will be dropped */
+       rx->u.rx.status->flag |= RX_FLAG_DECRYPTED;
+
+       return result;
 }
 
 static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
@@ -637,53 +696,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
        return TXRX_CONTINUE;
 } /* ieee80211_rx_h_sta_process */
 
-static ieee80211_txrx_result
-ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx)
-{
-       if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
-           (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-           !rx->key || rx->key->conf.alg != ALG_WEP ||
-           !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               return TXRX_CONTINUE;
-
-       /* Check for weak IVs, if hwaccel did not remove IV from the frame */
-       if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||
-           !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED))
-               if (ieee80211_wep_is_weak_iv(rx->skb, rx->key))
-                       rx->sta->wep_weak_iv_count++;
-
-       return TXRX_CONTINUE;
-}
-
-static ieee80211_txrx_result
-ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
-{
-       if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
-               return TXRX_CONTINUE;
-
-       if (!rx->key) {
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "%s: RX protected frame,"
-                              " but have no key\n", rx->dev->name);
-               return TXRX_DROP;
-       }
-
-       switch (rx->key->conf.alg) {
-       case ALG_WEP:
-               return ieee80211_crypto_wep_decrypt(rx);
-       case ALG_TKIP:
-               return ieee80211_crypto_tkip_decrypt(rx);
-       case ALG_CCMP:
-               return ieee80211_crypto_ccmp_decrypt(rx);
-       case ALG_NONE:
-               return TXRX_CONTINUE;
-       }
-
-       /* not reached */
-       WARN_ON(1);
-       return TXRX_DROP;
-}
-
 static inline struct ieee80211_fragment_entry *
 ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
                         unsigned int frag, unsigned int seq, int rx_queue,
@@ -886,6 +898,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 static ieee80211_txrx_result
 ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 {
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
        struct sk_buff *skb;
        int no_pending_pkts;
        DECLARE_MAC_BUF(mac);
@@ -896,6 +909,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
                   !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
                return TXRX_CONTINUE;
 
+       if ((sdata->type != IEEE80211_IF_TYPE_AP) &&
+           (sdata->type != IEEE80211_IF_TYPE_VLAN))
+               return TXRX_DROP;
+
        skb = skb_dequeue(&rx->sta->tx_filtered);
        if (!skb) {
                skb = skb_dequeue(&rx->sta->ps_tx_buf);
@@ -972,42 +989,38 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
        return TXRX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_drop_802_1x_pae(struct ieee80211_txrx_data *rx, int hdrlen)
 {
-       if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
+       if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb, hdrlen) &&
            rx->sdata->type != IEEE80211_IF_TYPE_STA &&
            (rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               return TXRX_CONTINUE;
+               return 0;
 
        if (unlikely(rx->sdata->ieee802_1x &&
                     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
                     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
                     (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) &&
-                    !ieee80211_is_eapol(rx->skb))) {
+                    !ieee80211_is_eapol(rx->skb, hdrlen))) {
 #ifdef CONFIG_MAC80211_DEBUG
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) rx->skb->data;
-               DECLARE_MAC_BUF(mac);
-               printk(KERN_DEBUG "%s: dropped frame from %s"
-                      " (unauthorized port)\n", rx->dev->name,
-                      print_mac(mac, hdr->addr2));
+               printk(KERN_DEBUG "%s: dropped frame "
+                      "(unauthorized port)\n", rx->dev->name);
 #endif /* CONFIG_MAC80211_DEBUG */
-               return TXRX_DROP;
+               return -EACCES;
        }
 
-       return TXRX_CONTINUE;
+       return 0;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx, int hdrlen)
 {
        /*
         * Pass through unencrypted frames if the hardware has
         * decrypted them already.
         */
        if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED)
-               return TXRX_CONTINUE;
+               return 0;
 
        /* Drop unencrypted frames if key is set. */
        if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
@@ -1015,26 +1028,25 @@ ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
                     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
                     (rx->key || rx->sdata->drop_unencrypted) &&
                     (rx->sdata->eapol == 0 ||
-                     !ieee80211_is_eapol(rx->skb)))) {
+                     !ieee80211_is_eapol(rx->skb, hdrlen)))) {
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
                               "encryption\n", rx->dev->name);
-               return TXRX_DROP;
+               return -EACCES;
        }
-       return TXRX_CONTINUE;
+       return 0;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
 {
        struct net_device *dev = rx->dev;
-       struct ieee80211_local *local = rx->local;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
        u16 fc, hdrlen, ethertype;
        u8 *payload;
        u8 dst[ETH_ALEN];
        u8 src[ETH_ALEN];
-       struct sk_buff *skb = rx->skb, *skb2;
+       struct sk_buff *skb = rx->skb;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        DECLARE_MAC_BUF(mac);
        DECLARE_MAC_BUF(mac2);
@@ -1042,11 +1054,9 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
        DECLARE_MAC_BUF(mac4);
 
        fc = rx->fc;
-       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
-               return TXRX_CONTINUE;
 
        if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-               return TXRX_DROP;
+               return -1;
 
        hdrlen = ieee80211_get_hdrlen(fc);
 
@@ -1075,7 +1085,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                                       print_mac(mac, hdr->addr1),
                                       print_mac(mac2, hdr->addr2),
                                       print_mac(mac3, hdr->addr3));
-                       return TXRX_DROP;
+                       return -1;
                }
                break;
        case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
@@ -1092,7 +1102,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                                       print_mac(mac2, hdr->addr2),
                                       print_mac(mac3, hdr->addr3),
                                       print_mac(mac4, hdr->addr4));
-                       return TXRX_DROP;
+                       return -1;
                }
                break;
        case IEEE80211_FCTL_FROMDS:
@@ -1103,7 +1113,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                if (sdata->type != IEEE80211_IF_TYPE_STA ||
                    (is_multicast_ether_addr(dst) &&
                     !compare_ether_addr(src, dev->dev_addr)))
-                       return TXRX_DROP;
+                       return -1;
                break;
        case 0:
                /* DA SA BSSID */
@@ -1119,21 +1129,20 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                                       print_mac(mac2, hdr->addr2),
                                       print_mac(mac3, hdr->addr3));
                        }
-                       return TXRX_DROP;
+                       return -1;
                }
                break;
        }
 
-       payload = skb->data + hdrlen;
-
        if (unlikely(skb->len - hdrlen < 8)) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: RX too short data frame "
                               "payload\n", dev->name);
                }
-               return TXRX_DROP;
+               return -1;
        }
 
+       payload = skb->data + hdrlen;
        ethertype = (payload[6] << 8) | payload[7];
 
        if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
@@ -1154,12 +1163,19 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(ehdr->h_source, src, ETH_ALEN);
                ehdr->h_proto = len;
        }
-       skb->dev = dev;
+       return 0;
+}
 
-       skb2 = NULL;
+static void
+ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
+{
+       struct net_device *dev = rx->dev;
+       struct ieee80211_local *local = rx->local;
+       struct sk_buff *skb, *xmit_skb;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
+       skb = rx->skb;
+       xmit_skb = NULL;
 
        if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
            || sdata->type == IEEE80211_IF_TYPE_VLAN) &&
@@ -1167,8 +1183,8 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                if (is_multicast_ether_addr(skb->data)) {
                        /* send multicast frames both to higher layers in
                         * local net stack and back to the wireless media */
-                       skb2 = skb_copy(skb, GFP_ATOMIC);
-                       if (!skb2 && net_ratelimit())
+                       xmit_skb = skb_copy(skb, GFP_ATOMIC);
+                       if (!xmit_skb && net_ratelimit())
                                printk(KERN_DEBUG "%s: failed to clone "
                                       "multicast frame\n", dev->name);
                } else {
@@ -1183,7 +1199,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                                 * AP, so send the frame directly to it and
                                 * do not pass the frame to local net stack.
                                 */
-                               skb2 = skb;
+                               xmit_skb = skb;
                                skb = NULL;
                        }
                        if (dsta)
@@ -1198,13 +1214,164 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                netif_rx(skb);
        }
 
-       if (skb2) {
+       if (xmit_skb) {
                /* send to wireless media */
-               skb2->protocol = __constant_htons(ETH_P_802_3);
-               skb_set_network_header(skb2, 0);
-               skb_set_mac_header(skb2, 0);
-               dev_queue_xmit(skb2);
+               xmit_skb->protocol = htons(ETH_P_802_3);
+               skb_set_network_header(xmit_skb, 0);
+               skb_set_mac_header(xmit_skb, 0);
+               dev_queue_xmit(xmit_skb);
        }
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
+{
+       struct net_device *dev = rx->dev;
+       struct ieee80211_local *local = rx->local;
+       u16 fc, ethertype;
+       u8 *payload;
+       struct sk_buff *skb = rx->skb, *frame = NULL;
+       const struct ethhdr *eth;
+       int remaining, err;
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       DECLARE_MAC_BUF(mac);
+
+       fc = rx->fc;
+       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+               return TXRX_CONTINUE;
+
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return TXRX_DROP;
+
+       if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU))
+               return TXRX_CONTINUE;
+
+       err = ieee80211_data_to_8023(rx);
+       if (unlikely(err))
+               return TXRX_DROP;
+
+       skb->dev = dev;
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+
+       /* skip the wrapping header */
+       eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
+       if (!eth)
+               return TXRX_DROP;
+
+       while (skb != frame) {
+               u8 padding;
+               __be16 len = eth->h_proto;
+               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
+
+               remaining = skb->len;
+               memcpy(dst, eth->h_dest, ETH_ALEN);
+               memcpy(src, eth->h_source, ETH_ALEN);
+
+               padding = ((4 - subframe_len) & 0x3);
+               /* the last MSDU has no padding */
+               if (subframe_len > remaining) {
+                       printk(KERN_DEBUG "%s: wrong buffer size", dev->name);
+                       return TXRX_DROP;
+               }
+
+               skb_pull(skb, sizeof(struct ethhdr));
+               /* if last subframe reuse skb */
+               if (remaining <= subframe_len + padding)
+                       frame = skb;
+               else {
+                       frame = dev_alloc_skb(local->hw.extra_tx_headroom +
+                                             subframe_len);
+
+                       if (frame == NULL)
+                               return TXRX_DROP;
+
+                       skb_reserve(frame, local->hw.extra_tx_headroom +
+                                   sizeof(struct ethhdr));
+                       memcpy(skb_put(frame, ntohs(len)), skb->data,
+                               ntohs(len));
+
+                       eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
+                                                       padding);
+                       if (!eth) {
+                               printk(KERN_DEBUG "%s: wrong buffer size ",
+                                      dev->name);
+                               dev_kfree_skb(frame);
+                               return TXRX_DROP;
+                       }
+               }
+
+               skb_set_network_header(frame, 0);
+               frame->dev = dev;
+               frame->priority = skb->priority;
+               rx->skb = frame;
+
+               if ((ieee80211_drop_802_1x_pae(rx, 0)) ||
+                   (ieee80211_drop_unencrypted(rx, 0))) {
+                       if (skb == frame) /* last frame */
+                               return TXRX_DROP;
+                       dev_kfree_skb(frame);
+                       continue;
+               }
+
+               payload = frame->data;
+               ethertype = (payload[6] << 8) | payload[7];
+
+               if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+                       ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+                       compare_ether_addr(payload,
+                                          bridge_tunnel_header) == 0)) {
+                       /* remove RFC1042 or Bridge-Tunnel
+                        * encapsulation and replace EtherType */
+                       skb_pull(frame, 6);
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               } else {
+                       memcpy(skb_push(frame, sizeof(__be16)), &len,
+                               sizeof(__be16));
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               }
+
+
+               ieee80211_deliver_skb(rx);
+       }
+
+       return TXRX_QUEUED;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+{
+       struct net_device *dev = rx->dev;
+       u16 fc;
+       int err, hdrlen;
+
+       fc = rx->fc;
+       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+               return TXRX_CONTINUE;
+
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return TXRX_DROP;
+
+       hdrlen = ieee80211_get_hdrlen(fc);
+
+       if ((ieee80211_drop_802_1x_pae(rx, hdrlen)) ||
+           (ieee80211_drop_unencrypted(rx, hdrlen)))
+               return TXRX_DROP;
+
+       err = ieee80211_data_to_8023(rx);
+       if (unlikely(err))
+               return TXRX_DROP;
+
+       rx->skb->dev = dev;
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += rx->skb->len;
+
+       ieee80211_deliver_skb(rx);
 
        return TXRX_QUEUED;
 }
@@ -1220,7 +1387,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
        sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
        if ((sdata->type == IEEE80211_IF_TYPE_STA ||
             sdata->type == IEEE80211_IF_TYPE_IBSS) &&
-           !rx->local->user_space_mlme)
+           !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
                ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
        else
                return TXRX_DROP;
@@ -1348,10 +1515,8 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
        ieee80211_rx_h_if_stats,
        ieee80211_rx_h_passive_scan,
        ieee80211_rx_h_check,
-       ieee80211_rx_h_load_key,
-       ieee80211_rx_h_sta_process,
-       ieee80211_rx_h_wep_weak_iv_detection,
        ieee80211_rx_h_decrypt,
+       ieee80211_rx_h_sta_process,
        ieee80211_rx_h_defragment,
        ieee80211_rx_h_ps_poll,
        ieee80211_rx_h_michael_mic_verify,
@@ -1360,8 +1525,7 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
         * are not passed to user space by these functions
         */
        ieee80211_rx_h_remove_qos_control,
-       ieee80211_rx_h_802_1x_pae,
-       ieee80211_rx_h_drop_unencrypted,
+       ieee80211_rx_h_amsdu,
        ieee80211_rx_h_data,
        ieee80211_rx_h_mgmt,
        NULL
@@ -1462,6 +1626,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
        u8 *bssid;
+       int hdrlen;
 
        /*
         * key references and virtual interfaces are protected using RCU
@@ -1491,6 +1656,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
        rx.fc = le16_to_cpu(hdr->frame_control);
        type = rx.fc & IEEE80211_FCTL_FTYPE;
 
+       /*
+        * Drivers are required to align the payload data to a four-byte
+        * boundary, so the last two bits of the address where it starts
+        * may not be set. The header is required to be directly before
+        * the payload data, padding like atheros hardware adds which is
+        * inbetween the 802.11 header and the payload is not supported,
+        * the driver is required to move the 802.11 header further back
+        * in that case.
+        */
+       hdrlen = ieee80211_get_hdrlen(rx.fc);
+       WARN_ON_ONCE(((unsigned long)(skb->data + hdrlen)) & 3);
+
        if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
                local->dot11ReceivedFragmentCount++;
 
@@ -1505,7 +1682,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                goto end;
        }
 
-       if (unlikely(local->sta_scanning))
+       if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
                rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
 
        if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,