Upgrade b43 and mac80211.
[openwrt/staging/lynxis/omap.git] / package / mac80211 / src / net / mac80211 / rx.c
index 064924cb289bb3533bfcbd20763990fcd2e82839..943ba908298c3c1d07d0df56976b52064910f52a 100644 (file)
 #include "tkip.h"
 #include "wme.h"
 
+u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+                               struct tid_ampdu_rx *tid_agg_rx,
+                               struct sk_buff *skb, u16 mpdu_seq_num,
+                               int bar_req);
 /*
  * monitor mode reception
  *
@@ -61,8 +65,12 @@ 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)) &&
+           ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) !=
+                       cpu_to_le16(IEEE80211_STYPE_BACK_REQ)))
                return 1;
        return 0;
 }
@@ -74,13 +82,14 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
  */
 static struct sk_buff *
 ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
-                    struct ieee80211_rx_status *status)
+                    struct ieee80211_rx_status *status,
+                    struct ieee80211_rate *rate)
 {
        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 +97,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 +114,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 +143,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,45 +162,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->bitrate / 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 =
+               if (status->band == IEEE80211_BAND_5GHZ)
+                       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);
+       skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
@@ -199,7 +220,10 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                if (!netif_running(sdata->dev))
                        continue;
 
-               if (sdata->type != IEEE80211_IF_TYPE_MNTR)
+               if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR)
+                       continue;
+
+               if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
                        continue;
 
                if (prev_dev) {
@@ -225,15 +249,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 }
 
 
-/* pre-rx handlers
- *
- * these don't have dev/sdata fields in the rx data
- * The sta value should also not be used because it may
- * be NULL even though a STA (in IBSS mode) will be added.
- */
-
-static ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx)
 {
        u8 *data = rx->skb->data;
        int tid;
@@ -243,6 +259,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 */
@@ -262,40 +282,59 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
        /* 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;
+}
+
+static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx)
+{
+#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
+       int hdrlen;
 
-       return TXRX_CONTINUE;
+       if (!WLAN_FC_DATA_PRESENT(rx->fc))
+               return;
+
+       /*
+        * Drivers are required to align the payload data in a way that
+        * guarantees that the contained IP header is aligned to a four-
+        * byte boundary. In the case of regular frames, this simply means
+        * aligning the payload to a four-byte boundary (because either
+        * the IP header is directly contained, or IV/RFC1042 headers that
+        * have a length divisible by four are in front of it.
+        *
+        * With A-MSDU frames, however, the payload data address must
+        * yield two modulo four because there are 14-byte 802.3 headers
+        * within the A-MSDU frames that push the IP header further back
+        * to a multiple of four again. Thankfully, the specs were sane
+        * enough this time around to require padding each A-MSDU subframe
+        * to a length that is a multiple of four.
+        *
+        * 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);
+       if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
+               hdrlen += ETH_HLEN;
+       WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
+#endif
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+
+static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
+                                  struct sk_buff *skb,
+                                  struct ieee80211_rx_status *status,
+                                  struct ieee80211_rate *rate)
 {
-       struct ieee80211_local *local = rx->local;
-       struct sk_buff *skb = rx->skb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u32 load = 0, hdrtime;
-       struct ieee80211_rate *rate;
-       struct ieee80211_hw_mode *mode = local->hw.conf.mode;
-       int i;
 
        /* Estimate total channel use caused by this frame */
 
-       if (unlikely(mode->num_rates < 0))
-               return TXRX_CONTINUE;
-
-       rate = &mode->rates[0];
-       for (i = 0; i < mode->num_rates; i++) {
-               if (mode->rates[i].val == rx->u.rx.status->rate) {
-                       rate = &mode->rates[i];
-                       break;
-               }
-       }
-
        /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
         * 1 usec = 1/8 * (1080 / 10) = 13.5 */
 
-       if (mode->mode == MODE_IEEE80211A ||
-           (mode->mode == MODE_IEEE80211G &&
-            rate->flags & IEEE80211_RATE_ERP))
+       if (status->band == IEEE80211_BAND_5GHZ ||
+           (status->band == IEEE80211_BAND_5GHZ &&
+            rate->flags & IEEE80211_RATE_ERP_G))
                hdrtime = CHAN_UTIL_HDR_SHORT;
        else
                hdrtime = CHAN_UTIL_HDR_LONG;
@@ -304,55 +343,53 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
        if (!is_multicast_ether_addr(hdr->addr1))
                load += hdrtime;
 
-       load += skb->len * rate->rate_inv;
+       /* TODO: optimise again */
+       load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
 
        /* Divide channel_use by 8 to avoid wrapping around the counter */
        load >>= CHAN_UTIL_SHIFT;
-       local->channel_use_raw += load;
-       rx->u.rx.load = load;
 
-       return TXRX_CONTINUE;
+       return load;
 }
 
-ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
-{
-       ieee80211_rx_h_parse_qos,
-       ieee80211_rx_h_load_stats,
-       NULL
-};
-
 /* rx handlers */
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
 {
        if (rx->sta)
                rx->sta->channel_use_raw += rx->u.rx.load;
        rx->sdata->channel_use_raw += rx->u.rx.load;
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 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);
-               return TXRX_QUEUED;
+       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)
+                   != RX_QUEUED)
+                       dev_kfree_skb(skb);
+               return RX_QUEUED;
        }
 
        if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) {
                /* scanning finished during invoking of handlers */
                I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
-               return TXRX_DROP;
+               return RX_DROP_UNUSABLE;
        }
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr;
@@ -367,28 +404,16 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
                                rx->local->dot11FrameDuplicateCount++;
                                rx->sta->num_duplicates++;
                        }
-                       return TXRX_DROP;
+                       return RX_DROP_MONITOR;
                } else
                        rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
        }
 
        if (unlikely(rx->skb->len < 16)) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
-               return TXRX_DROP;
+               return RX_DROP_MONITOR;
        }
 
-       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               rx->skb->pkt_type = PACKET_OTHERHOST;
-       else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)
-               rx->skb->pkt_type = PACKET_HOST;
-       else if (is_multicast_ether_addr(hdr->addr1)) {
-               if (is_broadcast_ether_addr(hdr->addr1))
-                       rx->skb->pkt_type = PACKET_BROADCAST;
-               else
-                       rx->skb->pkt_type = PACKET_MULTICAST;
-       } else
-               rx->skb->pkt_type = PACKET_OTHERHOST;
-
        /* Drop disallowed frame classes based on STA auth/assoc state;
         * IEEE 802.11, Chap 5.5.
         *
@@ -400,7 +425,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
        if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
                      ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
                       (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
-                    rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+                    rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
                     (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
                if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
                     !(rx->fc & IEEE80211_FCTL_TODS) &&
@@ -408,23 +433,23 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
                    || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
                        /* Drop IBSS frames and frames for other hosts
                         * silently. */
-                       return TXRX_DROP;
+                       return RX_DROP_MONITOR;
                }
 
-               return TXRX_DROP;
+               return RX_DROP_MONITOR;
        }
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 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;
+       ieee80211_rx_result result = RX_DROP_UNUSABLE;
        struct ieee80211_key *stakey = NULL;
 
        /*
@@ -454,14 +479,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
         */
 
        if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        /*
         * 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))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        if (rx->sta)
                stakey = rcu_dereference(rx->sta->key);
@@ -480,12 +505,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
                 */
                if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
                    (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
-                       return TXRX_CONTINUE;
+                       return RX_CONTINUE;
 
                hdrlen = ieee80211_get_hdrlen(rx->fc);
 
                if (rx->skb->len < 8 + hdrlen)
-                       return TXRX_DROP; /* TODO: count this? */
+                       return RX_DROP_UNUSABLE; /* TODO: count this? */
 
                /*
                 * no need to call ieee80211_wep_get_keyidx,
@@ -509,10 +534,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
                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);
-               return TXRX_DROP;
+#endif /* CONFIG_MAC80211_DEBUG */
+               return RX_DROP_MONITOR;
        }
 
        /* Check for weak IVs if possible */
@@ -544,6 +571,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata;
+       DECLARE_MAC_BUF(mac);
+
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 
        if (sdata->bss)
@@ -551,8 +580,8 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
        sta->flags |= WLAN_STA_PS;
        sta->pspoll = 0;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power "
-              "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+       printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
+              dev->name, print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
@@ -563,6 +592,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
        int sent = 0;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_tx_packet_data *pkt_data;
+       DECLARE_MAC_BUF(mac);
 
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
        if (sdata->bss)
@@ -576,8 +606,8 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
                        bss_tim_clear(local, sdata->bss, sta->aid);
        }
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power "
-              "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+       printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
+              dev->name, print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
        /* Send all buffered frames to the station */
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
@@ -591,9 +621,9 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
                local->total_ps_buffered--;
                sent++;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame "
+               printk(KERN_DEBUG "%s: STA %s aid %d send PS frame "
                       "since STA not sleeping anymore\n", dev->name,
-                      MAC_ARG(sta->addr), sta->aid);
+                      print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
                pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
                dev_queue_xmit(skb);
@@ -602,7 +632,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
        return sent;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 {
        struct sta_info *sta = rx->sta;
@@ -610,18 +640,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 
        if (!sta)
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        /* Update last_rx only for IBSS packets which are for the current
         * BSSID to avoid keeping the current IBSS network alive in cases where
         * other STAs are using different BSSID. */
-       if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len);
+       if (rx->sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+               u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
+                                               IEEE80211_IF_TYPE_IBSS);
                if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
                        sta->last_rx = jiffies;
        } else
        if (!is_multicast_ether_addr(hdr->addr1) ||
-           rx->sdata->type == IEEE80211_IF_TYPE_STA) {
+           rx->sdata->vif.type == IEEE80211_IF_TYPE_STA) {
                /* Update last_rx only for unicast frames in order to prevent
                 * the Probe Request frames (the only broadcast frames from a
                 * STA in infrastructure mode) from keeping a connection alive.
@@ -630,7 +661,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
        }
 
        if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
@@ -657,10 +688,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
                 * as a dropped packed. */
                sta->rx_packets++;
                dev_kfree_skb(rx->skb);
-               return TXRX_QUEUED;
+               return RX_QUEUED;
        }
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 } /* ieee80211_rx_h_sta_process */
 
 static inline struct ieee80211_fragment_entry *
@@ -680,13 +711,15 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_DEBUG
                struct ieee80211_hdr *hdr =
                        (struct ieee80211_hdr *) entry->skb_list.next->data;
+               DECLARE_MAC_BUF(mac);
+               DECLARE_MAC_BUF(mac2);
                printk(KERN_DEBUG "%s: RX reassembly removed oldest "
                       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
-                      "addr1=" MAC_FMT " addr2=" MAC_FMT "\n",
+                      "addr1=%s addr2=%s\n",
                       sdata->dev->name, idx,
                       jiffies - entry->first_frag_time, entry->seq,
-                      entry->last_frag, MAC_ARG(hdr->addr1),
-                      MAC_ARG(hdr->addr2));
+                      entry->last_frag, print_mac(mac, hdr->addr1),
+                      print_mac(mac2, hdr->addr2));
 #endif /* CONFIG_MAC80211_DEBUG */
                __skb_queue_purge(&entry->skb_list);
        }
@@ -744,7 +777,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
        return NULL;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 {
        struct ieee80211_hdr *hdr;
@@ -752,6 +785,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
        unsigned int frag, seq;
        struct ieee80211_fragment_entry *entry;
        struct sk_buff *skb;
+       DECLARE_MAC_BUF(mac);
 
        hdr = (struct ieee80211_hdr *) rx->skb->data;
        sc = le16_to_cpu(hdr->seq_ctrl);
@@ -780,7 +814,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                               rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
                               CCMP_PN_LEN);
                }
-               return TXRX_QUEUED;
+               return RX_QUEUED;
        }
 
        /* This is a fragment for a frame that should already be pending in
@@ -790,7 +824,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                                          rx->u.rx.queue, hdr);
        if (!entry) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
-               return TXRX_DROP;
+               return RX_DROP_MONITOR;
        }
 
        /* Verify that MPDUs within one MSDU have sequential PN values.
@@ -799,7 +833,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                int i;
                u8 pn[CCMP_PN_LEN], *rpn;
                if (!rx->key || rx->key->conf.alg != ALG_CCMP)
-                       return TXRX_DROP;
+                       return RX_DROP_UNUSABLE;
                memcpy(pn, entry->last_pn, CCMP_PN_LEN);
                for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
                        pn[i]++;
@@ -810,14 +844,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
                        if (net_ratelimit())
                                printk(KERN_DEBUG "%s: defrag: CCMP PN not "
-                                      "sequential A2=" MAC_FMT
+                                      "sequential A2=%s"
                                       " PN=%02x%02x%02x%02x%02x%02x "
                                       "(expected %02x%02x%02x%02x%02x%02x)\n",
-                                      rx->dev->name, MAC_ARG(hdr->addr2),
+                                      rx->dev->name, print_mac(mac, hdr->addr2),
                                       rpn[0], rpn[1], rpn[2], rpn[3], rpn[4],
                                       rpn[5], pn[0], pn[1], pn[2], pn[3],
                                       pn[4], pn[5]);
-                       return TXRX_DROP;
+                       return RX_DROP_UNUSABLE;
                }
                memcpy(entry->last_pn, pn, CCMP_PN_LEN);
        }
@@ -828,7 +862,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
        entry->extra_len += rx->skb->len;
        if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
                rx->skb = NULL;
-               return TXRX_QUEUED;
+               return RX_QUEUED;
        }
 
        rx->skb = __skb_dequeue(&entry->skb_list);
@@ -838,7 +872,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                                              GFP_ATOMIC))) {
                        I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
                        __skb_queue_purge(&entry->skb_list);
-                       return TXRX_DROP;
+                       return RX_DROP_UNUSABLE;
                }
        }
        while ((skb = __skb_dequeue(&entry->skb_list))) {
@@ -856,20 +890,26 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
                rx->local->dot11MulticastReceivedFrameCount++;
        else
                ieee80211_led_rx(rx->local);
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_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);
 
        if (likely(!rx->sta ||
                   (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
                   (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
                   !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
+
+       if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
+           (sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
+               return RX_DROP_UNUSABLE;
 
        skb = skb_dequeue(&rx->sta->tx_filtered);
        if (!skb) {
@@ -889,9 +929,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
                rx->sta->pspoll = 1;
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries "
-                      "after %d)\n",
-                      MAC_ARG(rx->sta->addr), rx->sta->aid,
+               printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
+                      print_mac(mac, rx->sta->addr), rx->sta->aid,
                       skb_queue_len(&rx->sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
@@ -914,21 +953,21 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
                }
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        } else if (!rx->u.rx.sent_ps_buffered) {
-               printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even "
+               printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
                       "though there is no buffered frames for it\n",
-                      rx->dev->name, MAC_ARG(rx->sta->addr));
+                      rx->dev->name, print_mac(mac, rx->sta->addr));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
        }
 
-       /* Free PS Poll skb here instead of returning TXRX_DROP that would
+       /* Free PS Poll skb here instead of returning RX_DROP that would
         * count as an dropped frame. */
        dev_kfree_skb(rx->skb);
 
-       return TXRX_QUEUED;
+       return RX_QUEUED;
 }
 
-static ieee80211_txrx_result
+static ieee80211_rx_result
 ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
 {
        u16 fc = rx->fc;
@@ -936,7 +975,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
 
        if (!WLAN_FC_IS_QOS_DATA(fc))
-               return TXRX_CONTINUE;
+               return RX_CONTINUE;
 
        /* remove the qos control field, update frame type and meta-data */
        memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
@@ -945,78 +984,67 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
        rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
        hdr->frame_control = cpu_to_le16(fc);
 
-       return TXRX_CONTINUE;
+       return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
+static int
+ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
 {
-       if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
-           rx->sdata->type != IEEE80211_IF_TYPE_STA &&
-           (rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               return TXRX_CONTINUE;
-
-       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))) {
+       if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
 #ifdef CONFIG_MAC80211_DEBUG
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) rx->skb->data;
-               printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT
-                      " (unauthorized port)\n", rx->dev->name,
-                      MAC_ARG(hdr->addr2));
+               if (net_ratelimit())
+                       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)
 {
        /*
         * 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) &&
                     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
                     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
-                    rx->sdata->drop_unencrypted &&
-                    (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) {
+                    (rx->key || rx->sdata->drop_unencrypted))) {
                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);
+       DECLARE_MAC_BUF(mac3);
+       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);
 
@@ -1036,18 +1064,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(dst, hdr->addr3, ETH_ALEN);
                memcpy(src, hdr->addr2, ETH_ALEN);
 
-               if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
-                            sdata->type != IEEE80211_IF_TYPE_VLAN)) {
+               if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_AP &&
+                            sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) {
                        if (net_ratelimit())
                                printk(KERN_DEBUG "%s: dropped ToDS frame "
-                                      "(BSSID=" MAC_FMT
-                                      " SA=" MAC_FMT
-                                      " DA=" MAC_FMT ")\n",
+                                      "(BSSID=%s SA=%s DA=%s)\n",
                                       dev->name,
-                                      MAC_ARG(hdr->addr1),
-                                      MAC_ARG(hdr->addr2),
-                                      MAC_ARG(hdr->addr3));
-                       return TXRX_DROP;
+                                      print_mac(mac, hdr->addr1),
+                                      print_mac(mac2, hdr->addr2),
+                                      print_mac(mac3, hdr->addr3));
+                       return -1;
                }
                break;
        case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
@@ -1055,18 +1081,16 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(dst, hdr->addr3, ETH_ALEN);
                memcpy(src, hdr->addr4, ETH_ALEN);
 
-               if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
+               if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) {
                        if (net_ratelimit())
                                printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
-                                      "frame (RA=" MAC_FMT
-                                      " TA=" MAC_FMT " DA=" MAC_FMT
-                                      " SA=" MAC_FMT ")\n",
+                                      "frame (RA=%s TA=%s DA=%s SA=%s)\n",
                                       rx->dev->name,
-                                      MAC_ARG(hdr->addr1),
-                                      MAC_ARG(hdr->addr2),
-                                      MAC_ARG(hdr->addr3),
-                                      MAC_ARG(hdr->addr4));
-                       return TXRX_DROP;
+                                      print_mac(mac, hdr->addr1),
+                                      print_mac(mac2, hdr->addr2),
+                                      print_mac(mac3, hdr->addr3),
+                                      print_mac(mac4, hdr->addr4));
+                       return -1;
                }
                break;
        case IEEE80211_FCTL_FROMDS:
@@ -1074,40 +1098,39 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
                memcpy(dst, hdr->addr1, ETH_ALEN);
                memcpy(src, hdr->addr3, ETH_ALEN);
 
-               if (sdata->type != IEEE80211_IF_TYPE_STA ||
+               if (sdata->vif.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 */
                memcpy(dst, hdr->addr1, ETH_ALEN);
                memcpy(src, hdr->addr2, ETH_ALEN);
 
-               if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
+               if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
                        if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: dropped IBSS frame (DA="
-                                      MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT
-                                      ")\n",
-                                      dev->name, MAC_ARG(hdr->addr1),
-                                      MAC_ARG(hdr->addr2),
-                                      MAC_ARG(hdr->addr3));
+                               printk(KERN_DEBUG "%s: dropped IBSS frame "
+                                      "(DA=%s SA=%s BSSID=%s)\n",
+                                      dev->name,
+                                      print_mac(mac, hdr->addr1),
+                                      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 &&
@@ -1121,6 +1144,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
        } else {
                struct ethhdr *ehdr;
                __be16 len;
+
                skb_pull(skb, hdrlen);
                len = htons(skb->len);
                ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
@@ -1128,36 +1152,72 @@ 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;
+/*
+ * requires that rx->skb is a frame with ethernet header
+ */
+static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
+{
+       static const u8 pae_group_addr[ETH_ALEN]
+               = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
+       struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
 
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
+       /*
+        * Allow EAPOL frames to us/the PAE group address regardless
+        * of whether the frame was encrypted or not.
+        */
+       if (ehdr->h_proto == htons(ETH_P_PAE) &&
+           (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 ||
+            compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
+               return true;
+
+       if (ieee80211_802_1x_port_control(rx) ||
+           ieee80211_drop_unencrypted(rx))
+               return false;
+
+       return true;
+}
+
+/*
+ * requires that rx->skb is a frame with ethernet header
+ */
+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);
+       struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
+       struct sta_info *dsta;
 
-       if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
-           || sdata->type == IEEE80211_IF_TYPE_VLAN) &&
+       skb = rx->skb;
+       xmit_skb = NULL;
+
+       if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+                                     sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
            (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
-               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())
+               if (is_multicast_ether_addr(ehdr->h_dest)) {
+                       /*
+                        * send multicast frames both to higher layers in
+                        * local net stack and back to the wireless medium
+                        */
+                       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 {
-                       struct sta_info *dsta;
                        dsta = sta_info_get(local, skb->data);
-                       if (dsta && !dsta->dev) {
-                               if (net_ratelimit())
-                                       printk(KERN_DEBUG "Station with null "
-                                              "dev structure!\n");
-                       } else if (dsta && dsta->dev == dev) {
-                               /* Destination station is associated to this
-                                * AP, so send the frame directly to it and
-                                * do not pass the frame to local net stack.
+                       if (dsta && dsta->dev == dev) {
+                               /*
+                                * The destination station is associated to
+                                * this AP (in this VLAN), so send the frame
+                                * directly to it and do not pass it to local
+                                * net stack.
                                 */
-                               skb2 = skb;
+                               xmit_skb = skb;
                                skb = NULL;
                        }
                        if (dsta)
@@ -1172,84 +1232,232 @@ 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 = __constant_htons(ETH_P_802_3);
+               skb_reset_network_header(xmit_skb);
+               skb_reset_mac_header(xmit_skb);
+               dev_queue_xmit(xmit_skb);
        }
-
-       return TXRX_QUEUED;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 {
-       struct ieee80211_sub_if_data *sdata;
+       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);
 
-       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-               return TXRX_DROP;
+       fc = rx->fc;
+       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+               return RX_CONTINUE;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-       if ((sdata->type == IEEE80211_IF_TYPE_STA ||
-            sdata->type == IEEE80211_IF_TYPE_IBSS) &&
-           !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
-               ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
-       else
-               return TXRX_DROP;
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return RX_DROP_MONITOR;
 
-       return TXRX_QUEUED;
+       if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU))
+               return RX_CONTINUE;
+
+       err = ieee80211_data_to_8023(rx);
+       if (unlikely(err))
+               return RX_DROP_UNUSABLE;
+
+       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 RX_DROP_UNUSABLE;
+
+       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 RX_DROP_UNUSABLE;
+               }
+
+               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 RX_DROP_UNUSABLE;
+
+                       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 RX_DROP_UNUSABLE;
+                       }
+               }
+
+               skb_reset_network_header(frame);
+               frame->dev = dev;
+               frame->priority = skb->priority;
+               rx->skb = frame;
+
+               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);
+               }
+
+               if (!ieee80211_frame_allowed(rx)) {
+                       if (skb == frame) /* last frame */
+                               return RX_DROP_UNUSABLE;
+                       dev_kfree_skb(frame);
+                       continue;
+               }
+
+               ieee80211_deliver_skb(rx);
+       }
+
+       return RX_QUEUED;
 }
 
-static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
-                               struct ieee80211_local *local,
-                               ieee80211_rx_handler *handlers,
-                               struct ieee80211_txrx_data *rx,
-                               struct sta_info *sta)
+static ieee80211_rx_result
+ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 {
-       ieee80211_rx_handler *handler;
-       ieee80211_txrx_result res = TXRX_DROP;
+       struct net_device *dev = rx->dev;
+       u16 fc;
+       int err;
 
-       for (handler = handlers; *handler != NULL; handler++) {
-               res = (*handler)(rx);
+       fc = rx->fc;
+       if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+               return RX_CONTINUE;
 
-               switch (res) {
-               case TXRX_CONTINUE:
-                       continue;
-               case TXRX_DROP:
-                       I802_DEBUG_INC(local->rx_handlers_drop);
-                       if (sta)
-                               sta->rx_dropped++;
-                       break;
-               case TXRX_QUEUED:
-                       I802_DEBUG_INC(local->rx_handlers_queued);
-                       break;
+       if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+               return RX_DROP_MONITOR;
+
+       err = ieee80211_data_to_8023(rx);
+       if (unlikely(err))
+               return RX_DROP_UNUSABLE;
+
+       if (!ieee80211_frame_allowed(rx))
+               return RX_DROP_MONITOR;
+
+       rx->skb->dev = dev;
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += rx->skb->len;
+
+       ieee80211_deliver_skb(rx);
+
+       return RX_QUEUED;
+}
+
+static ieee80211_rx_result
+ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
+{
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_hw *hw = &local->hw;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data;
+       struct tid_ampdu_rx *tid_agg_rx;
+       u16 start_seq_num;
+       u16 tid;
+
+       if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL))
+               return RX_CONTINUE;
+
+       if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) {
+               if (!rx->sta)
+                       return RX_CONTINUE;
+               tid = le16_to_cpu(bar->control) >> 12;
+               tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]);
+               if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
+                       return RX_CONTINUE;
+
+               start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
+
+               /* reset session timer */
+               if (tid_agg_rx->timeout) {
+                       unsigned long expires =
+                               jiffies + (tid_agg_rx->timeout / 1000) * HZ;
+                       mod_timer(&tid_agg_rx->session_timer, expires);
                }
-               break;
+
+               /* manage reordering buffer according to requested */
+               /* sequence number */
+               rcu_read_lock();
+               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
+                                                start_seq_num, 1);
+               rcu_read_unlock();
+               return RX_DROP_UNUSABLE;
        }
 
-       if (res == TXRX_DROP)
-               dev_kfree_skb(rx->skb);
-       return res;
+       return RX_CONTINUE;
 }
 
-static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
-                                               ieee80211_rx_handler *handlers,
-                                               struct ieee80211_txrx_data *rx,
-                                               struct sta_info *sta)
+static ieee80211_rx_result
+ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
 {
-       if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
-           TXRX_CONTINUE)
-               dev_kfree_skb(rx->skb);
+       struct ieee80211_sub_if_data *sdata;
+
+       if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+               return RX_DROP_MONITOR;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+       if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+            sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+           !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
+               ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+       else
+               return RX_DROP_MONITOR;
+
+       return RX_QUEUED;
 }
 
 static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                                            struct ieee80211_hdr *hdr,
-                                           struct sta_info *sta,
                                            struct ieee80211_txrx_data *rx)
 {
        int keyidx, hdrlen;
+       DECLARE_MAC_BUF(mac);
+       DECLARE_MAC_BUF(mac2);
 
        hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
        if (rx->skb->len >= hdrlen + 4)
@@ -1259,19 +1467,19 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 
        if (net_ratelimit())
                printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC "
-                      "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n",
-                      dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1),
-                      keyidx);
+                      "failure from %s to %s keyidx=%d\n",
+                      dev->name, print_mac(mac, hdr->addr2),
+                      print_mac(mac2, hdr->addr1), keyidx);
 
-       if (!sta) {
+       if (!rx->sta) {
                /*
                 * Some hardware seem to generate incorrect Michael MIC
                 * reports; ignore them to avoid triggering countermeasures.
                 */
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
-                              "error for unknown address " MAC_FMT "\n",
-                              dev->name, MAC_ARG(hdr->addr2));
+                              "error for unknown address %s\n",
+                              dev->name, print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
@@ -1279,11 +1487,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
                               "error for a frame with no PROTECTED flag (src "
-                              MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2));
+                              "%s)\n", dev->name, print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
-       if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) {
+       if (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP && keyidx) {
                /*
                 * APs with pairwise keys should never receive Michael MIC
                 * errors for non-zero keyidx because these are reserved for
@@ -1293,8 +1501,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: ignored Michael MIC error for "
                               "a frame with non-zero keyidx (%d)"
-                              " (src " MAC_FMT ")\n", dev->name, keyidx,
-                              MAC_ARG(hdr->addr2));
+                              " (src %s)\n", dev->name, keyidx,
+                              print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
@@ -1304,8 +1512,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
                               "error for a frame that cannot be encrypted "
-                              "(fc=0x%04x) (src " MAC_FMT ")\n",
-                              dev->name, rx->fc, MAC_ARG(hdr->addr2));
+                              "(fc=0x%04x) (src %s)\n",
+                              dev->name, rx->fc, print_mac(mac, hdr->addr2));
                goto ignore;
        }
 
@@ -1315,7 +1523,88 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
        rx->skb = NULL;
 }
 
-ieee80211_rx_handler ieee80211_rx_handlers[] =
+static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_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;
+               __le16 chan_freq;
+               __le16 chan_flags;
+       } __attribute__ ((packed)) *rthdr;
+       struct sk_buff *skb = rx->skb, *skb2;
+       struct net_device *prev_dev = NULL;
+       struct ieee80211_rx_status *status = rx->u.rx.status;
+
+       if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED)
+               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_RATE) |
+                           (1 << IEEE80211_RADIOTAP_CHANNEL));
+
+       rthdr->rate = rx->u.rx.rate->bitrate / 5;
+       rthdr->chan_freq = cpu_to_le16(status->freq);
+
+       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);
+
+       skb_set_mac_header(skb, 0);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = htons(ETH_P_802_2);
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!netif_running(sdata->dev))
+                       continue;
+
+               if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR ||
+                   !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+                       continue;
+
+               if (prev_dev) {
+                       skb2 = skb_clone(skb, GFP_ATOMIC);
+                       if (skb2) {
+                               skb2->dev = prev_dev;
+                               netif_rx(skb2);
+                       }
+               }
+
+               prev_dev = sdata->dev;
+               sdata->dev->stats.rx_packets++;
+               sdata->dev->stats.rx_bytes += skb->len;
+       }
+
+       if (prev_dev) {
+               skb->dev = prev_dev;
+               netif_rx(skb);
+               skb = NULL;
+       } else
+               goto out_free_skb;
+
+       rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED;
+       return;
+
+ out_free_skb:
+       dev_kfree_skb(skb);
+}
+
+typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *);
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
 {
        ieee80211_rx_h_if_stats,
        ieee80211_rx_h_passive_scan,
@@ -1330,13 +1619,54 @@ 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_ctrl,
        ieee80211_rx_h_mgmt,
        NULL
 };
 
+static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_txrx_data *rx,
+                                        struct sk_buff *skb)
+{
+       ieee80211_rx_handler *handler;
+       ieee80211_rx_result res = RX_DROP_MONITOR;
+
+       rx->skb = skb;
+       rx->sdata = sdata;
+       rx->dev = sdata->dev;
+
+       for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) {
+               res = (*handler)(rx);
+
+               switch (res) {
+               case RX_CONTINUE:
+                       continue;
+               case RX_DROP_UNUSABLE:
+               case RX_DROP_MONITOR:
+                       I802_DEBUG_INC(sdata->local->rx_handlers_drop);
+                       if (rx->sta)
+                               rx->sta->rx_dropped++;
+                       break;
+               case RX_QUEUED:
+                       I802_DEBUG_INC(sdata->local->rx_handlers_queued);
+                       break;
+               }
+               break;
+       }
+
+       switch (res) {
+       case RX_CONTINUE:
+       case RX_DROP_MONITOR:
+               ieee80211_rx_cooked_monitor(rx);
+               break;
+       case RX_DROP_UNUSABLE:
+               dev_kfree_skb(rx->skb);
+               break;
+       }
+}
+
 /* main receive path */
 
 static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
@@ -1345,7 +1675,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 {
        int multicast = is_multicast_ether_addr(hdr->addr1);
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_STA:
                if (!bssid)
                        return 0;
@@ -1416,99 +1746,70 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 }
 
 /*
- * This is the receive path handler. It is called by a low level driver when an
- * 802.11 MPDU is received from the hardware.
+ * This is the actual Rx frames handler. as it blongs to Rx path it must
+ * be called with rcu_read_lock protection.
  */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                   struct ieee80211_rx_status *status)
+static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
+                                        struct sk_buff *skb,
+                                        struct ieee80211_rx_status *status,
+                                        u32 load,
+                                        struct ieee80211_rate *rate)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
-       struct sta_info *sta;
        struct ieee80211_hdr *hdr;
        struct ieee80211_txrx_data rx;
        u16 type;
-       int prepres;
+       int prepares;
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
        u8 *bssid;
 
-       /*
-        * key references and virtual interfaces are protected using RCU
-        * and this requires that we are in a read-side RCU section during
-        * receive processing
-        */
-       rcu_read_lock();
-
-       /*
-        * Frames with failed FCS/PLCP checksum are not returned,
-        * all other frames are returned without radiotap header
-        * if it was previously present.
-        * Also, frames with less than 16 bytes are dropped.
-        */
-       skb = ieee80211_rx_monitor(local, skb, status);
-       if (!skb) {
-               rcu_read_unlock();
-               return;
-       }
-
        hdr = (struct ieee80211_hdr *) skb->data;
        memset(&rx, 0, sizeof(rx));
        rx.skb = skb;
        rx.local = local;
 
        rx.u.rx.status = status;
+       rx.u.rx.load = load;
+       rx.u.rx.rate = rate;
        rx.fc = le16_to_cpu(hdr->frame_control);
        type = rx.fc & IEEE80211_FCTL_FTYPE;
 
        if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
                local->dot11ReceivedFragmentCount++;
 
-       sta = rx.sta = sta_info_get(local, hdr->addr2);
-       if (sta) {
+       rx.sta = sta_info_get(local, hdr->addr2);
+       if (rx.sta) {
                rx.dev = rx.sta->dev;
                rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
        }
 
        if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-               ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
+               ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
                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,
-                                          sta) != TXRX_CONTINUE)
-               goto end;
-       skb = rx.skb;
-
-       if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
-           !atomic_read(&local->iff_promiscs) &&
-           !is_multicast_ether_addr(hdr->addr1)) {
-               rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
-               ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
-                                            rx.sta);
-               sta_info_put(sta);
-               rcu_read_unlock();
-               return;
-       }
+       ieee80211_parse_qos(&rx);
+       ieee80211_verify_ip_alignment(&rx);
 
-       bssid = ieee80211_get_bssid(hdr, skb->len);
+       skb = rx.skb;
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (!netif_running(sdata->dev))
                        continue;
 
-               if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+               if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR)
                        continue;
 
+               bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
                rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
-               prepres = prepare_for_handlers(sdata, bssid, &rx, hdr);
-               /* prepare_for_handlers can change sta */
-               sta = rx.sta;
+               prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
 
-               if (!prepres)
+               if (!prepares)
                        continue;
 
                /*
@@ -1536,27 +1837,266 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                                       prev->dev->name);
                        continue;
                }
-               rx.skb = skb_new;
-               rx.dev = prev->dev;
-               rx.sdata = prev;
-               ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-                                            &rx, sta);
+               rx.fc = le16_to_cpu(hdr->frame_control);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
                prev = sdata;
        }
        if (prev) {
-               rx.skb = skb;
-               rx.dev = prev->dev;
-               rx.sdata = prev;
-               ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-                                            &rx, sta);
+               rx.fc = le16_to_cpu(hdr->frame_control);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb);
        } else
                dev_kfree_skb(skb);
 
  end:
-       rcu_read_unlock();
+       if (rx.sta)
+               sta_info_put(rx.sta);
+}
 
+#define SEQ_MODULO 0x1000
+#define SEQ_MASK   0xfff
+
+static inline int seq_less(u16 sq1, u16 sq2)
+{
+       return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1));
+}
+
+static inline u16 seq_inc(u16 sq)
+{
+       return ((sq + 1) & SEQ_MASK);
+}
+
+static inline u16 seq_sub(u16 sq1, u16 sq2)
+{
+       return ((sq1 - sq2) & SEQ_MASK);
+}
+
+
+/*
+ * As it function blongs to Rx path it must be called with
+ * the proper rcu_read_lock protection for its flow.
+ */
+u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+                               struct tid_ampdu_rx *tid_agg_rx,
+                               struct sk_buff *skb, u16 mpdu_seq_num,
+                               int bar_req)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_rx_status status;
+       u16 head_seq_num, buf_size;
+       int index;
+       u32 pkt_load;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_rate *rate;
+
+       buf_size = tid_agg_rx->buf_size;
+       head_seq_num = tid_agg_rx->head_seq_num;
+
+       /* frame with out of date sequence number */
+       if (seq_less(mpdu_seq_num, head_seq_num)) {
+               dev_kfree_skb(skb);
+               return 1;
+       }
+
+       /* if frame sequence number exceeds our buffering window size or
+        * block Ack Request arrived - release stored frames */
+       if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) {
+               /* new head to the ordering buffer */
+               if (bar_req)
+                       head_seq_num = mpdu_seq_num;
+               else
+                       head_seq_num =
+                               seq_inc(seq_sub(mpdu_seq_num, buf_size));
+               /* release stored frames up to new head to stack */
+               while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+                       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]) {
+                               /* release the reordered frames to stack */
+                               memcpy(&status,
+                                       tid_agg_rx->reorder_buf[index]->cb,
+                                       sizeof(status));
+                               sband = local->hw.wiphy->bands[status.band];
+                               rate = &sband->bitrates[status.rate_idx];
+                               pkt_load = ieee80211_rx_load_stats(local,
+                                               tid_agg_rx->reorder_buf[index],
+                                               &status, rate);
+                               __ieee80211_rx_handle_packet(hw,
+                                       tid_agg_rx->reorder_buf[index],
+                                       &status, pkt_load, rate);
+                               tid_agg_rx->stored_mpdu_num--;
+                               tid_agg_rx->reorder_buf[index] = NULL;
+                       }
+                       tid_agg_rx->head_seq_num =
+                               seq_inc(tid_agg_rx->head_seq_num);
+               }
+               if (bar_req)
+                       return 1;
+       }
+
+       /* now the new frame is always in the range of the reordering */
+       /* buffer window */
+       index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn)
+                               % tid_agg_rx->buf_size;
+       /* check if we already stored this frame */
+       if (tid_agg_rx->reorder_buf[index]) {
+               dev_kfree_skb(skb);
+               return 1;
+       }
+
+       /* if arrived mpdu is in the right order and nothing else stored */
+       /* release it immediately */
+       if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
+                       tid_agg_rx->stored_mpdu_num == 0) {
+               tid_agg_rx->head_seq_num =
+                       seq_inc(tid_agg_rx->head_seq_num);
+               return 0;
+       }
+
+       /* put the frame in the reordering buffer */
+       tid_agg_rx->reorder_buf[index] = skb;
+       tid_agg_rx->stored_mpdu_num++;
+       /* release the buffer until next missing frame */
+       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
+                                               % tid_agg_rx->buf_size;
+       while (tid_agg_rx->reorder_buf[index]) {
+               /* release the reordered frame back to stack */
+               memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
+                       sizeof(status));
+               sband = local->hw.wiphy->bands[status.band];
+               rate = &sband->bitrates[status.rate_idx];
+               pkt_load = ieee80211_rx_load_stats(local,
+                                       tid_agg_rx->reorder_buf[index],
+                                       &status, rate);
+               __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
+                                            &status, pkt_load, rate);
+               tid_agg_rx->stored_mpdu_num--;
+               tid_agg_rx->reorder_buf[index] = NULL;
+               tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+               index = seq_sub(tid_agg_rx->head_seq_num,
+                       tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+       }
+       return 1;
+}
+
+static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
+                                    struct sk_buff *skb)
+{
+       struct ieee80211_hw *hw = &local->hw;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct sta_info *sta;
+       struct tid_ampdu_rx *tid_agg_rx;
+       u16 fc, sc;
+       u16 mpdu_seq_num;
+       u8 ret = 0, *qc;
+       int tid;
+
+       sta = sta_info_get(local, hdr->addr2);
+       if (!sta)
+               return ret;
+
+       fc = le16_to_cpu(hdr->frame_control);
+
+       /* filter the QoS data rx stream according to
+        * STA/TID and check if this STA/TID is on aggregation */
+       if (!WLAN_FC_IS_QOS_DATA(fc))
+               goto end_reorder;
+
+       qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN;
+       tid = qc[0] & QOS_CONTROL_TID_MASK;
+       tid_agg_rx = &(sta->ampdu_mlme.tid_rx[tid]);
+
+       if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
+               goto end_reorder;
+
+       /* null data frames are excluded */
+       if (unlikely(fc & IEEE80211_STYPE_NULLFUNC))
+               goto end_reorder;
+
+       /* new un-ordered ampdu frame - process it */
+
+       /* reset session timer */
+       if (tid_agg_rx->timeout) {
+               unsigned long expires =
+                       jiffies + (tid_agg_rx->timeout / 1000) * HZ;
+               mod_timer(&tid_agg_rx->session_timer, expires);
+       }
+
+       /* if this mpdu is fragmented - terminate rx aggregation session */
+       sc = le16_to_cpu(hdr->seq_ctrl);
+       if (sc & IEEE80211_SCTL_FRAG) {
+               ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
+                       tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
+               ret = 1;
+               goto end_reorder;
+       }
+
+       /* according to mpdu sequence number deal with reordering buffer */
+       mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
+       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
+                                               mpdu_seq_num, 0);
+end_reorder:
        if (sta)
                sta_info_put(sta);
+       return ret;
+}
+
+/*
+ * This is the receive path handler. It is called by a low level driver when an
+ * 802.11 MPDU is received from the hardware.
+ */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+                   struct ieee80211_rx_status *status)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       u32 pkt_load;
+       struct ieee80211_rate *rate = NULL;
+       struct ieee80211_supported_band *sband;
+
+       if (status->band < 0 ||
+           status->band > IEEE80211_NUM_BANDS) {
+               WARN_ON(1);
+               return;
+       }
+
+       sband = local->hw.wiphy->bands[status->band];
+
+       if (!sband ||
+           status->rate_idx < 0 ||
+           status->rate_idx >= sband->n_bitrates) {
+               WARN_ON(1);
+               return;
+       }
+
+       rate = &sband->bitrates[status->rate_idx];
+
+       /*
+        * key references and virtual interfaces are protected using RCU
+        * and this requires that we are in a read-side RCU section during
+        * receive processing
+        */
+       rcu_read_lock();
+
+       /*
+        * Frames with failed FCS/PLCP checksum are not returned,
+        * all other frames are returned without radiotap header
+        * if it was previously present.
+        * Also, frames with less than 16 bytes are dropped.
+        */
+       skb = ieee80211_rx_monitor(local, skb, status, rate);
+       if (!skb) {
+               rcu_read_unlock();
+               return;
+       }
+
+       pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
+       local->channel_use_raw += pkt_load;
+
+       if (!ieee80211_rx_reorder_ampdu(local, skb))
+               __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
+
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL(__ieee80211_rx);