diff -u -urN orinoco-0.13b/Makefile orinoco-0.13b+nortel+airsnort/Makefile --- orinoco-0.13b/Makefile Mon Feb 10 04:38:09 2003 +++ orinoco-0.13b+nortel+airsnort/Makefile Fri Apr 4 13:06:54 2003 @@ -5,14 +5,14 @@ KERNEL_SRC = /lib/modules/$(KERNEL_VERSION)/build KERNEL_HEADERS = $(KERNEL_SRC)/include -MODULES = hermes.o orinoco.o orinoco_cs.o orinoco_plx.o orinoco_pci.o +MODULES = hermes.o orinoco.o orinoco_cs.o orinoco_plx.o orinoco_pci.o nortel_pci.o ifeq ($(shell uname -m),ppc) MODULES += airport.o endif SRCS = hermes.c \ orinoco.c \ - airport.c orinoco_cs.c orinoco_plx.c orinoco_pci.c \ + airport.c orinoco_cs.c orinoco_plx.c orinoco_pci.c nortel_pci.c \ userhermes.c HDRS = hermes.h hermes_rid.h ieee802_11.h orinoco.h CONF = hermes.conf diff -u -urN orinoco-0.13b/hermes.c orinoco-0.13b+nortel+airsnort/hermes.c --- orinoco-0.13b/hermes.c Mon Feb 10 04:38:09 2003 +++ orinoco-0.13b+nortel+airsnort/hermes.c Fri Apr 4 13:06:54 2003 @@ -129,7 +129,9 @@ int io_space, int reg_spacing) { hw->iobase = address; - hw->io_space = io_space; + hw->iobase1 = 0; + hw->iobase2 = 0; + hw->io_space = io_space; hw->reg_spacing = reg_spacing; hw->inten = 0x0; @@ -183,6 +185,10 @@ err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); if (err) return err; + + for ( k = 0; k < HERMES_NUMPORTS_MAX; k++) { + hw->port_enabled[k] = 0; + } reg = hermes_read_regn(hw, EVSTAT); k = CMD_INIT_TIMEOUT; diff -u -urN orinoco-0.13b/hermes.h orinoco-0.13b+nortel+airsnort/hermes.h --- orinoco-0.13b/hermes.h Mon Feb 10 04:38:09 2003 +++ orinoco-0.13b+nortel+airsnort/hermes.h Fri Apr 4 13:06:54 2003 @@ -33,6 +33,10 @@ #include #include +#define HFA384x_PORTTYPE_IBSS ((uint16_t)3) +#define HFA384x_WEPFLAGS_DISABLE_TXCRYPT (0x10) +#define HFA384x_WEPFLAGS_DISABLE_RXCRYPT (0x80) + /* * Limits and constants */ @@ -149,6 +153,38 @@ #define HERMES_MONITOR_DISABLE (0x000f) /* + * Configuration RIDs + */ + +#define HERMES_RID_CNF_PORTTYPE (0xfc00) +#define HERMES_RID_CNF_CHANNEL (0xfc03) +#define HERMES_RID_CNF_PRISM2_WEP_ON (0xfc28) + +/*-- Status Fields --*/ +#define HERMES_RXSTATUS_MSGTYPE (0xE000) +#define HERMES_RXSTATUS_MACPORT (0x0700) +#define HERMES_RXSTATUS_UNDECR (0x0002) +#define HERMES_RXSTATUS_FCSERR (0x0001) + +/*-------------------------------------------------------------------- +Communication Frames: Test/Get/Set Field Values for Receive Frames +--------------------------------------------------------------------*/ +#define HERMES_RXSTATUS_MSGTYPE_GET(value) (((value) & HERMES_RXSTATUS_MSGTYPE) >> 13) +#define HERMES_RXSTATUS_MSGTYPE_SET(value) ((value) << 13) +#define HERMES_RXSTATUS_MACPORT_GET(value) (((value) & HERMES_RXSTATUS_MACPORT) >> 8) +#define HERMES_RXSTATUS_MACPORT_SET(value) ((value) << 8) +#define HERMES_RXSTATUS_ISUNDECR(value) ((value) & HERMES_RXSTATUS_UNDECR) +#define HERMES_RXSTATUS_ISFCSERR(value) ((value) & HERMES_RXSTATUS_FCSERR) + +/*-------------------------------------------------------------------- +Communication Frames: Field Masks for Receive Frames +--------------------------------------------------------------------*/ +/*-- Offsets --------*/ +#define HERMES_RX_DATA_LEN_OFF (44) +#define HERMES_RX_80211HDR_OFF (14) +#define HERMES_RX_DATA_OFF (60) + +/* * Frame structures and constants */ @@ -278,7 +314,7 @@ /* Basic control structure */ typedef struct hermes { - ulong iobase; + ulong iobase, iobase1, iobase2; int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */ #define HERMES_IO 1 #define HERMES_MEM 0 @@ -287,6 +323,7 @@ #define HERMES_32BIT_REGSPACING 1 u16 inten; /* Which interrupts should be enabled? */ + uint8_t port_enabled[HERMES_NUMPORTS_MAX]; #ifdef HERMES_DEBUG_BUFFER struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE]; @@ -340,12 +377,14 @@ static inline int hermes_enable_port(hermes_t *hw, int port) { + hw->port_enabled[port] = 1; return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), 0, NULL); } static inline int hermes_disable_port(hermes_t *hw, int port) { + hw->port_enabled[port] = 0; return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 0, NULL); } diff -u -urN orinoco-0.13b/nortel_pci.c orinoco-0.13b+nortel+airsnort/nortel_pci.c --- orinoco-0.13b/nortel_pci.c Thu Jan 1 01:00:00 1970 +++ orinoco-0.13b+nortel+airsnort/nortel_pci.c Fri Apr 4 13:23:02 2003 @@ -0,0 +1,357 @@ +/* nortel_pci.c (based on orinoco_plx.c and orinoco_pci.c) + * + * Driver for Prism II devices which would usually be driven by orinoco_cs, + * but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter. + * + * Copyright (C) 2001 Daniel Barlow + * (C) 2002 Tobias Hoffmann + * (C) 2003 Christoph Jungegger + * + * 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. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General 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. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hermes.h" +#include "orinoco.h" + +static char dev_info[] = "nortel_pci"; + +#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ + + +/* + * Do a soft reset of the PCI card using the Configuration Option Register + * We need this to get going... + * This is the part of the code that is strongly inspired from wlan-ng + * + * Note : This code is done with irq enabled. This mean that many + * interrupts will occur while we are there. This is why we use the + * jiffies to regulate time instead of a straight mdelay(). Usually we + * need only around 245 iteration of the loop to do 250 ms delay. + * + * Note bis : Don't try to access HERMES_CMD during the reset phase. + * It just won't work ! + */ +static int +nortel_pci_cor_reset(struct orinoco_private *priv) +{ + unsigned long brg1_ioaddr=priv->hw.iobase1; + unsigned long brg2_ioaddr=priv->hw.iobase2; + + /* Assert the reset until the card notice */ + outw_p(8, brg1_ioaddr+2); + inw(brg2_ioaddr+COR_OFFSET); + outw_p(0x80, brg2_ioaddr+COR_OFFSET); + mdelay(1); + printk(KERN_NOTICE "Reset done;\n"); + + /* Give time for the card to recover from this hard effort */ + outw_p(0, brg2_ioaddr+COR_OFFSET); + outw_p(0, brg2_ioaddr+COR_OFFSET); + mdelay(1); + printk(KERN_NOTICE "Clear Reset\n"); + + /* set COR as usual*/ + outw_p(COR_VALUE, brg2_ioaddr+COR_OFFSET); + outw_p(COR_VALUE, brg2_ioaddr+COR_OFFSET); + mdelay(1); + + outw_p(0x228, brg1_ioaddr+2); + + return 0; +} + +static int nortel_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err = 0; + u16 *attr_mem = NULL; + u32 reg; + struct orinoco_private *priv = NULL; + unsigned long brg1_ioaddr = 0, brg2_ioaddr = 0, pccard_ioaddr = 0; + unsigned long brg1_iolen = 0, brg2_iolen = 0, pccard_iolen = 0; + struct net_device *dev = NULL; + int netdev_registered = 0; + int i; + + err = pci_enable_device(pdev); + if (err) + return -EIO; + + brg1_ioaddr = pci_resource_start(pdev, 0); + brg1_iolen = pci_resource_len(pdev, 0); + if (! request_region(brg1_ioaddr, brg1_iolen, dev_info)) { + printk(KERN_ERR "nortel_pci: Bridge I/O resource 1 0x%lx @ 0x%lx busy\n", + brg1_iolen, brg1_ioaddr); + brg1_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + brg2_ioaddr = pci_resource_start(pdev, 1); + brg2_iolen = pci_resource_len(pdev, 1); + if (! request_region(brg2_ioaddr, brg2_iolen, dev_info)) { + printk(KERN_ERR "nortel_pci: Bridge I/O resource 2 0x%lx @ 0x%lx busy\n", + brg2_iolen, brg2_ioaddr); + brg2_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + pccard_ioaddr = pci_resource_start(pdev, 2); + pccard_iolen = pci_resource_len(pdev, 2); + if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { + printk(KERN_ERR "nortel_pci: I/O resource 0x%lx @ 0x%lx busy\n", + pccard_iolen, pccard_ioaddr); + pccard_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + /* setup bridge */ + if (inw(brg1_ioaddr)&1) { + printk(KERN_ERR "nortel_pci: brg1 answer1 wrong\n"); + goto fail; + } + outw_p(0x118,brg1_ioaddr+2); + outw_p(0x108,brg1_ioaddr+2); + mdelay(30); + outw_p(0x8,brg1_ioaddr+2); + for (i=0; i<30; i++) { + mdelay(30); + if (inw(brg1_ioaddr)&0x10) { + break; + } + } + if (i==30) { + printk(KERN_ERR "nortel_pci: brg1 timed out\n"); + goto fail; + } + if (inw(brg2_ioaddr+0xe0)&1) { + printk(KERN_ERR "nortel_pci: brg2 answer1 wrong\n"); + goto fail; + } + if (inw(brg2_ioaddr+0xe2)&1) { + printk(KERN_ERR "nortel_pci: brg2 answer2 wrong\n"); + goto fail; + } + if (inw(brg2_ioaddr+0xe4)&1) { + printk(KERN_ERR "nortel_pci: brg2 answer3 wrong\n"); + goto fail; + } + + /* set the PCMCIA COR-Register */ + outw_p(COR_VALUE, brg2_ioaddr+COR_OFFSET); + mdelay(1); + reg = inw(brg2_ioaddr+COR_OFFSET); + if (reg != COR_VALUE) { + printk(KERN_ERR "nortel_pci: Error setting COR value (reg=%x)\n", reg); + goto fail; + } + + /* set leds */ + outw_p(1,brg1_ioaddr+10); + + + dev = alloc_orinocodev(0, NULL); + if (! dev) { + err = -ENOMEM; + goto fail; + } + + priv = dev->priv; + dev->base_addr = pccard_ioaddr; + priv->hard_reset = nortel_pci_cor_reset; + SET_MODULE_OWNER(dev); + + printk(KERN_DEBUG + "Detected Nortel PCI device at %s irq:%d, io addr:0x%lx\n", + pdev->slot_name, pdev->irq, pccard_ioaddr); + + hermes_struct_init(&(priv->hw), dev->base_addr, + HERMES_IO, HERMES_16BIT_REGSPACING); + pci_set_drvdata(pdev, dev); + priv->hw.iobase1=brg1_ioaddr; + priv->hw.iobase2=brg2_ioaddr; + + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv); + if (err) { + printk(KERN_ERR "nortel_pci: Error allocating IRQ %d.\n", pdev->irq); + err = -EBUSY; + goto fail; + } + dev->irq = pdev->irq; + nortel_pci_cor_reset(priv); + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR "%s: Failed to register net device\n", dev->name); + goto fail; + } + netdev_registered = 1; + +// err = orinoco_proc_dev_init(dev); +// if (err) { +// printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name); +// err = -EIO; +// goto fail; +// } + + + return 0; /* succeeded */ + +fail: + if (!err) { + err=-1; + } + printk(KERN_DEBUG "nortel_pci: init_one(), FAIL!\n"); + + if (priv) { +// orinoco_proc_dev_cleanup(dev); + + if (netdev_registered) + unregister_netdev(dev); + + if (dev->irq) + free_irq(dev->irq, priv); + + pci_set_drvdata(pdev, NULL); + kfree(dev); + } + + if (brg1_ioaddr) + release_region(brg1_ioaddr, brg1_iolen); + if (brg2_ioaddr) + release_region(brg2_ioaddr, brg2_iolen); + if (pccard_ioaddr) + release_region(pccard_ioaddr, pccard_iolen); + + if (attr_mem) + iounmap(attr_mem); + + pci_disable_device(pdev); + + return err; +} + +static void __devexit nortel_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = dev->priv; + + /* clear leds */ + outw_p(0,priv->hw.iobase1+10); + + if (! dev) + BUG(); + +// orinoco_proc_dev_cleanup(dev); + + unregister_netdev(dev); + + if (dev->irq) + free_irq(dev->irq, priv); + + pci_set_drvdata(pdev, NULL); + kfree(dev); + + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); + release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); + + pci_disable_device(pdev); + +} + + +static struct pci_device_id nortel_pci_id_table[] __devinitdata = { + {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, /* Nortel emobility PCI */ + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, nortel_pci_id_table); + +static struct pci_driver nortel_pci_driver = { + .name = "nortel_pci", + .id_table = nortel_pci_id_table, + .probe = nortel_pci_init_one, + .remove = __devexit_p(nortel_pci_remove_one), + .suspend = 0, + .resume = 0 +}; + +static char version[] __initdata = "nortel_pci.c 0.13a (Daniel Barlow , Tobias Hoffmann, Christoph Jungegger)"; +MODULE_AUTHOR("Daniel Barlow , Tobias Hoffmann, Christoph Jungegger"); +MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual MPL/GPL"); +#endif + +static int __init nortel_pci_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_module_init(&nortel_pci_driver); +} + +extern void __exit nortel_pci_exit(void) +{ + pci_unregister_driver(&nortel_pci_driver); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); +} + +module_init(nortel_pci_init); +module_exit(nortel_pci_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -u -urN orinoco-0.13b/orinoco.c orinoco-0.13b+nortel+airsnort/orinoco.c --- orinoco-0.13b/orinoco.c Mon Feb 10 04:38:09 2003 +++ orinoco-0.13b+nortel+airsnort/orinoco.c Fri Apr 4 13:00:27 2003 @@ -1586,6 +1586,7 @@ struct header_struct hdr; struct ethhdr *eh; int err; + struct ieee802_11_hdr hdr80211; rxfid = hermes_read_regn(hw, RXFID); @@ -1602,6 +1603,7 @@ if (status & HERMES_RXSTAT_ERR) { if (status & HERMES_RXSTAT_UNDECRYPTABLE) { + if (dev->type != ARPHRD_ETHER) goto sniffing; wstats->discard.code++; DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", dev->name); @@ -1612,7 +1614,7 @@ stats->rx_errors++; goto drop; } - +sniffing: /* For now we ignore the 802.11 header completely, assuming that the card's firmware has handled anything vital */ @@ -1642,6 +1644,10 @@ stats->rx_errors++; goto drop; } + /* Now handle frame based on port# */ + switch( HERMES_RXSTATUS_MACPORT_GET(status) ) + { + case 0: /* We need space for the packet data itself, plus an ethernet header, plus 2 bytes so we can align the IP header on a @@ -1718,6 +1724,26 @@ return; + case 7: + if ( ! HERMES_RXSTATUS_ISFCSERR(status) ) { + if (hermes_bap_pread(hw, IRQ_BAP, &hdr80211, sizeof(hdr80211), + rxfid, HERMES_RX_80211HDR_OFF)) { + stats->rx_errors++; + } + else { + /* Copy to wlansnif skb */ + orinoco_int_rxmonitor( priv, rxfid, length, &desc, &hdr80211); + } + } else { + printk("Received monitor frame: FCSerr set\n"); + } + break; + + default: + printk("Received frame on unsupported port=%d\n", + HERMES_RXSTATUS_MACPORT_GET(status) ); + break; + } drop: stats->rx_dropped++; @@ -2348,6 +2374,24 @@ return err; } +//#define SET_MAC_ADDRESS +#ifdef SET_MAC_ADDRESS +static int +orinoco_set_mac_address(struct net_device *dev, void *addr) +{ + struct orinoco_private *priv = dev->priv; + struct sockaddr *mac = addr; + + /* Copy the address */ + memcpy(dev->dev_addr, mac->sa_data, WLAN_ADDR_LEN); + + /* Reconfig the beast */ + orinoco_reset(priv); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + static void orinoco_tx_timeout(struct net_device *dev) { @@ -2935,7 +2979,7 @@ if (!priv->has_sensitivity) return -EOPNOTSUPP; - if ((val < 1) || (val > 3)) + if ((val < 0) || (val > 3)) return -EINVAL; err = orinoco_lock(priv, &flags); @@ -3500,6 +3544,175 @@ return 0; } +/*---------------------------------------------------------------- +* orinoco_wlansniff +* +* Start or stop sniffing. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +static int orinoco_wlansniff(struct net_device *dev, struct iwreq *wrq) +{ + struct orinoco_private *priv = dev->priv; + + hermes_t *hw = &(priv->hw); + hermes_response_t resp; + int result = 0; + uint16_t word; + + int *parms = (int *) wrq->u.name; + int enable = parms[0] > 0; + unsigned long flags; + + orinoco_lock(priv, &flags); + + switch (enable) + { + case P80211ENUM_truth_false: + /* Confirm that we're in monitor mode */ + if ( dev->type == ARPHRD_ETHER ) { + result = -EFAULT; + } + /* Disable monitor mode */ + word = HERMES_CMD_MONITOR | (HERMES_MONITOR_DISABLE << 8); + result = hermes_docmd_wait(hw, word, 0, &resp); + + if ( result ) break; + + /* Disable port 0 */ + result = hermes_disable_port(hw, 0); + if ( result ) break; + + /* Clear the driver state */ + dev->type = ARPHRD_ETHER; + + /* Restore the wepflags */ //Orinoco doesn't like this +/* + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_WEP_ON, + priv->presniff_wepflags); + if ( result ) break; + +*/ + /* Set the port to its prior type and enable (if necessary) */ + if (priv->presniff_port_type != 0 ) { + word = priv->presniff_port_type; + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PORTTYPE, word); + if ( result ) break; + + /* Enable the port */ + result = hermes_enable_port(hw, 0); + if ( result ) break; + + } + + break; + case P80211ENUM_truth_true: + /* Re-initialize the card before changing channel as advised at + * http://lists.samba.org/pipermail/wireless/2002-June/004491.html + * by Ian Goldberg. Implementation by Pat Swieskowski. + */ +// __orinoco_down(dev); + hermes_set_irqmask(hw, 0); + hermes_init(hw); +// __orinoco_up(dev); + hermes_set_irqmask(hw, ORINOCO_INTEN); +/* + __orinoco_stop_irqs(priv); + hermes_reset(hw); + __orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + HERMES_EV_TX | HERMES_EV_TXEXC | + HERMES_EV_WTERR | HERMES_EV_INFO | + HERMES_EV_INFDROP); +*/ + /* Disable the port (if enabled), only check Port 0 */ + if ( hw->port_enabled[0] ) { + /* Save macport 0 state */ + result = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PORTTYPE, + &(priv->presniff_port_type)); + if ( result ) break; + + /* Save the wepflags state */ + result = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_WEP_ON, + &(priv->presniff_wepflags)); + if ( result ) break; + result = hermes_disable_port(hw, 0); + if ( result ) break; + + } + else { + priv->presniff_port_type = 0; + } + + /* Set the channel we wish to sniff */ + if (parms[1] > 0 && parms[1] < 15) { + word = parms[1]; + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_CHANNEL, word); + } else { + result = -EFAULT; + } + + if ( result ) break; + + /* Set the port type to pIbss */ + word = HFA384x_PORTTYPE_IBSS; + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PORTTYPE, word); + if ( result ) break; + +/* + if ( (msg->keepwepflags.status == P80211ENUM_msgitem_status_data_ok) && + (msg->keepwepflags.data != P80211ENUM_truth_true)) { + // Set the wepflags for no decryption //Orinoco doesn't like this + word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT | + HFA384x_WEPFLAGS_DISABLE_RXCRYPT; + result = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_PRISM2_WEP_ON, word); //won't work with the bits above + } + if ( result ) break; + +*/ + /* Enable the port */ + result = hermes_enable_port(hw, 0); + if ( result ) break; + + /* Enable monitor mode */ + word = HERMES_CMD_MONITOR | (HERMES_MONITOR_ENABLE << 8); + result = hermes_docmd_wait(hw, word, 0, &resp); + if ( result ) break; + + /* Set the driver state */ + /* Do we want the prism2 header? */ + if (parms[0] == 1) + dev->type = ARPHRD_IEEE80211_PRISM; + else + dev->type = ARPHRD_IEEE80211; + break; + default: + result = -EFAULT; + break; + } + orinoco_unlock(priv, &flags); + return result; + +} + static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { @@ -3732,6 +3945,9 @@ { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_ibssport" }, + { SIOCIWFIRSTPRIV + 0x8, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "monitor" }, { SIOCIWLASTPRIV, 0, 0, "dump_recs" }, }; @@ -3826,6 +4042,16 @@ err = orinoco_ioctl_getibssport(dev, wrq); break; + case SIOCIWFIRSTPRIV + 0x8: /* set sniff (monitor) mode */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x8 (monitor)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + err = orinoco_wlansniff(dev, wrq); + break; + case SIOCIWLASTPRIV: err = orinoco_debug_dump_recs(priv); if (err) @@ -4047,6 +4273,9 @@ dev->tx_timeout = orinoco_tx_timeout; dev->watchdog_timeo = HZ; /* 1 second timeout */ dev->get_stats = orinoco_get_stats; +#ifdef SET_MAC_ADDRESS + dev->set_mac_address = orinoco_set_mac_address; +#endif /* SET_MAC_ADDRESS */ dev->get_wireless_stats = orinoco_get_wireless_stats; dev->do_ioctl = orinoco_ioctl; dev->change_mtu = orinoco_change_mtu; @@ -4069,6 +4298,197 @@ return dev; +} + +/*---------------------------------------------------------------- +* orinoco_int_rxmonitor +* +* Helper function for int_rx. Handles monitor frames. +* Note that this function allocates space for the FCS and sets it +* to 0xffffffff. The hfa384x doesn't give us the FCS value but the +* higher layers expect it. 0xffffffff is used as a flag to indicate +* the FCS is bogus. +* +* Arguments: +* dev wlan device structure +* rxfid received FID +* rxdesc rx descriptor read from card in int_rx +* +* Returns: +* nothing +* +* Side effects: +* Allocates an skb and passes it up via the PF_PACKET interface. +* Call context: +* interrupt +----------------------------------------------------------------*/ +void orinoco_int_rxmonitor( struct orinoco_private *dev, uint16_t rxfid, int len, + struct hermes_rx_descriptor *rxdesc, struct ieee802_11_hdr *hdr) +{ + hermes_t *hw = &(dev->hw); + uint32_t hdrlen = 0; + uint32_t datalen = 0; + uint32_t skblen = 0; + p80211msg_lnxind_wlansniffrm_t *msg; + struct net_device_stats *stats = &dev->stats; + + + uint8_t *datap; + uint16_t fc; + struct sk_buff *skb; + + /* Don't forget the status, time, and data_len fields are in host order */ + /* Figure out how big the frame is */ + fc = le16_to_cpu(hdr->frame_ctl); + switch ( WLAN_GET_FC_FTYPE(fc) ) + { + case WLAN_FTYPE_DATA: + if ( WLAN_GET_FC_TODS(fc) && WLAN_GET_FC_FROMDS(fc) ) { + hdrlen = WLAN_HDR_A4_LEN; + } else { + hdrlen = WLAN_HDR_A3_LEN; + } + datalen = len; + break; + case WLAN_FTYPE_MGMT: + hdrlen = WLAN_HDR_A3_LEN; + datalen = len; + break; + case WLAN_FTYPE_CTL: + switch ( WLAN_GET_FC_FSTYPE(fc) ) + { + case WLAN_FSTYPE_PSPOLL: + case WLAN_FSTYPE_RTS: + case WLAN_FSTYPE_CFEND: + case WLAN_FSTYPE_CFENDCFACK: + hdrlen = 16; + break; + case WLAN_FSTYPE_CTS: + case WLAN_FSTYPE_ACK: + hdrlen = 10; + break; + } + datalen = 0; + break; + default: + printk("unknown frm: fc=0x%04x\n", fc); + return; + } + + /* Allocate an ind message+framesize skb */ + skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + + hdrlen + datalen; + + /* sanity check the length */ + if ( skblen > + (sizeof(p80211msg_lnxind_wlansniffrm_t) + + WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) { + printk("overlen frm: len=%d\n", + skblen - sizeof(p80211msg_lnxind_wlansniffrm_t)); + } + + if ( (skb = dev_alloc_skb(skblen)) == NULL ) { + printk("alloc_skb failed trying to allocate %d bytes\n", skblen); + return; + } + + /* only prepend the prism header if in the right mode */ + if (dev->ndev->type != ARPHRD_IEEE80211_PRISM) { + skb_put(skb, skblen - sizeof(p80211msg_lnxind_wlansniffrm_t)); + datap = skb->data; + } else { + skb_put(skb, skblen); + datap = skb->data + sizeof(p80211msg_lnxind_wlansniffrm_t); + msg = (p80211msg_lnxind_wlansniffrm_t*)skb->data; + + /* Initialize the message members */ + msg->msgcode = DIDmsg_lnxind_wlansniffrm; + msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t); + strcpy(msg->devname, dev->ndev->name); + + msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; + msg->hosttime.status = 0; + msg->hosttime.len = 4; + msg->hosttime.data = jiffies; + + msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; + msg->mactime.status = 0; + msg->mactime.len = 4; + msg->mactime.data = rxdesc->time; + + msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel; + msg->channel.status = P80211ENUM_msgitem_status_no_value; + msg->channel.len = 4; + msg->channel.data = 0; + + msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; + msg->rssi.status = P80211ENUM_msgitem_status_no_value; + msg->rssi.len = 4; + msg->rssi.data = 0; + + msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq; + msg->sq.status = P80211ENUM_msgitem_status_no_value; + msg->sq.len = 4; + msg->sq.data = 0; + + msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal; + msg->signal.status = 0; + msg->signal.len = 4; + msg->signal.data = rxdesc->signal; + + msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise; + msg->noise.status = 0; + msg->noise.len = 4; + msg->noise.data = rxdesc->silence; + + msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate; + msg->rate.status = 0; + msg->rate.len = 4; + msg->rate.data = rxdesc->rate / 5; /* set to 802.11 units */ + + msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx; + msg->istx.status = 0; + msg->istx.len = 4; + msg->istx.data = P80211ENUM_truth_false; + + msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; + msg->frmlen.status = 0; + msg->frmlen.len = 4; + msg->frmlen.data = hdrlen + datalen; + } + + /* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */ + memcpy( datap, &(hdr->frame_ctl), hdrlen); + + /* If any, copy the data from the card to the skb */ + if ( datalen > 0 ) + { + hermes_bap_pread(hw, IRQ_BAP, datap + hdrlen, (datalen+1)&~1, + rxfid, HERMES_RX_DATA_OFF); + + /* check for unencrypted stuff if WEP bit set. */ + if (*(datap+1) & 0x40) // wep set + if ((*(datap+hdrlen) == 0xaa) && (*(datap+hdrlen+1) == 0xaa)) + *(datap+1) &= 0xbf; // clear wep; it's the 802.2 header! + } + + /* pass it up via the PF_PACKET interface */ + { + skb->dev = dev->ndev; + skb->dev->last_rx = jiffies; + + skb->mac.raw = skb->data ; + skb->ip_summed = CHECKSUM_NONE; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_80211_RAW); /* XXX ETH_P_802_2? */ + + stats->rx_packets++; + stats->rx_bytes += skb->len; + + netif_rx(skb); + } + + return; } /********************************************************************/ diff -u -urN orinoco-0.13b/orinoco.h orinoco-0.13b+nortel+airsnort/orinoco.h --- orinoco-0.13b/orinoco.h Mon Feb 10 04:38:09 2003 +++ orinoco-0.13b+nortel+airsnort/orinoco.h Fri Apr 4 13:00:27 2003 @@ -17,6 +17,20 @@ /* To enable debug messages */ //#define ORINOCO_DEBUG 3 +#ifndef ETH_P_ECONET +#define ETH_P_ECONET 0x0018 /* needed for 2.2.x kernels */ +#endif + +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) + +#ifndef ARPHRD_IEEE80211 +#define ARPHRD_IEEE80211 801 /* kernel 2.4.6 */ +#endif + +#ifndef ARPHRD_IEEE80211_PRISM /* kernel 2.4.18 */ +#define ARPHRD_IEEE80211_PRISM 802 +#endif + #if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) #error "orinoco driver requires Wireless extensions v10 or later." #endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ @@ -34,6 +48,158 @@ HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \ HERMES_EV_INFDROP ) +#define WLAN_DEVNAMELEN_MAX 16 + +/* message data item for INT, BOUNDEDINT, ENUMINT */ +typedef struct p80211item_uint32 +{ + uint32_t did __attribute__ ((packed)); + uint16_t status __attribute__ ((packed)); + uint16_t len __attribute__ ((packed)); + uint32_t data __attribute__ ((packed)); +} __attribute__ ((packed)) p80211item_uint32_t; + +typedef struct p80211msg +{ + uint32_t msgcode __attribute__ ((packed)); + uint32_t msglen __attribute__ ((packed)); + uint8_t devname[WLAN_DEVNAMELEN_MAX] __attribute__ ((packed)); +} __attribute__ ((packed)) p80211msg_t; + +#define DIDmsg_lnxind_wlansniffrm 0x0041 +#define DIDmsg_lnxind_wlansniffrm_hosttime 0x1041 +#define DIDmsg_lnxind_wlansniffrm_mactime 0x2041 +#define DIDmsg_lnxind_wlansniffrm_channel 0x3041 +#define DIDmsg_lnxind_wlansniffrm_rssi 0x4041 +#define DIDmsg_lnxind_wlansniffrm_sq 0x5041 +#define DIDmsg_lnxind_wlansniffrm_signal 0x6041 +#define DIDmsg_lnxind_wlansniffrm_noise 0x7041 +#define DIDmsg_lnxind_wlansniffrm_rate 0x8041 +#define DIDmsg_lnxind_wlansniffrm_istx 0x9041 +#define DIDmsg_lnxind_wlansniffrm_frmlen 0xA041 + +typedef struct p80211msg_lnxind_wlansniffrm +{ + uint32_t msgcode; + uint32_t msglen; + uint8_t devname[WLAN_DEVNAMELEN_MAX]; + p80211item_uint32_t hosttime; + p80211item_uint32_t mactime; + p80211item_uint32_t channel; + p80211item_uint32_t rssi; + p80211item_uint32_t sq; + p80211item_uint32_t signal; + p80211item_uint32_t noise; + p80211item_uint32_t rate; + p80211item_uint32_t istx; + p80211item_uint32_t frmlen; +} __attribute__ ((packed)) p80211msg_lnxind_wlansniffrm_t; + +#define P80211ENUM_truth_false 0 +#define P80211ENUM_truth_true 1 +#define P80211ENUM_resultcode_success 1 +#define P80211ENUM_resultcode_invalid_parameters 2 +#define P80211ENUM_resultcode_not_supported 3 +#define P80211ENUM_resultcode_timeout 4 +#define P80211ENUM_resultcode_too_many_req 5 +#define P80211ENUM_resultcode_refused 6 +#define P80211ENUM_resultcode_bss_already 7 +#define P80211ENUM_resultcode_invalid_access 8 +#define P80211ENUM_resultcode_invalid_mibattribute 9 +#define P80211ENUM_resultcode_cant_set_readonly_mib 10 +#define P80211ENUM_resultcode_implementation_failure 11 +#define P80211ENUM_resultcode_cant_get_writeonly_mib 12 +#define P80211ENUM_msgitem_status_data_ok 0 +#define P80211ENUM_msgitem_status_no_value 1 +#define P80211ENUM_msgitem_status_invalid_itemname 2 +#define P80211ENUM_msgitem_status_invalid_itemdata 3 +#define P80211ENUM_msgitem_status_missing_itemdata 4 +#define P80211ENUM_msgitem_status_incomplete_itemdata 5 +#define P80211ENUM_msgitem_status_invalid_msg_did 6 +#define P80211ENUM_msgitem_status_invalid_mib_did 7 +#define P80211ENUM_msgitem_status_missing_conv_func 8 +#define P80211ENUM_msgitem_status_string_too_long 9 +#define P80211ENUM_msgitem_status_data_out_of_range 10 +#define P80211ENUM_msgitem_status_string_too_short 11 +#define P80211ENUM_msgitem_status_missing_valid_func 12 +#define P80211ENUM_msgitem_status_unknown 13 +#define P80211ENUM_msgitem_status_invalid_did 14 +#define P80211ENUM_msgitem_status_missing_print_func 15 + +#define WLAN_GET_FC_FTYPE(n) (((n) & 0x0C) >> 2) +#define WLAN_GET_FC_FSTYPE(n) (((n) & 0xF0) >> 4) +#define WLAN_GET_FC_TODS(n) (((n) & 0x0100) >> 8) +#define WLAN_GET_FC_FROMDS(n) (((n) & 0x0200) >> 9) + +/*--- Sizes -----------------------------------------------*/ +#define WLAN_ADDR_LEN 6 +#define WLAN_CRC_LEN 4 +#define WLAN_BSSID_LEN 6 +#define WLAN_BSS_TS_LEN 8 +#define WLAN_HDR_A3_LEN 24 +#define WLAN_HDR_A4_LEN 30 +#define WLAN_SSID_MAXLEN 32 +#define WLAN_DATA_MAXLEN 2312 + +/*--- Frame Control Field -------------------------------------*/ +/* Frame Types */ +#define WLAN_FTYPE_MGMT 0x00 +#define WLAN_FTYPE_CTL 0x01 +#define WLAN_FTYPE_DATA 0x02 + +/* Frame subtypes */ +/* Management */ +#define WLAN_FSTYPE_ASSOCREQ 0x00 +#define WLAN_FSTYPE_ASSOCRESP 0x01 +#define WLAN_FSTYPE_REASSOCREQ 0x02 +#define WLAN_FSTYPE_REASSOCRESP 0x03 +#define WLAN_FSTYPE_PROBEREQ 0x04 +#define WLAN_FSTYPE_PROBERESP 0x05 +#define WLAN_FSTYPE_BEACON 0x08 +#define WLAN_FSTYPE_ATIM 0x09 +#define WLAN_FSTYPE_DISASSOC 0x0a +#define WLAN_FSTYPE_AUTHEN 0x0b +#define WLAN_FSTYPE_DEAUTHEN 0x0c + +/* Control */ +#define WLAN_FSTYPE_PSPOLL 0x0a +#define WLAN_FSTYPE_RTS 0x0b +#define WLAN_FSTYPE_CTS 0x0c +#define WLAN_FSTYPE_ACK 0x0d +#define WLAN_FSTYPE_CFEND 0x0e +#define WLAN_FSTYPE_CFENDCFACK 0x0f + +/* Data */ +#define WLAN_FSTYPE_DATAONLY 0x00 +#define WLAN_FSTYPE_DATA_CFACK 0x01 +#define WLAN_FSTYPE_DATA_CFPOLL 0x02 +#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03 +#define WLAN_FSTYPE_NULL 0x04 +#define WLAN_FSTYPE_CFACK 0x05 +#define WLAN_FSTYPE_CFPOLL 0x06 +#define WLAN_FSTYPE_CFACK_CFPOLL 0x07 + +/*----------------------------------------------------------------*/ +/* Magic number, a quick test to see we're getting the desired struct */ + +#define P80211_IOCTL_MAGIC (0x4a2d464dUL) + +/*================================================================*/ +/* Types */ + +/*----------------------------------------------------------------*/ +/* A ptr to the following structure type is passed as the third */ +/* argument to the ioctl system call when issuing a request to */ +/* the p80211 module. */ + +typedef struct p80211ioctl_req +{ + char name[WLAN_DEVNAMELEN_MAX] __attribute__ ((packed)); + void *data __attribute__ ((packed)); + uint32_t magic __attribute__ ((packed)); + uint16_t len __attribute__ ((packed)); + uint32_t result __attribute__ ((packed)); +} __attribute__ ((packed)) p80211ioctl_req_t; struct orinoco_private { void *card; /* Pointer to card dependant structure */ @@ -95,6 +261,9 @@ /* Configuration dependent variables */ int port_type, createibss; int promiscuous, mc_count; + + uint16_t presniff_port_type; + uint16_t presniff_wepflags; }; #ifdef ORINOCO_DEBUG @@ -141,5 +310,14 @@ { spin_unlock_irqrestore(&priv->lock, *flags); } + +/*================================================================*/ +/* Function Declarations */ + +struct ieee802_11_hdr; + +void orinoco_int_rxmonitor( struct orinoco_private *dev, uint16_t rxfid, int len, + struct hermes_rx_descriptor *rxdesc, struct ieee802_11_hdr *hdr); + #endif /* _ORINOCO_H */ diff -u -urN orinoco-0.13b/orinoco_cs.c orinoco-0.13b+nortel+airsnort/orinoco_cs.c --- orinoco-0.13b/orinoco_cs.c Mon Feb 10 04:38:09 2003 +++ orinoco-0.13b+nortel+airsnort/orinoco_cs.c Fri Apr 4 12:56:23 2003 @@ -64,9 +64,13 @@ * don't have any CIS entry for it. This workaround it... */ static int ignore_cis_vcc; /* = 0 */ +/* Control device name allocation. 0 -> dldwdX ; 1 -> ethX */ +static int eth = 1; + MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); MODULE_PARM(ignore_cis_vcc, "i"); +MODULE_PARM(eth, "i"); /********************************************************************/ /* Magic constants */ @@ -88,6 +92,7 @@ struct orinoco_pccard { dev_link_t link; dev_node_t node; + int instance; /* Used to handle hard reset */ /* yuck, we need this hack to work around the insanity of the @@ -101,6 +106,7 @@ * dev_link_t structure (defined in ds.h). */ static dev_link_t *dev_list; /* = NULL */ +static int num_instances = 0; /********************************************************************/ /* Function prototypes */ @@ -198,6 +204,7 @@ card = priv->card; /* Link both structures together */ + card->instance = num_instances++; /* FIXME: Racy? */ link = &card->link; link->priv = dev; @@ -297,6 +304,9 @@ unregister_netdev(dev); } kfree(dev); + + num_instances--; /* FIXME: Racy? */ + } /* orinoco_cs_detach */ /* @@ -496,8 +506,12 @@ SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; - /* register_netdev will give us an ethX name */ - dev->name[0] = '\0'; + /* Instance name : by default, use hermesX, on demand use the + * regular ethX (less risky) - Jean II */ + if(!eth) + sprintf(dev->name, "wvlan%d", card->instance); + else + dev->name[0] = '\0'; /* Tell the stack we exist */ if (register_netdev(dev) != 0) { printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); @@ -703,11 +717,11 @@ printk(KERN_DEBUG "%s\n", version); CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "orinoco_cs: Card Services release " - "does not match!\n"); - return -1; - } +// if (serv.Revision != CS_RELEASE_CODE) { +// printk(KERN_NOTICE "orinoco_cs: Card Services release " +// "does not match!\n"); +// return -1; +// } register_pccard_driver(&dev_info, &orinoco_cs_attach, &orinoco_cs_detach);