diff -uNr linux-2.4.3-ac13.orig/Documentation/Configure.help linux-2.4.3-ac13/Documentation/Configure.help --- linux-2.4.3-ac13.orig/Documentation/Configure.help Thu Apr 26 15:43:32 2001 +++ linux-2.4.3-ac13/Documentation/Configure.help Thu Apr 26 17:18:37 2001 @@ -7683,6 +7683,17 @@ a module, say M here and read Documentation/modules.txt. If unsure, say N. +No Wires Need 11Mbps Wireless LAN PC Card support +CONFIG_PCMCIA_POLDHU + Say Y here if you intend to attach a No Wires Needed 11Mbps Wireless + LAN PC Card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called poldhu_cs.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. If unsure, + say N. + PLIP (parallel port) support CONFIG_PLIP PLIP (Parallel Line Internet Protocol) is used to create a diff -uNr linux-2.4.3-ac13.orig/drivers/net/pcmcia/Config.in linux-2.4.3-ac13/drivers/net/pcmcia/Config.in --- linux-2.4.3-ac13.orig/drivers/net/pcmcia/Config.in Thu Apr 26 15:44:26 2001 +++ linux-2.4.3-ac13/drivers/net/pcmcia/Config.in Thu Apr 26 15:37:20 2001 @@ -31,6 +31,7 @@ dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA + dep_tristate ' No Wires Needed 11Mbps Wireless LAN PC Card support' CONFIG_PCMCIA_POLDHU $CONFIG_PCMCIA fi fi @@ -39,7 +40,7 @@ "$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \ "$CONFIG_PCMCIA_XIRC2PS" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o \ "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" -o \ - "$CONFIG_PCMCIA_XIRTULIP" = "y" ]; then + "$CONFIG_PCMCIA_XIRTULIP" = "y" -o "$CONFIG_PCMCIA_POLDHU" = "y" ]; then define_bool CONFIG_PCMCIA_NETCARD y fi diff -uNr linux-2.4.3-ac13.orig/drivers/net/pcmcia/Makefile linux-2.4.3-ac13/drivers/net/pcmcia/Makefile --- linux-2.4.3-ac13.orig/drivers/net/pcmcia/Makefile Thu Apr 26 15:44:26 2001 +++ linux-2.4.3-ac13/drivers/net/pcmcia/Makefile Thu Apr 26 16:45:33 2001 @@ -30,7 +30,7 @@ obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o - +obj-$(CONFIG_PCMCIA_POLDHU) += poldhu_cs.o # Cardbus client drivers obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o obj-$(CONFIG_PCMCIA_XIRCOM) += xircom_cb.o @@ -45,3 +45,7 @@ ibmtr_cs.o: tmp-ibmtr.o ibmtr_cs.c $(CC) $(CFLAGS) -DPCMCIA -c -o tmp-$@ ibmtr_cs.c $(LD) -r -o $@ tmp-$@ tmp-ibmtr.o + +poldhu_cs.o: snwnmp.o poldhu.o + $(LD) -r -o $@ poldhu.o snwnmp.o + diff -uNr linux-2.4.3-ac13.orig/drivers/net/pcmcia/poldhu.c linux-2.4.3-ac13/drivers/net/pcmcia/poldhu.c --- linux-2.4.3-ac13.orig/drivers/net/pcmcia/poldhu.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.3-ac13/drivers/net/pcmcia/poldhu.c Fri Apr 6 15:02:38 2001 @@ -0,0 +1,1485 @@ +/*========================================================================= + + A PCMCIA ethernet driver for the NWN Poldhu cards. + + Copyright (C) 2000 Bas Vermeulen -- bvermeul@xxxxxxxxxxxx + + poldhu_cs.c 0.1.2 2001/03/07 + + Version 0.1.2 is designed to work with kernel version 2.4.0+, + where the PCMCIA code has been integrated into the kernel. + + This software may be used and distributed according to the + terms of the GNU Public License, incorporated herein by + reference. + +========================================================================= + + No Wires Needed provides NO SUPPORT for these drivers. + + If you have any questions, bug-reports, suggestions, feature-requests, + contact me at swallow@xxxxxxxxxxxx + +=========================================================================*/ +#include +#ifdef __IN_PCMCIA_PACKAGE__ +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "poldhu.h" +#include "snwnmp.h" + +#define TX_TIMEOUT ((500*HZ)/1000) +#define TX_CTS_TIMEOUT ((100*HZ)/1000) + +#define MAX_ROAMTABLE_SIZE 256 + +struct poldhu_roam_entry_t { + unsigned char bssid[MAX_ADDR_LEN]; + char essid[IW_ESSID_MAX_SIZE + 1]; + int bsstype; + int channel; + int roamage; + int quality; + int load; + int beaconperiod; + int dtimperiod; + u16 capinfo; + unsigned char rates[MAX_ADDR_LEN]; +}; + +struct poldhu_roam_table_t { + struct poldhu_roam_entry_t entry[MAX_ROAMTABLE_SIZE]; + int size; +}; + +struct poldhu_encryption { + int airlock; + int enable; + int restricted; + int index; + unsigned char keys[SNWNMP_MAX_KEY_SIZE]; +}; + +struct poldhu_private { + dev_node_t node; + struct net_device_stats stats; + struct poldhu_roam_table_t roam_table; + struct poldhu_encryption enc; + char ssid[IW_ESSID_MAX_SIZE + 1]; + char wanted_essid[IW_ESSID_MAX_SIZE + 1]; + unsigned char bssid[MAX_ADDR_LEN]; + unsigned long capinfo; + struct timer_list bssid_timer; + struct timer_list roam_timer; + spinlock_t lock; + int is_550; + unsigned sequence; + unsigned reset; +}; + +static char *version = "No Wires Needed Poldhu driver v0.1.2"; + +#ifdef CONFIG_PCMCIA_POLDHU_DEBUG +static int poldhu_debug = CONFIG_PCMCIA_POLDHU_DEBUG; +MODULE_PARM(poldhu_debug, "i"); +#define DEBUG(n, args...) if (poldhu_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) +#endif + +#define PRINT(n, args...) printk(KERN_INFO args) +#define kfree_s(o,s) kfree(o) + +/*======================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bitmap of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; +/* Network parameters */ +static char *ssid = "default"; + +/* Encryption parameters */ +static unsigned char keys[SNWNMP_MAX_KEY_SIZE] = + { 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, }; +static int keyid = 0; +static int encrypt = 0; +static int restricted = 0; +/* Airlock default disabled */ +static int airlock = 0; +MODULE_AUTHOR("Bas Vermeulen "); +MODULE_DESCRIPTION("No Wires Needed 11Mbps Wireless LAN PC Card ethernet driver"); +MODULE_PARM(ssid, "s"); +MODULE_PARM_DESC(ssid, "Default session to join"); +MODULE_PARM(encrypt, "i"); +MODULE_PARM_DESC(encrypt, "Enables Encryption"); +MODULE_PARM(keys, "5-20b"); +MODULE_PARM_DESC(keys, "Wired Equivalent Privacy keys"); +MODULE_PARM(keyid, "i"); +MODULE_PARM_DESC(keyid, "Index of the default WEP key"); +MODULE_PARM(restricted, "i"); +MODULE_PARM_DESC(restricted, "Exclude unencrypted traffic"); +MODULE_PARM(airlock, "i"); +MODULE_PARM_DESC(airlock, "Enables Airlock (tm) Security"); + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*======================================================================*/ +/* PCMCIA related definitions */ + +static void poldhu_pcmcia_config(dev_link_t *link); +static void poldhu_pcmcia_release(u_long arg); +static int poldhu_pcmcia_event(event_t event, int priority, + event_callback_args_t *args); +static dev_link_t *poldhu_pcmcia_attach(void); +static void poldhu_pcmcia_detach(dev_link_t *); + +static dev_info_t dev_info = "poldhu_cs"; +static dev_link_t *dev_list = NULL; + +static void flush_stale_links(void); +static void cs_error(client_handle_t handle, int func, int ret); + +/*======================================================================*/ +/* Ethernet device related functions */ + +static int poldhu_open(struct net_device *dev); +static int poldhu_close(struct net_device *dev); +static int poldhu_config(struct net_device *dev, struct ifmap *map); +static int poldhu_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void poldhu_timeout(struct net_device *dev); +static void poldhu_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats *poldhu_get_stats(struct net_device *dev); +static int poldhu_rx(struct net_device *dev); +static void poldhu_set_multicast_list(struct net_device *dev) { return; }; +static int poldhu_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static void poldhu_hw_reset(struct net_device *dev); +static int poldhu_encrypt(struct net_device *dev); + +/*======================================================================*/ +/* Stuff needed to initially configure the session/encryption/etc */ + +static int poldhu_device_event(struct notifier_block *unused, unsigned long +event, void *ptr); + +static struct notifier_block poldhu_dev_notifier = { + poldhu_device_event, + NULL, + 0 +}; + +static struct net_device* poldhus[MAX_POLDHUS] = + { NULL, NULL, NULL, NULL }; + +/*======================================================================*/ +/* Timers functions */ + +static void poldhu_bssid_timer(unsigned long data); +static void poldhu_roaming_timer(unsigned long data); + +/*======================================================================*/ +/* Proc filesystem functions */ +static int poldhu_proc_read(char *buf, char **start, off_t off, + int count, int *eof, void *data); + +static struct proc_dir_entry* poldhu_proc_dir = NULL; + +/*======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + poldhu_pcmcia_detach(link); + } +} + +/*======================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*======================================================================= + + We never need to do anything when a Poldhu device is + "initialized" by the net software, because we only register already- + found cards. + +=======================================================================*/ + +static int poldhu_init(struct net_device *dev) +{ + return 0; +} + +/*===================================================================== + + poldhu_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +=====================================================================*/ + +static dev_link_t *poldhu_pcmcia_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + struct net_device *dev; + struct poldhu_private* lp; + int i, ret; + + DEBUG(7, "poldhu_cs: poldhu_pcmcia_attach()\n"); + flush_stale_links(); + + /* Create new ethernet device */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &poldhu_pcmcia_release; + link->release.data = (u_long)link; + link->io.NumPorts1 = 0x3f; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + link->io.IOAddrLines = 6; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = &poldhu_interrupt; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + + /* Make up a Poldhu specific data structure. */ + dev->priv = kmalloc(sizeof(struct poldhu_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct poldhu_private)); + + lp = (struct poldhu_private*)dev->priv; + + /* Initialize the spinlock */ + spin_lock_init(&lp->lock); + + /* Initialize the timers */ + init_timer(&lp->bssid_timer); + lp->bssid_timer.data = (long)dev; + lp->bssid_timer.function = &poldhu_bssid_timer; + + init_timer(&lp->roam_timer); + lp->roam_timer.data = (long)dev; + lp->roam_timer.function = &poldhu_roaming_timer; + + /* Initialize the roaming table size */ + lp->roam_table.size = 8; + + /* The Poldhu specific entries in the device structure. */ + dev->hard_start_xmit = &poldhu_start_xmit; + dev->set_config = &poldhu_config; + dev->get_stats = &poldhu_get_stats; + dev->set_multicast_list = &poldhu_set_multicast_list; + dev->do_ioctl = &poldhu_do_ioctl; + dev->tx_timeout = &poldhu_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + ether_setup(dev); + + dev->init = &poldhu_init; + dev->open = &poldhu_open; + dev->stop = &poldhu_close; + link->priv = link->irq.Instance = dev; + netif_stop_queue(dev); + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &poldhu_pcmcia_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + poldhu_pcmcia_detach(link); + return NULL; + } + + return link; +} + +/*======================================================================= + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structure will be freed + when the device is released. + +=======================================================================*/ + +static void poldhu_pcmcia_detach(dev_link_t *link) +{ + dev_link_t **linkp; + long flags; + + DEBUG(7, "poldhu_cs: poldhu_pcmcia_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + if (link->state & DEV_CONFIG) { + poldhu_pcmcia_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + if (link->priv) { + struct net_device *dev = link->priv; + int i; + + for (i = 0; i < MAX_POLDHUS; i++) + if (poldhus[i] == dev) poldhus[i] = NULL; + + if (link->dev != NULL) + unregister_netdev(dev); + if (dev->priv) { + struct poldhu_private* lp = dev->priv; + del_timer(&lp->bssid_timer); + del_timer(&lp->roam_timer); + kfree_s(dev->priv, sizeof(struct poldhu_private)); + } + kfree_s(link->priv, sizeof(struct net_device)); + } + kfree_s(link, sizeof(struct dev_link_t)); +} + +/*======================================================================== + + poldhu_pcmcia_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +========================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret = CardServices(last_fn=(fn), args)) != 0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void poldhu_pcmcia_config(dev_link_t *link) +{ + client_handle_t handle; + struct net_device *dev; + struct poldhu_private *lp; + tuple_t tuple; + cisparse_t parse; + u_char buf[64]; + int last_fn, last_ret,i; + win_req_t req; + memreq_t map; + short ioaddr, *phys_addr; + + handle = link->handle; + dev = link->priv; + phys_addr = (short *)dev->dev_addr; + + DEBUG(7, "poldhu_pcmcia_config(0x%p)\n", link); + + /* This reads the card's CONFIG tuple to find it's configuration + * registers. + */ + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleData = (cisdata_t*)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Is this a Poldhu? */ + tuple.DesiredTuple = CISTPL_MANFID; + tuple.Attributes = TUPLE_RETURN_COMMON; + if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && + (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) { + if ((le16_to_cpu(buf[0]) != 0x0602) && (le16_to_cpu(buf[1]) == 0x0003)) + printk(KERN_INFO "poldhu_cs: hmmm, is this really a " + "Poldhu card??\n"); + } + /* Configure card */ + link->state |= DEV_CONFIG; + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. This should work for + any Poldhu card, since that has an accurate CIS. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; + if (cfg->index == 0) goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vcc.present & (1<conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; + + if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + + /* + Now set up a common memory window, if needed. There is room + in the dev_link_t structure for one memory window handle, + but if the base addresses need to be saved, or if multiple + windows are needed, the info should go in the private data + structure for this device. + + Note that the memory window base is a physical address, and + needs to be mapped to virtual space with ioremap() before it + is used. + */ + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req.Base = mem->win[0].host_addr; + req.Size = mem->win[0].len; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + CFG_CHECK(RequestWindow, &link->win, &req); + map.Page = 0; map.CardOffset = mem->win[0].card_addr; + CFG_CHECK(MapMemPage, link->win, &map); + } + /* If we got this far, we're cool! */ + break; + + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* Allocate an interrupt line. */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + /* Report what we've done so far */ + printk(KERN_INFO "poldhu_cs: index 0x%02x: Vcc %d.%d", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(" io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2 + link->io.NumPorts2 - 1); + if (link->win) + printk(", mem 0x%06lx-0x%06lx", req.Base, + req.Base + req.Size - 1); + printk("\n"); + + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "poldhu_cs: register_netdev() failed\n"); + goto failed; + } + + /* Create the device's /proc entry */ + create_proc_read_entry(dev->name, + S_IFREG | S_IRUGO | S_IWUSR, + poldhu_proc_dir, + poldhu_proc_read, + (void*)dev); + lp = dev->priv; + + strcpy(lp->node.dev_name, dev->name); + + ioaddr = dev->base_addr; + + /* Set the RST bit in Comms9 */ + outb(0x80, ioaddr + 0x09); + /* Wait for the RST_ACK bit in Comms7 */ + while((inb(ioaddr + 0x07) & 0x80) == 0x00) + udelay(10); + /* Reset the RST bit in Comms9 */ + outb(0x00, ioaddr + 0x09); + lp->sequence = 0; + /* Check for the right version */ + if (inb(ioaddr + 0x06) != 0xa0) + printk("poldhu_cs: Wrong version!\n"); + /* Read the MAC address */ + for (i = 0; i < ETH_ALEN; i++) + dev->dev_addr[i] = inb(ioaddr + i); + /* Enable interrupts */ + outb(0x80, ioaddr + 0x08); + + link->dev = &((struct poldhu_private *)dev->priv)->node; + + printk(KERN_INFO "%s: NWN Poldhu, port %03lX, irq %d, hw_addr ", dev->name, + dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + + for (i = 0; i < MAX_POLDHUS; i++) + if (poldhus[i] == NULL) + { + poldhus[i] = dev; + break; + } + + lp->enc.enable = encrypt; + memcpy(lp->enc.keys, keys, SNWNMP_MAX_KEY_SIZE); + lp->enc.index = keyid; + lp->enc.restricted = restricted; + lp->enc.airlock = airlock; + strcpy(lp->wanted_essid, ssid); + printk(KERN_INFO "%s: SSID(%s)\n", dev->name, lp->wanted_essid); + + netif_start_queue(dev); + + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + poldhu_pcmcia_release((u_long)link); + return; +} + +/*======================================================================== + + After a card is removed, poldhu_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +========================================================================*/ + +static void poldhu_pcmcia_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(7, "poldhu_pcmcia_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1, "poldhu_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Remove proc file */ + remove_proc_entry(link->dev->dev_name, poldhu_proc_dir); + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); +} + +/*======================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + +========================================================================*/ + +static int poldhu_pcmcia_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + + DEBUG(7, "poldhu_pcmcia_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_stop_queue(dev); + link->release.expires = jiffies + (HZ/20); + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + poldhu_pcmcia_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + netif_stop_queue(dev); + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) { + poldhu_hw_reset(dev); + netif_start_queue(dev); + } + } + break; + } + return 0; +} + +/*======================================================================== + + Set the Poldhu into a known state. + +========================================================================*/ + +static void poldhu_hw_reset(struct net_device *dev) +{ + ushort ioaddr = dev->base_addr; + struct poldhu_private *lp = (struct poldhu_private *)dev->priv; + + /* Set the RST bit in Comms9 */ + outb(0x80, ioaddr + 0x09); + /* Wait for the RST_ACK bit in Comms7 */ + while((inb(ioaddr + 0x07) & 0x80) == 0x00) + udelay(10); + /* Reset the RST bit in Comms9 */ + outb(inb(ioaddr + 0x09) & ~0x80, ioaddr + 0x09); + /* Read Comms6 */ + inb(ioaddr + 0x06); + lp->sequence = 0; +} + +static int poldhu_config(struct net_device *dev, struct ifmap *map) +{ + /* We really don't care */ + dev->if_port = map->port; + return 0; +} + +static int poldhu_open(struct net_device *dev) +{ + dev_link_t *link; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (!DEV_OK(link)) + return -ENODEV; + + link->open++; + MOD_INC_USE_COUNT; + + netif_start_queue(dev); + + poldhu_hw_reset(dev); + + DEBUG(2, "%s: opened.\n", dev->name); + + return 0; +} + +static void poldhu_timeout(struct net_device *dev) +{ + printk(KERN_INFO "%s: Transmit timeout\n", dev->name); + + poldhu_hw_reset(dev); +} + +static int poldhu_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct poldhu_private *lp = (struct poldhu_private *)dev->priv; + unsigned long timeout; + int retval = 0; + int ioaddr = dev->base_addr; + int bytes_written = 0; + int pkt_len = 0; + unsigned char *pkt_data; + int i; + + DEBUG(7, "poldhu_start_xmit(%p,%p)\n", skb, dev); + + netif_stop_queue(dev); + + if (skb == NULL) { + DEBUG(0, "poldhu_start_xmit: skb = NULL\n"); + return 0; + } else { + pkt_len = skb->len; + pkt_data = skb->data; + } + + /* Save the timestamp when we received the packet */ + dev->trans_start = jiffies; + + /* Set URG bit if sending SNWNMP packets */ + if (((struct ethhdr*)pkt_data)->h_proto == __constant_htons(ETH_P_SNWNMP)) { + outb(inb(ioaddr + 0x07) | 0x40, ioaddr + 0x07); + } + + /* Check for CTS */ + timeout = jiffies + TX_CTS_TIMEOUT; + while (time_before_eq(jiffies, timeout)) { + if ((inb(ioaddr + 0x07) & 0x10) == 0x10) break; + } + + if ((inb(ioaddr + 0x07) & 0x10) == 0x00) { + printk(KERN_INFO "%s: Failed to get CTS!", dev->name); + printk(" (0x%0X)\n", inb(ioaddr + 0x07)); + lp->stats.tx_errors++; + retval = 1; + goto poldhu_xmit_done; + } + + /* Initiate send sequence */ + outb((pkt_len >> 0) & 0xff, ioaddr + 0x0a); + outb((pkt_len >> 8) & 0xff, ioaddr + 0x0a); + outb(0xa5, ioaddr + 0x0a); + outb(0x03, ioaddr + 0x0a); + + /* Wait for CTS to clear */ + timeout = jiffies + TX_CTS_TIMEOUT; + while (time_before_eq(jiffies, timeout)) { + if ((inb(ioaddr + 0x07) & 0x10) == 0x00) break; + } + if ((inb(ioaddr + 0x07) & 0x10) == 0x10) { + printk(KERN_INFO "%s: Failed to reset CTS!", dev->name); + printk(" (0x%0X)\n", inb(ioaddr + 0x07)); + lp->stats.tx_errors++; + retval = 1; + goto poldhu_xmit_done; + } + + DEBUG(2, "poldhu_start_xmit: sending %d bytes\n", skb->len); + + for (i = 0; i < pkt_len; i++) + outb(pkt_data[i], ioaddr + 0x0a); + + /* Reset URG bit if sending SNWNMP packets */ + if (((struct ethhdr*)pkt_data)->h_proto == __constant_htons(ETH_P_SNWNMP)) { + outb(inb(ioaddr + 0x07) & ~0x40, ioaddr + 0x07); + } + + lp->stats.tx_packets++; + lp->stats.tx_bytes += bytes_written; + + DEBUG(6, "poldhu_start_xmit: Sent %d bytes\n", bytes_written); + + if (skb) dev_kfree_skb(skb); + +poldhu_xmit_done: + netif_start_queue(dev); + + return retval; +} + +static int poldhu_rx(struct net_device *dev) +{ + struct poldhu_private *lp = (struct poldhu_private *)dev->priv; + unsigned ioaddr = dev->base_addr; + struct sk_buff *skb; + unsigned char *frame; + unsigned long start_trans; + unsigned pkt_len, bytes_read; + unsigned version; + +#ifdef CONFIG_PCMCIA_POLDHU_DEBUG + unsigned i; +#endif + DEBUG(7, "poldhu_rx(%p)\n", dev); + /* Read the packet length */ + pkt_len = inb(ioaddr + 0x0a); + pkt_len |= (inb(ioaddr + 0x0a) << 8); + /* Check the magic number */ + version = inb(ioaddr + 0x0a); + version |= (inb(ioaddr + 0x0a) << 8); + if (version != 0xa503) + printk(KERN_INFO "poldhu_cs: Version mismatch (%0X)\n", version); + + frame = (unsigned char *)kmalloc(pkt_len, GFP_ATOMIC); + if (frame == NULL) { + printk(KERN_INFO "poldhu_rx: Low on memory.\n"); + return -ENOMEM; + } + + bytes_read = 0; + start_trans = jiffies; + while (bytes_read < pkt_len) { + frame[bytes_read++] = (unsigned char)inb(ioaddr + 0x0a); + } + + /* This is an SNWNMP packet. We process it ourselves, and + * then send it down to the network layer to be discarded. + */ + if (((struct ethhdr*)frame)->h_proto == __constant_htons(ETH_P_SNWNMP)) + { + snwnmp_process(dev, frame, pkt_len); + } + + /* Allocate the skb buffer */ + if ((skb = dev_alloc_skb(pkt_len + 5)) == NULL) { + kfree(frame); + printk(KERN_INFO "%s: couldn't allocate a sk_buff of" + " size %d.\n", dev->name, pkt_len); + return -ENOMEM; + } + else { + dev->last_rx = jiffies; + + skb->dev = dev; + skb->len = pkt_len; + + skb_reserve(skb, 2); /* IP headers on 16 byte boundaries */ + memcpy(skb_put(skb, pkt_len), frame, pkt_len); + skb->protocol = eth_type_trans(skb, dev); + + /* Free the frame buffer */ + kfree(frame); + } + + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + + netif_rx(skb); + netif_wake_queue(dev); + + DEBUG(7, "poldhu_rx: received %d out of %d bytes\n", bytes_read, pkt_len); + + return 0; +} + +static void poldhu_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct poldhu_private *lp; + int ioaddr; + unsigned char status = 0; + + if (dev == NULL) + return; + lp = (struct poldhu_private *)dev->priv; + ioaddr = dev->base_addr; + + /* Disable interrupts */ + outb(inb(ioaddr + 0x08) & ~0x80, ioaddr + 0x08); + + status = inb(ioaddr + 0x07); + if (status & 0x08) { + poldhu_hw_reset(dev); + } else { + if (status & 0x80) { + if (inb(ioaddr + 0x09) & 0x80) { + outb(inb(ioaddr + 0x09) & ~0x80, ioaddr + 0x09); + lp->sequence = 0; + } + } + if ((status & 0x20) != (lp->sequence & 0x20)) { + poldhu_rx(dev); + lp->sequence = status & 0x20; + } + } + + /* Enable interrupts again */ + outb(inb(ioaddr + 0x08) | 0x80, ioaddr + 0x08); + + return; +} + +static struct net_device_stats *poldhu_get_stats(struct net_device *dev) +{ + struct poldhu_private *lp = (struct poldhu_private *)dev->priv; + + return &lp->stats; +} + +static int poldhu_close(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + dev_link_t *link; + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + DEBUG(2, "%s: shutting down ethercard.\n", dev->name); + + if (DEV_OK(link)) { + outb(0x00, ioaddr + 0x08); + } + + link->open--; + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + (HZ/20); + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int poldhu_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct iwreq * wrq = (struct iwreq *) rq; + struct poldhu_private * lp = (struct poldhu_private *)dev->priv; + int ret = 0; + unsigned char keys[SNWNMP_MAX_KEY_SIZE]; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->poldhu_do_ioctl(cmd=0x%X)\n", dev->name, cmd); +#endif + + /* Check permissions for SET commands */ + if (IW_IS_SET(cmd) && !suser()) + return -EPERM; + + switch(cmd) + { + /* ----------------- WIRELESS EXTENSIONS ------------------- */ + case SIOCGIWNAME: + strcpy(wrq->u.name, "Poldhu"); + break; + case SIOCGIWAP: + memcpy(wrq->u.ap_addr.sa_data, lp->bssid, ETH_ALEN); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + break; + case SIOCGIWMODE: + wrq->u.mode = IW_MODE_INFRA; + break; + case SIOCGIWFREQ: + break; + case SIOCSIWENCODE: /* Set encryption key */ + if (wrq->u.encoding.pointer != (caddr_t) 0) { + /* Check the length of the key */ + if (wrq->u.encoding.length > SNWNMP_MAX_KEY_SIZE) { + ret = -EINVAL; + break; + } + + /* Copy the key from userspace */ + if (copy_from_user(keys, wrq->u.encoding.pointer, + wrq->u.encoding.length)) + { + ret = -EFAULT; + break; + } + memcpy(lp->enc.keys, keys, SNWNMP_MAX_KEY_SIZE); + } + + /* Decode the flags */ + lp->enc.enable = 1; + if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) + lp->enc.enable = 0; + if (wrq->u.encoding.flags & IW_ENCODE_RESTRICTED) + lp->enc.restricted = 1; + if (wrq->u.encoding.flags & IW_ENCODE_OPEN) + lp->enc.restricted = 0; + lp->enc.index = (long)(wrq->u.encoding.flags & IW_ENCODE_INDEX); + + poldhu_encrypt(dev); + + break; + case SIOCGIWENCODE: /* Get the encryption key */ + if (!suser()) + { + ret = -EPERM; + break; + } + + if (wrq->u.data.pointer != (caddr_t) 0) + { + copy_to_user(wrq->u.data.pointer, lp->enc.keys, SNWNMP_MAX_KEY_SIZE); + wrq->u.data.length = SNWNMP_MAX_KEY_SIZE; + } + wrq->u.data.flags = 0; + wrq->u.data.flags |= lp->enc.index & IW_ENCODE_INDEX; + if (!lp->enc.enable) wrq->u.data.flags |= IW_ENCODE_DISABLED; + if (lp->enc.restricted) wrq->u.data.flags |= IW_ENCODE_RESTRICTED; + if (!lp->enc.restricted) wrq->u.data.flags |= IW_ENCODE_OPEN; + break; + case SIOCGIWRANGE: /* ranges */ + if (wrq->u.data.pointer != (caddr_t) 0) + { + struct iw_range range; + + /* Verify the user buffer */ + ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, + sizeof(struct iw_range)); + if (ret) break; + + /* Set the length (it's constant). */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set information in the range struct. */ + range.throughput = 5.5 * 1024 * 1024; + range.min_nwid = 0x0000; + range.max_nwid = 0x0032; + range.num_channels = 13; + range.num_frequency = 0; + range.sensitivity = 0; + range.max_qual.qual = 0; + range.max_qual.level = 0; + range.max_qual.noise = 0; + + /* Copy structure to the user buffer. */ + copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range)); + } + break; +#if WIRELESS_EXT > 5 + case SIOCSIWESSID: + if (wrq->u.data.pointer != (caddr_t)0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + + /* Check the size of the string */ + if (wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) + { + ret = -E2BIG; + break; + } + + /* Copy the string from userspace */ + if (copy_from_user(essid, wrq->u.data.pointer, + wrq->u.data.length)) + { + ret = -EFAULT; + break; + } + essid[IW_ESSID_MAX_SIZE] = '\0'; + + DEBUG(0, "%s: Set desired SSID: %s", dev->name, essid); + memcpy(lp->wanted_essid, essid, IW_ESSID_MAX_SIZE); + snwnmp_set(dev, OID_DOT11_DOT11DESIREDSSID, + essid, IW_ESSID_MAX_SIZE); + } + break; + case SIOCGIWESSID: + /* Basic checking */ + if (wrq->u.data.pointer != (caddr_t) 0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + + /* Copy the SSID into a string */ + memcpy(essid, lp->ssid, IW_ESSID_MAX_SIZE); + essid[IW_ESSID_MAX_SIZE] = '\0'; + + /* Set the length */ + wrq->u.data.length = strlen(essid) + 1; + + /* Copy structure to the user pointer */ + if (copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)); + ret = -EFAULT; + } + break; +#endif + case SIOCGIWPRIV: /* Private ioctl's */ + if (wrq->u.data.pointer) + { + struct iw_priv_args priv[] = { + { SIOCDEVPRIVATE + 0x00, + IW_PRIV_TYPE_INT | 1, 0, "airlock" }, + }; + ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, + sizeof(priv)); + if (ret) + break; + wrq->u.data.length = sizeof(priv) / sizeof(priv[0]); + copy_to_user(wrq->u.data.pointer, priv, sizeof(priv)); + } + break; + case SIOCDEVPRIVATE + 0x00: + if (!suser()) + { + ret = -EPERM; + break; + } + + if (wrq->u.data.pointer != (caddr_t) 0) + { + /* Check what we should do */ + if (wrq->u.data.length != 0) /* Set */ + { + long airlock; + copy_from_user(&airlock, wrq->u.data.pointer, sizeof(long)); + + lp->enc.airlock = airlock; + + poldhu_encrypt(dev); + } + else /* Get */ + { + long airlock = lp->enc.airlock; + copy_to_user(wrq->u.data.pointer, &airlock, sizeof(airlock)); + } + } + break; + default: + ret = -EOPNOTSUPP; + break; + } +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-poldhu_do_ioctl()\n", dev->name); +#endif + return ret; +} + +static int poldhu_encrypt(struct net_device *dev) +{ + struct poldhu_private *lp = dev->priv; + struct poldhu_encryption *enc = &(lp->enc); + + long algorithm_enable[2]; + long privacy_invoked; + long exclude_unencrypted; + long public_key_enable; + long default_key_id; + unsigned char keys[SNWNMP_MAX_KEY_SIZE]; + + /* Set the default values */ + memcpy(keys, enc->keys, SNWNMP_MAX_KEY_SIZE); + default_key_id = htonl(enc->index); + exclude_unencrypted = htonl(2); + public_key_enable = htonl(2); + privacy_invoked = htonl(2); + algorithm_enable[0] = htonl(1); algorithm_enable[1] = htonl(2); + + if (enc->enable) + { + if (enc->restricted) exclude_unencrypted = htonl(1); + if (enc->airlock) public_key_enable = htonl(1); + privacy_invoked = htonl(1); + algorithm_enable[0] = htonl(2); algorithm_enable[1] = htonl(1); + } else + if (enc->airlock) { + public_key_enable = htonl(1); + algorithm_enable[0] = htonl(2); algorithm_enable[1] = htonl(1); + } + + + + /* Send out the SNWNMP packets */ + snwnmp_set(dev, OID_DOT11_DOT11AUTHENTICATIONALGORITHMENABLE, + (unsigned char *)algorithm_enable, sizeof(algorithm_enable)); + snwnmp_set(dev, OID_DOT11_DOT11PRIVACYINVOKED, + (unsigned char *)&privacy_invoked, sizeof(privacy_invoked)); + snwnmp_set(dev, OID_DOT11_DOT11EXCLUDEUNENCRYPTED, + (unsigned char *)&exclude_unencrypted, sizeof(exclude_unencrypted)); + snwnmp_set(dev, OID_NWN_SMTPUBLICKEYENABLE, + (unsigned char *)&public_key_enable, sizeof(public_key_enable)); + snwnmp_set(dev, OID_DOT11_DOT11WEPDEFAULTKEYID, + (unsigned char *)&default_key_id, sizeof(default_key_id)); + snwnmp_set(dev, OID_DOT11_DOT11WEPDEFAULTKEY, + keys, sizeof(keys)); + return 0; +} + +/*=====================================================================*/ +/* Device event handler */ + +static int poldhu_device_event(struct notifier_block *unused, unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + int i; + + switch (event) + { + case NETDEV_DOWN: + break; + case NETDEV_UP: + for (i = 0; i < MAX_POLDHUS; i++) { + if (poldhus[i] == dev) + { + struct poldhu_private* lp = dev->priv; + /* Update encryption */ + poldhu_encrypt(dev); + + /* Set the SSID */ + if (lp->wanted_essid[0] != 0) + snwnmp_set(dev, OID_DOT11_DOT11DESIREDSSID, + lp->wanted_essid, + IW_ESSID_MAX_SIZE); + mod_timer(&lp->roam_timer, jiffies + HZ * 5); + } + } + break; + default: + } + return NOTIFY_DONE; +} + +/*======================================================================*/ +/* Timer functions */ + +static void poldhu_bssid_timer(unsigned long data) +{ + struct net_device* dev = (struct net_device*)data; + snwnmp_get(dev, OID_NWN_SMTCURRENTBSSID); +} + +static void poldhu_roaming_timer(unsigned long data) +{ + struct net_device* dev = (struct net_device*)data; + + snwnmp_get(dev, OID_NWN_ROAMTABLELENGTH); + snwnmp_get(dev, OID_NWN_ROAMBSSID); + snwnmp_get(dev, OID_NWN_ROAMSSID); + snwnmp_get(dev, OID_NWN_ROAMBSSTYPE); + snwnmp_get(dev, OID_NWN_ROAMCHANNEL); + snwnmp_get(dev, OID_NWN_ROAMAGE); + snwnmp_get(dev, OID_NWN_ROAMQUALITY); + snwnmp_get(dev, OID_NWN_ROAMLOAD); + snwnmp_get(dev, OID_NWN_ROAMBEACONPERIOD); + snwnmp_get(dev, OID_NWN_ROAMDTIMPERIOD); + snwnmp_get(dev, OID_NWN_ROAMCAPABILITYINFORMATION); + snwnmp_get(dev, OID_NWN_ROAMRATES); +} + +/*======================================================================*/ +/* proc-filesystem */ + +static int poldhu_proc_read(char *buf, char **start, off_t off, + int len, int *eof, void *data) +{ + int i,j; + struct net_device* dev = (struct net_device*)data; + struct poldhu_private* lp = (struct poldhu_private*)dev->priv; + long flags; + int associated = 0; + + spin_lock_irqsave(&lp->lock, flags); + len = 0; + len += sprintf(buf + len, "%s\n", version); + len += sprintf(buf + len, "\n"); + len += sprintf(buf + len, "I/O address\t: 0x%03x\n", dev->base_addr); + len += sprintf(buf + len, "IRQ\t\t: %d\n", dev->irq); + len += sprintf(buf + len, "MAC address\t: "); + for (i=0;i<6;i++) + len += sprintf(buf + len, "%02x%s", dev->dev_addr[i], + i < 5 ? ":" : "\n"); + len += sprintf(buf + len, "Current SSID\t: %s\n", lp->ssid); + len += sprintf(buf + len, "Current BSSID\t: "); + for (i=0;i<6;i++) + if (lp->bssid[i] != 0) associated = 1; + if (associated) + for (i=0;i<6;i++) + len += sprintf(buf + len, "%02x%s", lp->bssid[i], + i < 5 ? ":" : "\n"); + else + len += sprintf(buf + len, "Not Associated\n"); + len += sprintf(buf + len, "Capabilities\t: 0x%08X\n", lp->capinfo); + + len += sprintf(buf + len, "\n"); + len += sprintf(buf + len, "Roaming Table\n"); + + for (i= 0;iroam_table.size;i++) + { + int print_entry = 0; + for (j=0;j<6;j++) if (lp->roam_table.entry[i].bssid[j] != 0) print_entry = 1; + if (strlen(lp->roam_table.entry[i].essid) == 0) print_entry = 0; + + if (print_entry) { + len += sprintf(buf + len, "\n"); + len += sprintf(buf + len, "BSSID\t\t: "); + for (j=0;j<6;j++) + len += sprintf(buf + len, "%02x%s", + lp->roam_table.entry[i].bssid[j], + j < 5 ? ":" : "\n"); + len += sprintf(buf + len, "SSID\t\t: %s\n", lp->roam_table.entry[i].essid); + len += sprintf(buf + len, "Capabilities\t: 0x%08X\n", lp->roam_table.entry[i].capinfo); + len += sprintf(buf + len, "BSS Type\t: 0x%08X\n", lp->roam_table.entry[i].bsstype); + len += sprintf(buf + len, "Channel\t\t: 0x%08X\n", + lp->roam_table.entry[i].channel); + len += sprintf(buf + len, "Roamage\t\t: 0x%08X\n", + lp->roam_table.entry[i].roamage); + len += sprintf(buf + len, "Quality\t\t: 0x%08X\n", + lp->roam_table.entry[i].quality); + len += sprintf(buf + len, "Load\t\t: 0x%08X\n", + lp->roam_table.entry[i].load); + } + } + + spin_unlock_irqrestore(&lp->lock, flags); + + return len; +} + +/*======================================================================*/ +/* Module initialization */ + +static int __init init_poldhu_cs(void) +{ + servinfo_t serv; + printk(KERN_INFO "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "poldhu_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &poldhu_pcmcia_attach, &poldhu_pcmcia_detach); + /* Add a notifier, so we can configure new devices */ + register_netdevice_notifier(&poldhu_dev_notifier); + + /* Create the proc entry */ + poldhu_proc_dir = proc_mkdir("poldhu", proc_root_driver); + /*create_proc_info_entry("roaming", 0, poldhu_proc_dir, + poldhu_proc_read);*/ + return 0; +} + +static void __exit exit_poldhu_cs(void) +{ + DEBUG(1, "poldhu_cs: unloading\n"); + /* Remove the proc entry */ + remove_proc_entry("poldhu", proc_root_driver); + + /* Unregister the notifier */ + unregister_netdevice_notifier(&poldhu_dev_notifier); + + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + poldhu_pcmcia_detach(dev_list); +} + +module_init(init_poldhu_cs); +module_exit(exit_poldhu_cs); diff -uNr linux-2.4.3-ac13.orig/drivers/net/pcmcia/poldhu.h linux-2.4.3-ac13/drivers/net/pcmcia/poldhu.h --- linux-2.4.3-ac13.orig/drivers/net/pcmcia/poldhu.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.3-ac13/drivers/net/pcmcia/poldhu.h Thu Feb 8 11:45:17 2001 @@ -0,0 +1,23 @@ +#ifndef POLDHU_H +#define POLDHU_H + +/* Maximum cards allowed */ +#define MAX_POLDHUS 4 + +/* Poldhu registers */ +#define MAC(base) (base + 0x00) +#define MAC0(base) (base + 0x00) /* MAC Address */ +#define MAC1(base) (base + 0x01) +#define MAC2(base) (base + 0x02) +#define MAC3(base) (base + 0x03) +#define MAC4(base) (base + 0x04) +#define MAC5(base) (base + 0x05) +#define VERSION(base) (base + 0x06) +#define STATUS(base) (base + 0x07) +#define INTR(base) (base + 0x08) +#define RESET(base) (base + 0x09) +#define IN(base) (base + 0x0a) +#define OUT(base) (base + 0x0a) + +#endif /* POLDHU_H */ + diff -uNr linux-2.4.3-ac13.orig/drivers/net/pcmcia/snwnmp.c linux-2.4.3-ac13/drivers/net/pcmcia/snwnmp.c --- linux-2.4.3-ac13.orig/drivers/net/pcmcia/snwnmp.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.3-ac13/drivers/net/pcmcia/snwnmp.c Thu Mar 8 09:16:12 2001 @@ -0,0 +1,584 @@ +/*========================================================================= + + Copyright (C) 2000 Bas Vermeulen -- bvermeul@xxxxxxxxxxxx + + No Wires Needed SNWNMP + + snwnmp.c 0.1.0 2001/02/06 + +=========================================================================*/ +#include +#ifdef __IN_PCMCIA_PACKAGE__ +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "snwnmp.h" + +static char *version = "No Wires Needed SNWNMP driver v0.1.0"; + +#define MAX_ROAMTABLE_SIZE 256 + +struct roam_entry_t { + unsigned char bssid[MAX_ADDR_LEN]; + char essid[IW_ESSID_MAX_SIZE + 1]; + int bsstype; + int channel; + int roamage; + int quality; + int load; + int beaconperiod; + int dtimperiod; + u16 capinfo; + unsigned char rates[MAX_ADDR_LEN]; +}; + +struct roam_table_t { + struct roam_entry_t entry[MAX_ROAMTABLE_SIZE]; + int size; +}; + +struct nwn_encryption { + int airlock; + int enable; + int restricted; + int index; + unsigned char keys[SNWNMP_MAX_KEY_SIZE]; +}; + +struct nwn_private { + dev_node_t node; + struct net_device_stats stats; + struct roam_table_t roam_table; + struct nwn_encryption enc; + char ssid[IW_ESSID_MAX_SIZE + 1]; + char wanted_essid[IW_ESSID_MAX_SIZE + 1]; + unsigned char bssid[MAX_ADDR_LEN]; + unsigned long capinfo; + struct timer_list bssid_timer; + struct timer_list roam_timer; + spinlock_t lock; + int is_550; +}; + +#ifdef CONFIG_SNWNMP_DEBUG +static int snwnmp_debug = CONFIG_SNWNMP_DEBUG; +#define DEBUG(n, args...) if (snwnmp_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) +#endif + +#define PRINT(n, args...) printk(KERN_INFO args) +#define kfree_s(o,s) kfree(o) +#define SNWNMP_STRING(n) (n + ETH_HLEN + SNWNMP_HLEN) +#define SNWNMP_LONG(n) *((long*) (n + ETH_HLEN + SNWNMP_HLEN)) + +/*======================================================================*/ +/* SNWNMP functions */ + + +/*======================================================================*/ +/* SNWNMP functions */ +int snwnmp_handle_trap(struct net_device *dev, unsigned char *frame, unsigned len) +{ + struct snwnmp_header *header= (struct snwnmp_header *)frame; + + switch (ntohl(header->oid)) + { + case OID_NWN_BSSCHANGETRAP: + snwnmp_get(dev, OID_NWN_SMTCURRENTSSID); + break; + default: + printk(KERN_INFO "%s: SNWNMP TRAP (oid %x)\n", + dev->name, ntohl(header->oid)); + } + return 0; +} + +int snwnmp_handle_response(struct net_device *dev, unsigned char *frame, unsigned len) +{ + struct snwnmp_header *header= (struct snwnmp_header *)frame; + struct nwn_private *lp = (struct nwn_private*)dev->priv; + int i, associated = 0; + int print_bssid = 0; + +#if defined(SNWNMP_DEBUG) + printk(KERN_INFO "%s: SNWNMP response to 0x%lx received: ", dev->name, + ntohl(header->oid)); + for (i=0;ilock); + + switch(ntohl(header->oid)) + { + case OID_NWN_SMTCURRENTSSID: + if (strcmp(SNWNMP_STRING(frame), lp->ssid) == 0) + { + PRINT(0, "%s: Current SSID is %s\n", + dev->name, SNWNMP_STRING(frame) ); + snwnmp_get(dev, OID_NWN_SMTCURRENTBSSID); + } + break; + case OID_NWN_SMTCURRENTBSSID: + print_bssid = 0; + for (i=0;i<6;i++) { + if (lp->bssid[i] != frame[i + ETH_HLEN + SNWNMP_HLEN]) { + lp->bssid[i] = frame[i + ETH_HLEN + SNWNMP_HLEN]; + print_bssid = 1; + } + if (frame[i + ETH_HLEN + SNWNMP_HLEN] != 0) + associated = 1; + } + if (print_bssid) { + printk(KERN_INFO "%s: Current BSSID is ", dev->name); + for (i=0;i<6;i++) + printk("%02x%s", frame[i+ ETH_HLEN + SNWNMP_HLEN], + i < 5 ? ":" : "\n"); + } + if (associated) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + break; + case OID_NWN_SMTCAPABILITYINFO: + PRINT(1, "%s: Capabilities (%08X)\n", dev->name, + ntohl(SNWNMP_LONG(frame))); + lp->capinfo = ntohl(SNWNMP_LONG(frame)); + break; + case OID_DOT11_DOT11DESIREDSSID: + PRINT(0, "%s: Requested SSID (%s)\n", + dev->name, SNWNMP_STRING(frame)); + memcpy(lp->ssid, SNWNMP_STRING(frame), 32); + break; + case OID_DOT11_DOT11AUTHENTICATIONALGORITHMENABLE: + PRINT(0, "%s: Current authentication algorithm (%d,%d)\n", + dev->name, + ntohl(SNWNMP_LONG(frame)), + ntohl(SNWNMP_LONG(frame + sizeof(long)))); + break; + case OID_DOT11_DOT11PRIVACYINVOKED: + PRINT(0, "%s: Current privacy setting (%d)\n", + dev->name, + ntohl(SNWNMP_LONG(frame))); + break; + case OID_DOT11_DOT11EXCLUDEUNENCRYPTED: + PRINT(0, "%s: Excluding unencrypted traffic (%d)\n", + dev->name, + ntohl(SNWNMP_LONG(frame))); + break; + case OID_NWN_SMTPUBLICKEYENABLE: + PRINT(0, "%s: Public key enable (%d)\n", + dev->name, + ntohl(SNWNMP_LONG(frame))); + break; + case OID_DOT11_DOT11WEPDEFAULTKEYID: + PRINT(0, "%s: Default key ID (%d)\n", + dev->name, + ntohl(SNWNMP_LONG(frame))); + break; + case OID_DOT11_DOT11WEPDEFAULTKEY: +#if CONFIG_PCMCIA_SWALLOW_DEBUG + if (swallow_debug > 0) { + printk(KERN_INFO "%s: Default key(s) ", dev->name); + for (i=0;ilength);i++) + printk("%02x ", frame[i + ETH_HLEN + SNWNMP_HLEN]); + printk("\n"); + } +#endif + break; + /* Roaming OID's */ + case OID_NWN_ROAMTABLELENGTH: + lp->roam_table.size = + ntohl(SNWNMP_LONG(frame)); + mod_timer(&lp->roam_timer, jiffies + HZ * 5 * 60); + break; + case OID_NWN_ROAMSSID: + if (lp->is_550) + { + int start, end, index = 0; + start = end = ETH_HLEN + SNWNMP_HLEN; + while (end < len) { + while (frame[end++]); + memcpy(lp->roam_table.entry[index++].essid, + frame + start, end - start); + start = end; + } + } + else + { + for (i=0;iroam_table.size;i++) + { + memcpy(lp->roam_table.entry[i].essid, + frame + ETH_HLEN + SNWNMP_HLEN + i * IW_ESSID_MAX_SIZE, + IW_ESSID_MAX_SIZE); + lp->roam_table.entry[i].essid[IW_ESSID_MAX_SIZE] = '\0'; + } + } + break; + case OID_NWN_ROAMBSSID: + for (i=0;iroam_table.size;i++) + { + memcpy(lp->roam_table.entry[i].bssid, + frame + ETH_HLEN + SNWNMP_HLEN + i * 6, 6); + } + break; + case OID_NWN_ROAMCAPABILITYINFORMATION: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].capinfo = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMQUALITY: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].quality = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMLOAD: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].load = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMCHANNEL: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].channel = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMBSSTYPE: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].bsstype = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMAGE: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].roamage = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMBEACONPERIOD: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].beaconperiod = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMDTIMPERIOD: + for (i=0;iroam_table.size;i++) + { + lp->roam_table.entry[i].dtimperiod = ntohl( + SNWNMP_LONG(frame + i * sizeof(long))); + } + break; + case OID_NWN_ROAMRATES: + for (i=0;iroam_table.size;i++) + { + memcpy(lp->roam_table.entry[i].rates, + frame + ETH_HLEN + SNWNMP_HLEN + i * 6, 6); + } + break; + default: + printk(KERN_INFO "%s: Received unknown oid %X with length %d\n", + dev->name, ntohl(header->oid), ntohl(header->length)); + break; + } + /* Release the lock */ + spin_unlock(&lp->lock); + return 0; +} + +/* + * This function re-sends failed SNWNMP get packages, after fixing them up. + */ +int snwnmp_handle_error(struct net_device *dev, unsigned char *frame, unsigned len) +{ + struct sk_buff *skb; + struct snwnmp_header *header= (struct snwnmp_header*)frame; + unsigned pkt_len = 0, header_len = 0; +#if defined(SNWNMP_DEBUG) + int i; +#endif + + if ((ntohl(header->length) == 0x5a5a5a5a) || + (ntohl(header->length) == 0x00000000)) + { + switch(ntohl(header->oid)) + { + case OID_NWN_SMTCURRENTSSID: + header->length = htonl(32); + break; + case OID_NWN_SMTCURRENTBSSID: + header->length = htonl(6); + break; + case OID_NWN_ROAMTABLELENGTH: + header->length = htonl(4); + break; + case OID_NWN_ROAMSSID: + header->length = htonl(128); + break; + case OID_NWN_ROAMBSSID: + header->length = htonl(48); + break; + case OID_NWN_ROAMBSSTYPE: + header->length = htonl(32); + break; + case OID_NWN_ROAMCAPABILITYINFORMATION: + header->length = htonl(16); + break; + case OID_NWN_ROAMAGE: + header->length = htonl(32); + break; + case OID_NWN_ROAMCHANNEL: + header->length = htonl(32); + break; + case OID_NWN_ROAMQUALITY: + header->length = htonl(32); + break; + case OID_NWN_ROAMLOAD: + header->length = htonl(32); + break; + case OID_NWN_ROAMBEACONPERIOD: + header->length = htonl(32); + break; + case OID_NWN_ROAMDTIMPERIOD: + header->length = htonl(32); + break; + case OID_NWN_ROAMRATES: + header->length = htonl(48); + break; + default: + printk(KERN_INFO "swallow_cs: Unsupported OID(0x%x)\n", + ntohl(header->oid)); + return -EOPNOTSUPP; + } + } + + header_len = ETH_HLEN + 12; + pkt_len = header_len + ntohl(header->length); + +#if defined(SNWNMP_DEBUG) + printk(KERN_INFO "%s: Resending %d bytes.\n", dev->name, pkt_len); +#endif + + memcpy(header->h_dest, dev->dev_addr, ETH_ALEN); + memcpy(header->h_source, dev->dev_addr, ETH_ALEN); + header->h_proto = __constant_htons(ETH_P_SNWNMP); + header->version = 1; + header->operation = SNWNMP_GET; + + if ((skb = dev_alloc_skb(pkt_len + 5)) == NULL) { + printk(KERN_INFO "%s: couldn't allocate an sk_buff of" + " size %d in snwnmp_handle_error()\n", dev->name, pkt_len + 5); + return -ENOMEM; + } + + memcpy(skb_put(skb, header_len), frame, header_len); + memset(skb_put(skb, ntohl(header->length)), 0, ntohl(header->length)); + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_SNWNMP); + skb->nh.raw = skb->data; + if (dev->hard_header) + skb->nh.raw += dev->hard_header_len; + + return dev_queue_xmit(skb); +} + +/* + * Get all values for a specific OID. + * We send a packet to find out how large the buffer should be; + * the processing part will make sure the request gets sent out again. + */ +int snwnmp_get(struct net_device *dev, unsigned long oid) +{ + struct sk_buff *skb; + struct snwnmp_header *header; + unsigned char *packet; + + unsigned int pkt_len = 0; +#if defined(SNWNMP_DEBUG) + int i; +#endif + +#if defined(SNWNMP_DEBUG) + printk(KERN_INFO "%s: Getting OID 0x%lx\n", dev->name, oid); +#endif + + pkt_len = ETH_HLEN + SNWNMP_HLEN; + + if ((packet = (unsigned char*) + kmalloc(pkt_len, GFP_ATOMIC)) == NULL) { + printk(KERN_INFO "snwnmp_get: Low on memory.\n"); + return -ENOMEM; + } + memset(packet, 0, pkt_len); + header = (struct snwnmp_header *)packet; + + /* Fill in the ether packet to send up to the card */ + memcpy(header->h_dest, dev->dev_addr, ETH_ALEN); + memcpy(header->h_source, dev->dev_addr, ETH_ALEN); + header->h_proto = __constant_htons(ETH_P_SNWNMP); + header->version = 0x01; + header->operation = SNWNMP_GET; + header->oid = htonl(oid); + header->index = 0; + header->flags = 0; + header->length = 0; + + /* Allocate an sk_buffer */ + if ((skb = dev_alloc_skb(pkt_len + dev->hard_header_len + 15)) == NULL) { + kfree(packet); + printk(KERN_INFO "%s: couldn't allocate an sk_buff of" + " size %d in snwnmp_get()\n", dev->name, pkt_len); + return -ENOMEM; + } + + skb_reserve(skb, 2); + + memcpy(skb_put(skb, pkt_len), packet, pkt_len); + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_SNWNMP); + skb->nh.raw = skb->data; + if (dev->hard_header) + skb->nh.raw += dev->hard_header_len; + + if (skb->len != pkt_len) + printk(KERN_INFO "%s: Error! skb->len != pkt_len\n", dev->name); + +#if defined(SNWNMP_DEBUG) + printk(KERN_INFO "%s: Sending SNWNMP get: ", dev->name); + for (i = 0; i < pkt_len; i++) + printk("%02x ", ((unsigned char*)packet)[i]); + printk("\n"); +#endif + + kfree(packet); + + return dev_queue_xmit(skb); +} + +int snwnmp_set(struct net_device *dev, unsigned long oid, unsigned char *data, unsigned len) +{ + struct sk_buff *skb; + struct snwnmp_header *header; + unsigned char *packet; + + unsigned int pkt_len = 0; +#if defined(SNWNMP_DEBUG) + int i; +#endif + + pkt_len = ETH_HLEN + SNWNMP_HLEN + len; + +#if defined(SNWNMP_DEBUG) + printk(KERN_INFO "%s: Setting OID 0x%lx\n", dev->name, oid); +#endif + + if ((packet = (unsigned char*)kmalloc(pkt_len, GFP_ATOMIC)) == NULL) { + printk(KERN_INFO "%s: Unable to allocate %d bytes in snwnmp_set()\n", + dev->name, pkt_len); + return -ENOMEM; + } + memset(packet, 0, pkt_len); + header = (struct snwnmp_header *)packet; + + /* Fill in the ethernet header */ + memcpy(header->h_dest, dev->dev_addr, ETH_ALEN); + memcpy(header->h_source, dev->dev_addr, ETH_ALEN); + header->h_proto = __constant_htons(ETH_P_SNWNMP); + /* Fill in the SNWNMP header */ + header->version = 1; + header->operation = SNWNMP_SET; + header->oid = htonl(oid); + header->length = htonl(len); + + /* Copy in the data */ + memcpy(packet + ETH_HLEN + SNWNMP_HLEN, data, len); + + /* Allocate an sk_buffer */ + if ((skb = dev_alloc_skb(pkt_len + dev->hard_header_len + 15)) == NULL) { + kfree(packet); + printk(KERN_INFO "%s: couldn't allocate an sk_buff of" + " size %d in snwnmp_set()\n", dev->name, pkt_len); + return -ENOMEM; + } + + skb_reserve(skb, 2); + + memcpy(skb_put(skb, pkt_len), packet, pkt_len); + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_SNWNMP); + skb->nh.raw = skb->data; + if (dev->hard_header) + skb->nh.raw += dev->hard_header_len; + + if (skb->len != pkt_len) + printk(KERN_INFO "%s: Error! skb->len != pkt_len\n", dev->name); + +#if defined(SNWNMP_DEBUG) + printk(KERN_INFO "%s: Sending SNWNMP set: ", dev->name); + for (i=0;ih_proto != __constant_htons(ETH_P_SNWNMP)) { + printk(KERN_INFO "%s: Wrong ether type(0x%x) in process_snwnmp.\n", + dev->name, ntohs(header->h_proto)); + return -EOPNOTSUPP; + } + + switch (header->operation) { + case SNWNMP_ERROR: + return snwnmp_handle_error(dev, frame, len); + case SNWNMP_TRAP: + return snwnmp_handle_trap(dev, frame, len); + case SNWNMP_RESPONSE: + return snwnmp_handle_response(dev, frame, len); + case SNWNMP_GET: + case SNWNMP_SET: + printk(KERN_INFO "%s: Unexpected operation received (%d)\n", + dev->name, header->operation); + break; + default: + printk(KERN_INFO "%s: Don't know how to handle operation (%d)\n", + dev->name, header->operation); + break; + } + + return -EOPNOTSUPP; +} diff -uNr linux-2.4.3-ac13.orig/drivers/net/pcmcia/snwnmp.h linux-2.4.3-ac13/drivers/net/pcmcia/snwnmp.h --- linux-2.4.3-ac13.orig/drivers/net/pcmcia/snwnmp.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.3-ac13/drivers/net/pcmcia/snwnmp.h Thu Feb 8 11:30:30 2001 @@ -0,0 +1,228 @@ +#ifndef SNWNMP_H +#define SNWNMP_H + +/* SNWNMP Functions */ +extern int snwnmp_process(struct net_device *dev, unsigned char *frame, unsigned len); +extern int snwnmp_handle_trap(struct net_device *dev, unsigned char *frame, unsigned len); +extern int snwnmp_handle_response(struct net_device *dev, unsigned char *frame, unsigned len); +extern int snwnmp_handle_error(struct net_device *dev, unsigned char *frame, unsigned len); +extern int snwnmp_get(struct net_device *dev, unsigned long oid); +extern int snwnmp_set(struct net_device *dev, unsigned long oid, unsigned char *data, unsigned len); + +/* SNWNMP Ether type */ +#define ETH_P_SNWNMP 0x8828 + +/* SNWNMP header length */ +#define SNWNMP_HLEN 12 + +/* SNWNMP Operations */ +#define SNWNMP_GET 0 +#define SNWNMP_SET 1 +#define SNWNMP_RESPONSE 2 +#define SNWNMP_ERROR 3 +#define SNWNMP_TRAP 4 + +struct snwnmp_header { + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + unsigned short h_proto; + unsigned char version; + unsigned char operation; + unsigned long oid __attribute__ ((packed)); + unsigned char index; + unsigned char flags; + unsigned long length __attribute__ ((packed)); +}; + +/* SNWNMP Encryption */ +#define SNWNMP_KEY_SIZE 5 +#define SNWNMP_MAX_KEYS 4 +#define SNWNMP_MAX_KEY_SIZE SNWNMP_MAX_KEYS * SNWNMP_KEY_SIZE + + +/* OID defines */ +#define OID_DOT11_DOT11STATIONID 0xFF010100 /* W */ +#define OID_DOT11_DOT11MEDIUMOCCUPANCYLIMIT 0xFF010101 /* W */ +#define OID_DOT11_DOT11CFPOLLABLE 0xFF010102 +#define OID_DOT11_DOT11CFPPERIOD 0xFF010103 +#define OID_DOT11_DOT11CFPMAXDURATION 0xFF010104 +#define OID_DOT11_DOT11AUTHENTICATIONRESPONSETIMEOUT 0xFF010105 /* W */ +#define OID_DOT11_DOT11PRIVACYOPTIONIMPLEMENTED 0xFF010106 +#define OID_DOT11_DOT11POWERMANAGEMENTMODE 0xFF010107 /* W */ +/* aanvragen ESSID */ +#define OID_DOT11_DOT11DESIREDSSID 0xFF010108 /* W */ +#define OID_DOT11_DOT11DESIREDBSSTYPE 0xFF010109 /* W */ +#define OID_DOT11_DOT11OPERATIONALRATESET 0xFF01010A /* W */ +#define OID_DOT11_DOT11BEACONPERIOD 0xFF01010B /* W */ +#define OID_DOT11_DOT11DTIMPERIOD 0xFF01010C /* W */ +#define OID_DOT11_DOT11ASSOCIATIONRESPONSETIMEOUT 0xFF01010D /* W */ +#define OID_DOT11_DOT11DISASSOCIATEREASON 0xFF01010E +#define OID_DOT11_DOT11DISASSOCIATESTATION 0xFF01010F +#define OID_DOT11_DOT11DEAUTHENTICATEREASON 0xFF010110 +#define OID_DOT11_DOT11DEAUTHENTICATESTATION 0xFF010111 +#define OID_DOT11_DOT11AUTHENTICATEFAILSTATUS 0xFF010112 +#define OID_DOT11_DOT11AUTHENTICATEFAILSTATION 0xFF010113 + +#define OID_DOT11_DOT11AUTHENTICATIONALGORITHM 0xFF010114 +#define OID_DOT11_DOT11AUTHENTICATIONALGORITHMENABLE 0xFF010115 /* W */ + +#define OID_DOT11_DOT11WEPDEFAULTKEY 0xFF010116 /* W */ + +#define OID_DOT11_DOT11WEPKEYMAPPINGADDRESS 0xFF010117 /* W */ +#define OID_DOT11_DOT11WEPKEYMAPPINGKEY 0xFF010118 /* W */ +#define OID_DOT11_DOT11WEPKEYMAPPINGWEPON 0xFF010119 /* W */ + +#define OID_DOT11_DOT11PRIVACYINVOKED 0xFF01011A /* W */ +#define OID_DOT11_DOT11WEPDEFAULTKEYID 0xFF01011B /* W */ +#define OID_DOT11_DOT11WEPKEYMAPPINGLENGTH 0xFF01011C /* W */ +#define OID_DOT11_DOT11EXCLUDEUNENCRYPTED 0xFF01011D /* W */ +#define OID_DOT11_DOT11WEPICVERRORCOUNT 0xFF01011E +#define OID_DOT11_DOT11WEPEXCLUDEDCOUNT 0xFF01011F + +#define OID_DOT11_DOT11MACADDRESS 0xFF010120 +#define OID_DOT11_DOT11RTSTHRESHOLD 0xFF010121 /* W */ +#define OID_DOT11_DOT11SHORTRETRYLIMIT 0xFF010122 /* W */ +#define OID_DOT11_DOT11LONGRETRYLIMIT 0xFF010123 /* W */ +#define OID_DOT11_DOT11FRAGMENTATIONTHRESHOLD 0xFF010124 /* W */ +#define OID_DOT11_DOT11MAXTRANSMITMSDULIFETIME 0xFF010125 /* W */ +#define OID_DOT11_DOT11MAXRECEIVELIFETIME 0xFF010126 /* W */ +#define OID_DOT11_DOT11MANUFACTURERID 0xFF010127 +#define OID_DOT11_DOT11PRODUCTID 0xFF010128 + +#define OID_DOT11_DOT11TRANSMITTEDFRAGMENTCOUNT 0xFF010129 +#define OID_DOT11_DOT11MULTICASTTRANSMITTEDFRAMECOUNT 0xFF01012A +#define OID_DOT11_DOT11FAILEDCOUNT 0xFF01012B +#define OID_DOT11_DOT11RETRYCOUNT 0xFF01012C +#define OID_DOT11_DOT11MULTIPLERETRYCOUNT 0xFF01012D +#define OID_DOT11_DOT11FRAMEDUPLICATECOUNT 0xFF01012E +#define OID_DOT11_DOT11RTSSUCCESSCOUNT 0xFF01012F +#define OID_DOT11_DOT11RTSFAILURECOUNT 0xFF010130 +#define OID_DOT11_DOT11ACKFAILURECOUNT 0xFF010131 +#define OID_DOT11_DOT11RECEIVEDFRAGMENTCOUNT 0xFF010132 +#define OID_DOT11_DOT11MULTICASTRECEIVEDFRAMECOUNT 0xFF010133 +#define OID_DOT11_DOT11FCSERRORCOUNT 0xFF010134 +#define OID_DOT11_DOT11TRANSMITTEDFRAMECOUNT 0xFF010135 +#define OID_DOT11_DOT11WEPUNDECRYPTABLECOUNT 0xFF010136 + +#define OID_DOT11_DOT11GROUPADDRESSES 0xFF010137 /* W */ + +#define OID_DOT11_DOT11MANUFACTUREROUI 0xFF010138 +#define OID_DOT11_DOT11MANUFACTURERNAME 0xFF010139 +#define OID_DOT11_DOT11MANUFACTURERPRODUCTNAME 0xFF01013A +#define OID_DOT11_DOT11MANUFACTURERPRODUCTVERSION 0xFF01013B + +#define OID_DOT11_DOT11PHYTYPE 0xFF01013C +#define OID_DOT11_DOT11CURRENTREGDOMAIN 0xFF01013D /* W */ +#define OID_DOT11_DOT11TEMPTYPE 0xFF01013E +#define OID_DOT11_DOT11CURRENTTXANTENNA 0xFF01013F /* W */ +#define OID_DOT11_DOT11DIVERSITYSUPPORT 0xFF010140 +#define OID_DOT11_DOT11CURRENTRXANTENNA 0xFF010141 +/* W */ +#define OID_DOT11_DOT11NUMBERSUPPORTEDPOWERLEVELS 0xFF010142 +#define OID_DOT11_DOT11TXPOWERLEVEL1 0xFF010143 +#define OID_DOT11_DOT11TXPOWERLEVEL2 0xFF010144 +#define OID_DOT11_DOT11TXPOWERLEVEL3 0xFF010145 +#define OID_DOT11_DOT11TXPOWERLEVEL4 0xFF010146 +#define OID_DOT11_DOT11TXPOWERLEVEL5 0xFF010147 +#define OID_DOT11_DOT11TXPOWERLEVEL6 0xFF010148 +#define OID_DOT11_DOT11TXPOWERLEVEL7 0xFF010149 +#define OID_DOT11_DOT11TXPOWERLEVEL8 0xFF01014A +#define OID_DOT11_DOT11CURRENTTXPOWERLEVEL 0xFF01014B /* W */ +#define OID_DOT11_DOT11CURRENTCHANNEL 0xFF01014C /* W */ +#define OID_DOT11_DOT11CCAMODESUPPORTED 0xFF01014D +#define OID_DOT11_DOT11CURRENTCCAMODE 0xFF01014E /* W */ +#define OID_DOT11_DOT11EDTHRESHOLD 0xFF01014F /* W */ +#define OID_DOT11_DOT11REGDOMAINSSUPPORTED 0xFF010150 +#define OID_DOT11_DOT11SUPPORTEDTXANTENNAS 0xFF010151 /* W */ +#define OID_DOT11_DOT11SUPPORTEDRXANTENNAS 0xFF010152 /* W */ +#define OID_DOT11_DOT11DIVERSITYSELECTIONRX 0xFF010153 /* W */ +#define OID_DOT11_DOT11SUPPORTEDDATARATESTX 0xFF010154 +#define OID_DOT11_DOT11SUPPORTEDDATARATESRX 0xFF010155 + +#define OID_NWN_SMTASSOCIATIONID 0xFF0101A0 + +#define OID_NWN_SMTCAPABILITYINFO 0xFF0101A1 +#define OID_NWN_SMTPOWERSAVEINTERVAL 0xFF0101A2 /* W */ +#define OID_NWN_SMTLISTENINTERVAL 0xFF0101A3 /* W */ +#define OID_NWN_SMTATIMWINDOW 0xFF0101A4 /* W */ +/* */ +#define OID_NWN_SMTOPERATIONALCHANNELS 0xFF0101A5 /* W */ +/* mac adres accespoint */ +#define OID_NWN_SMTCURRENTBSSID 0xFF0101A6 + +/* ESSID */ +#define OID_NWN_SMTCURRENTSSID 0xFF0101A7 +#define OID_NWN_SMTCURRENTBSSTYPE 0xFF0101A8 +#define OID_NWN_SMTPUBLICKEYENABLE 0xFF0101A9 + /* Notice non-sequential numbering */ +#define OID_NWN_SMTQUALITYLEVEL0 0xFF0101D0 + +#define OID_NWN_SMTQUALITYLEVEL1 0xFF0101D1 +#define OID_NWN_SMTQUALITYLEVEL2 0xFF0101D2 +#define OID_NWN_SMTQUALITYPENALTY 0xFF0101D3 +#define OID_NWN_SMTSTATIONDBTIMEOUT 0xFF0101D4 + +#define OID_NWN_ROAMSCANTYPE 0xFF0101AA /* W */ +#define OID_NWN_ROAMSCANINTERVAL 0xFF0101AB /* W */ +#define OID_NWN_ROAMPROBEDELAY 0xFF0101AC /* W */ +#define OID_NWN_ROAMMINCHANNELTIME 0xFF0101AD /* W */ +#define OID_NWN_ROAMMAXCHANNELTIME 0xFF0101AE /* W */ +#define OID_NWN_ROAMJOINTIMEOUT 0xFF0101AF /* W */ +#define OID_NWN_ROAMBEACONPERIODTIMEOUT 0xFF0101B0 /* W */ +#define OID_NWN_ROAMDONTSWITCH 0xFF0101B1 /* W */ +#define OID_NWN_ROAMBLACKOUT 0xFF0101B2 /* W */ +#define OID_NWN_ROAMDISASSOCIATETIME 0xFF0101B3 /* W */ +#define OID_NWN_ROAMHANDOFFTIME 0xFF0101B4 /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC1 0xFF0101B5 /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC2 0xFF0101B6 /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC3 0xFF0101B7 /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC4 0xFF0101B8 /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC5 0xFF0101B9 /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC6 0xFF0101BA /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC7 0xFF0101BB /* W */ +#define OID_NWN_ROAMWEIGHTMETRIC8 0xFF0101BC /* W */ +#define OID_NWN_ROAMMISC1 0xFF0101BD /* W */ +#define OID_NWN_ROAMRSSIAVERAGETIME1 0xFF0101BD /* W */ + /* Note: same as previous entry, old name */ +#define OID_NWN_ROAMMISC2 0xFF0101BE /* W */ +#define OID_NWN_ROAMRSSIAVERAGETIME2 0xFF0101BE /* W */ + /* Note: same as previous entry, old name */ +#define OID_NWN_ROAMTABLELENGTH 0xFF0101BF + +#define OID_NWN_ROAMBSSID 0xFF0101C0 +#define OID_NWN_ROAMSSID 0xFF0101C1 +#define OID_NWN_ROAMBSSTYPE 0xFF0101C2 +#define OID_NWN_ROAMCHANNEL 0xFF0101C3 +#define OID_NWN_ROAMAGE 0xFF0101C4 +#define OID_NWN_ROAMQUALITY 0xFF0101C5 +#define OID_NWN_ROAMLOAD 0xFF0101C6 +#define OID_NWN_ROAMBEACONPERIOD 0xFF0101C7 +#define OID_NWN_ROAMDTIMPERIOD 0xFF0101C8 +#define OID_NWN_ROAMCAPABILITYINFORMATION 0xFF0101C9 +#define OID_NWN_ROAMRATES 0xFF0101CC + +#define OID_NWN_BSSCHANGETRAP 0xFF0101D5 + +#define OID_NWN_DRIVER_VERSION 0xFF0101E0 +#define OID_NWN_UPGRADE 0xFF0101E1 +#define OID_NWN_HARDCONFIG 0xFF0101E2 + +#define OID_NWN_TESTREGISTER1 0xFF0101F0 +#define OID_NWN_TESTREGISTER2 0xFF0101F1 +#define OID_NWN_TESTREGISTER3 0xFF0101F2 +#define OID_NWN_TESTREGISTER4 0xFF0101F3 +#define OID_NWN_TESTREGISTER5 0xFF0101F4 +#define OID_NWN_TESTREGISTER6 0xFF0101F5 +#define OID_NWN_TESTREGISTER7 0xFF0101F6 +#define OID_NWN_TESTREGISTER8 0xFF0101F7 +#define OID_NWN_TESTREGISTER9 0xFF0101F8 +#define OID_NWN_TESTREGISTER10 0xFF0101F9 +#define OID_NWN_TESTREGISTER11 0xFF0101FA +#define OID_NWN_TESTREGISTER12 0xFF0101FB +#define OID_NWN_TESTREGISTER13 0xFF0101FC +#define OID_NWN_TESTREGISTER14 0xFF0101FD +#define OID_NWN_TESTREGISTER15 0xFF0101FE +#define OID_NWN_TESTREGISTER16 0xFF0101FF + +#endif /* SNWNMP_H */ +