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) &&
                     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
                     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
                     (rx->key || rx->sdata->drop_unencrypted) &&
-                    (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) {
+                    (rx->sdata->eapol == 0 ||
+                     !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);
        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);
 
                                       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):
                                       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:
                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 */
                                       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 &&
                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) &&
                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 {
                                 * 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)
                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_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_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;
 }
         * 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_data,
        ieee80211_rx_h_mgmt,
        NULL