rtc: cleanup example code
[safe/jmp/linux-2.6] / net / ieee80211 / ieee80211_rx.c
index de402b7..1e3f87c 100644 (file)
@@ -3,8 +3,8 @@
  * for Intersil Prism2/2.5/3 - hostap.o module, common routines
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2004-2005, Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
@@ -14,7 +14,6 @@
  */
 
 #include <linux/compiler.h>
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/if_arp.h>
 #include <linux/in6.h>
@@ -43,10 +42,10 @@ static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
        u16 fc = le16_to_cpu(hdr->frame_ctl);
 
        skb->dev = ieee->dev;
-       skb->mac.raw = skb->data;
+       skb_reset_mac_header(skb);
        skb_pull(skb, ieee80211_get_hdrlen(fc));
        skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = __constant_htons(ETH_P_80211_RAW);
+       skb->protocol = htons(ETH_P_80211_RAW);
        memset(skb->cb, 0, sizeof(skb->cb));
        netif_rx(skb);
 }
@@ -272,6 +271,7 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
 {
        struct ieee80211_hdr_3addr *hdr;
        int res, hdrlen;
+       DECLARE_MAC_BUF(mac);
 
        if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
                return 0;
@@ -283,8 +283,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
        res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
        atomic_dec(&crypt->refcnt);
        if (res < 0) {
-               IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT
-                                    ") res=%d\n", MAC_ARG(hdr->addr2), res);
+               IEEE80211_DEBUG_DROP("decryption failed (SA=%s"
+                                    ") res=%d\n", print_mac(mac, hdr->addr2), res);
                if (res == -2)
                        IEEE80211_DEBUG_DROP("Decryption failed ICV "
                                             "mismatch (key %d)\n",
@@ -304,6 +304,7 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
 {
        struct ieee80211_hdr_3addr *hdr;
        int res, hdrlen;
+       DECLARE_MAC_BUF(mac);
 
        if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
                return 0;
@@ -316,8 +317,8 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
        atomic_dec(&crypt->refcnt);
        if (res < 0) {
                printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
-                      " (SA=" MAC_FMT " keyidx=%d)\n",
-                      ieee->dev->name, MAC_ARG(hdr->addr2), keyidx);
+                      " (SA=%s keyidx=%d)\n",
+                      ieee->dev->name, print_mac(mac, hdr->addr2), keyidx);
                return -1;
        }
 
@@ -351,6 +352,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        struct ieee80211_crypt_data *crypt = NULL;
        int keyidx = 0;
        int can_be_decrypted = 0;
+       DECLARE_MAC_BUF(mac);
 
        hdr = (struct ieee80211_hdr_4addr *)skb->data;
        stats = &ieee->stats;
@@ -367,10 +369,16 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        frag = WLAN_GET_SEQ_FRAG(sc);
        hdrlen = ieee80211_get_hdrlen(fc);
 
+       if (skb->len < hdrlen) {
+               printk(KERN_INFO "%s: invalid SKB length %d\n",
+                       dev->name, skb->len);
+               goto rx_dropped;
+       }
+
        /* Put this code here so that we avoid duplicating it in all
         * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
 #ifdef IW_WIRELESS_SPY         /* defined in iw_handler.h */
-#ifdef CONFIG_NET_RADIO
        /* If spy monitoring on */
        if (ieee->spy_data.spy_number > 0) {
                struct iw_quality wstats;
@@ -397,17 +405,17 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                /* Update spy records */
                wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
        }
-#endif                         /* CONFIG_NET_RADIO */
 #endif                         /* IW_WIRELESS_SPY */
+#endif                         /* CONFIG_WIRELESS_EXT */
 
 #ifdef NOT_YET
        hostap_update_rx_stats(local->ap, hdr, rx_stats);
 #endif
 
        if (ieee->iw_mode == IW_MODE_MONITOR) {
-               ieee80211_monitor_rx(ieee, skb, rx_stats);
                stats->rx_packets++;
                stats->rx_bytes += skb->len;
+               ieee80211_monitor_rx(ieee, skb, rx_stats);
                return 1;
        }
 
@@ -416,17 +424,16 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
            ieee->host_mc_decrypt : ieee->host_decrypt;
 
        if (can_be_decrypted) {
-               int idx = 0;
                if (skb->len >= hdrlen + 3) {
                        /* Top two-bits of byte 3 are the key index */
-                       idx = skb->data[hdrlen + 3] >> 6;
+                       keyidx = skb->data[hdrlen + 3] >> 6;
                }
 
-               /* ieee->crypt[] is WEP_KEY (4) in length.  Given that idx
-                * is only allowed 2-bits of storage, no value of idx can
-                * be provided via above code that would result in idx
+               /* ieee->crypt[] is WEP_KEY (4) in length.  Given that keyidx
+                * is only allowed 2-bits of storage, no value of keyidx can
+                * be provided via above code that would result in keyidx
                 * being out of range */
-               crypt = ieee->crypt[idx];
+               crypt = ieee->crypt[keyidx];
 
 #ifdef NOT_YET
                sta = NULL;
@@ -455,8 +462,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                         * frames silently instead of filling system log with
                         * these reports. */
                        IEEE80211_DEBUG_DROP("Decryption failed (not set)"
-                                            " (SA=" MAC_FMT ")\n",
-                                            MAC_ARG(hdr->addr2));
+                                            " (SA=%s)\n",
+                                            print_mac(mac, hdr->addr2));
                        ieee->ieee_stats.rx_discards_undecryptable++;
                        goto rx_dropped;
                }
@@ -467,8 +474,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                    fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
                    (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
                        printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
-                              "from " MAC_FMT "\n", dev->name,
-                              MAC_ARG(hdr->addr2));
+                              "from %s\n", dev->name,
+                              print_mac(mac, hdr->addr2));
                        /* TODO: could inform hostapd about this so that it
                         * could send auth failure report */
                        goto rx_dropped;
@@ -480,6 +487,11 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                        goto rx_exit;
        }
 #endif
+       /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */
+       if (sc == ieee->prev_seq_ctl)
+               goto rx_dropped;
+       else
+               ieee->prev_seq_ctl = sc;
 
        /* Data frame - extract src/dst addresses */
        if (skb->len < IEEE80211_3ADDR_LEN)
@@ -574,7 +586,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        /* skb: hdr + (possibly fragmented) plaintext payload */
        // PR: FIXME: hostap has additional conditions in the "if" below:
        // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
-       if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+       if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
                int flen;
                struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
                IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
@@ -603,12 +615,12 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                if (frag == 0) {
                        /* copy first fragment (including full headers) into
                         * beginning of the fragment cache skb */
-                       memcpy(skb_put(frag_skb, flen), skb->data, flen);
+                       skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
                } else {
                        /* append frame payload to the end of the fragment
                         * cache skb */
-                       memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
-                              flen);
+                       skb_copy_from_linear_data_offset(skb, hdrlen,
+                                     skb_put(frag_skb, flen), flen);
                }
                dev_kfree_skb_any(skb);
                skb = NULL;
@@ -641,8 +653,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                         * configured */
                } else {
                        IEEE80211_DEBUG_DROP("encryption configured, but RX "
-                                            "frame not encrypted (SA=" MAC_FMT
-                                            ")\n", MAC_ARG(hdr->addr2));
+                                            "frame not encrypted (SA=%s"
+                                            ")\n", print_mac(mac, hdr->addr2));
                        goto rx_dropped;
                }
        }
@@ -650,12 +662,57 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
            !ieee80211_is_eapol_frame(ieee, skb)) {
                IEEE80211_DEBUG_DROP("dropped unencrypted RX data "
-                                    "frame from " MAC_FMT
+                                    "frame from %s"
                                     " (drop_unencrypted=1)\n",
-                                    MAC_ARG(hdr->addr2));
+                                    print_mac(mac, hdr->addr2));
                goto rx_dropped;
        }
 
+       /* If the frame was decrypted in hardware, we may need to strip off
+        * any security data (IV, ICV, etc) that was left behind */
+       if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
+           ieee->host_strip_iv_icv) {
+               int trimlen = 0;
+
+               /* Top two-bits of byte 3 are the key index */
+               if (skb->len >= hdrlen + 3)
+                       keyidx = skb->data[hdrlen + 3] >> 6;
+
+               /* To strip off any security data which appears before the
+                * payload, we simply increase hdrlen (as the header gets
+                * chopped off immediately below). For the security data which
+                * appears after the payload, we use skb_trim. */
+
+               switch (ieee->sec.encode_alg[keyidx]) {
+               case SEC_ALG_WEP:
+                       /* 4 byte IV */
+                       hdrlen += 4;
+                       /* 4 byte ICV */
+                       trimlen = 4;
+                       break;
+               case SEC_ALG_TKIP:
+                       /* 4 byte IV, 4 byte ExtIV */
+                       hdrlen += 8;
+                       /* 8 byte MIC, 4 byte ICV */
+                       trimlen = 12;
+                       break;
+               case SEC_ALG_CCMP:
+                       /* 8 byte CCMP header */
+                       hdrlen += 8;
+                       /* 8 byte MIC */
+                       trimlen = 8;
+                       break;
+               }
+
+               if (skb->len < trimlen)
+                       goto rx_dropped;
+
+               __skb_trim(skb, skb->len - trimlen);
+
+               if (skb->len < hdrlen)
+                       goto rx_dropped;
+       }
+
        /* skb: hdr + (possible reassembled) full plaintext payload */
 
        payload = skb->data + hdrlen;
@@ -697,7 +754,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
                memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
        } else {
-               u16 len;
+               __be16 len;
                /* Leave Ethernet header part of hdr and full payload */
                skb_pull(skb, hdrlen);
                len = htons(skb->len);
@@ -711,8 +768,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                    IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
                /* Non-standard frame: get addr4 from its bogus location after
                 * the payload */
-               memcpy(skb->data + ETH_ALEN,
-                      skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+               skb_copy_to_linear_data_offset(skb, ETH_ALEN,
+                                              skb->data + skb->len - ETH_ALEN,
+                                              ETH_ALEN);
                skb_trim(skb, skb->len - ETH_ALEN);
        }
 #endif
@@ -741,10 +799,11 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 
        if (skb2 != NULL) {
                /* send to wireless media */
-               skb2->protocol = __constant_htons(ETH_P_802_3);
-               skb2->mac.raw = skb2->nh.raw = skb2->data;
-               /* skb2->nh.raw = skb2->data + ETH_HLEN; */
                skb2->dev = dev;
+               skb2->protocol = htons(ETH_P_802_3);
+               skb_reset_mac_header(skb2);
+               skb_reset_network_header(skb2);
+               /* skb2->network_header += ETH_HLEN; */
                dev_queue_xmit(skb2);
        }
 #endif
@@ -752,7 +811,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        if (skb) {
                skb->protocol = eth_type_trans(skb, dev);
                memset(skb->cb, 0, sizeof(skb->cb));
-               skb->dev = dev;
                skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
                if (netif_rx(skb) == NET_RX_DROP) {
                        /* netif_rx always succeeds, but it might drop
@@ -780,6 +838,97 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        return 0;
 }
 
+/* Filter out unrelated packets, call ieee80211_rx[_mgt]
+ * This function takes over the skb, it should not be used again after calling
+ * this function. */
+void ieee80211_rx_any(struct ieee80211_device *ieee,
+                    struct sk_buff *skb, struct ieee80211_rx_stats *stats)
+{
+       struct ieee80211_hdr_4addr *hdr;
+       int is_packet_for_us;
+       u16 fc;
+
+       if (ieee->iw_mode == IW_MODE_MONITOR) {
+               if (!ieee80211_rx(ieee, skb, stats))
+                       dev_kfree_skb_irq(skb);
+               return;
+       }
+
+       if (skb->len < sizeof(struct ieee80211_hdr))
+               goto drop_free;
+
+       hdr = (struct ieee80211_hdr_4addr *)skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       if ((fc & IEEE80211_FCTL_VERS) != 0)
+               goto drop_free;
+
+       switch (fc & IEEE80211_FCTL_FTYPE) {
+       case IEEE80211_FTYPE_MGMT:
+               if (skb->len < sizeof(struct ieee80211_hdr_3addr))
+                       goto drop_free;
+               ieee80211_rx_mgt(ieee, hdr, stats);
+               dev_kfree_skb_irq(skb);
+               return;
+       case IEEE80211_FTYPE_DATA:
+               break;
+       case IEEE80211_FTYPE_CTL:
+               return;
+       default:
+               return;
+       }
+
+       is_packet_for_us = 0;
+       switch (ieee->iw_mode) {
+       case IW_MODE_ADHOC:
+               /* our BSS and not from/to DS */
+               if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0)
+               if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
+                       /* promisc: get all */
+                       if (ieee->dev->flags & IFF_PROMISC)
+                               is_packet_for_us = 1;
+                       /* to us */
+                       else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+                               is_packet_for_us = 1;
+                       /* mcast */
+                       else if (is_multicast_ether_addr(hdr->addr1))
+                               is_packet_for_us = 1;
+               }
+               break;
+       case IW_MODE_INFRA:
+               /* our BSS (== from our AP) and from DS */
+               if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0)
+               if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
+                       /* promisc: get all */
+                       if (ieee->dev->flags & IFF_PROMISC)
+                               is_packet_for_us = 1;
+                       /* to us */
+                       else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+                               is_packet_for_us = 1;
+                       /* mcast */
+                       else if (is_multicast_ether_addr(hdr->addr1)) {
+                               /* not our own packet bcasted from AP */
+                               if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN))
+                                       is_packet_for_us = 1;
+                       }
+               }
+               break;
+       default:
+               /* ? */
+               break;
+       }
+
+       if (is_packet_for_us)
+               if (!ieee80211_rx(ieee, skb, stats))
+                       dev_kfree_skb_irq(skb);
+       return;
+
+drop_free:
+       dev_kfree_skb_irq(skb);
+       ieee->stats.rx_dropped++;
+       return;
+}
+
 #define MGMT_FRAME_FIXED_PART_LENGTH           0x24
 
 static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
@@ -883,16 +1032,16 @@ static int ieee80211_qos_convert_ac_to_parameters(struct
                qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2;
 
                cw_min = ac_params->ecw_min_max & 0x0F;
-               qos_param->cw_min[i] = (u16) ((1 << cw_min) - 1);
+               qos_param->cw_min[i] = cpu_to_le16((1 << cw_min) - 1);
 
                cw_max = (ac_params->ecw_min_max & 0xF0) >> 4;
-               qos_param->cw_max[i] = (u16) ((1 << cw_max) - 1);
+               qos_param->cw_max[i] = cpu_to_le16((1 << cw_max) - 1);
 
                qos_param->flag[i] =
                    (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
 
                txop = le16_to_cpu(ac_params->tx_op_limit) * 32;
-               qos_param->tx_op_limit[i] = (u16) txop;
+               qos_param->tx_op_limit[i] = cpu_to_le16(txop);
        }
        return rc;
 }
@@ -937,6 +1086,45 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
        return rc;
 }
 
+#ifdef CONFIG_IEEE80211_DEBUG
+#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x
+
+static const char *get_info_element_string(u16 id)
+{
+       switch (id) {
+               MFIE_STRING(SSID);
+               MFIE_STRING(RATES);
+               MFIE_STRING(FH_SET);
+               MFIE_STRING(DS_SET);
+               MFIE_STRING(CF_SET);
+               MFIE_STRING(TIM);
+               MFIE_STRING(IBSS_SET);
+               MFIE_STRING(COUNTRY);
+               MFIE_STRING(HOP_PARAMS);
+               MFIE_STRING(HOP_TABLE);
+               MFIE_STRING(REQUEST);
+               MFIE_STRING(CHALLENGE);
+               MFIE_STRING(POWER_CONSTRAINT);
+               MFIE_STRING(POWER_CAPABILITY);
+               MFIE_STRING(TPC_REQUEST);
+               MFIE_STRING(TPC_REPORT);
+               MFIE_STRING(SUPP_CHANNELS);
+               MFIE_STRING(CSA);
+               MFIE_STRING(MEASURE_REQUEST);
+               MFIE_STRING(MEASURE_REPORT);
+               MFIE_STRING(QUIET);
+               MFIE_STRING(IBSS_DFS);
+               MFIE_STRING(ERP_INFO);
+               MFIE_STRING(RSN);
+               MFIE_STRING(RATES_EX);
+               MFIE_STRING(GENERIC);
+               MFIE_STRING(QOS_PARAMETER);
+       default:
+               return "UNKNOWN";
+       }
+}
+#endif
+
 static int ieee80211_parse_info_param(struct ieee80211_info_element
                                      *info_element, u16 length,
                                      struct ieee80211_network *network)
@@ -955,7 +1143,10 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                                             info_element->len +
                                             sizeof(*info_element),
                                             length, info_element->id);
-                       return 1;
+                       /* We stop processing but don't return an error here
+                        * because some misbehaviour APs break this rule. ie.
+                        * Orinoco AP1000. */
+                       break;
                }
 
                switch (info_element->id) {
@@ -1054,6 +1245,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
 
                case MFIE_TYPE_ERP_INFO:
                        network->erp_value = info_element->data[0];
+                       network->flags |= NETWORK_HAS_ERP_VALUE;
                        IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
                                             network->erp_value);
                        break;
@@ -1100,10 +1292,48 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                        printk(KERN_ERR
                               "QoS Error need to parse QOS_PARAMETER IE\n");
                        break;
+                       /* 802.11h */
+               case MFIE_TYPE_POWER_CONSTRAINT:
+                       network->power_constraint = info_element->data[0];
+                       network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
+                       break;
+
+               case MFIE_TYPE_CSA:
+                       network->power_constraint = info_element->data[0];
+                       network->flags |= NETWORK_HAS_CSA;
+                       break;
+
+               case MFIE_TYPE_QUIET:
+                       network->quiet.count = info_element->data[0];
+                       network->quiet.period = info_element->data[1];
+                       network->quiet.duration = info_element->data[2];
+                       network->quiet.offset = info_element->data[3];
+                       network->flags |= NETWORK_HAS_QUIET;
+                       break;
+
+               case MFIE_TYPE_IBSS_DFS:
+                       if (network->ibss_dfs)
+                               break;
+                       network->ibss_dfs = kmemdup(info_element->data,
+                                                   info_element->len,
+                                                   GFP_ATOMIC);
+                       if (!network->ibss_dfs)
+                               return 1;
+                       network->flags |= NETWORK_HAS_IBSS_DFS;
+                       break;
+
+               case MFIE_TYPE_TPC_REPORT:
+                       network->tpc_report.transmit_power =
+                           info_element->data[0];
+                       network->tpc_report.link_margin = info_element->data[1];
+                       network->flags |= NETWORK_HAS_TPC_REPORT;
+                       break;
 
                default:
-                       IEEE80211_DEBUG_MGMT("unsupported IE %d\n",
-                                            info_element->id);
+                       IEEE80211_DEBUG_MGMT
+                           ("Unsupported info element: %s (%d)\n",
+                            get_info_element_string(info_element->id),
+                            info_element->id);
                        break;
                }
 
@@ -1119,7 +1349,9 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
 static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
                                       *frame, struct ieee80211_rx_stats *stats)
 {
-       struct ieee80211_network network_resp;
+       struct ieee80211_network network_resp = {
+               .ibss_dfs = NULL,
+       };
        struct ieee80211_network *network = &network_resp;
        struct net_device *dev = ieee->dev;
 
@@ -1182,6 +1414,8 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021
                                         struct ieee80211_network *network,
                                         struct ieee80211_rx_stats *stats)
 {
+       DECLARE_MAC_BUF(mac);
+
        network->qos_data.active = 0;
        network->qos_data.supported = 0;
        network->qos_data.param_count = 0;
@@ -1228,11 +1462,11 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021
        }
 
        if (network->mode == 0) {
-               IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' "
+               IEEE80211_DEBUG_SCAN("Filtered out '%s (%s)' "
                                     "network.\n",
                                     escape_essid(network->ssid,
                                                  network->ssid_len),
-                                    MAC_ARG(network->bssid));
+                                    print_mac(mac, network->bssid));
                return 1;
        }
 
@@ -1261,8 +1495,24 @@ static void update_network(struct ieee80211_network *dst,
 {
        int qos_active;
        u8 old_param;
+       DECLARE_MAC_BUF(mac);
+
+       ieee80211_network_reset(dst);
+       dst->ibss_dfs = src->ibss_dfs;
+
+       /* We only update the statistics if they were created by receiving
+        * the network information on the actual channel the network is on.
+        *
+        * This keeps beacons received on neighbor channels from bringing
+        * down the signal level of an AP. */
+       if (dst->channel == src->stats.received_channel)
+               memcpy(&dst->stats, &src->stats,
+                      sizeof(struct ieee80211_rx_stats));
+       else
+               IEEE80211_DEBUG_SCAN("Network %s info received "
+                       "off channel (%d vs. %d)\n", print_mac(mac, src->bssid),
+                       dst->channel, src->stats.received_channel);
 
-       memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
        dst->capability = src->capability;
        memcpy(dst->rates, src->rates, src->rates_len);
        dst->rates_len = src->rates_len;
@@ -1311,7 +1561,7 @@ static void update_network(struct ieee80211_network *dst,
        /* dst->last_associate is not overwritten */
 }
 
-static inline int is_beacon(int fc)
+static inline int is_beacon(__le16 fc)
 {
        return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
 }
@@ -1323,44 +1573,44 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                                                    *stats)
 {
        struct net_device *dev = ieee->dev;
-       struct ieee80211_network network;
+       struct ieee80211_network network = {
+               .ibss_dfs = NULL,
+       };
        struct ieee80211_network *target;
        struct ieee80211_network *oldest = NULL;
 #ifdef CONFIG_IEEE80211_DEBUG
        struct ieee80211_info_element *info_element = beacon->info_element;
 #endif
        unsigned long flags;
-
-       IEEE80211_DEBUG_SCAN("'%s' (" MAC_FMT
-                            "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
-                            escape_essid(info_element->data,
-                                         info_element->len),
-                            MAC_ARG(beacon->header.addr3),
-                            (beacon->capability & (1 << 0xf)) ? '1' : '0',
-                            (beacon->capability & (1 << 0xe)) ? '1' : '0',
-                            (beacon->capability & (1 << 0xd)) ? '1' : '0',
-                            (beacon->capability & (1 << 0xc)) ? '1' : '0',
-                            (beacon->capability & (1 << 0xb)) ? '1' : '0',
-                            (beacon->capability & (1 << 0xa)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x9)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x8)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x7)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x6)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x5)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x4)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x3)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x2)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x1)) ? '1' : '0',
-                            (beacon->capability & (1 << 0x0)) ? '1' : '0');
+       DECLARE_MAC_BUF(mac);
+
+       IEEE80211_DEBUG_SCAN("'%s' (%s"
+                    "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+                    escape_essid(info_element->data, info_element->len),
+                    print_mac(mac, beacon->header.addr3),
+                    (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0xc)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0xb)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0xa)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x9)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x8)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x7)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x6)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x5)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x4)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x3)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x2)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0',
+                    (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
 
        if (ieee80211_network_init(ieee, beacon, &network, stats)) {
-               IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n",
+               IEEE80211_DEBUG_SCAN("Dropped '%s' (%s) via %s.\n",
                                     escape_essid(info_element->data,
                                                  info_element->len),
-                                    MAC_ARG(beacon->header.addr3),
-                                    is_beacon(le16_to_cpu
-                                              (beacon->header.
-                                               frame_ctl)) ?
+                                    print_mac(mac, beacon->header.addr3),
+                                    is_beacon(beacon->header.frame_ctl) ?
                                     "BEACON" : "PROBE RESPONSE");
                return;
        }
@@ -1393,11 +1643,12 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                        /* If there are no more slots, expire the oldest */
                        list_del(&oldest->list);
                        target = oldest;
-                       IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from "
+                       IEEE80211_DEBUG_SCAN("Expired '%s' (%s) from "
                                             "network list.\n",
                                             escape_essid(target->ssid,
                                                          target->ssid_len),
-                                            MAC_ARG(target->bssid));
+                                            print_mac(mac, target->bssid));
+                       ieee80211_network_reset(target);
                } else {
                        /* Otherwise just pull from the free list */
                        target = list_entry(ieee->network_free_list.next,
@@ -1406,37 +1657,35 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                }
 
 #ifdef CONFIG_IEEE80211_DEBUG
-               IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n",
+               IEEE80211_DEBUG_SCAN("Adding '%s' (%s) via %s.\n",
                                     escape_essid(network.ssid,
                                                  network.ssid_len),
-                                    MAC_ARG(network.bssid),
-                                    is_beacon(le16_to_cpu
-                                              (beacon->header.
-                                               frame_ctl)) ?
+                                    print_mac(mac, network.bssid),
+                                    is_beacon(beacon->header.frame_ctl) ?
                                     "BEACON" : "PROBE RESPONSE");
 #endif
                memcpy(target, &network, sizeof(*target));
+               network.ibss_dfs = NULL;
                list_add_tail(&target->list, &ieee->network_list);
        } else {
-               IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
+               IEEE80211_DEBUG_SCAN("Updating '%s' (%s) via %s.\n",
                                     escape_essid(target->ssid,
                                                  target->ssid_len),
-                                    MAC_ARG(target->bssid),
-                                    is_beacon(le16_to_cpu
-                                              (beacon->header.
-                                               frame_ctl)) ?
+                                    print_mac(mac, target->bssid),
+                                    is_beacon(beacon->header.frame_ctl) ?
                                     "BEACON" : "PROBE RESPONSE");
                update_network(target, &network);
+               network.ibss_dfs = NULL;
        }
 
        spin_unlock_irqrestore(&ieee->lock, flags);
 
-       if (is_beacon(le16_to_cpu(beacon->header.frame_ctl))) {
+       if (is_beacon(beacon->header.frame_ctl)) {
                if (ieee->handle_beacon != NULL)
-                       ieee->handle_beacon(dev, beacon, &network);
+                       ieee->handle_beacon(dev, beacon, target);
        } else {
                if (ieee->handle_probe_response != NULL)
-                       ieee->handle_probe_response(dev, beacon, &network);
+                       ieee->handle_probe_response(dev, beacon, target);
        }
 }
 
@@ -1461,7 +1710,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                break;
 
        case IEEE80211_STYPE_PROBE_REQ:
-               IEEE80211_DEBUG_MGMT("recieved auth (%d)\n",
+               IEEE80211_DEBUG_MGMT("received auth (%d)\n",
                                     WLAN_FC_GET_STYPE(le16_to_cpu
                                                       (header->frame_ctl)));
 
@@ -1495,7 +1744,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                break;
        case IEEE80211_STYPE_AUTH:
 
-               IEEE80211_DEBUG_MGMT("recieved auth (%d)\n",
+               IEEE80211_DEBUG_MGMT("received auth (%d)\n",
                                     WLAN_FC_GET_STYPE(le16_to_cpu
                                                       (header->frame_ctl)));
 
@@ -1511,23 +1760,57 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                                              header);
                break;
 
+       case IEEE80211_STYPE_ACTION:
+               IEEE80211_DEBUG_MGMT("ACTION\n");
+               if (ieee->handle_action)
+                       ieee->handle_action(ieee->dev,
+                                           (struct ieee80211_action *)
+                                           header, stats);
+               break;
+
+       case IEEE80211_STYPE_REASSOC_REQ:
+               IEEE80211_DEBUG_MGMT("received reassoc (%d)\n",
+                                    WLAN_FC_GET_STYPE(le16_to_cpu
+                                                      (header->frame_ctl)));
+
+               IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n",
+                                    ieee->dev->name);
+               if (ieee->handle_reassoc_request != NULL)
+                       ieee->handle_reassoc_request(ieee->dev,
+                                                   (struct ieee80211_reassoc_request *)
+                                                    header);
+               break;
+
+       case IEEE80211_STYPE_ASSOC_REQ:
+               IEEE80211_DEBUG_MGMT("received assoc (%d)\n",
+                                    WLAN_FC_GET_STYPE(le16_to_cpu
+                                                      (header->frame_ctl)));
+
+               IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n",
+                                    ieee->dev->name);
+               if (ieee->handle_assoc_request != NULL)
+                       ieee->handle_assoc_request(ieee->dev);
+               break;
+
        case IEEE80211_STYPE_DEAUTH:
-               printk("DEAUTH from AP\n");
+               IEEE80211_DEBUG_MGMT("DEAUTH\n");
                if (ieee->handle_deauth != NULL)
-                       ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *)
+                       ieee->handle_deauth(ieee->dev,
+                                           (struct ieee80211_deauth *)
                                            header);
                break;
        default:
                IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
                                     WLAN_FC_GET_STYPE(le16_to_cpu
                                                       (header->frame_ctl)));
-               IEEE80211_WARNING("%s: Unknown management packet: %d\n",
-                                 ieee->dev->name,
-                                 WLAN_FC_GET_STYPE(le16_to_cpu
-                                                   (header->frame_ctl)));
+               IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n",
+                                    ieee->dev->name,
+                                    WLAN_FC_GET_STYPE(le16_to_cpu
+                                                      (header->frame_ctl)));
                break;
        }
 }
 
+EXPORT_SYMBOL_GPL(ieee80211_rx_any);
 EXPORT_SYMBOL(ieee80211_rx_mgt);
 EXPORT_SYMBOL(ieee80211_rx);