From mboxrd@z Thu Jan 1 00:00:00 1970 From: Zhu Yi Subject: [PATCH] Merge p80211 to ieee80211 subsystem Date: Fri, 25 Mar 2005 16:55:52 +0800 Message-ID: <1111740953.17276.84.camel@debian.sh.intel.com> Mime-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: 7bit Cc: Jeff Garzik , "David S.Miller" To: netdev@oss.sgi.com Sender: netdev-bounce@oss.sgi.com Errors-to: netdev-bounce@oss.sgi.com List-Id: netdev.vger.kernel.org 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 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 + * Copyright (C) 2003 Arlando Carvalho de Melo + * + * + * 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 + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 + * Copyright (C) 2003 Arlando Carvalho de Melo + * + * + * 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 + * 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 + * + * + * 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 + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 + * + * p80211: + * Copyright (C) 2003 David S. Miller + * + * + * 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 + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 #include +#include "ieee80211_impl.h" MODULE_DESCRIPTION("802.11 data/management/control stack"); MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation "); @@ -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 + * + * + * 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 + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 #include +#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; }