netdev
[Top] [All Lists]

[PATCH] Merge p80211 to ieee80211 subsystem

To: netdev@xxxxxxxxxxx
Subject: [PATCH] Merge p80211 to ieee80211 subsystem
From: Zhu Yi <yi.zhu@xxxxxxxxx>
Date: Fri, 25 Mar 2005 16:55:52 +0800
Cc: Jeff Garzik <jgarzik@xxxxxxxxx>, "David S.Miller" <davem@xxxxxxxxxxxxx>
Organization: Intel Corp.
Sender: netdev-bounce@xxxxxxxxxxx
Hi,

This patch merged David Miller's p80211 (with Vladimir's modification)
into the ieee80211 subsystem in wireless-2.6. This makes the ieee80211
code hook into the kernel as a true native network stack:

- It registers a new packet type ETH_P_802_11
- Build 802.11 headers via ->hard_header and friends for TX
- Handle RX packets passed by netif_rx or netif_receive_skb

The new stack will do host based encryption (if necessary) and
fragmentation before delivering the skb to the hardware's
->hard_start_xmit. Also It does decryption and reassembly for a skb
received from the hardware before delivering it to the upper network
layer (i.e IP).

In the future, more work needs to be done in areas:

- Support all 802.11 management frames for soft MAC and host based AP
- Offload more wireless extension support from device to the stack
- Native WPA/802.11i?


Comparing with p80211, this is a workable stack. The first driver
supports the new stack is ipw2200. You can download the modified version
of ipw2200 tarball from:
http://www.bughost.org/ipw/downloads/ipw2200-ieee80211.tgz

Currently the driver doesn't support WPA yet, because wpa_supplicant
only handles 802.3 packets but not 802.11 packets. For this reason, I
only want this patch to be RFC, but not intend for inclusion now. After
the ipw driver is in wireless-2.6, I'll submit an updated stack
(hopfully with WPA support) together with patches switching the ipw
drivers to use the native stack.

Patch against latest wireless-2.6 bk.

Thanks,
-yi


Signed-off-by: Zhu Yi <yi.zhu@xxxxxxxxx>

 include/linux/if_ether.h         |    1 
 include/net/ieee80211.h          |  144 ++++++----
 net/ieee80211/Makefile           |    6 
 net/ieee80211/ieee80211_crypt.c  |   14 -
 net/ieee80211/ieee80211_header.c |  369 +++++++++++++++++++++++++++
 net/ieee80211/ieee80211_impl.h   |   55 ++++
 net/ieee80211/ieee80211_input.c  |  389 ++++++++++++++++++++++++++++
 net/ieee80211/ieee80211_mgmt.c   |  265 +++++++++++++++++++
 net/ieee80211/ieee80211_module.c |  162 ++----------
 net/ieee80211/ieee80211_output.c |  416 +++++++++++++++++++++++++++++++
 net/ieee80211/ieee80211_rx.c     |   59 +---
 net/ieee80211/ieee80211_tx.c     |  128 +++------
 net/ieee80211/ieee80211_wx.c     |   12 
 13 files changed, 1713 insertions(+), 307 deletions(-)


diff -Nru a/include/linux/if_ether.h b/include/linux/if_ether.h
--- a/include/linux/if_ether.h  2005-03-02 15:00:13 +08:00
+++ b/include/linux/if_ether.h  2005-03-02 15:00:13 +08:00
@@ -92,6 +92,7 @@
 #define ETH_P_ECONET   0x0018          /* Acorn Econet                 */
 #define ETH_P_HDLC     0x0019          /* HDLC frames                  */
 #define ETH_P_ARCNET   0x001A          /* 1A for ArcNet :-)            */
+#define ETH_P_802_11   0x001B          /* 802.11 frames                */
 
 /*
  *     This is an Ethernet frame header.
diff -Nru a/include/net/ieee80211.h b/include/net/ieee80211.h
--- a/include/net/ieee80211.h   2005-03-02 15:00:13 +08:00
+++ b/include/net/ieee80211.h   2005-03-02 15:00:13 +08:00
@@ -101,21 +101,28 @@
 #define        MAX_FRAG_THRESHOLD     2346U
 
 /* Frame control field constants */
-#define IEEE80211_FCTL_VERS            0x0002
+#define IEEE80211_FCTL_VERS_0          0x0000
 #define IEEE80211_FCTL_FTYPE           0x000c
 #define IEEE80211_FCTL_STYPE           0x00f0
+#define IEEE80211_FCTL_NODS            0x0000
 #define IEEE80211_FCTL_TODS            0x0100
 #define IEEE80211_FCTL_FROMDS          0x0200
+#define IEEE80211_FCTL_DSTODS          0x0300
+#define IEEE80211_FCTL_DIRMASK         0x0300
 #define IEEE80211_FCTL_MOREFRAGS       0x0400
 #define IEEE80211_FCTL_RETRY           0x0800
 #define IEEE80211_FCTL_PM              0x1000
-#define IEEE80211_FCTL_MOREDATA        0x2000
+#define IEEE80211_FCTL_MOREDATA                0x2000
 #define IEEE80211_FCTL_WEP             0x4000
 #define IEEE80211_FCTL_ORDER           0x8000
 
+#define IEEE80211_FTYPE_SHIFT          2
+#define IEEE80211_STYPE_SHIFT          4
+
 #define IEEE80211_FTYPE_MGMT           0x0000
 #define IEEE80211_FTYPE_CTL            0x0004
 #define IEEE80211_FTYPE_DATA           0x0008
+#define IEEE80211_FTYPE_INVALID                0x000C
 
 /* management */
 #define IEEE80211_STYPE_ASSOC_REQ      0x0000
@@ -230,24 +237,29 @@
 
 #define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
 
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
-#endif
-
 /* IEEE 802.11 defines */
 
 #define P80211_OUI_LEN 3
 
 struct ieee80211_snap_hdr {
+        u8     dsap;   /* always 0xAA */
+        u8     ssap;   /* always 0xAA */
+        u8     ctrl;   /* always 0x03 */
+        u8     oui[P80211_OUI_LEN];    /* organizational universal id */
+       u16     ethertype;
+} __attribute__ ((packed));
 
-        u8    dsap;   /* always 0xAA */
-        u8    ssap;   /* always 0xAA */
-        u8    ctrl;   /* always 0x03 */
-        u8    oui[P80211_OUI_LEN];    /* organizational universal id */
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
 
+/* Actually, 802.11 + LLC header.  */
+struct ieee80211_data_header {
+       /* 802.11 */
+       struct ieee80211_hdr_3addr hdr;
+       /* LLC */
+       struct ieee80211_snap_hdr  snap;
 } __attribute__ ((packed));
 
-#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+#define IEEE80211_HEADER_LEN  sizeof(struct ieee80211_data_header)
 
 #define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
 #define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
@@ -300,6 +312,8 @@
 
 
 /* Information Element IDs */
+#define WLAN_EID_SIZE 2
+
 #define WLAN_EID_SSID 0
 #define WLAN_EID_SUPP_RATES 1
 #define WLAN_EID_FH_PARAMS 2
@@ -309,6 +323,7 @@
 #define WLAN_EID_IBSS_PARAMS 6
 #define WLAN_EID_CHALLENGE 16
 #define WLAN_EID_RSN 48
+#define WLAN_EID_EX_RATES 50
 #define WLAN_EID_GENERIC 221
 
 #define IEEE80211_MGMT_HDR_LEN 24
@@ -489,15 +504,6 @@
 
 */
 
-struct ieee80211_header_data {
-       u16 frame_ctl;
-       u16 duration_id;
-       u8 addr1[6];
-       u8 addr2[6];
-       u8 addr3[6];
-       u16 seq_ctrl;
-};
-
 #define BEACON_PROBE_SSID_ID_POSITION 12
 
 /* Management Frame Information Element Types */
@@ -542,16 +548,22 @@
 */
 
 struct ieee80211_authentication {
-       struct ieee80211_header_data header;
+       struct ieee80211_hdr_3addr header;
        u16 algorithm;
        u16 transaction;
        u16 status;
        struct ieee80211_info_element info_element;
 } __attribute__ ((packed));
 
+struct ieee80211_beacon {
+       u32 time_stamp[2];
+       u16 beacon_interval;
+       u16 capability;
+       struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
 
 struct ieee80211_probe_response {
-       struct ieee80211_header_data header;
+       struct ieee80211_hdr_3addr header;
        u32 time_stamp[2];
        u16 beacon_interval;
        u16 capability;
@@ -632,15 +644,13 @@
        size_t rsn_ie_len;
        struct list_head list;
 };
+#define ieee80211_network_entry(entry) \
+       list_entry(entry, struct ieee80211_network, list)
 
 enum ieee80211_state {
-       IEEE80211_UNINITIALIZED = 0,
-       IEEE80211_INITIALIZED,
-       IEEE80211_ASSOCIATING,
-       IEEE80211_ASSOCIATED,
-       IEEE80211_AUTHENTICATING,
+       IEEE80211_INITIALIZED = 0,
        IEEE80211_AUTHENTICATED,
-       IEEE80211_SHUTDOWN
+       IEEE80211_ASSOCIATED,
 };
 
 #define DEFAULT_MAX_SCAN_AGE (15 * HZ)
@@ -663,23 +673,47 @@
 #define CFG_IEEE80211_RESERVE_FCS (1<<0)
 #define CFG_IEEE80211_COMPUTE_FCS (1<<1)
 
+#define WIRELESS_MAX_RATES     MAX_RATES_LENGTH + MAX_RATES_EX_LENGTH
+struct wireless_rates {
+       u8 num;
+       u8 rates[WIRELESS_MAX_RATES];
+};
+
+struct wireless_ops {
+       int (*hard_start_xmit)(struct ieee80211_txb *txb,
+                              struct net_device *dev);
+       void (*set_security)(struct net_device *dev,
+                            struct ieee80211_security *sec);
+       int (*reset_port)(struct net_device *dev);
+};
+
 struct ieee80211_device {
+       struct list_head all_device;
+
        struct net_device *dev;
+       struct wireless_ops *ops;
 
        /* Bookkeeping structures */
        struct net_device_stats stats;
        struct ieee80211_stats ieee_stats;
 
        /* Probe / Beacon management */
+       spinlock_t network_lock;
        struct list_head network_free_list;
        struct list_head network_list;
        struct ieee80211_network *networks;
        int scans;
        int scan_age;
+       struct wireless_rates supp;     /**< software defined */
+       struct wireless_rates extended; /**< use for corresp. IE, AP only */
+       u8 essid[IW_ESSID_MAX_SIZE];
+       u8 essid_len;
+       u8 channel;
+       u32 capability;
 
        int iw_mode; /* operating mode (IW_MODE_*) */
 
-       spinlock_t lock;
+       atomic_t refcnt;
 
        int tx_headroom; /* Set to size of any additional room needed at front
                          * of allocated Tx SKBs */
@@ -704,6 +738,7 @@
        size_t wpa_ie_len;
        u8 *wpa_ie;
 
+       spinlock_t crypt_lock;
        struct list_head crypt_deinit_list;
        struct ieee80211_crypt_data *crypt[WEP_KEYS];
        int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
@@ -720,35 +755,35 @@
        /* Association info */
        u8 bssid[ETH_ALEN];
 
+       spinlock_t state_lock;
        enum ieee80211_state state;
 
        int mode;       /* A, B, G */
        int modulation; /* CCK, OFDM */
        int freq_band;  /* 2.4Ghz, 5.2Ghz, Mixed */
        int abg_ture;   /* ABG flag              */
-
-       /* Callback functions */
-       void (*set_security)(struct net_device *dev,
-                            struct ieee80211_security *sec);
-       int (*hard_start_xmit)(struct ieee80211_txb *txb,
-                              struct net_device *dev);
-       int (*reset_port)(struct net_device *dev);
-
-       /* This must be the last item so that it points to the data
-        * allocated beyond this structure by alloc_ieee80211 */
-       u8 priv[0];
 };
 
-#define IEEE_A            (1<<0)
-#define IEEE_B            (1<<1)
-#define IEEE_G            (1<<2)
-#define IEEE_MODE_MASK    (IEEE_A|IEEE_B|IEEE_G)
-
-extern inline void *ieee80211_priv(struct net_device *dev)
-{
-       return ((struct ieee80211_device *)netdev_priv(dev))->priv;
-}
+#define ieee80211_device_entry(entry) \
+       list_entry(entry, struct ieee80211_device, all_device)
 
+#define IEEE80211_PHY_CUR_INV  0
+#define IEEE_A                 (1<<0)
+#define IEEE_B                 (1<<1)
+#define IEEE_G                 (1<<2)
+#define IEEE_MODE_MASK         (IEEE_A|IEEE_B|IEEE_G)
+
+extern void ieee80211_setup(struct net_device *dev);
+extern struct ieee80211_device *ieee80211_open(struct net_device *,
+                                              struct wireless_ops *);
+extern void ieee80211_close(struct net_device *, struct
ieee80211_device *);
+extern int ieee80211_set_mode(struct ieee80211_device *, u8);
+extern int ieee80211_start_scan(struct ieee80211_device *);
+extern enum ieee80211_state ieee80211_get_state(struct ieee80211_device
*wp);
+extern void ieee80211_set_state(struct ieee80211_device *wp,
+                               enum ieee80211_state st);
+extern unsigned short ieee80211_type_trans(struct sk_buff *,struct
net_device*);
+ 
 extern inline int ieee80211_is_empty_essid(const char *essid, int
essid_len)
 {
        /* Single white space is for Linksys APs */
@@ -819,22 +854,21 @@
 
 
 /* ieee80211.c */
-extern void free_ieee80211(struct net_device *dev);
-extern struct net_device *alloc_ieee80211(int sizeof_priv);
 
 extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
 
 /* ieee80211_tx.c */
 
 
-extern int ieee80211_xmit(struct sk_buff *skb,
-                         struct net_device *dev);
+extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev);
 extern void ieee80211_txb_free(struct ieee80211_txb *);
 
 
 /* ieee80211_rx.c */
-extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff
*skb,
-                       struct ieee80211_rx_stats *rx_stats);
+extern int ieee80211_rx(struct sk_buff *skb, struct ieee80211_device
*ieee);
+extern void ieee80211_process_probe_response(struct ieee80211_device
*ieee,
+                       struct ieee80211_probe_response *beacon,
+                       struct ieee80211_rx_stats *stats);
 extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                             struct ieee80211_hdr *header,
                             struct ieee80211_rx_stats *stats);
diff -Nru a/net/ieee80211/Makefile b/net/ieee80211/Makefile
--- a/net/ieee80211/Makefile    2005-03-02 15:00:13 +08:00
+++ b/net/ieee80211/Makefile    2005-03-02 15:00:13 +08:00
@@ -7,5 +7,9 @@
        ieee80211_module.o \
        ieee80211_tx.o \
        ieee80211_rx.o \
-       ieee80211_wx.o
+       ieee80211_wx.o \
+       ieee80211_header.o \
+       ieee80211_mgmt.o \
+       ieee80211_input.o \
+       ieee80211_output.o
 
diff -Nru a/net/ieee80211/ieee80211_crypt.c
b/net/ieee80211/ieee80211_crypt.c
--- a/net/ieee80211/ieee80211_crypt.c   2005-03-02 15:00:13 +08:00
+++ b/net/ieee80211/ieee80211_crypt.c   2005-03-02 15:00:13 +08:00
@@ -43,7 +43,9 @@
 {
        struct list_head *ptr, *n;
        struct ieee80211_crypt_data *entry;
+       unsigned long flags;
 
+       spin_lock_irqsave(&ieee->crypt_lock, flags);
        for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
             ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
                entry = list_entry(ptr, struct ieee80211_crypt_data, list);
@@ -59,6 +61,7 @@
                }
                kfree(entry);
        }
+       spin_unlock_irqrestore(&ieee->crypt_lock, flags);
 }
 
 void ieee80211_crypt_deinit_handler(unsigned long data)
@@ -66,7 +69,7 @@
        struct ieee80211_device *ieee = (struct ieee80211_device *)data;
        unsigned long flags;
 
-       spin_lock_irqsave(&ieee->lock, flags);
+       spin_lock_irqsave(&ieee->crypt_lock, flags);
        ieee80211_crypt_deinit_entries(ieee, 0);
        if (!list_empty(&ieee->crypt_deinit_list)) {
                printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
@@ -74,7 +77,7 @@
                ieee->crypt_deinit_timer.expires = jiffies + HZ;
                add_timer(&ieee->crypt_deinit_timer);
        }
-       spin_unlock_irqrestore(&ieee->lock, flags);
+       spin_unlock_irqrestore(&ieee->crypt_lock, flags);
 
 }
 
@@ -94,13 +97,13 @@
         * decrypt operations. Use a list of delayed deinits to avoid needing
         * locking. */
 
-       spin_lock_irqsave(&ieee->lock, flags);
+       spin_lock_irqsave(&ieee->crypt_lock, flags);
        list_add(&tmp->list, &ieee->crypt_deinit_list);
        if (!timer_pending(&ieee->crypt_deinit_timer)) {
                ieee->crypt_deinit_timer.expires = jiffies + HZ;
                add_timer(&ieee->crypt_deinit_timer);
        }
-       spin_unlock_irqrestore(&ieee->lock, flags);
+       spin_unlock_irqrestore(&ieee->crypt_lock, flags);
 }
 
 int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops)
@@ -230,10 +233,12 @@
 static void __exit ieee80211_crypto_deinit(void)
 {
        struct list_head *ptr, *n;
+       unsigned long flags;
 
        if (hcrypt == NULL)
                return;
 
+       spin_lock_irqsave(&hcrypt->lock, flags);
        for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
             ptr = n, n = ptr->next) {
                struct ieee80211_crypto_alg *alg =
@@ -243,6 +248,7 @@
                       "'%s' (deinit)\n", alg->ops->name);
                kfree(alg);
        }
+       spin_unlock_irqrestore(&hcrypt->lock, flags);
 
        kfree(hcrypt);
 }
diff -Nru a/net/ieee80211/ieee80211_header.c
b/net/ieee80211/ieee80211_header.c
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/net/ieee80211/ieee80211_header.c  2005-03-02 15:00:13 +08:00
@@ -0,0 +1,369 @@
+/* ieee80211_header.c: 802.11 type handling.
+ *
+ * Copyright (C) 2004-2005 Intel Corporation, Zhu Yi. All rights
reserved.
+ *
+ * Portions of this file are based on p80211
+ *     Copyright (C) 2003 David S. Miller <davem@xxxxxxxxxx>
+ *     Copyright (C) 2003 Arlando Carvalho de Melo <acme@xxxxxxxxxxxxxxxx>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution
in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@xxxxxxxxxxxxxxx>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR
97124-6497
+ */
+
+#ifndef EXPORT_SYMTAB
+#define        EXPORT_SYMTAB
+#endif
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <net/neighbour.h>
+#include <net/arp.h>
+
+#include <net/ieee80211.h>
+#include "ieee80211_impl.h"
+
+/* Create the 802.11 MAC header for an arbitrary protocol layer.
+ *
+ * saddr == NULL means use device source address
+ * daddr == NULL means leave destination address (eg unresolved arp)
+ */
+
+static int ieee80211_header(struct sk_buff *skb, struct net_device
*dev,
+                           unsigned short type, void *daddr, void *saddr,
+                           unsigned int len)
+{
+       struct ieee80211_data_header *p =
+               (struct ieee80211_data_header *) skb_push(skb, sizeof(*p));
+       void *s_ptr, *d_ptr, *bss_ptr;
+       u16 fctrl;
+       int ret, mode;
+       struct ieee80211_device *wp = ieee80211_find_by_dev(dev);
+
+       if (!wp)
+               return -1;
+
+       /* We fill in shost/dhost, wireless driver fills in self-node address.
+        * This layout works for station mode only.
+        */
+       mode = wp->iw_mode;
+       fctrl = cpu_to_le16(IEEE80211_FCTL_VERS_0 |
+                           IEEE80211_FTYPE_DATA |
+                           IEEE80211_STYPE_DATA);
+
+       switch (mode) {
+       case IW_MODE_INFRA:
+               fctrl |= cpu_to_le16(IEEE80211_FCTL_TODS);
+               s_ptr = p->hdr.addr2;
+               d_ptr = p->hdr.addr3;
+               bss_ptr = p->hdr.addr1;
+               break;
+
+       case IW_MODE_MASTER:
+               fctrl |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+               s_ptr = p->hdr.addr3;
+               d_ptr = p->hdr.addr1;
+               bss_ptr = p->hdr.addr2;
+               break;
+
+       case IW_MODE_ADHOC:
+               fctrl |= cpu_to_le16(0);
+               s_ptr = p->hdr.addr2;
+               d_ptr = p->hdr.addr1;
+               bss_ptr = p->hdr.addr3;
+               break;
+
+       default:
+               /* Unexpected... */
+               ret = -1;
+               goto out;
+       };
+       p->hdr.frame_ctl = fctrl;
+
+       /* Filled in by driver, if necessary. */
+       p->hdr.duration_id = 0;
+
+       if (daddr) {
+               memcpy(d_ptr, daddr, ETH_ALEN);
+               ret = dev->hard_header_len;
+       } else
+               ret = -dev->hard_header_len;
+
+       memcpy(bss_ptr, wp->bssid, ETH_ALEN);
+       memcpy(s_ptr, (saddr ? saddr : dev->dev_addr), ETH_ALEN);
+
+       p->snap.dsap = 0xaa;
+       p->snap.ssap = 0xaa;
+       p->snap.ctrl = 0x03;
+       p->snap.oui[0] = 0x00;
+       p->snap.oui[1] = 0x00;
+       if (type == ETH_P_IPX || type == ETH_P_AARP)
+               p->snap.oui[2] = 0x08;  /* P802_1H_OUI */
+       else
+               p->snap.oui[2] = 0x00;  /* RFC1042_OUI */
+
+       if (type != ETH_P_802_3)
+               p->snap.ethertype = htons(type);
+       else
+               p->snap.ethertype = htons(len);
+
+out:
+       wireless_put(wp);
+       return ret;
+}
+
+/* Rebuild the MAC header.  This is invoked after ARP completes.  */
+static int ieee80211_rebuild_header(struct sk_buff *skb)
+{
+       struct ieee80211_data_header *p =
+                       (struct ieee80211_data_header *) skb->data;
+       struct net_device *dev = skb->dev;
+
+       switch (p->snap.ethertype) {
+#ifdef CONFIG_INET
+       case __constant_htons(ETH_P_IP):
+               return arp_find(p->hdr.addr3, skb);
+#endif
+       default:
+               printk(KERN_DEBUG
+                      "%s: unable to resolve type %X addresses.\n", 
+                      dev->name, (int) p->snap.ethertype);
+       };
+
+       return 0;
+}
+
+/* Determine the RX packet's protocol ID.  */
+unsigned short ieee80211_type_trans(struct sk_buff *skb, struct
net_device *dev)
+{
+#if 0
+    struct ieee80211_data_header *p;
+       u8 *daddr;
+
+       skb->mac.raw = skb->data;
+       p = (struct ieee80211_data_header *) skb->mac.raw;
+
+       /* First, check the type, if it isn't data we want to
+        * keep the 802.11 header in place.
+        */
+       if (((p->hdr.frame_ctl & cpu_to_le16(IEEE80211_FCTL_FTYPE))
+            != cpu_to_le16(IEEE80211_FTYPE_DATA)) ||
+           ((p->hdr.frame_ctl & cpu_to_le16(IEEE80211_FCTL_STYPE))
+            != cpu_to_le16(IEEE80211_STYPE_DATA))) {
+               return __constant_htons(ETH_P_802_11);
+       }
+#endif
+       skb->mac.raw = skb->data;
+       return __constant_htons(ETH_P_802_11);
+#if 0
+       skb_pull(skb, dev->hard_header_len);
+       skb_trim(skb, skb->len - 4); /* Zap trailing CRC */
+
+       switch (p->hdr.frame_ctl & cpu_to_le16(IEEE80211_FCTL_DIRMASK)) {
+       case cpu_to_le16(IEEE80211_FCTL_NODS):
+       case cpu_to_le16(IEEE80211_FCTL_TODS):
+               daddr = p->hdr.addr1;
+               break;
+
+       case cpu_to_le16(IEEE80211_FCTL_FROMDS):
+       case cpu_to_le16(IEEE80211_FCTL_DSTODS):
+       default:
+               daddr = p->hdr.addr3;
+               break;
+       };
+
+       if (daddr[0] & 0x1) {
+               if (memcmp(daddr, dev->broadcast, ETH_ALEN) == 0)
+                       skb->pkt_type = PACKET_BROADCAST;
+               else
+                       skb->pkt_type = PACKET_MULTICAST;
+       } else {
+               if (memcmp(daddr, dev->dev_addr, ETH_ALEN))
+                       skb->pkt_type = PACKET_OTHERHOST;
+       }
+       if (p->snap.dsap == 0xaa &&
+           p->snap.ssap == 0xaa &&
+           p->snap.control == 0x03 &&
+           p->snap.oui[0] == 0 && p->snap.oui[1] == 0 && p->snap.oui[2] == 0)
{
+               if (ntohs(p->snap.ethertype) >= 1536)
+                       return p->snap.ethertype;
+               if (*(unsigned short *)skb->data == 0xffff)
+                       return __constant_htons(ETH_P_802_3);
+
+               /* XXX LLC-in-LLC, is it legal? -DaveM */
+               goto out_llc;
+       }
+
+       /* Put the LLC header back. */
+       skb_push(skb, sizeof(struct ieee802_11_snap));
+
+out_llc:
+       return __constant_htons(ETH_P_802_2);
+#endif
+}
+EXPORT_SYMBOL(ieee80211_type_trans);
+
+static int ieee80211_header_parse(struct sk_buff *skb, unsigned char
*haddr)
+{
+       struct ieee80211_data_header *p =
+                       (struct ieee80211_data_header *) skb->mac.raw;
+       u8 *saddr;
+
+       switch (p->hdr.frame_ctl & cpu_to_le16(IEEE80211_FCTL_DIRMASK)) {
+       case cpu_to_le16(IEEE80211_FCTL_NODS):
+       case cpu_to_le16(IEEE80211_FCTL_FROMDS):
+               saddr = p->hdr.addr2;
+               break;
+
+       case cpu_to_le16(IEEE80211_FCTL_TODS):
+               saddr = p->hdr.addr3;
+               break;
+
+       case cpu_to_le16(IEEE80211_FCTL_DSTODS):
+       default: {
+               struct ieee80211_hdr *p4 = (struct ieee80211_hdr *) p;
+               saddr = p4->addr4;
+               break;
+       }
+       };
+
+       memcpy(haddr, saddr, ETH_ALEN);
+       return ETH_ALEN;
+}
+
+extern void hh_data_is_too_small(void);
+
+static int ieee80211_header_cache(struct neighbour *neigh, struct
hh_cache *hh)
+{
+       unsigned short type = hh->hh_type;
+       struct ieee80211_data_header *p = (struct ieee80211_data_header *)
+               (((u8*)hh->hh_data) + (HH_DATA_OFF(sizeof(*p)) % HH_DATA_MOD));
+       struct net_device *dev = neigh->dev;
+       void *s_ptr, *d_ptr, *bss_ptr;
+       u16 fctrl;
+       int mode;
+       struct ieee80211_device *wp = ieee80211_find_by_dev(dev);
+       int ret = 0;
+
+       if (!wp)
+               return -1;
+
+       if (sizeof(hh->hh_data) < sizeof(*p))
+               hh_data_is_too_small();
+
+       if (type == __constant_htons(ETH_P_802_11)) {
+               ret = -1;
+               goto out;
+       }
+
+       mode = wp->iw_mode;
+       fctrl = cpu_to_le16(IEEE80211_FCTL_VERS_0 |
+                           IEEE80211_FTYPE_DATA |
+                           IEEE80211_STYPE_DATA);
+       switch (mode) {
+       case IW_MODE_INFRA:
+               fctrl |= cpu_to_le16(IEEE80211_FCTL_TODS);
+               s_ptr = p->hdr.addr2;
+               d_ptr = p->hdr.addr3;
+               bss_ptr = p->hdr.addr1;
+               break;
+
+       case IW_MODE_MASTER:
+               fctrl |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+               s_ptr = p->hdr.addr3;
+               d_ptr = p->hdr.addr1;
+               bss_ptr = p->hdr.addr2;
+               break;
+
+       case IW_MODE_ADHOC:
+               fctrl |= cpu_to_le16(0);
+               s_ptr = p->hdr.addr2;
+               d_ptr = p->hdr.addr1;
+               bss_ptr = p->hdr.addr3;
+               break;
+
+       default:
+               /* Unexpected... */
+               ret = -1;
+               goto out;
+       };
+       p->hdr.frame_ctl = fctrl;
+
+       /* Filled in by driver, if necessary. */
+       p->hdr.duration_id = 0;
+
+       memcpy(d_ptr, neigh->ha, ETH_ALEN);
+       memcpy(bss_ptr, wp->bssid, ETH_ALEN);
+       memcpy(s_ptr, dev->dev_addr, ETH_ALEN);
+
+       /* Filled in by driver. */
+       p->hdr.seq_ctl = 0;
+
+       p->snap.dsap = 0xaa;
+       p->snap.ssap = 0xaa;
+       p->snap.ctrl = 0x03;
+       p->snap.oui[0] = 0x00;
+       p->snap.oui[1] = 0x00;
+       if (type == ETH_P_IPX || type == ETH_P_AARP)
+               p->snap.oui[2] = 0x08;  /* P802_1H_OUI */
+       else
+               p->snap.oui[2] = 0x00;  /* RFC1042_OUI */
+
+       p->snap.ethertype = type;
+
+       hh->hh_len = sizeof(*p);
+
+out:
+       wireless_put(wp);
+       return ret;
+}
+
+static void ieee80211_header_cache_update(struct hh_cache *hh,
+                                         struct net_device *dev,
+                                         unsigned char *haddr)
+{
+       struct ieee80211_data_header *p = (struct ieee80211_data_header *)
+                       ((u8*)hh->hh_data + LL_MAX_HEADER - sizeof(*p));
+
+       memcpy(p->hdr.addr3, haddr, dev->addr_len);
+}
+
+void ieee80211_setup(struct net_device *dev)
+{
+       ether_setup(dev);
+
+       dev->hard_header        = ieee80211_header;
+       dev->rebuild_header     = ieee80211_rebuild_header;
+       dev->hard_header_cache  = ieee80211_header_cache;
+       dev->header_cache_update= ieee80211_header_cache_update;
+       dev->hard_header_parse  = ieee80211_header_parse;
+       dev->hard_header_len    = sizeof(struct ieee80211_data_header);
+       dev->mtu                = 1500;
+       dev->hard_start_xmit    = ieee80211_xmit;
+       dev->type               = ARPHRD_ETHER; /* XXX: For APs don't support
+                                                * ARPHRD_IEEE80211.*/
+}
+EXPORT_SYMBOL(ieee80211_setup);
diff -Nru a/net/ieee80211/ieee80211_impl.h
b/net/ieee80211/ieee80211_impl.h
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/net/ieee80211/ieee80211_impl.h    2005-03-02 15:00:13 +08:00
@@ -0,0 +1,55 @@
+/* ieee80211_impl.h: ieee80211 stack implementation specific header.
+ *
+ * Copyright (C) 2004-2005 Intel Corporation, Zhu Yi. All rights
reserved.
+ *
+ * Portions of this file are based on p80211
+ *     Copyright (C) 2003 David S. Miller <davem@xxxxxxxxxx>
+ *     Copyright (C) 2003 Arlando Carvalho de Melo <acme@xxxxxxxxxxxxxxxx>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution
in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@xxxxxxxxxxxxxxx>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR
97124-6497
+ */
+
+#ifndef _IEEE80211_IMPL_H
+#define _IEEE80211_IMPL_H
+
+/* Module init/cleanup */
+extern int ieee80211_input_init(void);
+extern void ieee80211_input_cleanup(void);
+
+int ieee80211_output(struct ieee80211_device *, u16);
+
+struct ieee80211_device *ieee80211_find_by_dev(struct net_device *);
+
+static inline void wireless_get(struct ieee80211_device *p)
+{
+       atomic_inc(&p->refcnt);
+}
+
+extern void __ieee80211_destroy(struct ieee80211_device *);
+
+static inline void wireless_put(struct ieee80211_device *p)
+{
+       if (atomic_dec_and_test(&p->refcnt))
+               __ieee80211_destroy(p);
+}
+
+#endif /* !(_IEEE80211_IMPL_H) */
diff -Nru a/net/ieee80211/ieee80211_input.c
b/net/ieee80211/ieee80211_input.c
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/net/ieee80211/ieee80211_input.c   2005-03-02 15:00:13 +08:00
@@ -0,0 +1,389 @@
+/* ieeee80211_input.c: 802.11 packet input processing.
+ *
+ * Copyright (C) 2004-2005 Intel Corporation, Zhu Yi. All rights
reserved.
+ *
+ * Portions of this file are based on p80211
+ *     Copyright (C) 2003 David S. Miller <davem@xxxxxxxxxx>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution
in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@xxxxxxxxxxxxxxx>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR
97124-6497
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <net/ieee80211.h>
+#include "ieee80211_impl.h"
+
+typedef int (*ieee80211_recv_t)(struct sk_buff *, struct
ieee80211_device *);
+
+static int ieee80211_recv_invalid(struct sk_buff *, struct
ieee80211_device *);
+
+/* management */
+static int ieee80211_recv_assoc_req(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_assoc_resp(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_reassoc_req(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_reassoc_resp(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_probe_req(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_probe_resp(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_beacon(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_atim(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_disassoc(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_auth(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_deauth(struct sk_buff *, struct
ieee80211_device *);
+
+/* control */
+static int ieee80211_recv_pspoll(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_rts(struct sk_buff *, struct ieee80211_device
*);
+static int ieee80211_recv_cts(struct sk_buff *, struct ieee80211_device
*);
+static int ieee80211_recv_ack(struct sk_buff *, struct ieee80211_device
*);
+static int ieee80211_recv_cfend(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_cfendack(struct sk_buff *, struct
ieee80211_device *);
+
+/* data */
+extern int ieee80211_recv_data(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_data_cfack(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_data_cfpoll(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_data_cfackpoll(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_nullfunc(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_cfack(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_cfpoll(struct sk_buff *, struct
ieee80211_device *);
+static int ieee80211_recv_cfackpoll(struct sk_buff *, struct
ieee80211_device *);
+
+static ieee80211_recv_t input_methods[0x4][0x10] = {
+/* management */
+[IEEE80211_FTYPE_MGMT >> IEEE80211_FTYPE_SHIFT] = {
+       [IEEE80211_STYPE_ASSOC_REQ >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_assoc_req,
+       [IEEE80211_STYPE_ASSOC_RESP >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_assoc_resp,
+       [IEEE80211_STYPE_REASSOC_REQ >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_reassoc_req,
+       [IEEE80211_STYPE_REASSOC_RESP >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_reassoc_resp,
+       [IEEE80211_STYPE_PROBE_REQ >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_probe_req,
+       [IEEE80211_STYPE_PROBE_RESP >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_probe_resp,
+       [0x6] = ieee80211_recv_invalid,
+       [0x7] = ieee80211_recv_invalid,
+       [IEEE80211_STYPE_BEACON >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_beacon,
+       [IEEE80211_STYPE_ATIM >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_atim,
+       [IEEE80211_STYPE_DISASSOC >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_disassoc,
+       [IEEE80211_STYPE_AUTH >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_auth,
+       [IEEE80211_STYPE_DEAUTH >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_deauth,
+       [0xd] = ieee80211_recv_invalid,
+       [0xe] = ieee80211_recv_invalid,
+       [0xf] = ieee80211_recv_invalid,
+},
+/* control */
+[IEEE80211_FTYPE_CTL >> IEEE80211_FTYPE_SHIFT] = {
+       [0x0] = ieee80211_recv_invalid,
+       [0x1] = ieee80211_recv_invalid,
+       [0x2] = ieee80211_recv_invalid,
+       [0x3] = ieee80211_recv_invalid,
+       [0x4] = ieee80211_recv_invalid,
+       [0x5] = ieee80211_recv_invalid,
+       [0x6] = ieee80211_recv_invalid,
+       [0x7] = ieee80211_recv_invalid,
+       [0x8] = ieee80211_recv_invalid,
+       [0x9] = ieee80211_recv_invalid,
+       [IEEE80211_STYPE_PSPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_pspoll,
+       [IEEE80211_STYPE_RTS >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_rts,
+       [IEEE80211_STYPE_CTS >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_cts,
+       [IEEE80211_STYPE_ACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_ack,
+       [IEEE80211_STYPE_CFEND >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_cfend,
+       [IEEE80211_STYPE_CFENDACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_cfendack,
+},
+/* data */
+[IEEE80211_FTYPE_DATA >> IEEE80211_FTYPE_SHIFT] = {
+       [IEEE80211_STYPE_DATA >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_data,
+       [IEEE80211_STYPE_DATA_CFACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_data_cfack,
+       [IEEE80211_STYPE_DATA_CFPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_data_cfpoll,
+       [IEEE80211_STYPE_DATA_CFACKPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_data_cfackpoll,
+       [IEEE80211_STYPE_NULLFUNC >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_nullfunc,
+       [IEEE80211_STYPE_CFACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_cfack,
+       [IEEE80211_STYPE_CFPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_cfpoll,
+       [IEEE80211_STYPE_CFACKPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_recv_cfackpoll,
+       [0x8] = ieee80211_recv_invalid,
+       [0x9] = ieee80211_recv_invalid,
+       [0xa] = ieee80211_recv_invalid,
+       [0xb] = ieee80211_recv_invalid,
+       [0xc] = ieee80211_recv_invalid,
+       [0xd] = ieee80211_recv_invalid,
+       [0xe] = ieee80211_recv_invalid,
+       [0xf] = ieee80211_recv_invalid,
+},
+/* invalid ftype */
+[IEEE80211_FTYPE_INVALID >> 2] = {
+       [0x0] = ieee80211_recv_invalid,
+       [0x1] = ieee80211_recv_invalid,
+       [0x2] = ieee80211_recv_invalid,
+       [0x3] = ieee80211_recv_invalid,
+       [0x4] = ieee80211_recv_invalid,
+       [0x5] = ieee80211_recv_invalid,
+       [0x6] = ieee80211_recv_invalid,
+       [0x7] = ieee80211_recv_invalid,
+       [0x8] = ieee80211_recv_invalid,
+       [0x9] = ieee80211_recv_invalid,
+       [0xa] = ieee80211_recv_invalid,
+       [0xb] = ieee80211_recv_invalid,
+       [0xc] = ieee80211_recv_invalid,
+       [0xd] = ieee80211_recv_invalid,
+       [0xe] = ieee80211_recv_invalid,
+       [0xf] = ieee80211_recv_invalid,
+},
+};
+
+static inline int demultiplex(struct sk_buff *skb, struct
ieee80211_device *wp, u16 ctl)
+{
+       int type, subtype;
+
+       type = (ctl & IEEE80211_FCTL_FTYPE) >> IEEE80211_FTYPE_SHIFT;
+       subtype = (ctl & IEEE80211_FCTL_STYPE) >> IEEE80211_STYPE_SHIFT;
+ 
+       return input_methods[type][subtype](skb, wp);
+}
+
+static int ieee80211_rcv(struct sk_buff *skb, struct net_device *dev,
+                        struct packet_type *pt)
+{
+       struct ieee80211_hdr_3addr *p = (struct ieee80211_hdr_3addr
*)skb->data;
+       struct ieee80211_device *wp = ieee80211_find_by_dev(dev);
+       int ret;
+
+       if (wp) {
+               ret = demultiplex(skb, wp, le16_to_cpu(p->frame_ctl));
+               wireless_put(wp);
+       } else {
+               ret = NET_RX_DROP;
+               kfree_skb(skb);
+       }
+       return ret;
+}
+
+int ieee80211_recv_invalid(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+/* management */
+int ieee80211_recv_assoc_req(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_assoc_resp(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_reassoc_req(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_reassoc_resp(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_probe_req(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_probe_resp(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       struct ieee80211_probe_response *beacon =
+               (struct ieee80211_probe_response *)skb->data;
+       struct ieee80211_rx_stats *stats =
+               (struct ieee80211_rx_stats *)&(skb->cb[0]);
+
+       ieee80211_process_probe_response(wp, beacon, stats);
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_beacon(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       struct ieee80211_probe_response *beacon =
+               (struct ieee80211_probe_response *)skb->data;
+       struct ieee80211_rx_stats *stats =
+               (struct ieee80211_rx_stats *)&(skb->cb[0]);
+
+       ieee80211_process_probe_response(wp, beacon, stats);
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_atim(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_disassoc(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_auth(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_deauth(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+/* control */
+int ieee80211_recv_pspoll(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_rts(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_cts(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_ack(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_cfend(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_cfendack(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+/* data */
+int ieee80211_recv_data_cfack(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_data_cfpoll(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_data_cfackpoll(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_nullfunc(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       printk("In %s\n", __FUNCTION__);
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_cfack(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_cfpoll(struct sk_buff *skb, struct ieee80211_device
*wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+int ieee80211_recv_cfackpoll(struct sk_buff *skb, struct
ieee80211_device *wp)
+{
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+static struct packet_type ieee80211_packet_type = {
+       .type   =       __constant_htons(ETH_P_802_11),
+       .func   =       ieee80211_rcv,
+};
+
+int ieee80211_input_init(void)
+{
+       dev_add_pack(&ieee80211_packet_type);
+
+       return 0;
+}
+
+void ieee80211_input_cleanup(void)
+{
+       dev_remove_pack(&ieee80211_packet_type);
+}
diff -Nru a/net/ieee80211/ieee80211_mgmt.c
b/net/ieee80211/ieee80211_mgmt.c
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/net/ieee80211/ieee80211_mgmt.c    2005-03-02 15:00:13 +08:00
@@ -0,0 +1,265 @@
+/* ieee80211_mgmt.c: 802.11 management layer.
+ *
+ * Copyright (C) 2004-2005 Intel Corporation, Zhu Yi. All rights
reserved.
+ *
+ * Portions of this file are based on:
+
+ * WEP enablement code provided by the Host AP project hostap-drivers
v0.1.3
+ *     Copyright (C) 2001-2002, SSH Communications Security Corp and
+ *     Copyright (C) 2002-2003, Jouni Malinen <jkmaline@xxxxxxxxx>
+ *
+ * p80211:
+ *     Copyright (C) 2003 David S. Miller <davem@xxxxxxxxxx>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution
in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@xxxxxxxxxxxxxxx>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR
97124-6497
+ */
+
+#ifndef EXPORT_SYMTAB
+#define        EXPORT_SYMTAB
+#endif
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <net/ieee80211.h>
+#include "ieee80211_impl.h"
+
+static LIST_HEAD(wireless_all);
+static spinlock_t wireless_lock = SPIN_LOCK_UNLOCKED;
+
+static struct ieee80211_device *__wireless_find_by_dev(struct
net_device *dev)
+{
+       struct list_head *entry;
+
+       list_for_each(entry, &wireless_all) {
+               struct ieee80211_device *p = ieee80211_device_entry(entry);
+
+               if (p->dev == dev)
+                       return p;
+       }
+       return NULL;
+}
+
+struct ieee80211_device *ieee80211_find_by_dev(struct net_device *dev)
+{
+       struct ieee80211_device *wp;
+
+       spin_lock_irq(&wireless_lock);
+       wp = __wireless_find_by_dev(dev);
+       if (wp)
+               wireless_get(wp);
+       spin_unlock_irq(&wireless_lock);
+
+       return wp;
+}
+
+static inline int ieee80211_networks_allocate(struct ieee80211_device
*ieee)
+{
+       if (ieee->networks)
+               return 0;
+
+       ieee->networks = kmalloc(
+               MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
+               GFP_KERNEL);
+       if (!ieee->networks) {
+               printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
+                      ieee->dev->name);
+               return -ENOMEM;
+       }
+
+       memset(ieee->networks, 0,
+              MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
+
+       return 0;
+}
+
+static inline void ieee80211_networks_free(struct ieee80211_device
*ieee)
+{
+       if (!ieee->networks)
+               return;
+       kfree(ieee->networks);
+       ieee->networks = NULL;
+}
+
+static inline void ieee80211_networks_initialize(struct
ieee80211_device *ieee)
+{
+       int i;
+
+       INIT_LIST_HEAD(&ieee->network_free_list);
+       INIT_LIST_HEAD(&ieee->network_list);
+       for (i = 0; i < MAX_NETWORK_COUNT; i++)
+               list_add_tail(&ieee->networks[i].list,
+                             &ieee->network_free_list);
+}
+
+struct ieee80211_device *ieee80211_open(struct net_device *dev,
+                                       struct wireless_ops *ops)
+{
+       struct ieee80211_device *p;
+       int err;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return NULL;
+
+       memset(p, 0, sizeof(*p));
+
+       err = ieee80211_networks_allocate(p);
+       if (err) {
+               IEEE80211_ERROR("Unable to allocate beacon storage.\n");
+               return NULL;
+       }
+       ieee80211_networks_initialize(p);
+
+       atomic_set(&p->refcnt, 1);
+       spin_lock_init(&p->network_lock);
+       spin_lock_init(&p->crypt_lock);
+       spin_lock_init(&p->state_lock);
+       p->iw_mode = IW_MODE_AUTO;
+       p->state = IEEE80211_INITIALIZED;
+       p->scan_age = 0;
+       p->capability = 0;
+       p->mode = IEEE80211_PHY_CUR_INV;
+       p->essid_len = 0;
+
+       /* Default fragmentation threshold is maximum payload size */
+       p->fts = DEFAULT_FTS;
+       p->scan_age = DEFAULT_MAX_SCAN_AGE;
+       p->open_wep = 1;
+
+       /* Default to enabling full open WEP with host based encrypt/decrypt
*/
+       p->host_encrypt = 1;
+       p->host_decrypt = 1;
+       p->ieee802_1x = 1; /* Default to supporting 802.1x */
+
+       INIT_LIST_HEAD(&p->crypt_deinit_list);
+       init_timer(&p->crypt_deinit_timer);
+       p->crypt_deinit_timer.data = (unsigned long)p;
+       p->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
+
+       p->wpa_enabled = 0;
+       p->tkip_countermeasures = 0;
+       p->drop_unencrypted = 0;
+       p->privacy_invoked = 0;
+
+       p->dev = dev;
+       p->ops = ops;
+
+       spin_lock_irq(&wireless_lock);
+       list_add(&p->all_device, &wireless_all);
+       spin_unlock_irq(&wireless_lock);
+
+       return p;
+}
+EXPORT_SYMBOL(ieee80211_open);
+
+void __ieee80211_destroy(struct ieee80211_device *p)
+{
+       int i;
+
+       if (atomic_read(&p->refcnt))
+               BUG();
+
+       del_timer_sync(&p->crypt_deinit_timer);
+       ieee80211_crypt_deinit_entries(p, 1);
+
+       for (i = 0; i < WEP_KEYS; i++) {
+               struct ieee80211_crypt_data *crypt = p->crypt[i];
+               if (crypt) {
+                       if (crypt->ops) {
+                               crypt->ops->deinit(crypt->priv);
+                               module_put(crypt->ops->owner);
+                       }
+                       kfree(crypt);
+                       p->crypt[i] = NULL;
+               }
+       }
+       p->state = IEEE80211_INITIALIZED;
+       p->mode = IEEE80211_PHY_CUR_INV;
+       memset(p->essid, 0, sizeof(p->essid));
+       p->essid_len = 0;
+       p->dev = NULL;
+       p->ops = NULL;
+       ieee80211_networks_free(p);
+       kfree(p);
+}
+
+void ieee80211_close(struct net_device *dev, struct ieee80211_device
*p)
+{
+       spin_lock_irq(&wireless_lock);
+       list_del_init(&p->network_list);
+       spin_unlock_irq(&wireless_lock);
+
+       wireless_put(p);
+}
+EXPORT_SYMBOL(ieee80211_close);
+
+int ieee80211_set_mode(struct ieee80211_device *wp, u8 mode)
+{
+       switch (mode) {
+       case IW_MODE_AUTO:
+       case IW_MODE_INFRA:
+       case IW_MODE_MASTER:
+       case IW_MODE_ADHOC:
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       /* XXX Flush everything here... */
+
+       wp->iw_mode = mode;
+       return 0;
+}
+EXPORT_SYMBOL(ieee80211_set_mode);
+
+int ieee80211_start_scan(struct ieee80211_device *wp)
+{
+       return 0;
+}
+EXPORT_SYMBOL(ieee80211_start_scan);
+
+enum ieee80211_state ieee80211_get_state(struct ieee80211_device *wp)
+{
+       unsigned long flags;
+       enum ieee80211_state st;
+
+       spin_lock_irqsave(&wp->state_lock, flags);
+       st = wp->state;
+       spin_unlock_irqrestore(&wp->state_lock, flags);
+
+       return st;
+}
+
+void ieee80211_set_state(struct ieee80211_device *wp, enum
ieee80211_state st)
+{
+       spin_lock(&wp->state_lock);
+       wp->state = st;
+       spin_unlock(&wp->state_lock);
+}
+EXPORT_SYMBOL(ieee80211_set_state);
diff -Nru a/net/ieee80211/ieee80211_module.c
b/net/ieee80211/ieee80211_module.c
--- a/net/ieee80211/ieee80211_module.c  2005-03-02 15:00:13 +08:00
+++ b/net/ieee80211/ieee80211_module.c  2005-03-02 15:00:13 +08:00
@@ -53,6 +53,7 @@
 #include <net/arp.h>
 
 #include <net/ieee80211.h>
+#include "ieee80211_impl.h"
 
 MODULE_DESCRIPTION("802.11 data/management/control stack");
 MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation
<jketreno@xxxxxxxxxxxxxxx>");
@@ -60,128 +61,6 @@
 
 #define DRV_NAME "ieee80211"
 
-static inline int ieee80211_networks_allocate(struct ieee80211_device
*ieee)
-{
-       if (ieee->networks)
-               return 0;
-
-       ieee->networks = kmalloc(
-               MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
-               GFP_KERNEL);
-       if (!ieee->networks) {
-               printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
-                      ieee->dev->name);
-               return -ENOMEM;
-       }
-
-       memset(ieee->networks, 0,
-              MAX_NETWORK_COUNT * sizeof(struct ieee80211_network));
-
-       return 0;
-}
-
-static inline void ieee80211_networks_free(struct ieee80211_device
*ieee)
-{
-       if (!ieee->networks)
-               return;
-       kfree(ieee->networks);
-       ieee->networks = NULL;
-}
-
-static inline void ieee80211_networks_initialize(struct
ieee80211_device *ieee)
-{
-       int i;
-
-       INIT_LIST_HEAD(&ieee->network_free_list);
-       INIT_LIST_HEAD(&ieee->network_list);
-       for (i = 0; i < MAX_NETWORK_COUNT; i++)
-               list_add_tail(&ieee->networks[i].list, 
&ieee->network_free_list);
-}
-
-
-struct net_device *alloc_ieee80211(int sizeof_priv)
-{
-       struct ieee80211_device *ieee;
-       struct net_device *dev;
-       int err;
-
-       IEEE80211_DEBUG_INFO("Initializing...\n");
-
-       dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
-       if (!dev) {
-               IEEE80211_ERROR("Unable to network device.\n");
-               goto failed;
-       }
-       ieee = netdev_priv(dev);
-       dev->hard_start_xmit = ieee80211_xmit;
-
-       ieee->dev = dev;
-
-       err = ieee80211_networks_allocate(ieee);
-       if (err) {
-               IEEE80211_ERROR("Unable to allocate beacon storage: %d\n",
-                               err);
-               goto failed;
-       }
-       ieee80211_networks_initialize(ieee);
-
-       /* Default fragmentation threshold is maximum payload size */
-       ieee->fts = DEFAULT_FTS;
-       ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
-       ieee->open_wep = 1;
-
-       /* Default to enabling full open WEP with host based encrypt/decrypt
*/
-       ieee->host_encrypt = 1;
-       ieee->host_decrypt = 1;
-       ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
-
-       INIT_LIST_HEAD(&ieee->crypt_deinit_list);
-       init_timer(&ieee->crypt_deinit_timer);
-       ieee->crypt_deinit_timer.data = (unsigned long)ieee;
-       ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
-
-       spin_lock_init(&ieee->lock);
-
-       ieee->wpa_enabled = 0;
-       ieee->tkip_countermeasures = 0;
-       ieee->drop_unencrypted = 0;
-       ieee->privacy_invoked = 0;
-       ieee->ieee802_1x = 1;
-
-       return dev;
-
- failed:
-       if (dev)
-               free_netdev(dev);
-       return NULL;
-}
-
-
-void free_ieee80211(struct net_device *dev)
-{
-       struct ieee80211_device *ieee = netdev_priv(dev);
-
-       int i;
-
-       del_timer_sync(&ieee->crypt_deinit_timer);
-       ieee80211_crypt_deinit_entries(ieee, 1);
-
-       for (i = 0; i < WEP_KEYS; i++) {
-               struct ieee80211_crypt_data *crypt = ieee->crypt[i];
-               if (crypt) {
-                       if (crypt->ops) {
-                               crypt->ops->deinit(crypt->priv);
-                               module_put(crypt->ops->owner);
-                       }
-                       kfree(crypt);
-                       ieee->crypt[i] = NULL;
-               }
-       }
-
-       ieee80211_networks_free(ieee);
-       free_netdev(dev);
-}
-
 #ifdef CONFIG_IEEE80211_DEBUG
 
 static int debug = 0;
@@ -221,7 +100,7 @@
        return strnlen(buf, count);
 }
 
-static int __init ieee80211_init(void)
+static int ieee80211_debug_init(void)
 {
        struct proc_dir_entry *e;
 
@@ -246,7 +125,7 @@
        return 0;
 }
 
-static void __exit ieee80211_exit(void)
+static void ieee80211_debug_cleanup(void)
 {
        if (ieee80211_proc) {
                remove_proc_entry("debug_level", ieee80211_proc);
@@ -259,10 +138,37 @@
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
 
+#endif /* CONFIG_IEEE80211_DEBUG */
 
-module_exit(ieee80211_exit);
-module_init(ieee80211_init);
+static int __init ieee80211_init(void)
+{
+       int err;
+
+       printk(KERN_INFO "IEEE 802.11 protocol stack loading.\n");
+
+#ifdef CONFIG_IEEE80211_DEBUG
+       err = ieee80211_debug_init();
+       if (err)
+               goto out;
 #endif
+       err = ieee80211_input_init();
+       if (err) {
+               printk(KERN_ERR
+                      "ieee80211_init: Failed to init input processing.\n");
+               goto out;
+       }
 
-EXPORT_SYMBOL(alloc_ieee80211);
-EXPORT_SYMBOL(free_ieee80211);
+out:
+       return err;
+}
+
+static void __exit ieee80211_cleanup(void)
+{
+       ieee80211_input_cleanup();
+#ifdef CONFIG_IEEE80211_DEBUG
+       ieee80211_debug_cleanup();
+#endif
+}
+
+module_init(ieee80211_init);
+module_exit(ieee80211_cleanup);
diff -Nru a/net/ieee80211/ieee80211_output.c
b/net/ieee80211/ieee80211_output.c
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/net/ieee80211/ieee80211_output.c  2005-03-02 15:00:13 +08:00
@@ -0,0 +1,416 @@
+/* ieee80211_output.c: 802.11 packet output processing.
+ *
+ * Copyright (C) 2004-2005 Intel Corporation, Zhu Yi. All rights
reserved.
+ *
+ * Portions of this file are based on p80211
+ *     Copyright (C) 2003 David S. Miller <davem@xxxxxxxxxx>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution
in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@xxxxxxxxxxxxxxx>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR
97124-6497
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <net/ieee80211.h>
+#include "ieee80211_impl.h"
+
+typedef int (*ieee80211_send_t)(struct ieee80211_device *, u16);
+
+static int ieee80211_send_invalid(struct ieee80211_device *, u16);
+
+/* management */
+static int ieee80211_send_assoc_req(struct ieee80211_device *, u16);
+static int ieee80211_send_assoc_resp(struct ieee80211_device *, u16);
+static int ieee80211_send_reassoc_req(struct ieee80211_device *, u16);
+static int ieee80211_send_reassoc_resp(struct ieee80211_device *, u16);
+static int ieee80211_send_probe_req(struct ieee80211_device *, u16);
+static int ieee80211_send_probe_resp(struct ieee80211_device *, u16);
+static int ieee80211_send_beacon(struct ieee80211_device *, u16);
+static int ieee80211_send_atim(struct ieee80211_device *, u16);
+static int ieee80211_send_disassoc(struct ieee80211_device *, u16);
+static int ieee80211_send_auth(struct ieee80211_device *, u16);
+static int ieee80211_send_deauth(struct ieee80211_device *, u16);
+
+/* control */
+static int ieee80211_send_pspoll(struct ieee80211_device *, u16);
+static int ieee80211_send_rts(struct ieee80211_device *, u16);
+static int ieee80211_send_cts(struct ieee80211_device *, u16);
+static int ieee80211_send_ack(struct ieee80211_device *, u16);
+static int ieee80211_send_cfend(struct ieee80211_device *, u16);
+static int ieee80211_send_cfendack(struct ieee80211_device *, u16);
+
+/* data */
+static int ieee80211_send_data(struct ieee80211_device *, u16);
+static int ieee80211_send_data_cfack(struct ieee80211_device *, u16);
+static int ieee80211_send_data_cfpoll(struct ieee80211_device *, u16);
+static int ieee80211_send_data_cfackpoll(struct ieee80211_device *,
u16);
+static int ieee80211_send_nullfunc(struct ieee80211_device *, u16);
+static int ieee80211_send_cfack(struct ieee80211_device *, u16);
+static int ieee80211_send_cfpoll(struct ieee80211_device *, u16);
+static int ieee80211_send_cfackpoll(struct ieee80211_device *, u16);
+
+static ieee80211_send_t output_methods[0x4][0x10] = {
+/* management */
+[IEEE80211_FTYPE_MGMT >> IEEE80211_FTYPE_SHIFT] = {
+       [IEEE80211_STYPE_ASSOC_REQ >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_assoc_req,
+       [IEEE80211_STYPE_ASSOC_RESP >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_assoc_resp,
+       [IEEE80211_STYPE_REASSOC_REQ >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_reassoc_req,
+       [IEEE80211_STYPE_REASSOC_RESP >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_reassoc_resp,
+       [IEEE80211_STYPE_PROBE_REQ >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_probe_req,
+       [IEEE80211_STYPE_PROBE_RESP >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_probe_resp,
+       [0x6] = ieee80211_send_invalid,
+       [0x7] = ieee80211_send_invalid,
+       [IEEE80211_STYPE_BEACON >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_beacon,
+       [IEEE80211_STYPE_ATIM >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_atim,
+       [IEEE80211_STYPE_DISASSOC >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_disassoc,
+       [IEEE80211_STYPE_AUTH >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_auth,
+       [IEEE80211_STYPE_DEAUTH >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_deauth,
+       [0xd] = ieee80211_send_invalid,
+       [0xe] = ieee80211_send_invalid,
+       [0xf] = ieee80211_send_invalid,
+},
+/* control */
+[IEEE80211_FTYPE_CTL >> IEEE80211_FTYPE_SHIFT] = {
+       [0x0] = ieee80211_send_invalid,
+       [0x1] = ieee80211_send_invalid,
+       [0x2] = ieee80211_send_invalid,
+       [0x3] = ieee80211_send_invalid,
+       [0x4] = ieee80211_send_invalid,
+       [0x5] = ieee80211_send_invalid,
+       [0x6] = ieee80211_send_invalid,
+       [0x7] = ieee80211_send_invalid,
+       [0x8] = ieee80211_send_invalid,
+       [0x9] = ieee80211_send_invalid,
+       [IEEE80211_STYPE_PSPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_pspoll,
+       [IEEE80211_STYPE_RTS >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_rts,
+       [IEEE80211_STYPE_CTS >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_cts,
+       [IEEE80211_STYPE_ACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_ack,
+       [IEEE80211_STYPE_CFEND >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_cfend,
+       [IEEE80211_STYPE_CFENDACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_cfendack,
+},
+/* data */
+[IEEE80211_FTYPE_DATA >> IEEE80211_FTYPE_SHIFT] = {
+       [IEEE80211_STYPE_DATA >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_data,
+       [IEEE80211_STYPE_DATA_CFACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_data_cfack,
+       [IEEE80211_STYPE_DATA_CFPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_data_cfpoll,
+       [IEEE80211_STYPE_DATA_CFACKPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_data_cfackpoll,
+       [IEEE80211_STYPE_NULLFUNC >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_nullfunc,
+       [IEEE80211_STYPE_CFACK >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_cfack,
+       [IEEE80211_STYPE_CFPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_cfpoll,
+       [IEEE80211_STYPE_CFACKPOLL >> IEEE80211_STYPE_SHIFT] =
+               ieee80211_send_cfackpoll,
+       [0x8] = ieee80211_send_invalid,
+       [0x9] = ieee80211_send_invalid,
+       [0xa] = ieee80211_send_invalid,
+       [0xb] = ieee80211_send_invalid,
+       [0xc] = ieee80211_send_invalid,
+       [0xd] = ieee80211_send_invalid,
+       [0xe] = ieee80211_send_invalid,
+       [0xf] = ieee80211_send_invalid,
+},
+/* invalid ftype */
+[IEEE80211_FTYPE_INVALID >> 2] = {
+       [0x0] = ieee80211_send_invalid,
+       [0x1] = ieee80211_send_invalid,
+       [0x2] = ieee80211_send_invalid,
+       [0x3] = ieee80211_send_invalid,
+       [0x4] = ieee80211_send_invalid,
+       [0x5] = ieee80211_send_invalid,
+       [0x6] = ieee80211_send_invalid,
+       [0x7] = ieee80211_send_invalid,
+       [0x8] = ieee80211_send_invalid,
+       [0x9] = ieee80211_send_invalid,
+       [0xa] = ieee80211_send_invalid,
+       [0xb] = ieee80211_send_invalid,
+       [0xc] = ieee80211_send_invalid,
+       [0xd] = ieee80211_send_invalid,
+       [0xe] = ieee80211_send_invalid,
+       [0xf] = ieee80211_send_invalid,
+},
+};
+
+int ieee80211_output(struct ieee80211_device *wp, u16 ctl)
+{
+       int type, subtype;
+
+       type = (ctl & IEEE80211_FCTL_FTYPE) >> IEEE80211_FTYPE_SHIFT;
+       subtype = (ctl & IEEE80211_FCTL_STYPE) >> IEEE80211_STYPE_SHIFT;
+
+       return output_methods[type][subtype](wp, ctl);
+}
+
+/* Packet building helpers. */
+static void mgmt_build_and_send(struct ieee80211_device *wp,
+                               struct sk_buff *skb,
+                               u16 stype)
+{
+       struct ieee80211_hdr_3addr *p;
+
+       p = (struct ieee80211_hdr_3addr *) skb_push(skb, sizeof(*p));
+
+       p->frame_ctl = cpu_to_le16(IEEE80211_FCTL_VERS_0 |
+                                  IEEE80211_FTYPE_MGMT |
+                                  stype |
+                                  IEEE80211_FCTL_NODS);
+       p->duration_id = 0; /* Set by driver, if necessary */
+
+       memcpy(p->addr2, wp->dev->dev_addr, ETH_ALEN);
+       memcpy(p->addr3, wp->bssid, ETH_ALEN);
+
+       p->seq_ctl = 0; /* Set by driver, if necessary */
+
+       dev_queue_xmit(skb);
+}
+
+static void put_essid(struct sk_buff *skb, struct ieee80211_device *wp)
+{
+       u8 *p;
+
+       if (wp->essid_len > IW_ESSID_MAX_SIZE)
+               BUG();
+
+       p = (u8 *) skb_put(skb, WLAN_EID_SIZE + wp->essid_len);
+       *p++ = WLAN_EID_SSID;
+       *p++ = wp->essid_len;
+       if (wp->essid_len) {
+               memcpy(p, wp->essid, wp->essid_len);
+               p += wp->essid_len;
+       }
+       if (p != skb->tail)
+               BUG();
+}
+
+static void put_rates(struct sk_buff *skb, struct wireless_rates *rd,
+                     struct wireless_rates *xrd)
+{
+       u8 *p;
+       int base_num, ext_num, pkt_len;
+
+       base_num = rd->num;
+       ext_num = xrd->num;
+       pkt_len = rd->num + xrd->num;
+
+       p = (u8 *) skb_put(skb, pkt_len);
+       *p++ = WLAN_EID_SUPP_RATES;
+       *p++ = base_num;
+       memcpy(p, rd->rates, base_num);
+       p += base_num;
+
+       if (ext_num) {
+               *p++ = WLAN_EID_EX_RATES;
+               *p++ = ext_num;
+               memcpy(p, xrd->rates, ext_num);
+               p += ext_num;
+       }
+
+       if (p != skb->tail)
+               BUG();
+}
+
+static struct sk_buff *mgmt_alloc_skb(int len)
+{
+       struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
+
+       if (skb)
+               skb_reserve(skb, sizeof(struct ieee80211_hdr_3addr));
+
+       return skb;
+}
+
+int ieee80211_send_invalid(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+/* management */
+int ieee80211_send_assoc_req(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_assoc_resp(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_reassoc_req(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_reassoc_resp(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_probe_req(struct ieee80211_device *wp, u16 ctl)
+{
+       struct ieee80211_hdr_3addr *p;
+       struct sk_buff *skb;
+       int len;
+
+       len = sizeof(*p) +
+               (WLAN_EID_SIZE + wp->essid_len) +
+               (WLAN_EID_SIZE + wp->supp.num + wp->extended.num);
+       skb = mgmt_alloc_skb(len);
+       if (skb) {
+               put_essid(skb, wp);
+               put_rates(skb, &wp->supp, &wp->extended);
+
+               mgmt_build_and_send(wp, skb, IEEE80211_STYPE_PROBE_REQ);
+               return 0;
+       }
+
+       return -ENOMEM;
+}
+
+int ieee80211_send_probe_resp(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_beacon(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_atim(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_disassoc(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_auth(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_deauth(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+/* control */
+int ieee80211_send_pspoll(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_rts(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_cts(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_ack(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_cfend(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_cfendack(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+/* data */
+int ieee80211_send_data(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_data_cfack(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_data_cfpoll(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_data_cfackpoll(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_nullfunc(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_cfack(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_cfpoll(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
+
+int ieee80211_send_cfackpoll(struct ieee80211_device *wp, u16 ctl)
+{
+       return -ENOSYS;
+}
diff -Nru a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
--- a/net/ieee80211/ieee80211_rx.c      2005-03-02 15:00:13 +08:00
+++ b/net/ieee80211/ieee80211_rx.c      2005-03-02 15:00:13 +08:00
@@ -48,7 +48,7 @@
        skb->mac.raw = skb->data;
        skb_pull(skb, ieee80211_get_hdrlen(fc));
        skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = __constant_htons(ETH_P_80211_RAW);
+       skb->protocol = __constant_htons(ETH_P_802_11);
        memset(skb->cb, 0, sizeof(skb->cb));
        netif_rx(skb);
 }
@@ -168,7 +168,7 @@
  *
  * Responsible for handling management control frames
  *
- * Called by ieee80211_rx */
+ * Called by ieee80211_recv_data */
 static inline int
 ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff
*skb,
                        struct ieee80211_rx_stats *rx_stats, u16 type,
@@ -270,7 +270,7 @@
        return 0;
 }
 
-/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+/* Called only as a tasklet (software IRQ), by ieee80211_recv_data */
 static inline int
 ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct
sk_buff *skb,
                           struct ieee80211_crypt_data *crypt)
@@ -315,7 +315,7 @@
 }
 
 
-/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+/* Called only as a tasklet (software IRQ), by ieee80211_recv_data */
 static inline int
 ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct
sk_buff *skb,
                             int keyidx, struct ieee80211_crypt_data *crypt)
@@ -346,14 +346,14 @@
 /* All received frames are sent to this function. @skb contains the
frame in
  * IEEE 802.11 format, i.e., in the format it was sent over air.
  * This function is called only as a tasklet (software IRQ). */
-int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
-                struct ieee80211_rx_stats *rx_stats)
+int ieee80211_recv_data(struct sk_buff *skb, struct ieee80211_device
*ieee)
 {
        struct net_device *dev = ieee->dev;
        struct ieee80211_hdr *hdr;
        size_t hdrlen;
        u16 fc, type, stype, sc;
        struct net_device_stats *stats;
+       struct ieee80211_rx_stats *rx_stats;
        unsigned int frag;
        u8 *payload;
        u16 ethertype;
@@ -372,10 +372,10 @@
 
        hdr = (struct ieee80211_hdr *)skb->data;
        stats = &ieee->stats;
+       rx_stats = (struct ieee80211_rx_stats *) &(skb->cb[0]);
 
        if (skb->len < 10) {
-               printk(KERN_INFO "%s: SKB length < 10\n",
-                      dev->name);
+               printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
                goto rx_dropped;
        }
 
@@ -697,24 +697,15 @@
        }
 #endif
 
-       /* convert hdr + possible LLC headers into Ethernet header */
-       if (skb->len - hdrlen >= 8 &&
-           ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
-             ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-            memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
+       /* get EtherType */
+       if (skb->len - hdrlen < 8 ||
+           ((memcmp(payload, rfc1042_header, SNAP_SIZE - 2) ||
+             ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) &&
+            memcmp(payload, bridge_tunnel_header, SNAP_SIZE - 2))) {
                /* remove RFC1042 or Bridge-Tunnel encapsulation and
-                * replace EtherType */
-               skb_pull(skb, hdrlen + SNAP_SIZE);
-               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
-               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
-       } else {
-               u16 len;
-               /* Leave Ethernet header part of hdr and full payload */
-               skb_pull(skb, hdrlen);
-               len = htons(skb->len);
-               memcpy(skb_push(skb, 2), &len, 2);
-               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
-               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+                * replace EtherType else Leave Ethernet header part
+                * of hdr and full payload */
+               ethertype = skb->len;
        }
 
 #ifdef NOT_YET
@@ -764,10 +755,11 @@
 #endif
 
        if (skb) {
-               skb->protocol = eth_type_trans(skb, dev);
+               skb->mac.raw = skb->data;
+               skb_pull(skb, IEEE80211_HEADER_LEN);
+               skb->protocol = htons(ethertype);
                memset(skb->cb, 0, sizeof(skb->cb));
-               skb->dev = dev;
-               skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
+
                netif_rx(skb);
        }
 
@@ -1049,7 +1041,7 @@
        /* dst->last_associate is not overwritten */
 }
 
-static inline void ieee80211_process_probe_response(
+void ieee80211_process_probe_response(
        struct ieee80211_device *ieee,
        struct ieee80211_probe_response *beacon,
        struct ieee80211_rx_stats *stats)
@@ -1057,10 +1049,10 @@
        struct ieee80211_network network;
        struct ieee80211_network *target;
        struct ieee80211_network *oldest = NULL;
+       unsigned long flags;
 #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",
@@ -1104,8 +1096,7 @@
        /* Search for this entry in the list and update it if it is
         * already there. */
 
-       spin_lock_irqsave(&ieee->lock, flags);
-
+       spin_lock_irqsave(&ieee->network_lock, flags);
        list_for_each_entry(target, &ieee->network_list, list) {
                if (is_same_network(target, &network))
                        break;
@@ -1157,7 +1148,7 @@
                update_network(target, &network);
        }
 
-       spin_unlock_irqrestore(&ieee->lock, flags);
+       spin_unlock_irqrestore(&ieee->network_lock, flags);
 }
 
 void ieee80211_rx_mgt(struct ieee80211_device *ieee,
@@ -1203,4 +1194,4 @@
 
 
 EXPORT_SYMBOL(ieee80211_rx_mgt);
-EXPORT_SYMBOL(ieee80211_rx);
+EXPORT_SYMBOL(ieee80211_recv_data);
diff -Nru a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
--- a/net/ieee80211/ieee80211_tx.c      2005-03-02 15:00:13 +08:00
+++ b/net/ieee80211/ieee80211_tx.c      2005-03-02 15:00:13 +08:00
@@ -45,6 +45,7 @@
 #include <asm/uaccess.h>
 
 #include <net/ieee80211.h>
+#include "ieee80211_impl.h"
 
 
 /*
@@ -150,9 +151,9 @@
        snap->oui[1] = oui[1];
        snap->oui[2] = oui[2];
 
-       *(u16 *)(data + SNAP_SIZE) = htons(h_proto);
+       snap->ethertype = htons(h_proto);
 
-       return SNAP_SIZE + sizeof(u16);
+       return SNAP_SIZE;
 }
 
 static inline int ieee80211_encrypt_fragment(
@@ -244,48 +245,39 @@
 }
 
 /* SKBs are added to the ieee->tx_queue. */
-int ieee80211_xmit(struct sk_buff *skb,
-                  struct net_device *dev)
+int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct ieee80211_device *ieee = netdev_priv(dev);
+       struct ieee80211_device *ieee = ieee80211_find_by_dev(dev);
        struct ieee80211_txb *txb = NULL;
-       struct ieee80211_hdr *frag_hdr;
+       struct ieee80211_data_header *frag_hdr;
        int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
-       unsigned long flags;
        struct net_device_stats *stats = &ieee->stats;
        int ether_type, encrypt;
-       int bytes, fc, hdr_len;
+       int bytes, fc;
        struct sk_buff *skb_frag;
-       struct ieee80211_hdr header = { /* Ensure zero initialized */
-               .duration_id = 0,
-               .seq_ctl = 0
-       };
-       u8 dest[ETH_ALEN], src[ETH_ALEN];
-
+       struct ieee80211_data_header header;
+       u8 dest[ETH_ALEN];
        struct ieee80211_crypt_data* crypt;
 
-       spin_lock_irqsave(&ieee->lock, flags);
+       if (!ieee)
+               return -1;
 
        /* If there is no driver handler to take the TXB, dont' bother
         * creating it... */
-       if (!ieee->hard_start_xmit) {
+       if (!ieee->ops->hard_start_xmit) {
                printk(KERN_WARNING "%s: No xmit handler.\n",
                       ieee->dev->name);
                goto success;
        }
 
-       if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
-               printk(KERN_WARNING "%s: skb too small (%d).\n",
-                      ieee->dev->name, skb->len);
-               goto success;
-       }
-
-       ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
+       memcpy(&header, skb->data, IEEE80211_HEADER_LEN);
+       skb_pull(skb, IEEE80211_HEADER_LEN);
+       ether_type = ntohs(header.snap.ethertype);
 
        crypt = ieee->crypt[ieee->tx_keyidx];
 
        encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
-               ieee->host_encrypt && crypt && crypt->ops;
+                       ieee->host_encrypt && crypt && crypt->ops;
 
        if (!encrypt && ieee->ieee802_1x &&
            ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
@@ -295,45 +287,22 @@
 
 #ifdef CONFIG_IEEE80211_DEBUG
        if (crypt && !encrypt && ether_type == ETH_P_PAE) {
+               /* FIXME: eap is wrong */
                struct eapol *eap = (struct eapol *)(skb->data +
-                       sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16));
+                       sizeof(struct ethhdr) - SNAP_SIZE);
                IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n",
                        eap_get_type(eap->type));
        }
 #endif
 
-       /* Save source and destination addresses */
-       memcpy(&dest, skb->data, ETH_ALEN);
-       memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN);
-
-       /* Advance the SKB to the start of the payload */
-       skb_pull(skb, sizeof(struct ethhdr));
-
-       /* Determine total amount of storage required for TXB packets */
-       bytes = skb->len + SNAP_SIZE + sizeof(u16);
-
-       if (encrypt)
-               fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
-                       IEEE80211_FCTL_WEP;
-       else
-               fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
-
-       if (ieee->iw_mode == IW_MODE_INFRA) {
-               fc |= IEEE80211_FCTL_TODS;
-               /* To DS: Addr1 = BSSID, Addr2 = SA,
-                  Addr3 = DA */
-               memcpy(&header.addr1, ieee->bssid, ETH_ALEN);
-               memcpy(&header.addr2, &src, ETH_ALEN);
-               memcpy(&header.addr3, &dest, ETH_ALEN);
-       } else if (ieee->iw_mode == IW_MODE_ADHOC) {
-               /* not From/To DS: Addr1 = DA, Addr2 = SA,
-                  Addr3 = BSSID */
-               memcpy(&header.addr1, dest, ETH_ALEN);
-               memcpy(&header.addr2, src, ETH_ALEN);
-               memcpy(&header.addr3, ieee->bssid, ETH_ALEN);
+       fc = le16_to_cpu(header.hdr.frame_ctl);
+       if (encrypt) {
+               fc |= IEEE80211_FCTL_WEP;
+               header.hdr.frame_ctl = cpu_to_le16(fc);
        }
-       header.frame_ctl = cpu_to_le16(fc);
-       hdr_len = IEEE80211_3ADDR_LEN;
+
+       /* TODO: handle IBSS (and WDS?) here */
+       memcpy(&dest, &header.hdr.addr3, ETH_ALEN);
 
        /* Determine fragmentation size based on destination (multicast
         * and broadcast are not fragmented) */
@@ -357,6 +326,9 @@
                bytes_per_frag -= crypt->ops->extra_prefix_len +
                        crypt->ops->extra_postfix_len;
 
+       /* Determine total amount of storage required for TXB packets */
+       bytes = skb->len + SNAP_SIZE;
+
        /* Number of fragments is the total bytes_per_frag /
         * payload_per_fragment */
        nr_frags = bytes / bytes_per_frag;
@@ -376,7 +348,7 @@
                goto failed;
        }
        txb->encrypted = encrypt;
-       txb->payload_size = bytes;
+       txb->payload_size = skb->len;
 
        for (i = 0; i < nr_frags; i++) {
                skb_frag = txb->fragments[i];
@@ -384,26 +356,27 @@
                if (encrypt)
                        skb_reserve(skb_frag, crypt->ops->extra_prefix_len);
 
-               frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
-               memcpy(frag_hdr, &header, hdr_len);
+               frag_hdr = (struct ieee80211_data_header *)
+                               skb_put(skb_frag, IEEE80211_3ADDR_LEN);
+               memcpy(frag_hdr, &header.hdr, IEEE80211_3ADDR_LEN);
+
+               bytes = 0;
+               /* Only put a SNAP header on the first fragment */
+               if (i == 0) {
+                       skb_put(skb_frag, SNAP_SIZE);
+                       memcpy(&frag_hdr->snap, &header.snap, SNAP_SIZE);
+                       bytes = -SNAP_SIZE;
+               }
 
                /* If this is not the last fragment, then add the MOREFRAGS
                 * bit to the frame control */
                if (i != nr_frags - 1) {
-                       frag_hdr->frame_ctl = cpu_to_le16(
-                               fc | IEEE80211_FCTL_MOREFRAGS);
-                       bytes = bytes_per_frag;
+                       fc |= IEEE80211_FCTL_MOREFRAGS;
+                       frag_hdr->hdr.frame_ctl = cpu_to_le16(fc);
+                       bytes += bytes_per_frag;
                } else {
                        /* The last fragment takes the remaining length */
-                       bytes = bytes_last_frag;
-               }
-
-               /* Put a SNAP header on the first fragment */
-               if (i == 0) {
-                       ieee80211_put_snap(
-                               skb_put(skb_frag, SNAP_SIZE + sizeof(u16)),
-                               ether_type);
-                       bytes -= SNAP_SIZE + sizeof(u16);
+                       bytes += bytes_last_frag;
                }
 
                memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
@@ -414,20 +387,20 @@
                /* Encryption routine will move the header forward in order
                 * to insert the IV between the header and the payload */
                if (encrypt)
-                       ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+                       ieee80211_encrypt_fragment(ieee, skb_frag,
+                                                  IEEE80211_3ADDR_LEN);
                if (ieee->config &
                    (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
-                       skb_put(skb_frag, 4);
+                       skb_put(skb_frag, IEEE80211_FCS_LEN);
        }
 
 
  success:
-       spin_unlock_irqrestore(&ieee->lock, flags);
-
        dev_kfree_skb_any(skb);
+       wireless_put(ieee);
 
        if (txb) {
-               if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
+               if (ieee->ops->hard_start_xmit(txb, dev) == 0) {
                        stats->tx_packets++;
                        stats->tx_bytes += txb->payload_size;
                        return 0;
@@ -438,11 +411,10 @@
        return 0;
 
  failed:
-       spin_unlock_irqrestore(&ieee->lock, flags);
        netif_stop_queue(dev);
        stats->tx_errors++;
+       wireless_put(ieee);
        return 1;
-
 }
 
 EXPORT_SYMBOL(ieee80211_txb_free);
diff -Nru a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
--- a/net/ieee80211/ieee80211_wx.c      2005-03-02 15:00:13 +08:00
+++ b/net/ieee80211/ieee80211_wx.c      2005-03-02 15:00:13 +08:00
@@ -220,8 +220,7 @@
 
        IEEE80211_DEBUG_WX("Getting scan\n");
 
-       spin_lock_irqsave(&ieee->lock, flags);
-
+       spin_lock_irqsave(&ieee->network_lock, flags);
        list_for_each_entry(network, &ieee->network_list, list) {
                i++;
                if (ieee->scan_age == 0 ||
@@ -236,8 +235,7 @@
                                MAC_ARG(network->bssid),
                                (jiffies - network->last_scanned) / (HZ / 100));
        }
-
-       spin_unlock_irqrestore(&ieee->lock, flags);
+       spin_unlock_irqrestore(&ieee->network_lock, flags);
 
        wrqu->data.length = ev -  extra;
        wrqu->data.flags = 0;
@@ -401,8 +399,8 @@
        sec.flags |= SEC_LEVEL;
        sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
 
-       if (ieee->set_security)
-               ieee->set_security(dev, &sec);
+       if (ieee->ops->set_security)
+               ieee->ops->set_security(dev, &sec);
 
        /* Do not reset port if card is in Managed mode since resetting will
         * generate new IEEE 802.11 authentication which may end up in looping
@@ -411,7 +409,7 @@
         * the callbacks structures used to initialize the 802.11 stack. */
        if (ieee->reset_on_keychange &&
            ieee->iw_mode != IW_MODE_INFRA &&
-           ieee->reset_port && ieee->reset_port(dev)) {
+           ieee->ops->reset_port && ieee->ops->reset_port(dev)) {
                printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
                return -EINVAL;
        }



<Prev in Thread] Current Thread [Next in Thread>