📄 orinoco.c
字号:
/* orinoco.c 0.06 - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). * It should also be usable on various Prism II based cards such as the * Linksys, D-Link and Farallon Skyline. It should also work on Symbol * cards such as the 3Com AirConnect and Ericsson WLAN. * * Copyright (C) 2000 David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au> * With some help from : * Copyright (C) 2001 Jean Tourrilhes, HP Labs <jt@hpl.hp.com> * Copyright (C) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org> * * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 * * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy@fasta.fh-dortmund.de> * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License * at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and * limitations under the License. * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights * Reserved. * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License version 2 (the "GPL"), in which * case the provisions of the GPL are applicable instead of the above. * If you wish to allow the use of your version of this file only * under the terms of the GPL and not to allow others to use your * version of this file under the MPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the MPL or the GPL. *//* Notes on locking: * * The basic principle of operation is that everything except the * interrupt handler is serialized through a single spinlock in the * dldwd_priv_t structure, using dldwd_lock() and * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). * * The kernel's IRQ handling stuff ensures that the interrupt handler * does not re-enter itself. The interrupt handler is written such * that everything it does is safe without a lock: chiefly this means * that the Rx path uses one of the Hermes chipset's BAPs while * everything else uses the other. * * For the moment access to the device statistics from the interrupt * handler is unsafe - we just put up with any resulting errors in the * statisics. FIXME: This should probably be changed to store the * stats in atomic types. * * EXCEPT that we don't want the irq handler running when we actually * reset or shut down the card, because strange things might happen * (probably the worst would be one packet of garbage, but you can't * be too careful). For this we use __dldwd_stop_irqs() which will set * a flag to disable the interrupt handler, and wait for any * outstanding instances of the handler to complete. THIS WILL LOSE * INTERRUPTS! so it shouldn't be used except for resets, when we * don't care about that.*//* * Tentative changelog... * * v0.01 -> v0.02 - 21/3/2001 - Jean II * o Allow to use regular ethX device name instead of dldwdX * o Warning on IBSS with ESSID=any for firmware 6.06 * o Put proper range.throughput values (optimistic) * o IWSPY support (IOCTL and stat gather in Rx path) * o Allow setting frequency in Ad-Hoc mode * o Disable WEP setting if !has_wep to work on old firmware * o Fix txpower range * o Start adding support for Samsung/Compaq firmware * * v0.02 -> v0.03 - 23/3/2001 - Jean II * o Start adding Symbol support - need to check all that * o Fix Prism2/Symbol WEP to accept 128 bits keys * o Add Symbol WEP (add authentication type) * o Add Prism2/Symbol rate * o Add PM timeout (holdover duration) * o Enable "iwconfig eth0 key off" and friends (toggle flags) * o Enable "iwconfig eth0 power unicast/all" (toggle flags) * o Try with an intel card. It report firmware 1.01, behave like * an antiquated firmware, however on windows it says 2.00. Yuck ! * o Workaround firmware bug in allocate buffer (Intel 1.01) * o Finish external renaming to orinoco... * o Testing with various Wavelan firmwares * * v0.03 -> v0.04 - 30/3/2001 - Jean II * o Update to Wireless 11 -> add retry limit/lifetime support * o Tested with a D-Link DWL 650 card, fill in firmware support * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot) * o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-( * It work on D-Link *only* after a tcpdump. Weird... * And still doesn't work on Intel card. Grrrr... * o Update the mode after a setport3 * o Add preamble setting for Symbol cards (not yet enabled) * o Don't complain as much about Symbol cards... * * v0.04 -> v0.04b - 22/4/2001 - David Gibson * o Removed the 'eth' parameter - always use ethXX as the * interface name instead of dldwdXX. The other was racy * anyway. * o Clean up RID definitions in hermes.h, other cleanups * * v0.04b -> v0.04c - 24/4/2001 - Jean II * o Tim Hurley <timster@seiki.bliztech.com> reported a D-Link card * with vendor 02 and firmware 0.08. Added in the capabilities... * o Tested Lucent firmware 7.28, everything works... * * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt * o Spin-off Pcmcia code. This file is renamed orinoco.c, * and orinoco_cs.c now contains only the Pcmcia specific stuff * o Add Airport driver support on top of orinoco.c (see airport.c) * * v0.05 -> v0.05a - 4/5/2001 - Jean II * o Revert to old Pcmcia code to fix breakage of Ben's changes... * * v0.05a -> v0.05b - 4/5/2001 - Jean II * o add module parameter 'ignore_cis_vcc' for D-Link @ 5V * o D-Link firmware doesn't support multicast. We just print a few * error messages, but otherwise everything works... * o For David : set/getport3 works fine, just upgrade iwpriv... * * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt * o Adapt airport.c to latest changes in orinoco.c * o Remove deferred power enabling code * * v0.05c -> v0.05d - 5/5/2001 - Jean II * o Workaround to SNAP decapsulate frame from LinkSys AP * original patch from : Dong Liu <dliu@research.bell-labs.com> * (note : the memcmp bug was mine - fixed) * o Remove set_retry stuff, no firmware support it (bloat--). * * v0.05d -> v0.06 - 25/5/2001 - Jean II * Original patch from "Hong Lin" <alin@redhat.com>, * "Ian Kinner" <ikinner@redhat.com> * and "David Smith" <dsmith@redhat.com> * o Init of priv->tx_rate_ctrl in firmware specific section. * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh ! * o Spectrum card always need cor_reset (for every reset) * o Fix cor_reset to not loose bit 7 in the register * o flush_stale_links to remove zombie Pcmcia instances * o Ack previous hermes event before reset * Me (with my little hands) * o Allow orinoco.c to call cor_reset via priv->card_reset_handler * o Add priv->need_card_reset to toggle this feature * o Fix various buglets when setting WEP in Symbol firmware * Now, encryption is fully functional on Symbol cards. Youpi ! * * v0.06 -> v0.06b - 25/5/2001 - Jean II * o IBSS on Symbol use port_mode = 4. Please don't ask... * * v0.06b -> v0.06c - 29/5/2001 - Jean II * o Show first spy address in /proc/net/wireless for IBSS mode as well * * v0.06c -> v0.06d - 6/7/2001 - David Gibson * o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus' * wishes to reduce the number of unecessary messages. * o Removed bogus message on CRC error. * o Merged fixeds for v0.08 Prism 2 firmware from William Waghorn * <willwaghorn@yahoo.co.uk> * o Slight cleanup/re-arrangement of firmware detection code. * * TODO - Jean II * o inline functions (lot's of candidate, need to reorder code) * o Test PrismII/Symbol cards & firmware versions * o Mini-PCI support (some people have reported success - JII) */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ioport.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/system.h>#include <linux/proc_fs.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/etherdevice.h>#include <linux/wireless.h>#include <linux/list.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/ds.h>#include <pcmcia/bus_ops.h>#include "hermes.h"#include "orinoco.h"static char *version = "orinoco.c 0.07 (David Gibson <hermes@gibson.dropbear.id.au> and others)";/* Level of debugging. Used in the macros in orinoco.h */#ifdef ORINOCO_DEBUGint dldwd_debug = ORINOCO_DEBUG;MODULE_PARM(dldwd_debug, "i");#endifconst long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484};#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. It gives the rate in halfMb/s, negative indicates auto mode */const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0};#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0]))struct p80211_hdr { uint16_t frame_ctl; uint16_t duration_id; uint8_t addr1[ETH_ALEN]; uint8_t addr2[ETH_ALEN]; uint8_t addr3[ETH_ALEN]; uint16_t seq_ctl; uint8_t addr4[ETH_ALEN]; uint16_t data_len;} __attribute__ ((packed));/* Frame control field constants */#define DLDWD_FCTL_VERS 0x0002#define DLDWD_FCTL_FTYPE 0x000c#define DLDWD_FCTL_STYPE 0x00f0#define DLDWD_FCTL_TODS 0x0100#define DLDWD_FCTL_FROMDS 0x0200#define DLDWD_FCTL_MOREFRAGS 0x0400#define DLDWD_FCTL_RETRY 0x0800#define DLDWD_FCTL_PM 0x1000#define DLDWD_FCTL_MOREDATA 0x2000#define DLDWD_FCTL_WEP 0x4000#define DLDWD_FCTL_ORDER 0x8000#define DLDWD_FTYPE_MGMT 0x0000#define DLDWD_FTYPE_CTL 0x0004#define DLDWD_FTYPE_DATA 0x0008struct p8022_hdr { uint8_t dsap; uint8_t ssap; uint8_t ctrl; uint8_t oui[3];} __attribute__ ((packed));struct dldwd_frame_hdr { hermes_frame_desc_t desc; struct p80211_hdr p80211; struct ethhdr p8023; struct p8022_hdr p8022; uint16_t ethertype;} __attribute__ ((packed));#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ sizeof(struct p80211_hdr))#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2)/* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */struct p8022_hdr encaps_hdr = { 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8}};/* * Function prototypes */static void dldwd_stat_gather(struct net_device *dev, struct sk_buff *skb, struct dldwd_frame_hdr *hdr);static struct net_device_stats *dldwd_get_stats(struct net_device *dev);static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev);/* Hardware control routines */static int __dldwd_hw_reset(dldwd_priv_t *priv);static int __dldwd_hw_setup_wep(dldwd_priv_t *priv);static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]);static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]);static long dldwd_hw_get_freq(dldwd_priv_t *priv);static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, int32_t *rates, int max);/* Interrupt handling routines */static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw);static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw);static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw);static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw);static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw);static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw);static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw);static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw);static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq);static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq);static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq);static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq);static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq);static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq);static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq);static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq);static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);static void __dldwd_set_multicast_list(struct net_device *dev);/* /proc debugging stuff */static int dldwd_proc_init(void);static void dldwd_proc_cleanup(void);/* * Inline functions */static inline voiddldwd_lock(dldwd_priv_t *priv){ spin_lock_bh(&priv->lock);}static inline voiddldwd_unlock(dldwd_priv_t *priv){ spin_unlock_bh(&priv->lock);}static inline intdldwd_irqs_allowed(dldwd_priv_t *priv){ return test_bit(DLDWD_STATE_DOIRQ, &priv->state);}static inline void__dldwd_stop_irqs(dldwd_priv_t *priv){ hermes_t *hw = &priv->hw; hermes_set_irqmask(hw, 0); clear_bit(DLDWD_STATE_DOIRQ, &priv->state); while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) ;}static inline void__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask){ hermes_t *hw = &priv->hw; TRACE_ENTER(priv->ndev.name); __cli(); set_bit(DLDWD_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, irqmask); __sti(); TRACE_EXIT(priv->ndev.name);}static inline voidset_port_type(dldwd_priv_t *priv){ switch (priv->iw_mode) { case IW_MODE_INFRA: priv->port_type = 1; priv->allow_ibss = 0; break; case IW_MODE_ADHOC: if (priv->prefer_port3) { priv->port_type = 3; priv->allow_ibss = 0; } else { /* Symbol is different here */ if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) priv->port_type = 4; else priv->port_type = 1; priv->port_type = priv->ibss_port; priv->allow_ibss = 1; } break; default: printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", priv->ndev.name); }}extern voiddldwd_set_multicast_list(struct net_device *dev){ dldwd_priv_t *priv = dev->priv; dldwd_lock(priv); __dldwd_set_multicast_list(dev); dldwd_unlock(priv);}/* * Hardware control routines */static int__dldwd_hw_reset(dldwd_priv_t *priv){ hermes_t *hw = &priv->hw; int err; if (! priv->broken_reset) return hermes_reset(hw); else { hw->inten = 0; hermes_write_regn(hw, INTEN, 0); err = hermes_disable_port(hw, 0); hermes_write_regn(hw, EVACK, 0xffff); return err; }}voiddldwd_shutdown(dldwd_priv_t *priv){/* hermes_t *hw = &priv->hw; */ int err = 0; TRACE_ENTER(priv->ndev.name); dldwd_lock(priv); __dldwd_stop_irqs(priv); err = __dldwd_hw_reset(priv); if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); dldwd_unlock(priv); TRACE_EXIT(priv->ndev.name);}intdldwd_reset(dldwd_priv_t *priv){ struct net_device *dev = &priv->ndev; hermes_t *hw = &priv->hw; int err = 0; hermes_id_t idbuf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -