From: Zhu Yi <yi.zhu@intel.com>
To: netdev@oss.sgi.com
Cc: Jeff Garzik <jgarzik@pobox.com>, "David S.Miller" <davem@davemloft.net>
Subject: [PATCH] Merge p80211 to ieee80211 subsystem
Date: Fri, 25 Mar 2005 16:55:52 +0800 [thread overview]
Message-ID: <1111740953.17276.84.camel@debian.sh.intel.com> (raw)
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@intel.com>
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@redhat.com>
+ * Copyright (C) 2003 Arlando Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *
+ * 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@linux.intel.com>
+ * 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@redhat.com>
+ * Copyright (C) 2003 Arlando Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *
+ * 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@linux.intel.com>
+ * 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@redhat.com>
+ *
+ *
+ * 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@linux.intel.com>
+ * 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@cc.hut.fi>
+ *
+ * p80211:
+ * Copyright (C) 2003 David S. Miller <davem@redhat.com>
+ *
+ *
+ * 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@linux.intel.com>
+ * 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@linux.intel.com>");
@@ -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@redhat.com>
+ *
+ *
+ * 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@linux.intel.com>
+ * 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;
}
next reply other threads:[~2005-03-25 8:55 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-03-25 8:55 Zhu Yi [this message]
2005-03-25 9:10 ` [PATCH] Merge p80211 to ieee80211 subsystem Jeff Garzik
2005-03-27 2:37 ` Jouni Malinen
2005-03-28 7:19 ` Zhu Yi
2005-03-28 14:53 ` Jouni Malinen
2005-03-28 19:47 ` jamal
-- strict thread matches above, loose matches on Subject: below --
2005-03-25 9:41 Zhu, Yi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1111740953.17276.84.camel@debian.sh.intel.com \
--to=yi.zhu@intel.com \
--cc=davem@davemloft.net \
--cc=jgarzik@pobox.com \
--cc=netdev@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).