diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-04-14 20:48:55 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-04-14 20:48:55 -0400 |
commit | 2acab771b7e676125cb8c96b61dcdefe9ba67e57 (patch) | |
tree | 86227af3c9ad0d90823e5488a86f7f453ed1837a /drivers/net | |
parent | 201e06279823c73242de987f192f43d2b30e5331 (diff) | |
parent | 64541d19702cfdb7ea946fdc20faee849f6874b1 (diff) |
Merge branch 'master'
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/irda/irda-usb.c | 6 | ||||
-rw-r--r-- | drivers/net/irda/smsc-ircc2.c | 316 | ||||
-rw-r--r-- | drivers/net/wan/Kconfig | 97 | ||||
-rw-r--r-- | drivers/net/wan/Makefile | 13 | ||||
-rw-r--r-- | drivers/net/wan/sdla_chdlc.c | 4428 | ||||
-rw-r--r-- | drivers/net/wan/sdla_fr.c | 5061 | ||||
-rw-r--r-- | drivers/net/wan/sdla_ft1.c | 345 | ||||
-rw-r--r-- | drivers/net/wan/sdla_ppp.c | 3430 | ||||
-rw-r--r-- | drivers/net/wan/sdla_x25.c | 5497 | ||||
-rw-r--r-- | drivers/net/wan/sdladrv.c | 2314 | ||||
-rw-r--r-- | drivers/net/wan/sdlamain.c | 1346 | ||||
-rw-r--r-- | drivers/net/wan/wanpipe_multppp.c | 2358 |
12 files changed, 268 insertions, 24943 deletions
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 606243d1179..96bdb73c228 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1815,14 +1815,14 @@ static int irda_usb_probe(struct usb_interface *intf, self->needspatch = (ret < 0); if (ret < 0) { printk("patch_device failed\n"); - goto err_out_4; + goto err_out_5; } /* replace IrDA class descriptor with what patched device is now reporting */ irda_desc = irda_usb_find_class_desc (self->usbintf); if (irda_desc == NULL) { ret = -ENODEV; - goto err_out_4; + goto err_out_5; } if (self->irda_desc) kfree (self->irda_desc); @@ -1832,6 +1832,8 @@ static int irda_usb_probe(struct usb_interface *intf, return 0; +err_out_5: + unregister_netdev(self->netdev); err_out_4: kfree(self->speed_buff); err_out_3: diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index bbcfc8ec35a..58f76cefbc8 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -225,6 +225,8 @@ static int __init smsc_superio_lpc(unsigned short cfg_base); #ifdef CONFIG_PCI static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port); static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, @@ -2327,9 +2329,14 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) * pre-configuration not properly done by the BIOS (especially laptops) * This code is based in part on smcinit.c, tosh1800-smcinit.c * and tosh2450-smcinit.c. The table lists the device entries - * for ISA bridges with an LPC (Local Peripheral Configurator) - * that are in turn used to configure the SMSC device with default - * SIR and FIR I/O ports, DMA and IRQ. + * for ISA bridges with an LPC (Low Pin Count) controller which + * handles the communication with the SMSC device. After the LPC + * controller is initialized through PCI, the SMSC device is initialized + * through a dedicated port in the ISA port-mapped I/O area, this latter + * area is used to configure the SMSC device with default + * SIR and FIR I/O ports, DMA and IRQ. Different vendors have + * used different sets of parameters and different control port + * addresses making a subsystem device table necessary. */ #ifdef CONFIG_PCI #define PCIID_VENDOR_INTEL 0x8086 @@ -2340,9 +2347,10 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x088c, - .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ + /* Quite certain these are the same for nc8000 as for nc6000 */ + .sir_io = 0x02f8, .fir_io = 0x0130, - .fir_irq = 0x09, + .fir_irq = 0x05, .fir_dma = 0x03, .cfg_base = 0x004e, .preconfigure = preconfigure_through_82801, @@ -2355,60 +2363,79 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev .subdevice = 0x0890, .sir_io = 0x02f8, .fir_io = 0x0130, - .fir_irq = 0x09, + .fir_irq = 0x05, .fir_dma = 0x03, .cfg_base = 0x004e, .preconfigure = preconfigure_through_82801, .name = "HP nc6000", }, { - .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + .vendor = PCIID_VENDOR_INTEL, .device = 0x24c0, .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .subdevice = 0xffff, /* 0xffff is "any" */ .sir_io = 0x03f8, .fir_io = 0x0130, .fir_irq = 0x07, .fir_dma = 0x01, .cfg_base = 0x002e, .preconfigure = preconfigure_through_82801, - .name = "Toshiba Satellite 2450", + .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", }, { .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ - .device = 0x248c, /* Some use 24cc? */ + .device = 0x248c, .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .subdevice = 0xffff, /* 0xffff is "any" */ .sir_io = 0x03f8, .fir_io = 0x0130, .fir_irq = 0x03, .fir_dma = 0x03, .cfg_base = 0x002e, .preconfigure = preconfigure_through_82801, - .name = "Toshiba Satellite 5100/5200, Tecra 9100", + .name = "Toshiba laptop with Intel 82801CAM ISA bridge", }, { - .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + /* 82801DBM (ICH4-M) LPC Interface Bridge */ + .vendor = PCIID_VENDOR_INTEL, + .device = 0x24cc, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 8281DBM LPC bridge", + }, + { + /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + .vendor = PCIID_VENDOR_ALI, .device = 0x1533, .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .subdevice = 0xffff, /* 0xffff is "any" */ .sir_io = 0x02e8, .fir_io = 0x02f8, .fir_irq = 0x07, .fir_dma = 0x03, .cfg_base = 0x002e, .preconfigure = preconfigure_through_ali, - .name = "Toshiba Satellite 1800", + .name = "Toshiba laptop with ALi ISA bridge", }, { } // Terminator }; /* - * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) + * This sets up the basic SMSC parameters + * (FIR port, SIR port, FIR DMA, FIR IRQ) * through the chip configuration port. */ -static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) +static int __init preconfigure_smsc_chip(struct + smsc_ircc_subsystem_configuration + *conf) { unsigned short iobase = conf->cfg_base; unsigned char tmpbyte; @@ -2416,7 +2443,9 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID tmpbyte = inb(iobase +1); // Read device ID - IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); + IRDA_DEBUG(0, + "Detected Chip id: 0x%02x, setting up registers...\n", + tmpbyte); /* Disable UART1 and set up SIR I/O port */ outb(0x24, iobase); // select CR24 - UART1 base addr @@ -2426,6 +2455,7 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio tmpbyte = inb(iobase + 1); if (tmpbyte != (conf->sir_io >> 2) ) { IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); + IRDA_WARNING("Try to supply ircc_cfg argument.\n"); return -ENXIO; } @@ -2461,7 +2491,8 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode tmpbyte = inb(iobase + 1); - tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; + tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | + SMSCSIOFLAT_UART2MODE_VAL_IRDA; outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel @@ -2486,53 +2517,226 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio return 0; } -/* 82801CAM registers */ +/* 82801CAM generic registers */ #define VID 0x00 #define DID 0x02 -#define PIRQA_ROUT 0x60 +#define PIRQ_A_D_ROUT 0x60 +#define SIRQ_CNTL 0x64 +#define PIRQ_E_H_ROUT 0x68 #define PCI_DMA_C 0x90 +/* LPC-specific registers */ #define COM_DEC 0xe0 +#define GEN1_DEC 0xe4 #define LPC_EN 0xe6 #define GEN2_DEC 0xec /* - * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or - * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! + * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge + * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. + * They all work the same way! */ static int __init preconfigure_through_82801(struct pci_dev *dev, - struct smsc_ircc_subsystem_configuration *conf) + struct + smsc_ircc_subsystem_configuration + *conf) { unsigned short tmpword; - int ret; + unsigned char tmpbyte; - IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); - pci_write_config_byte(dev, COM_DEC, 0x10); + IRDA_MESSAGE("Setting up Intel 82801 controller and SMSC device\n"); + /* + * Select the range for the COMA COM port (SIR) + * Register COM_DEC: + * Bit 7: reserved + * Bit 6-4, COMB decode range + * Bit 3: reserved + * Bit 2-0, COMA decode range + * + * Decode ranges: + * 000 = 0x3f8-0x3ff (COM1) + * 001 = 0x2f8-0x2ff (COM2) + * 010 = 0x220-0x227 + * 011 = 0x228-0x22f + * 100 = 0x238-0x23f + * 101 = 0x2e8-0x2ef (COM4) + * 110 = 0x338-0x33f + * 111 = 0x3e8-0x3ef (COM3) + */ + pci_read_config_byte(dev, COM_DEC, &tmpbyte); + tmpbyte &= 0xf8; /* mask COMA bits */ + switch(conf->sir_io) { + case 0x3f8: + tmpbyte |= 0x00; + break; + case 0x2f8: + tmpbyte |= 0x01; + break; + case 0x220: + tmpbyte |= 0x02; + break; + case 0x228: + tmpbyte |= 0x03; + break; + case 0x238: + tmpbyte |= 0x04; + break; + case 0x2e8: + tmpbyte |= 0x05; + break; + case 0x338: + tmpbyte |= 0x06; + break; + case 0x3e8: + tmpbyte |= 0x07; + break; + default: + tmpbyte |= 0x01; /* COM2 default */ + } + IRDA_DEBUG(1, "COM_DEC (write): 0x%02x\n", tmpbyte); + pci_write_config_byte(dev, COM_DEC, tmpbyte); - /* Enable LPC */ - pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ - tmpword &= 0xfffd; /* mask bit 1 */ - tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ + /* Enable Low Pin Count interface */ + pci_read_config_word(dev, LPC_EN, &tmpword); + /* These seem to be set up at all times, + * just make sure it is properly set. + */ + switch(conf->cfg_base) { + case 0x04e: + tmpword |= 0x2000; + break; + case 0x02e: + tmpword |= 0x1000; + break; + case 0x062: + tmpword |= 0x0800; + break; + case 0x060: + tmpword |= 0x0400; + break; + default: + IRDA_WARNING("Uncommon I/O base address: 0x%04x\n", + conf->cfg_base); + break; + } + tmpword &= 0xfffd; /* disable LPC COMB */ + tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ + IRDA_DEBUG(1, "LPC_EN (write): 0x%04x\n", tmpword); pci_write_config_word(dev, LPC_EN, tmpword); - /* Setup DMA */ - pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ - pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ + /* + * Configure LPC DMA channel + * PCI_DMA_C bits: + * Bit 15-14: DMA channel 7 select + * Bit 13-12: DMA channel 6 select + * Bit 11-10: DMA channel 5 select + * Bit 9-8: Reserved + * Bit 7-6: DMA channel 3 select + * Bit 5-4: DMA channel 2 select + * Bit 3-2: DMA channel 1 select + * Bit 1-0: DMA channel 0 select + * 00 = Reserved value + * 01 = PC/PCI DMA + * 10 = Reserved value + * 11 = LPC I/F DMA + */ + pci_read_config_word(dev, PCI_DMA_C, &tmpword); + switch(conf->fir_dma) { + case 0x07: + tmpword |= 0xc000; + break; + case 0x06: + tmpword |= 0x3000; + break; + case 0x05: + tmpword |= 0x0c00; + break; + case 0x03: + tmpword |= 0x00c0; + break; + case 0x02: + tmpword |= 0x0030; + break; + case 0x01: + tmpword |= 0x000c; + break; + case 0x00: + tmpword |= 0x0003; + break; + default: + break; /* do not change settings */ + } + IRDA_DEBUG(1, "PCI_DMA_C (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, PCI_DMA_C, tmpword); + + /* + * GEN2_DEC bits: + * Bit 15-4: Generic I/O range + * Bit 3-1: reserved (read as 0) + * Bit 0: enable GEN2 range on LPC I/F + */ + tmpword = conf->fir_io & 0xfff8; + tmpword |= 0x0001; + IRDA_DEBUG(1, "GEN2_DEC (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, GEN2_DEC, tmpword); /* Pre-configure chip */ - ret = preconfigure_smsc_chip(conf); + return preconfigure_smsc_chip(conf); +} - /* Disable LPC */ - pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ - tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ - pci_write_config_word(dev, LPC_EN, tmpword); - return ret; +/* + * Pre-configure a certain port on the ALi 1533 bridge. + * This is based on reverse-engineering since ALi does not + * provide any data sheet for the 1533 chip. + */ +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port) +{ + unsigned char reg; + /* These bits obviously control the different ports */ + unsigned char mask; + unsigned char tmpbyte; + + switch(port) { + case 0x0130: + case 0x0178: + reg = 0xb0; + mask = 0x80; + break; + case 0x03f8: + reg = 0xb4; + mask = 0x80; + break; + case 0x02f8: + reg = 0xb4; + mask = 0x30; + break; + case 0x02e8: + reg = 0xb4; + mask = 0x08; + break; + default: + IRDA_ERROR("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", port); + return; + } + + pci_read_config_byte(dev, reg, &tmpbyte); + /* Turn on the right bits */ + tmpbyte |= mask; + pci_write_config_byte(dev, reg, tmpbyte); + IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); + return; } static int __init preconfigure_through_ali(struct pci_dev *dev, - struct smsc_ircc_subsystem_configuration *conf) + struct + smsc_ircc_subsystem_configuration + *conf) { - /* TODO: put in ALi 1533 configuration here. */ - IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); - return -ENODEV; + /* Configure the two ports on the ALi 1533 */ + preconfigure_ali_port(dev, conf->sir_io); + preconfigure_ali_port(dev, conf->fir_io); + + /* Pre-configure chip */ + return preconfigure_smsc_chip(conf); } static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, @@ -2552,9 +2756,10 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, struct smsc_ircc_subsystem_configuration *conf; /* - * Cache the subsystem vendor/device: some manufacturers fail to set - * this for all components, so we save it in case there is just - * 0x0000 0x0000 on the device we want to check. + * Cache the subsystem vendor/device: + * some manufacturers fail to set this for all components, + * so we save it in case there is just 0x0000 0x0000 on the + * device we want to check. */ if (dev->subsystem_vendor != 0x0000U) { ss_vendor = dev->subsystem_vendor; @@ -2564,13 +2769,20 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, for( ; conf->subvendor; conf++) { if(conf->vendor == dev->vendor && conf->device == dev->device && - conf->subvendor == ss_vendor && /* Sometimes these are cached values */ - (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { - struct smsc_ircc_subsystem_configuration tmpconf; + conf->subvendor == ss_vendor && + /* Sometimes these are cached values */ + (conf->subdevice == ss_device || + conf->subdevice == 0xffff)) { + struct smsc_ircc_subsystem_configuration + tmpconf; - memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); + memcpy(&tmpconf, conf, + sizeof(struct smsc_ircc_subsystem_configuration)); - /* Override the default values with anything passed in as parameter */ + /* + * Override the default values with anything + * passed in as parameter + */ if (ircc_cfg != 0) tmpconf.cfg_base = ircc_cfg; if (ircc_fir != 0) diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 883cf7da10f..b5328b0ff92 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -410,103 +410,6 @@ config WAN_ROUTER_DRIVERS If unsure, say N. -config VENDOR_SANGOMA - tristate "Sangoma WANPIPE(tm) multiprotocol cards" - depends on WAN_ROUTER_DRIVERS && WAN_ROUTER && (PCI || ISA) && BROKEN - ---help--- - Driver for S514-PCI/ISA Synchronous Data Link Adapters (SDLA). - - WANPIPE from Sangoma Technologies Inc. <http://www.sangoma.com/> - is a family of intelligent multiprotocol WAN adapters with data - transfer rates up to 4Mbps. Cards support: - - - X.25, Frame Relay, PPP, Cisco HDLC protocols. - - - API for protocols like HDLC (LAPB), HDLC Streaming, X.25, - Frame Relay and BiSync. - - - Ethernet Bridging over Frame Relay protocol. - - - MULTILINK PPP - - - Async PPP (Modem Dialup) - - The next questions will ask you about the protocols you want - the driver to support. - - If you have one or more of these cards, say M to this option; - and read <file:Documentation/networking/wan-router.txt>. - - To compile this driver as a module, choose M here: the - module will be called wanpipe. - -config WANPIPE_CHDLC - bool "WANPIPE Cisco HDLC support" - depends on VENDOR_SANGOMA - ---help--- - Connect a WANPIPE card to a leased line using the Cisco HDLC. - - - Supports Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards - which allows user to build applications using the HDLC streaming API. - - - CHDLC Streaming MULTILINK PPP that can bind multiple WANPIPE T1 - cards into a single logical channel. - - Say Y and the Cisco HDLC support, HDLC streaming API and - MULTILINK PPP will be included in the driver. - -config WANPIPE_FR - bool "WANPIPE Frame Relay support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a Frame Relay network, or use Frame Relay - API to develop custom applications. - - Contains the Ethernet Bridging over Frame Relay feature, where - a WANPIPE frame relay link can be directly connected to the Linux - kernel bridge. The Frame Relay option is supported on S514-PCI - and S508-ISA cards. - - Say Y and the Frame Relay support will be included in the driver. - -config WANPIPE_X25 - bool "WANPIPE X.25 support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to an X.25 network. - - Includes the X.25 API support for custom applications over the - X.25 protocol. The X.25 option is supported on S514-PCI and - S508-ISA cards. - - Say Y and the X.25 support will be included in the driver. - -config WANPIPE_PPP - bool "WANPIPE PPP support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a leased line using Point-to-Point - Protocol (PPP). - - The PPP option is supported on S514-PCI/S508-ISA cards. - - Say Y and the PPP support will be included in the driver. - -config WANPIPE_MULTPPP - bool "WANPIPE Multi-Port PPP support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a leased line using Point-to-Point - Protocol (PPP). - - Uses in-kernel SyncPPP protocol over the Sangoma HDLC Streaming - adapter. In this case each Sangoma adapter port can support an - independent PPP connection. For example, a single Quad-Port PCI - adapter can support up to four independent PPP links. The PPP - option is supported on S514-PCI/S508-ISA cards. - - Say Y and the Multi-Port PPP support will be included in the driver. - config CYCLADES_SYNC tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" depends on WAN_ROUTER_DRIVERS && (PCI || ISA) diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index ce6c56b903e..823c6d5ab90 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -5,14 +5,6 @@ # Rewritten to use lists instead of if-statements. # -wanpipe-y := sdlamain.o sdla_ft1.o -wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o -wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o -wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o -wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o -wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o -wanpipe-objs := $(wanpipe-y) - cyclomx-y := cycx_main.o cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o cyclomx-objs := $(cyclomx-y) @@ -43,11 +35,6 @@ obj-$(CONFIG_LANMEDIA) += lmc/ obj-$(CONFIG_DLCI) += dlci.o obj-$(CONFIG_SDLA) += sdla.o -ifeq ($(CONFIG_WANPIPE_MULTPPP),y) - obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o -else - obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o -endif obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c deleted file mode 100644 index 496d29237e9..00000000000 --- a/drivers/net/wan/sdla_chdlc.c +++ /dev/null @@ -1,4428 +0,0 @@ -/***************************************************************************** -* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. -* -* Authors: Nenad Corbic <ncorbic@sangoma.com> -* Gideon Hack -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for -* 2.4.X kernels. -* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the -* HDLC streaming protocol -* Added a TTY Async serial driver over the -* Async protocol. -* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support -* Nov 13, 2000 Nenad Corbic Added true interface type encoding option. -* Tcpdump doesn't support CHDLC inteface -* types, to fix this "true type" option will set -* the interface type to RAW IP mode. -* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: -* Deny all and specify allowed requests. -* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the -* latest update. -* May 09, 2000 Nenad Corbic Option to bring down an interface -* upon disconnect. -* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. -* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. -* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. -* Feb 10, 2000 Gideon Hack Added ASYNC support. -* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and -* if_stats() functions. -* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, -* condition between if_open and isr. -* Jan 10, 2000 Nenad Corbic Added new socket API support. -* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels -* Nov 20, 1999 Nenad Corbic Fixed zero length API bug. -* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. -* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing -* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). -* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. -* Aug 07, 1998 David Fong Initial version. -*****************************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/wanrouter.h> /* WAN router definitions */ -#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <linux/if_arp.h> /* ARPHRD_* defines */ - - -#include <asm/uaccess.h> -#include <linux/inetdevice.h> -#include <linux/netdevice.h> - -#include <linux/in.h> /* sockaddr_in */ -#include <linux/inet.h> -#include <linux/if.h> -#include <asm/byteorder.h> /* htons(), etc. */ -#include <linux/sdlapci.h> -#include <asm/io.h> - -#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ -#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ - -#include <linux/if_wanpipe_common.h> /* Socket Driver common area */ -#include <linux/if_wanpipe.h> - -/* TTY Includes */ -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> - - -/****** Defines & Macros ****************************************************/ - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_CONFIG 0x10 - -#define MAX_IP_ERRORS 10 - -#define TTY_CHDLC_MAX_MTU 2000 -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) -#define MAX_BH_BUFF 10 - -//#define PRINT_DEBUG -#ifdef PRINT_DEBUG -#define dbg_printk(format, a...) printk(format, ## a) -#else -#define dbg_printk(format, a...) -#endif - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - wanpipe_common_t common; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - u32 ip_local; - u32 ip_remote; - u32 ip_local_tmp; - u32 ip_remote_tmp; - u8 ip_error; - u8 config_chdlc; - u8 config_chdlc_timeout; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - - bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - unsigned char interface_down; - - /* Polling work queue entry. Each interface - * has its own work queue entry, which is used - * to defer events from the interrupt */ - struct work_struct poll_work; - struct timer_list poll_delay_timer; - - u8 gateway; - u8 true_if_encoding; - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -/* variable for tracking how many interfaces to open for WANPIPE on the - two ports */ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); - -/* Network device interface */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len); - -static int if_rebuild_hdr (struct sk_buff *skb); -static struct net_device_stats* if_stats(struct net_device* dev); - -static int if_send(struct sk_buff* skb, struct net_device* dev); - -/* CHDLC Firmware interface functions */ -static int chdlc_configure (sdla_t* card, void* data); -static int chdlc_comm_enable (sdla_t* card); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); -static int chdlc_send (sdla_t* card, void* data, unsigned len); -static int chdlc_read_comm_err_stats (sdla_t* card); -static int chdlc_read_op_stats (sdla_t* card); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); - - -static int chdlc_disable_comm_shutdown (sdla_t *card); -static void if_tx_timeout(struct net_device *dev); - -/* Miscellaneous CHDLC Functions */ -static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff( sdla_t* card); -static int process_chdlc_exception(sdla_t *card); -static int process_global_exception(sdla_t *card); -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area); -static int configure_ip (sdla_t* card); -static int unconfigure_ip (sdla_t* card); -static void process_route(sdla_t *card); -static void port_set_state (sdla_t *card, int); -static int config_chdlc (sdla_t *card); -static void disable_comm (sdla_t *card); - -static void trigger_chdlc_poll(struct net_device *dev); -static void chdlc_poll(struct net_device *dev); -static void chdlc_poll_delay (unsigned long dev_ptr); - - -/* Miscellaneous asynchronous interface Functions */ -static int set_asy_config (sdla_t* card); -static int asy_comm_enable (sdla_t* card); - -/* Interrupt handlers */ -static void wpc_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void timer_intr(sdla_t *); - -/* Bottom half handlers */ -static void chdlc_work(struct net_device *dev); -static int chdlc_work_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - -/* Miscellaneous functions */ -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, - struct sk_buff *skb); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card); -static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static unsigned short calc_checksum (char *, int); -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); - - -static int Intr_test_counter; - -/* TTY Global Definitions */ - -#define NR_PORTS 4 -#define WAN_TTY_MAJOR 226 -#define WAN_TTY_MINOR 0 - -#define WAN_CARD(port) (tty_card_map[port]) -#define MIN_PORT 0 -#define MAX_PORT NR_PORTS-1 - -#define CRC_LENGTH 2 - -static int wanpipe_tty_init(sdla_t *card); -static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); -static void wanpipe_tty_trigger_poll(sdla_t *card); - -static struct tty_driver serial_driver; -static int tty_init_cnt=0; - -static struct serial_state rs_table[NR_PORTS]; - -static char tty_driver_mode=WANOPT_TTY_SYNC; - -static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", - "CRTSCTS XONXOFF-RX","XONXOFF-TX", - "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; -static char *p_decode[] = {"NONE","ODD","EVEN"}; - -static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; - - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpc_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - unsigned long max_permitted_baud = 0; - SHARED_MEMORY_INFO_STRUCT *flags; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_CHDLC) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Find out which Port to use */ - if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ - if (card->next){ - - if (conf->comm_port != card->next->u.c.comm_port){ - card->u.c.comm_port = conf->comm_port; - }else{ - printk(KERN_INFO "%s: ERROR - %s port used!\n", - card->wandev.name, PORT(conf->comm_port)); - return -EINVAL; - } - }else{ - card->u.c.comm_port = conf->comm_port; - } - }else{ - printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", - card->wandev.name); - return -EINVAL; - } - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + - SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; - } - }else{ - /* for a S514 adapter, set a pointer to the actual mailbox in the */ - /* allocated virtual memory area */ - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - }else{ - card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; - } - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if ((jiffies - timeout) > 1*HZ) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", - card->devname, u.str); - - card->isr = &wpc_isr; - card->poll = NULL; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = NULL; - card->wandev.udp_port = conf->udp_port; - card->disable_comm = &disable_comm; - card->wandev.new_if_cnt = 0; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = conf->ttl; - card->wandev.interface = conf->interface; - - if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& - card->hw.type != SDLA_S514){ - printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", - card->devname, PORT(card->u.c.comm_port)); - return -EIO; - } - - card->wandev.clocking = conf->clocking; - - port_num = card->u.c.comm_port; - - /* in API mode, we can configure for "receive only" buffering */ - if(card->hw.type == SDLA_S514) { - card->u.c.receive_only = conf->receive_only; - if(conf->receive_only) { - printk(KERN_INFO - "%s: Configured for 'receive only' mode\n", - card->devname); - } - } - - /* Setup Port Bps */ - - if(card->wandev.clocking) { - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - /* For Primary Port 0 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - PRI_MAX_BAUD_RATE_S514 : - PRI_MAX_BAUD_RATE_S508; - - }else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - SEC_MAX_BAUD_RATE_S514 : - SEC_MAX_BAUD_RATE_S508; - } - - if(conf->bps > max_permitted_baud) { - conf->bps = max_permitted_baud; - printk(KERN_INFO "%s: Baud too high!\n", - card->wandev.name); - printk(KERN_INFO "%s: Baud rate set to %lu bps\n", - card->wandev.name, max_permitted_baud); - } - card->wandev.bps = conf->bps; - }else{ - card->wandev.bps = 0; - } - - /* Setup the Port MTU */ - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - - /* For Primary Port 0 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - if(card->hw.type != SDLA_S514) - enable_irq(card->hw.irq); - - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - flags = card->u.c.flags; - - /* This is for the ports link state */ - card->wandev.state = WAN_DUALPORT; - card->u.c.state = WAN_DISCONNECTED; - - - if (!card->wandev.piggyback){ - int err; - - /* Perform interrupt testing */ - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_INFO "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_INFO "%s: Please choose another interrupt\n", - card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - card->configured = 1; - } - - if ((card->tty_opt=conf->tty) == WANOPT_YES){ - int err; - card->tty_minor = conf->tty_minor; - - /* On ASYNC connections internal clocking - * is mandatory */ - if ((card->u.c.async_mode = conf->tty_mode)){ - card->wandev.clocking = 1; - } - err=wanpipe_tty_init(card); - if (err){ - return err; - } - }else{ - - - if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: " - "Failed to set interrupt triggers!\n", - card->devname); - return -EIO; - } - - /* Mask the Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } - - /* If we are using CHDLC in backup mode, this flag will - * indicate not to look for IP addresses in config_chdlc()*/ - card->u.c.backup = conf->backup; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics - * This procedure is called when updating the PROC file system and returns - * various communications statistics. These statistics are accumulated from 3 - * different locations: - * 1) The 'if_stats' recorded for the device. - * 2) Communication error statistics on the adapter. - * 3) CHDLC operational statistics on the adapter. - * The board level statistics are read during a timer interrupt. Note that we - * read the error and operational statistics during consecitive timer ticks so - * as to minimize the time that we are inside the interrupt handler. - * - */ -static int update(struct wan_device* wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile chdlc_private_area_t* chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags; - unsigned long timeout; - - /* sanity checks */ - if((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if(wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* more sanity checks */ - if(!card->u.c.flags) - return -ENODEV; - - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) - return -EAGAIN; - - if((dev=card->wandev.dev) == NULL) - return -ENODEV; - - if((chdlc_priv_area=dev->priv) == NULL) - return -ENODEV; - - flags = card->u.c.flags; - if(chdlc_priv_area->update_comms_stats){ - return -EAGAIN; - } - - /* we will need 2 timer interrupts to complete the */ - /* reading of the statistics */ - chdlc_priv_area->update_comms_stats = 2; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies; - for(;;) { - if(chdlc_priv_area->update_comms_stats == 0) - break; - if ((jiffies - timeout) > (1 * HZ)){ - chdlc_priv_area->update_comms_stats = 0; - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - chdlc_private_area_t* chdlc_priv_area; - - - printk(KERN_INFO "%s: Configuring Interface: %s\n", - card->devname, conf->name); - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); - - if(chdlc_priv_area == NULL) - return -ENOMEM; - - memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - - chdlc_priv_area->card = card; - chdlc_priv_area->common.sk = NULL; - chdlc_priv_area->common.func = NULL; - - /* initialize data */ - strcpy(card->u.c.if_name, conf->name); - - if(card->wandev.new_if_cnt > 0) { - kfree(chdlc_priv_area); - return -EEXIST; - } - - card->wandev.new_if_cnt++; - - chdlc_priv_area->TracingEnabled = 0; - chdlc_priv_area->route_status = NO_ROUTE; - chdlc_priv_area->route_removed = 0; - - card->u.c.async_mode = conf->async_mode; - - /* setup for asynchronous mode */ - if(conf->async_mode) { - printk(KERN_INFO "%s: Configuring for asynchronous mode\n", - wandev->name); - - if(card->u.c.comm_port == WANOPT_PRI) { - printk(KERN_INFO - "%s:Asynchronous mode on secondary port only\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - if(strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO - "%s: Running in WANIPE Async Mode\n", wandev->name); - card->u.c.usedby = WANPIPE; - }else{ - card->u.c.usedby = API; - } - - if(!card->wandev.clocking) { - printk(KERN_INFO - "%s: Asynch. clocking must be 'Internal'\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - if((card->wandev.bps < MIN_ASY_BAUD_RATE) || - (card->wandev.bps > MAX_ASY_BAUD_RATE)) { - printk(KERN_INFO "%s: Selected baud rate is invalid.\n", - wandev->name); - printk(KERN_INFO "Must be between %u and %u bps.\n", - MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); - kfree(chdlc_priv_area); - return -EINVAL; - } - - card->u.c.api_options = 0; - if (conf->asy_data_trans == WANOPT_YES) { - card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; - } - - card->u.c.protocol_options = 0; - if (conf->rts_hs_for_receive == WANOPT_YES) { - card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; - } - if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { - card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; - } - if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; - } - if (conf->dcd_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; - } - if (conf->cts_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; - } - - card->u.c.tx_bits_per_char = conf->tx_bits_per_char; - card->u.c.rx_bits_per_char = conf->rx_bits_per_char; - card->u.c.stop_bits = conf->stop_bits; - card->u.c.parity = conf->parity; - card->u.c.break_timer = conf->break_timer; - card->u.c.inter_char_timer = conf->inter_char_timer; - card->u.c.rx_complete_length = conf->rx_complete_length; - card->u.c.xon_char = conf->xon_char; - - } else { /* setup for synchronous mode */ - - card->u.c.protocol_options = 0; - if (conf->ignore_dcd == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; - } - if (conf->ignore_cts == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; - } - - if (conf->ignore_keepalive == WANOPT_YES) { - card->u.c.protocol_options |= - IGNORE_KPALV_FOR_LINK_STAT; - card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; - card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; - card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; - - } else { /* Do not ignore keepalives */ - card->u.c.kpalv_tx = - ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) - >= 0) ? - min_t(unsigned int, conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : - DEFAULT_Tx_KPALV_TIMER; - - card->u.c.kpalv_rx = - ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) - >= 0) ? - min_t(unsigned int, conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : - DEFAULT_Rx_KPALV_TIMER; - - card->u.c.kpalv_err = - ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) - >= 0) ? - min_t(unsigned int, conf->keepalive_err_margin, - MAX_KPALV_ERR_TOL) : - DEFAULT_KPALV_ERR_TOL; - } - - /* Setup slarp timer to control delay between slarps */ - card->u.c.slarp_timer = - ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? - min_t(unsigned int, conf->slarp_timer, MAX_SLARP_REQ_TIMER) : - DEFAULT_SLARP_REQ_TIMER; - - if (conf->hdlc_streaming == WANOPT_YES) { - printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", - wandev->name); - card->u.c.protocol_options = HDLC_STREAMING_MODE; - } - - if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ - printk(KERN_INFO - "%s: Enabling, true interface type encoding.\n", - card->devname); - } - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - - printk(KERN_INFO "%s: Running in WANPIPE mode!\n", - wandev->name); - card->u.c.usedby = WANPIPE; - - /* Option to bring down the interface when - * the link goes down */ - if (conf->if_down){ - set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); - printk(KERN_INFO - "%s: Dynamic interface configuration enabled\n", - card->devname); - } - - } else if( strcmp(conf->usedby, "API") == 0) { - card->u.c.usedby = API; - printk(KERN_INFO "%s: Running in API mode !\n", - wandev->name); - } - } - - /* Tells us that if this interface is a - * gateway or not */ - if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,card->u.c.if_name); - } - - /* Get Multicast Information */ - chdlc_priv_area->mc = conf->mc; - - /* prepare network device data space for registration */ - strcpy(dev->name,card->u.c.if_name); - - dev->init = &if_init; - dev->priv = chdlc_priv_area; - - /* Initialize the polling work routine */ - INIT_WORK(&chdlc_priv_area->poll_work, (void*)(void*)chdlc_poll, dev); - - /* Initialize the polling delay timer */ - init_timer(&chdlc_priv_area->poll_delay_timer); - chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; - chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; - - printk(KERN_INFO "\n"); - - return 0; -} - - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Mulitcasting if user selected */ - if (chdlc_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - if (chdlc_priv_area->true_if_encoding){ - dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ - }else{ - dev->type = ARPHRD_PPP; - } - - dev->mtu = card->wandev.mtu; - /* for API usage, add the API header size to the requested MTU size */ - if(card->u.c.usedby == API) { - dev->mtu += sizeof(api_tx_hdr_t); - } - - dev->hard_header_len = CHDLC_HDR_LEN; - - /* Initialize hardware parameters */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length - * If too low packets will not be retransmitted - * by stack. - */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct timeval tv; - int err = 0; - - /* Only one open per interface is allowed */ - - if (netif_running(dev)) - return -EBUSY; - - /* Initialize the work queue entry */ - chdlc_priv_area->tq_working=0; - - INIT_WORK(&chdlc_priv_area->common.wanpipe_work, - (void *)(void *)chdlc_work, dev); - - /* Allocate and initialize BH circular buffer */ - /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ - chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); - memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); - atomic_set(&chdlc_priv_area->bh_buff_used, 0); - - do_gettimeofday(&tv); - chdlc_priv_area->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - wanpipe_open(card); - - /* TTY is configured during wanpipe_set_termios - * call, not here */ - if (card->tty_opt) - return err; - - set_bit(0,&chdlc_priv_area->config_chdlc); - chdlc_priv_area->config_chdlc_timeout=jiffies; - - /* Start the CHDLC configuration after 1sec delay. - * This will give the interface initilization time - * to finish its configuration */ - mod_timer(&chdlc_priv_area->poll_delay_timer, jiffies + HZ); - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last close, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - - if (chdlc_priv_area->bh_head){ - int i; - struct sk_buff *skb; - - for (i=0; i<(MAX_BH_BUFF+1); i++){ - skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; - if (skb != NULL){ - dev_kfree_skb_any(skb); - } - } - kfree(chdlc_priv_area->bh_head); - chdlc_priv_area->bh_head=NULL; - } - - netif_stop_queue(dev); - wanpipe_close(card); - del_timer(&chdlc_priv_area->poll_delay_timer); - return 0; -} - -static void disable_comm (sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - chdlc_disable_comm_shutdown (card); - }else{ - flags->interrupt_info_struct.interrupt_permission = 0; - } - - if (!tty_init_cnt) - return; - - if (card->tty_opt){ - struct serial_state * state; - if (!(--tty_init_cnt)){ - int e1; - serial_driver.refcount=0; - - if ((e1 = tty_unregister_driver(&serial_driver))) - printk("SERIAL: failed to unregister serial driver (%d)\n", - e1); - printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", - card->devname,WAN_TTY_MAJOR); - } - card->tty=NULL; - tty_card_map[card->tty_minor]=NULL; - state = &rs_table[card->tty_minor]; - memset(state, 0, sizeof(*state)); - } - return; -} - - -/*============================================================================ - * Build media header. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If packet type is not - * supported, set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len) -{ - skb->protocol = htons(type); - - return CHDLC_HDR_LEN; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - netif_wake_queue (dev); -} - - - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff *skb) -{ - return 1; -} - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - int udp_type = 0; - unsigned long smp_flags; - int err=0; - - netif_stop_queue(dev); - - if (skb == NULL){ - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - - netif_wake_queue(dev); - return 0; - } - - if (ntohs(skb->protocol) != htons(PVC_PROT)){ - - /* check the udp packet type */ - - udp_type = udp_pkt_type(skb, card); - - if (udp_type == UDP_CPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)){ - chdlc_int->interrupt_permission |= - APP_INT_ON_TIMER; - } - netif_start_queue(dev); - return 0; - } - - /* check to see if the source IP address is a broadcast or */ - /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - if(card->u.c.state != WAN_CONNECTED){ - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - - }else if(!skb->protocol){ - ++card->wandev.stats.tx_errors; - netif_start_queue(dev); - - }else { - void* data = skb->data; - unsigned len = skb->len; - unsigned char attr; - - /* If it's an API packet pull off the API - * header. Also check that the packet size - * is larger than the API header - */ - if (card->u.c.usedby == API){ - api_tx_hdr_t* api_tx_hdr; - - /* discard the frame if we are configured for */ - /* 'receive only' mode or if there is no data */ - if (card->u.c.receive_only || - (len <= sizeof(api_tx_hdr_t))) { - - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - api_tx_hdr = (api_tx_hdr_t *)data; - attr = api_tx_hdr->attr; - data += sizeof(api_tx_hdr_t); - len -= sizeof(api_tx_hdr_t); - } - - if(chdlc_send(card, data, len)) { - netif_stop_queue(dev); - }else{ - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - - netif_start_queue(dev); - - dev->trans_start = jiffies; - } - } - -if_send_exit_crit: - - if (!(err=netif_queue_stopped(dev))) { - dev_kfree_skb_any(skb); - }else{ - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 12); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* fill in UDP reply */ - c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - c_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = c_udp_pkt->udp_pkt.udp_src_port; - c_udp_pkt->udp_pkt.udp_src_port = - c_udp_pkt->udp_pkt.udp_dst_port; - c_udp_pkt->udp_pkt.udp_dst_port = temp; - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - - /* calculate UDP checksum */ - c_udp_pkt->udp_pkt.udp_checksum = 0; - c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - c_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = c_udp_pkt->ip_pkt.ip_src_address; - c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; - c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - c_udp_pkt->ip_pkt.hdr_checksum = 0; - c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i <len; i+=2 ) { - memcpy(&temp,&data[i],2); - sum += (unsigned long)temp; - } - - while (sum >> 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats* if_stats(struct net_device* dev) -{ - sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area; - - if ((chdlc_priv_area=dev->priv) == NULL) - return NULL; - - my_card = chdlc_priv_area->card; - return &my_card->wandev.stats; -} - - -/****** Cisco HDLC Firmware Interface Functions *******************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*----------------------------------------------------------------------------- - * Configure CHDLC firmware. - */ -static int chdlc_configure (sdla_t* card, void* data) -{ - int err; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); - - mailbox->buffer_length = data_length; - memcpy(mailbox->data, data, data_length); - mailbox->command = SET_CHDLC_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) chdlc_error (card, err, mailbox); - - return err; -} - - -/*============================================================================ - * Set interrupt mode -- HDLC Version. - */ - -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - int_data->CHDLC_interrupt_triggers = mode; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - return err; -} - - -/*=========================================================== - * chdlc_disable_comm_shutdown - * - * Shutdown() disables the communications. We must - * have a sparate functions, because we must not - * call chdlc_error() hander since the private - * area has already been replaced */ - -static int chdlc_disable_comm_shutdown (sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - /* Disable Interrutps */ - int_data->CHDLC_interrupt_triggers = 0; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - /* Disable Communications */ - - if (card->u.c.async_mode) { - mb->command = DISABLE_ASY_COMMUNICATIONS; - }else{ - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - } - - mb->buffer_length = 0; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - card->u.c.comm_enabled = 0; - - return 0; -} - -/*============================================================================ - * Enable communications. - */ - -static int chdlc_comm_enable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - else - card->u.c.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Read communication error statistics. - */ -static int chdlc_read_comm_err_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_COMMS_ERROR_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Read CHDLC operational statistics. - */ -static int chdlc_read_op_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_OPERATIONAL_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Update communications error and general packet statistics. - */ -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - COMMS_ERROR_STATS_STRUCT* err_stats; - CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; - - /* on the first timer interrupt, read the comms error statistics */ - if(chdlc_priv_area->update_comms_stats == 2) { - if(chdlc_read_comm_err_stats(card)) - return 1; - err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_over_errors = - err_stats->Rx_overrun_err_count; - card->wandev.stats.rx_crc_errors = - err_stats->CRC_err_count; - card->wandev.stats.rx_frame_errors = - err_stats->Rx_abort_count; - card->wandev.stats.rx_fifo_errors = - err_stats->Rx_dis_pri_bfrs_full_count; - card->wandev.stats.rx_missed_errors = - card->wandev.stats.rx_fifo_errors; - card->wandev.stats.tx_aborted_errors = - err_stats->sec_Tx_abort_count; - } - - /* on the second timer interrupt, read the operational statistics */ - else { - if(chdlc_read_op_stats(card)) - return 1; - op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_length_errors = - (op_stats->Rx_Data_discard_short_count + - op_stats->Rx_Data_discard_long_count); - } - - return 0; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int chdlc_send (sdla_t* card, void* data, unsigned len) -{ - CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; - - if (txbuf->opp_flag) - return 1; - - sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); - - txbuf->frame_length = len; - txbuf->opp_flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.c.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.c.txbuf_last) - card->u.c.txbuf = card->u.c.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_INFO "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - - -/********** Bottom Half Handlers ********************************************/ - -/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. - * DO NOT INSERT ANY CODE HERE, NOTICE THE - * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE - * DOING */ - -static void chdlc_work(struct net_device * dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb != NULL){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - chdlc_work_cleanup(dev); - continue; - } - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for another - * try */ - atomic_set(&chan->common.receive_block,1); - return; - }else{ - chdlc_work_cleanup(dev); - } - }else{ - chdlc_work_cleanup(dev); - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -static int chdlc_work_cleanup(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == MAX_BH_BUFF){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - /* Check for full */ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == MAX_BH_BUFF){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - return 0; -} - -/* END OF API BH Support */ - - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * Cisco HDLC interrupt service routine. - */ -static void wpc_isr (sdla_t* card) -{ - struct net_device* dev; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i; - sdla_t *my_card; - - - /* Check for which port the interrupt has been generated - * Since Secondary Port is piggybacking on the Primary - * the check must be done here. - */ - - flags = card->u.c.flags; - if (!flags->interrupt_info_struct.interrupt_type){ - /* Check for a second port (piggybacking) */ - if ((my_card = card->next)){ - flags = my_card->u.c.flags; - if (flags->interrupt_info_struct.interrupt_type){ - card = my_card; - card->isr(card); - return; - } - } - } - - flags = card->u.c.flags; - card->in_isr = 1; - dev = card->wandev.dev; - - /* If we get an interrupt with no network device, stop the interrupts - * and issue an error */ - if (!card->tty_opt && !dev && - flags->interrupt_info_struct.interrupt_type != - COMMAND_COMPLETE_APP_INT_PEND){ - - goto isr_done; - } - - /* if critical due to peripheral operations - * ie. update() or getstats() then reset the interrupt and - * wait for the board to retrigger. - */ - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "ISR CRIT TO PERI\n"); - goto isr_done; - } - - /* On a 508 Card, if critical due to if_send - * Major Error !!! */ - if(card->hw.type != SDLA_S514) { - if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %lx\n", - card->devname, card->wandev.critical); - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; - return; - } - } - - switch(flags->interrupt_info_struct.interrupt_type) { - - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - rx_intr(card); - break; - - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; - - if (card->tty_opt){ - wanpipe_tty_trigger_poll(card); - break; - } - - if (dev && netif_queue_stopped(dev)){ - if (card->u.c.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - break; - - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - ++ Intr_test_counter; - break; - - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - process_chdlc_exception(card); - break; - - case GLOBAL_EXCEP_COND_APP_INT_PEND: - process_global_exception(card); - break; - - case TIMER_APP_INT_PEND: - timer_intr(card); - break; - - default: - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, - flags->interrupt_info_struct.interrupt_type); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - break; - } - -isr_done: - - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; - return; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr (sdla_t* card) -{ - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - unsigned addr = rxbuf->ptr_data_bfr; - void *buf; - int i,udp_type; - - if (rxbuf->opp_flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->opp_flag); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it measn that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - chdlc_set_intr_mode(card,0); - return; - } - - len = rxbuf->frame_length; - - if (card->tty_opt){ - - if (rxbuf->error_flag){ - goto rx_exit; - } - - if (len <= CRC_LENGTH){ - goto rx_exit; - } - - if (!card->u.c.async_mode){ - len -= CRC_LENGTH; - } - - wanpipe_tty_receive(card,addr,len); - goto rx_exit; - } - - dev = card->wandev.dev; - - if (!dev){ - goto rx_exit; - } - - if (!netif_running(dev)) - goto rx_exit; - - chdlc_priv_area = dev->priv; - - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb == NULL) { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++card->wandev.stats.rx_dropped; - goto rx_exit; - } - - /* Copy data to the socket buffer */ - if((addr + len) > card->u.c.rx_top + 1) { - unsigned tmp = card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - skb->protocol = htons(ETH_P_IP); - - card->wandev.stats.rx_packets ++; - card->wandev.stats.rx_bytes += skb->len; - udp_type = udp_pkt_type( skb, card ); - - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. - interrupt_permission |= - APP_INT_ON_TIMER; - } - } else if(card->u.c.usedby == API) { - - api_rx_hdr_t* api_rx_hdr; - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->error_flag = rxbuf->error_flag; - api_rx_hdr->time_stamp = rxbuf->time_stamp; - - skb->protocol = htons(PVC_PROT); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->pkt_type = WAN_PACKET_DATA; - - bh_enqueue(dev, skb); - - if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)) - wanpipe_queue_work(&chdlc_priv_area->common.wanpipe_work); - }else{ - /* FIXME: we should check to see if the received packet is a - multicast packet so that we can increment the multicast - statistic - ++ chdlc_priv_area->if_stats.multicast; - */ - /* Pass it up the protocol stack */ - - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - dev->last_rx = jiffies; - } - -rx_exit: - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->opp_flag = 0x00; - card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last){ - card->u.c.rxmb = card->u.c.rxbuf_base; - } -} - -/*============================================================================ - * Timer interrupt handler. - * The timer interrupt is used for two purposes: - * 1) Processing udp calls from 'cpipemon'. - * 2) Reading board-level statistics for updating the proc file system. - */ -void timer_intr(sdla_t *card) -{ - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area = NULL; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - - if ((dev = card->wandev.dev)==NULL){ - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - return; - } - - chdlc_priv_area = dev->priv; - - if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { - if (!config_chdlc(card)){ - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - } - - /* process a udp call if pending */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { - process_udp_mgmt_pkt(card, dev, - chdlc_priv_area); - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - /* read the communications statistics if required */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - update_comms_stats(card, chdlc_priv_area); - if(!(-- chdlc_priv_area->update_comms_stats)) { - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* only disable the timer interrupt if there are no udp or statistic */ - /* updates pending */ - if(!chdlc_priv_area->timer_int_enabled) { - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } -} - -/*------------------------------------------------------------------------------ - Miscellaneous Functions - - set_chdlc_config() used to set configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_chdlc_config(sdla_t* card) -{ - CHDLC_CONFIGURATION_STRUCT cfg; - - memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking){ - cfg.baud_rate = card->wandev.bps; - } - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - cfg.modem_status_timer = 100; - - cfg.CHDLC_protocol_options = card->u.c.protocol_options; - - if (card->tty_opt){ - cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; - } - - cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; - cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - - if (card->tty_opt){ - card->wandev.mtu = TTY_CHDLC_MAX_MTU; - } - cfg.max_CHDLC_data_field_length = card->wandev.mtu; - cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; - cfg.receive_keepalive_timer = card->u.c.kpalv_rx; - cfg.keepalive_error_tolerance = card->u.c.kpalv_err; - cfg.SLARP_request_timer = card->u.c.slarp_timer; - - if (cfg.SLARP_request_timer) { - cfg.IP_address = 0; - cfg.IP_netmask = 0; - - }else if (card->wandev.dev){ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - - struct in_device *in_dev = dev->ip_ptr; - - if(in_dev != NULL) { - struct in_ifaddr *ifa = in_dev->ifa_list; - - if (ifa != NULL ) { - cfg.IP_address = ntohl(ifa->ifa_local); - cfg.IP_netmask = ntohl(ifa->ifa_mask); - chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); - chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); - } - } - - /* FIXME: We must re-think this message in next release - if((cfg.IP_address & 0x000000FF) > 2) { - printk(KERN_WARNING "\n"); - printk(KERN_WARNING " WARNING:%s configured with an\n", - card->devname); - printk(KERN_WARNING " invalid local IP address.\n"); - printk(KERN_WARNING " Slarp pragmatics will fail.\n"); - printk(KERN_WARNING " IP address should be of the\n"); - printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); - } - */ - } - - return chdlc_configure(card, &cfg); -} - - -/*----------------------------------------------------------------------------- - set_asy_config() used to set asynchronous configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_asy_config(sdla_t* card) -{ - - ASY_CONFIGURATION_STRUCT cfg; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int err; - - memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking) - cfg.baud_rate = card->wandev.bps; - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - cfg.asy_API_options = card->u.c.api_options; - cfg.asy_protocol_options = card->u.c.protocol_options; - cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; - cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; - cfg.stop_bits = card->u.c.stop_bits; - cfg.parity = card->u.c.parity; - cfg.break_timer = card->u.c.break_timer; - cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; - cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; - cfg.XON_char = card->u.c.xon_char; - cfg.XOFF_char = card->u.c.xoff_char; - cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - - mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); - memcpy(mailbox->data, &cfg, mailbox->buffer_length); - mailbox->command = SET_ASY_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mailbox); - return err; -} - -/*============================================================================ - * Enable asynchronous communications. - */ - -static int asy_comm_enable (sdla_t* card) -{ - - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_ASY_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK && card->wandev.dev) - chdlc_error(card, err, mb); - - if (!err) - card->u.c.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Process global exception condition - */ -static int process_global_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int err; - - mbox->buffer_length = 0; - mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; - err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; - - if(err != CMD_TIMEOUT ){ - - switch(mbox->return_code) { - - case EXCEP_MODEM_STATUS_CHANGE: - - printk(KERN_INFO "%s: Modem status change\n", - card->devname); - - switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { - case (DCD_HIGH): - printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); - break; - case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); - break; - case ((DCD_HIGH | CTS_HIGH)): - printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); - break; - default: - printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); - break; - } - break; - - case EXCEP_TRC_DISABLED: - printk(KERN_INFO "%s: Line trace disabled\n", - card->devname); - break; - - case EXCEP_IRQ_TIMEOUT: - printk(KERN_INFO "%s: IRQ timeout occurred\n", - card->devname); - break; - - case 0x17: - if (card->tty_opt){ - if (card->tty && card->tty_open){ - printk(KERN_INFO - "%s: Modem Hangup Exception: Hanging Up!\n", - card->devname); - tty_hangup(card->tty); - } - break; - } - - /* If TTY is not used just drop throught */ - - default: - printk(KERN_INFO "%s: Global exception %x\n", - card->devname, mbox->return_code); - break; - } - } - return 0; -} - - -/*============================================================================ - * Process chdlc exception condition - */ -static int process_chdlc_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_EXCEPTION_CONDITION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if(err != CMD_TIMEOUT) { - - switch (err) { - - case EXCEP_LINK_ACTIVE: - port_set_state(card, WAN_CONNECTED); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_LINK_INACTIVE_MODEM: - port_set_state(card, WAN_DISCONNECTED); - unconfigure_ip(card); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_LINK_INACTIVE_KPALV: - port_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO "%s: Keepalive timer expired.\n", - card->devname); - unconfigure_ip(card); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_IP_ADDRESS_DISCOVERED: - if (configure_ip(card)) - return -1; - break; - - case EXCEP_LOOPBACK_CONDITION: - printk(KERN_INFO "%s: Loopback Condition Detected.\n", - card->devname); - break; - - case NO_CHDLC_EXCEP_COND_TO_REPORT: - printk(KERN_INFO "%s: No exceptions reported.\n", - card->devname); - break; - } - - } - return 0; -} - - -/*============================================================================ - * Configure IP from SLARP negotiation - * This adds dynamic routes when SLARP has provided valid addresses - */ - -static int configure_ip (sdla_t* card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area; - char err; - - if (!dev) - return 0; - - chdlc_priv_area = dev->priv; - - - /* set to discover */ - if(card->u.c.slarp_timer != 0x00) { - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_CONFIGURATION_STRUCT *cfg; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - return -1; - } - - cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; - chdlc_priv_area->IP_address = cfg->IP_address; - chdlc_priv_area->IP_netmask = cfg->IP_netmask; - - /* Set flag to add route */ - chdlc_priv_area->route_status = ADD_ROUTE; - - /* The idea here is to add the route in the poll routine. - This way, we aren't in interrupt context when adding routes */ - trigger_chdlc_poll(dev); - } - - return 0; -} - - -/*============================================================================ - * Un-Configure IP negotiated by SLARP - * This removes dynamic routes when the link becomes inactive. - */ - -static int unconfigure_ip (sdla_t* card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area; - - if (!dev) - return 0; - - chdlc_priv_area= dev->priv; - - if (chdlc_priv_area->route_status == ROUTE_ADDED) { - - /* Note: If this function is called, the - * port state has been DISCONNECTED. This state - * change will trigger a poll_disconnected - * function, that will check for this condition. - */ - chdlc_priv_area->route_status = REMOVE_ROUTE; - - } - return 0; -} - -/*============================================================================ - * Routine to add/remove routes - * Called like a polling routine when Routes are flagged to be added/removed. - */ - -static void process_route (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - unsigned char port_num; - chdlc_private_area_t *chdlc_priv_area = NULL; - u32 local_IP_addr = 0; - u32 remote_IP_addr = 0; - u32 IP_netmask, IP_addr; - int err = 0; - struct in_device *in_dev; - mm_segment_t fs; - struct ifreq if_info; - struct sockaddr_in *if_data1, *if_data2; - - chdlc_priv_area = dev->priv; - port_num = card->u.c.comm_port; - - /* Bug Fix Mar 16 2000 - * AND the IP address to the Mask before checking - * the last two bits. */ - - if((chdlc_priv_area->route_status == ADD_ROUTE) && - ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { - - printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); - - if(card->u.c.slarp_timer) { - u32 addr_net = htonl(chdlc_priv_area->IP_address); - - printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n", - card->devname, - NIPQUAD(addr_net)); - printk(KERN_INFO "%s: from remote station.\n", - card->devname); - - }else{ - u32 addr_net = htonl(chdlc_priv_area->IP_address); - - printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n", - card->devname, - NIPQUAD(addr_net)); - printk(KERN_INFO "%s: to remote station. Local\n", - card->devname); - printk(KERN_INFO "%s: IP address must be A.B.C.1\n", - card->devname); - printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname); - } - - /* remove the route due to the IP address error condition */ - chdlc_priv_area->route_status = REMOVE_ROUTE; - err = 1; - } - - /* If we are removing a route with bad IP addressing, then use the */ - /* locally configured IP addresses */ - if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) { - - /* do not remove a bad route that has already been removed */ - if(chdlc_priv_area->route_removed) { - return; - } - - in_dev = dev->ip_ptr; - - if(in_dev != NULL) { - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL ) { - local_IP_addr = ifa->ifa_local; - IP_netmask = ifa->ifa_mask; - } - } - }else{ - /* According to Cisco HDLC, if the point-to-point address is - A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa. - */ - IP_netmask = ntohl(chdlc_priv_area->IP_netmask); - remote_IP_addr = ntohl(chdlc_priv_area->IP_address); - - - /* If Netmask is 255.255.255.255 the local address - * calculation will fail. Default it back to 255.255.255.0 */ - if (IP_netmask == 0xffffffff) - IP_netmask &= 0x00ffffff; - - /* Bug Fix Mar 16 2000 - * AND the Remote IP address with IP netmask, instead - * of static netmask of 255.255.255.0 */ - local_IP_addr = (remote_IP_addr & IP_netmask) + - (~remote_IP_addr & ntohl(0x0003)); - - if(!card->u.c.slarp_timer) { - IP_addr = local_IP_addr; - local_IP_addr = remote_IP_addr; - remote_IP_addr = IP_addr; - } - } - - fs = get_fs(); /* Save file system */ - set_fs(get_ds()); /* Get user space block */ - - /* Setup a structure for adding/removing routes */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - switch (chdlc_priv_area->route_status) { - - case ADD_ROUTE: - - if(!card->u.c.slarp_timer) { - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = remote_IP_addr; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } else { - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = local_IP_addr; - if_data1->sin_family = AF_INET; - if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){ - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = remote_IP_addr; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } - } - - if(err) { - printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n", - card->devname, NIPQUAD(remote_IP_addr), err); - } else { - ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED; - printk(KERN_INFO "%s: Dynamic route added.\n", - card->devname); - printk(KERN_INFO "%s: Local IP addr : %u.%u.%u.%u\n", - card->devname, NIPQUAD(local_IP_addr)); - printk(KERN_INFO "%s: Remote IP addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(remote_IP_addr)); - chdlc_priv_area->route_removed = 0; - } - break; - - - case REMOVE_ROUTE: - - /* Change the local ip address of the interface to 0. - * This will also delete the destination route. - */ - if(!card->u.c.slarp_timer) { - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = 0; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } else { - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = 0; - if_data1->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFADDR,&if_info); - - } - if(err) { - printk(KERN_INFO - "%s: Remove route %u.%u.%u.%u failed, (err %d)\n", - card->devname, NIPQUAD(remote_IP_addr), - err); - } else { - ((chdlc_private_area_t *)dev->priv)->route_status = - NO_ROUTE; - printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n", - card->devname, NIPQUAD(local_IP_addr)); - chdlc_priv_area->route_removed = 1; - } - break; - } - - set_fs(fs); /* Restore file system */ - -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area) -{ - int udp_pkt_stored = 0; - - if(!chdlc_priv_area->udp_pkt_lgth && - (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { - chdlc_priv_area->udp_pkt_lgth = skb->len; - chdlc_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - -/*============================================================================= - * Process UDP management packet. - */ - -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short buffer_length, real_len; - unsigned long data_ptr; - unsigned data_length; - int udp_mgmt_req_valid = 1; - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - chdlc_udp_pkt_t *chdlc_udp_pkt; - struct timeval tv; - int err; - char ut_char; - - chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - - /* Only these commands are support for remote debugging. - * All others are not */ - switch(chdlc_udp_pkt->cblock.command) { - - case READ_GLOBAL_STATISTICS: - case READ_MODEM_STATUS: - case READ_CHDLC_LINK_STATUS: - case CPIPE_ROUTER_UP_TIME: - case READ_COMMS_ERROR_STATS: - case READ_CHDLC_OPERATIONAL_STATS: - - /* These two commands are executed for - * each request */ - case READ_CHDLC_CONFIGURATION: - case READ_CHDLC_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - chdlc_udp_pkt->cblock.buffer_length = 0; - - /* set return code */ - chdlc_udp_pkt->cblock.return_code = 0xCD; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,chdlc_udp_pkt->cblock.command); - } - - } else { - unsigned long trace_status_cfg_addr = 0; - TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; - TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; - - switch(chdlc_udp_pkt->cblock.command) { - - case CPIPE_ENABLE_TRACING: - if (!chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_ACTIVE; - /* Trace delay mode is not used because it slows - down transfer and results in a standoff situation - when there is a lot of data */ - - /* Configure the Trace based on user inputs */ - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= - chdlc_udp_pkt->data[0]; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_deactivation_timer = 4000; - - - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - card->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - /* Get the base address of the trace element list */ - mb->buffer_length = 0; - mb->command = READ_TRACE_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) - mb->data) -> ptr_trace_stat_el_cfg_struct; - - sdla_peek(&card->hw, trace_status_cfg_addr, - &trace_cfg_struct, sizeof(trace_cfg_struct)); - - chdlc_priv_area->start_trace_addr = trace_cfg_struct. - base_addr_trace_status_elements; - - chdlc_priv_area->number_trace_elements = - trace_cfg_struct.number_trace_status_elements; - - chdlc_priv_area->end_trace_addr = (unsigned long) - ((TRACE_STATUS_ELEMENT_STRUCT *) - chdlc_priv_area->start_trace_addr + - (chdlc_priv_area->number_trace_elements - 1)); - - chdlc_priv_area->base_addr_trace_buffer = - trace_cfg_struct.base_addr_trace_buffer; - - chdlc_priv_area->end_addr_trace_buffer = - trace_cfg_struct.end_addr_trace_buffer; - - chdlc_priv_area->curr_trace_addr = - trace_cfg_struct.next_trace_element_to_use; - - chdlc_priv_area->available_buffer_space = 2000 - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t) - - sizeof(trace_info_t); - } - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - chdlc_priv_area->TracingEnabled = 1; - break; - - - case CPIPE_DISABLE_TRACING: - if (chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_INACTIVE; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - break; - - - case CPIPE_GET_TRACE_INFO: - - if (!chdlc_priv_area->TracingEnabled) { - chdlc_udp_pkt->cblock.return_code = 1; - mb->buffer_length = 0; - break; - } - - chdlc_udp_pkt->trace_info.ismoredata = 0x00; - buffer_length = 0; /* offset of packet already occupied */ - - for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &chdlc_udp_pkt->data[buffer_length]; - - sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, - (unsigned char *)&trace_element_struct, - sizeof(TRACE_STATUS_ELEMENT_STRUCT)); - - if (trace_element_struct.opp_flag == 0x00) { - break; - } - - /* get pointer to real data */ - data_ptr = trace_element_struct.ptr_data_bfr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element_struct.trace_length; - }else{ - data_length = 0; - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - - if( (chdlc_priv_area->available_buffer_space - buffer_length) - < ( sizeof(trace_pkt_t) + data_length) ) { - - /* indicate there are more frames on board & exit */ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - break; - } - - trace_pkt->status = trace_element_struct.trace_type; - - trace_pkt->time_stamp = - trace_element_struct.trace_time_stamp; - - trace_pkt->real_length = - trace_element_struct.trace_length; - - /* see if we can fit the frame into the user buffer */ - real_len = trace_pkt->real_length; - - if (data_ptr == 0) { - trace_pkt->data_avail = 0x00; - } else { - unsigned tmp = 0; - - /* get the data from circular buffer - must check for end of buffer */ - trace_pkt->data_avail = 0x01; - - if ((data_ptr + real_len) > - chdlc_priv_area->end_addr_trace_buffer + 1){ - - tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; - sdla_peek(&card->hw, data_ptr, - trace_pkt->data,tmp); - data_ptr = chdlc_priv_area->base_addr_trace_buffer; - } - - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data[tmp], real_len - tmp); - } - - /* zero the opp flag to show we got the frame */ - ut_char = 0x00; - sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); - - /* now move onto the next frame */ - chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); - - /* check if we went over the last address */ - if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { - chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; - } - - if(trace_pkt->data_avail == 0x01) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += sizeof(trace_pkt_t); - - } /* For Loop */ - - if (frames == chdlc_priv_area->number_trace_elements){ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - chdlc_udp_pkt->trace_info.num_frames = frames; - - mb->buffer_length = buffer_length; - chdlc_udp_pkt->cblock.buffer_length = buffer_length; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - - break; - - - case CPIPE_FT1_READ_STATUS: - ((unsigned char *)chdlc_udp_pkt->data )[0] = - flags->FT1_info_struct.parallel_port_A_input; - - ((unsigned char *)chdlc_udp_pkt->data )[1] = - flags->FT1_info_struct.parallel_port_B_input; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - chdlc_udp_pkt->cblock.buffer_length = 2; - mb->buffer_length = 2; - break; - - case CPIPE_ROUTER_UP_TIME: - do_gettimeofday( &tv ); - chdlc_priv_area->router_up_time = tv.tv_sec - - chdlc_priv_area->router_start_time; - *(unsigned long *)&chdlc_udp_pkt->data = - chdlc_priv_area->router_up_time; - mb->buffer_length = sizeof(unsigned long); - chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long); - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - break; - - case FT1_MONITOR_STATUS_CTRL: - /* Enable FT1 MONITOR STATUS */ - if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || - (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { - - if( rCount++ != 0 ) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( chdlc_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - goto dflt_1; - - default: -dflt_1: - /* it's a board command */ - mb->command = chdlc_udp_pkt->cblock.command; - mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; - if (mb->buffer_length) { - memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> - data, mb->buffer_length); - } - /* run the command on the board */ - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - break; - } - - /* copy the result back to our buffer */ - memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); - - if (mb->buffer_length) { - memcpy(&chdlc_udp_pkt->data, &mb->data, - mb->buffer_length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - - len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - - /* Must check if we interrupted if_send() routine. The - * tx buffers might be used. If so drop the packet */ - if (!test_bit(SEND_CRIT,&card->wandev.critical)) { - - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - } - } - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf, chdlc_priv_area->udp_pkt_data, len); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - } - - chdlc_priv_area->udp_pkt_lgth = 0; - - return 0; -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ - -static void init_chdlc_tx_rx_buff( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; - CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; - char err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - if (card->wandev.dev){ - chdlc_error(card,err,mb); - } - return; - } - - if(card->hw.type == SDLA_S514) { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct)); - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - tx_config->base_addr_Tx_status_elements); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *) - card->u.c.txbuf_base + - (tx_config->number_Tx_status_elements - 1); - - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - rx_config->base_addr_Rx_status_elements); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *) - card->u.c.rxbuf_base + - (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - tx_config->next_Tx_status_element_to_use); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - rx_config->next_Rx_status_element_to_use); - } - else { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base - + (tx_config->number_Tx_status_elements - 1); - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base - + (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); - } - - /* Setup Actual Buffer Start and end addresses */ - card->u.c.rx_base = rx_config->base_addr_Rx_buffer; - card->u.c.rx_top = rx_config->end_addr_Rx_buffer; - -} - -/*============================================================================= - * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err,i; - - Intr_test_counter = 0; - - err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); - - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != CMD_OK) - chdlc_error(card, err, mb); - } - } - else { - return err; - } - - err = chdlc_set_intr_mode(card, 0); - - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. CPIPEAB ? - */ -static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) -{ - chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; - -#ifdef _WAN_UDP_DEBUG - printk(KERN_INFO "SIG %s = %s\n\ - UPP %x = %x\n\ - PRT %x = %x\n\ - REQ %i = %i\n\ - 36 th = %x 37th = %x\n", - chdlc_udp_pkt->wp_mgmt.signature, - UDPMGMT_SIGNATURE, - chdlc_udp_pkt->udp_pkt.udp_dst_port, - ntohs(card->wandev.udp_port), - chdlc_udp_pkt->ip_pkt.protocol, - UDPMGMT_UDP_PROTOCOL, - chdlc_udp_pkt->wp_mgmt.request_reply, - UDPMGMT_REQUEST, - skb->data[36], skb->data[37]); -#endif - - if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && - (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - - return UDP_CPIPE_TYPE; - - }else{ - return UDP_INVALID_TYPE; - } -} - -/*============================================================================ - * Set PORT state. - */ -static void port_set_state (sdla_t *card, int state) -{ - if (card->u.c.state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: Link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: Link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: Link disconnected!\n", - card->devname); - break; - } - - card->wandev.state = card->u.c.state = state; - if (card->wandev.dev){ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - chdlc_priv_area->common.state = state; - } - } -} - -/*=========================================================================== - * config_chdlc - * - * Configure the chdlc protocol and enable communications. - * - * The if_open() function binds this function to the poll routine. - * Therefore, this function will run every time the chdlc interface - * is brought up. We cannot run this function from the if_open - * because if_open does not have access to the remote IP address. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses have changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - * - */ - -static int config_chdlc (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - - /* Jun 20. 2000: NC - * IP addresses are not used in the API mode */ - - if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || - chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && - card->u.c.usedby == WANPIPE) { - - /* The IP addersses have changed, we must - * stop the communications and reconfigure - * the card. Reason: the firmware must know - * the local and remote IP addresses. */ - disable_comm(card); - port_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO - "%s: IP addresses changed!\n", - card->devname); - printk(KERN_INFO - "%s: Restarting communications ...\n", - card->devname); - }else{ - /* IP addresses are the same and the link is up, - * we don't have to do anything here. Therefore, exit */ - return 0; - } - } - - chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; - chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; - - - /* Setup the Board for asynchronous mode */ - if (card->u.c.async_mode){ - - if (set_asy_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", - card->devname); - return 0; - } - }else{ - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC configuration!\n", - card->devname); - return 0; - } - } - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return 0; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - /* In TTY mode, receive interrupt will be enabled during - * wanpipe_tty_open() operation */ - if (card->tty_opt){ - flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME; - } - - /* Enable communications */ - if (card->u.c.async_mode){ - if (asy_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable async commnunication!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - }else{ - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card); - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -/*============================================================ - * chdlc_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * CHDLC polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each CHDLC - * interface through a tq_schedule bottom half. - * - * trigger_chdlc_poll() function is used to kick - * the chldc_poll routine. - */ - -static void chdlc_poll(struct net_device *dev) -{ - chdlc_private_area_t *chdlc_priv_area; - sdla_t *card; - u8 check_gateway=0; - SHARED_MEMORY_INFO_STRUCT* flags; - - - if (!dev || (chdlc_priv_area=dev->priv) == NULL) - return; - - card = chdlc_priv_area->card; - flags = card->u.c.flags; - - /* (Re)Configuraiton is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* if_open() function has triggered the polling routine - * to determine the configured IP addresses. Once the - * addresses are found, trigger the chdlc configuration */ - if (test_bit(0,&chdlc_priv_area->config_chdlc)){ - - chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); - chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - /* Jun 20. 2000 Bug Fix - * Only perform this check in WANPIPE mode, since - * IP addresses are not used in the API mode. */ - - if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && - card->u.c.slarp_timer == 0x00 && - !card->u.c.backup && - card->u.c.usedby == WANPIPE){ - - if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ - printk(KERN_INFO "\n%s: --- WARNING ---\n", - card->devname); - printk(KERN_INFO - "%s: The local IP address is the same as the\n", - card->devname); - printk(KERN_INFO - "%s: Point-to-Point IP address.\n", - card->devname); - printk(KERN_INFO "%s: --- WARNING ---\n\n", - card->devname); - }else{ - clear_bit(POLL_CRIT,&card->wandev.critical); - chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; - add_timer(&chdlc_priv_area->poll_delay_timer); - return; - } - } - - clear_bit(0,&chdlc_priv_area->config_chdlc); - clear_bit(POLL_CRIT,&card->wandev.critical); - - chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - return; - } - /* Dynamic interface implementation, as well as dynamic - * routing. */ - - switch (card->u.c.state){ - - case WAN_DISCONNECTED: - - /* If the dynamic interface configuration is on, and interface - * is up, then bring down the netowrk interface */ - - if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && - !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && - card->wandev.dev->flags & IFF_UP){ - - printk(KERN_INFO "%s: Interface %s down.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP)); - set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); - chdlc_priv_area->route_status = NO_ROUTE; - - }else{ - /* We need to check if the local IP address is - * zero. If it is, we shouldn't try to remove it. - */ - - if (card->wandev.dev->flags & IFF_UP && - get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && - chdlc_priv_area->route_status != NO_ROUTE && - card->u.c.slarp_timer){ - - process_route(card); - } - } - break; - - case WAN_CONNECTED: - - /* In SMP machine this code can execute before the interface - * comes up. In this case, we must make sure that we do not - * try to bring up the interface before dev_open() is finished */ - - - /* DEV_DOWN will be set only when we bring down the interface - * for the very first time. This way we know that it was us - * that brought the interface down */ - - if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && - test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && - !(card->wandev.dev->flags & IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s up.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); - clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); - check_gateway=1; - } - - if (chdlc_priv_area->route_status == ADD_ROUTE && - card->u.c.slarp_timer){ - - process_route(card); - check_gateway=1; - } - - if (chdlc_priv_area->gateway && check_gateway) - add_gateway(card,dev); - - break; - } - - clear_bit(POLL_CRIT,&card->wandev.critical); -} - -/*============================================================ - * trigger_chdlc_poll - * - * Description: - * Add a chdlc_poll() work entry into the keventd work queue - * for a specific dlci/interface. This will kick - * the fr_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ -static void trigger_chdlc_poll(struct net_device *dev) -{ - chdlc_private_area_t *chdlc_priv_area; - sdla_t *card; - - if (!dev) - return; - - if ((chdlc_priv_area = dev->priv)==NULL) - return; - - card = chdlc_priv_area->card; - - if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - return; - } - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - schedule_work(&chdlc_priv_area->poll_work); -} - - -static void chdlc_poll_delay (unsigned long dev_ptr) -{ - struct net_device *dev = (struct net_device *)dev_ptr; - trigger_chdlc_poll(dev); -} - - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -//*********** TTY SECTION **************** - -static void wanpipe_tty_trigger_tx_irq(sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; -} - -static void wanpipe_tty_trigger_poll(sdla_t *card) -{ - schedule_work(&card->tty_work); -} - -static void tty_poll_work (void* data) -{ - sdla_t *card = (sdla_t*)data; - struct tty_struct *tty; - - if ((tty=card->tty)==NULL) - return; - - tty_wakeup(tty); -#if defined(SERIAL_HAVE_POLL_WAIT) - wake_up_interruptible(&tty->poll_wait); -#endif - return; -} - -static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) -{ - sdla_t *card; - unsigned long smp_flags; - - if (!tty || !tty->driver_data){ - return; - } - - card = (sdla_t*)tty->driver_data; - - if (!card) - return; - - printk(KERN_INFO "%s: Closing TTY Driver!\n", - card->devname); - - /* Sanity Check */ - if (!card->tty_open) - return; - - wanpipe_close(card); - if (--card->tty_open == 0){ - - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=NULL; - chdlc_disable_comm_shutdown(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - - kfree(card->tty_buf); - card->tty_buf = NULL; - kfree(card->tty_rx); - card->tty_rx = NULL; - } - return; -} -static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) -{ - unsigned long smp_flags; - sdla_t *card; - - if (!tty){ - return -ENODEV; - } - - if (!tty->driver_data){ - int port; - port = tty->index; - if ((port < 0) || (port >= NR_PORTS)) - return -ENODEV; - - tty->driver_data = WAN_CARD(port); - if (!tty->driver_data) - return -ENODEV; - } - - card = (sdla_t*)tty->driver_data; - - if (!card){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=NULL; - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - return -ENODEV; - } - - printk(KERN_INFO "%s: Opening TTY Driver!\n", - card->devname); - - if (card->tty_open == 0){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=tty; - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - - if (!card->tty_buf){ - card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); - if (!card->tty_buf){ - card->tty_buf=NULL; - card->tty=NULL; - return -ENOMEM; - } - } - - if (!card->tty_rx){ - card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); - if (!card->tty_rx){ - /* Free the buffer above */ - kfree(card->tty_buf); - card->tty_buf=NULL; - card->tty=NULL; - return -ENOMEM; - } - } - } - - ++card->tty_open; - wanpipe_open(card); - return 0; -} - -static int wanpipe_tty_write(struct tty_struct * tty, const unsigned char *buf, int count) -{ - unsigned long smp_flags=0; - sdla_t *card=NULL; - - if (!tty){ - dbg_printk(KERN_INFO "NO TTY in Write\n"); - return -ENODEV; - } - - card = (sdla_t *)tty->driver_data; - - if (!card){ - dbg_printk(KERN_INFO "No Card in TTY Write\n"); - return -ENODEV; - } - - if (count > card->wandev.mtu){ - dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n", - count,card->wandev.mtu); - return -EINVAL; - } - - if (card->wandev.state != WAN_CONNECTED){ - dbg_printk(KERN_INFO "Card not connected in TTY Write\n"); - return -EINVAL; - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ - printk(KERN_INFO "%s: Critical in TTY Write\n", - card->devname); - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return -EINVAL; - } - - if (chdlc_send(card,(void*)buf,count)){ - dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n", - card->devname); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - wanpipe_tty_trigger_tx_irq(card); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - return 0; - } - dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return count; -} - -static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) -{ - unsigned offset=0; - unsigned olen=len; - char fp=0; - struct tty_struct *tty; - int i; - struct tty_ldisc *ld; - - if (!card->tty_open){ - dbg_printk(KERN_INFO "%s: TTY not open during receive\n", - card->devname); - return; - } - - if ((tty=card->tty) == NULL){ - dbg_printk(KERN_INFO "%s: No TTY on receive\n", - card->devname); - return; - } - - if (!tty->driver_data){ - dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n", - card->devname); - return; - } - - - if (card->u.c.async_mode){ - if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Received packet size too big: %i bytes, Max: %i!\n", - card->devname,len,TTY_FLIPBUF_SIZE); - } - return; - } - - - if((addr + len) > card->u.c.rx_top + 1) { - offset = card->u.c.rx_top - addr + 1; - - sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset); - - addr = card->u.c.rx_base; - len -= offset; - - tty->flip.char_buf_ptr+=offset; - tty->flip.count+=offset; - for (i=0;i<offset;i++){ - *tty->flip.flag_buf_ptr = 0; - tty->flip.flag_buf_ptr++; - } - } - - sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len); - - tty->flip.char_buf_ptr+=len; - card->tty->flip.count+=len; - for (i=0;i<len;i++){ - *tty->flip.flag_buf_ptr = 0; - tty->flip.flag_buf_ptr++; - } - - tty->low_latency=1; - tty_flip_buffer_push(tty); - }else{ - if (!card->tty_rx){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Receive sync buffer not available!\n", - card->devname); - } - return; - } - - if (len > TTY_CHDLC_MAX_MTU){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Received packet size too big: %i bytes, Max: %i!\n", - card->devname,len,TTY_FLIPBUF_SIZE); - } - return; - } - - - if((addr + len) > card->u.c.rx_top + 1) { - offset = card->u.c.rx_top - addr + 1; - - sdla_peek(&card->hw, addr, card->tty_rx, offset); - - addr = card->u.c.rx_base; - len -= offset; - } - sdla_peek(&card->hw, addr, card->tty_rx+offset, len); - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->receive_buf) - ld->receive_buf(tty,card->tty_rx,&fp,olen); - tty_ldisc_deref(ld); - }else{ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: NO TTY Sync line discipline!\n", - card->devname); - } - } - } - - dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen); - return; -} - -#if 0 -static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - return -ENOIOCTLCMD; -} -#endif - -static void wanpipe_tty_stop(struct tty_struct *tty) -{ - return; -} - -static void wanpipe_tty_start(struct tty_struct *tty) -{ - return; -} - -static int config_tty (sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - /* Setup the Board for asynchronous mode */ - if (card->u.c.async_mode){ - - if (set_asy_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", - card->devname); - return -EINVAL; - } - }else{ - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC configuration!\n", - card->devname); - return -EINVAL; - } - } - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return -EINVAL; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - /* Enable communications */ - if (card->u.c.async_mode){ - if (asy_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable async commnunication!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return -EINVAL; - } - }else{ - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return -EINVAL; - } - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card); - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -static int change_speed(sdla_t *card, struct tty_struct *tty, - struct termios *old_termios) -{ - int baud, ret=0; - unsigned cflag; - int dbits,sbits,parity,handshaking; - - cflag = tty->termios->c_cflag; - - /* There is always one stop bit */ - sbits=WANOPT_ONE; - - /* Parity is defaulted to NONE */ - parity = WANOPT_NONE; - - handshaking=0; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: dbits = 5; break; - case CS6: dbits = 6; break; - case CS7: dbits = 7; break; - case CS8: dbits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: dbits = 8; break; - } - - /* One more stop bit should be supported, thus increment - * the number of stop bits Max=2 */ - if (cflag & CSTOPB) { - sbits = WANOPT_TWO; - } - if (cflag & PARENB) { - parity = WANOPT_EVEN; - } - if (cflag & PARODD){ - parity = WANOPT_ODD; - } - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(tty); - - if (!baud) - baud = 9600; /* B0 transition handled in rs_set_termios */ - - if (cflag & CRTSCTS) { - handshaking|=ASY_RTS_HS_FOR_RX; - } - - if (I_IGNPAR(tty)) - parity = WANOPT_NONE; - - if (I_IXOFF(tty)){ - handshaking|=ASY_XON_XOFF_HS_FOR_RX; - handshaking|=ASY_XON_XOFF_HS_FOR_TX; - } - - if (I_IXON(tty)){ - handshaking|=ASY_XON_XOFF_HS_FOR_RX; - handshaking|=ASY_XON_XOFF_HS_FOR_TX; - } - - if (card->u.c.async_mode){ - if (card->wandev.bps != baud) - ret=1; - card->wandev.bps = baud; - } - - if (card->u.c.async_mode){ - if (card->u.c.protocol_options != handshaking) - ret=1; - card->u.c.protocol_options = handshaking; - - if (card->u.c.tx_bits_per_char != dbits) - ret=1; - card->u.c.tx_bits_per_char = dbits; - - if (card->u.c.rx_bits_per_char != dbits) - ret=1; - card->u.c.rx_bits_per_char = dbits; - - if (card->u.c.stop_bits != sbits) - ret=1; - card->u.c.stop_bits = sbits; - - if (card->u.c.parity != parity) - ret=1; - card->u.c.parity = parity; - - card->u.c.break_timer = 50; - card->u.c.inter_char_timer = 10; - card->u.c.rx_complete_length = 100; - card->u.c.xon_char = 0xFE; - }else{ - card->u.c.protocol_options = HDLC_STREAMING_MODE; - } - - return ret; -} - - -static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - sdla_t *card; - int err=1; - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - - if (!card) - return; - - if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ - unsigned long smp_flags; - - if (card->u.c.comm_enabled){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - chdlc_disable_comm_shutdown(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - } - lock_adapter_irq(&card->wandev.lock,&smp_flags); - err = config_tty(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - if (card->u.c.async_mode){ - printk(KERN_INFO "%s: TTY Async Configuration:\n" - " Baud =%i\n" - " Handshaking =%s\n" - " Tx Dbits =%i\n" - " Rx Dbits =%i\n" - " Parity =%s\n" - " Stop Bits =%i\n", - card->devname, - card->wandev.bps, - opt_decode[card->u.c.protocol_options], - card->u.c.tx_bits_per_char, - card->u.c.rx_bits_per_char, - p_decode[card->u.c.parity] , - card->u.c.stop_bits); - }else{ - printk(KERN_INFO "%s: TTY Sync Configuration:\n" - " Baud =%i\n" - " Protocol =HDLC_STREAMING\n", - card->devname,card->wandev.bps); - } - if (!err){ - port_set_state(card,WAN_CONNECTED); - }else{ - port_set_state(card,WAN_DISCONNECTED); - } - } - return; -} - -static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) -{ - sdla_t *card; - unsigned long smp_flags=0; - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - - if (!card) - return; - - if (card->wandev.state != WAN_CONNECTED) - return; - - if(card->hw.type != SDLA_S514) - s508_lock(card,&smp_flags); - - if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ - - wanpipe_tty_trigger_tx_irq(card); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - return; - } - - if (chdlc_send(card,(void*)&ch,1)){ - wanpipe_tty_trigger_tx_irq(card); - dbg_printk("%s: Failed to TX char!\n",card->devname); - } - - dbg_printk("%s: Char TX OK\n",card->devname); - - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return; -} - -static void wanpipe_tty_flush_chars(struct tty_struct *tty) -{ - return; -} - -static void wanpipe_tty_flush_buffer(struct tty_struct *tty) -{ - if (!tty) - return; - -#if defined(SERIAL_HAVE_POLL_WAIT) - wake_up_interruptible(&tty->poll_wait); -#endif - tty_wakeup(tty); - return; -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) -{ - return; -} - - -static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - - -static int wanpipe_tty_write_room(struct tty_struct *tty) -{ - sdla_t *card; - - printk(KERN_INFO "TTY Write Room\n"); - - if (!tty){ - return 0; - } - - card = (sdla_t *)tty->driver_data; - if (!card) - return 0; - - if (card->wandev.state != WAN_CONNECTED) - return 0; - - return SEC_MAX_NO_DATA_BYTES_IN_FRAME; -} - - -static int set_modem_status(sdla_t *card, unsigned char data) -{ - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - int err; - - mb->buffer_length=1; - mb->command=SET_MODEM_STATUS; - mb->data[0]=data; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - - return err; -} - -static void wanpipe_tty_hangup(struct tty_struct *tty) -{ - sdla_t *card; - unsigned long smp_flags; - - printk(KERN_INFO "TTY Hangup!\n"); - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - if (!card) - return; - - lock_adapter_irq(&card->wandev.lock,&smp_flags); - set_modem_status(card,0); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - return; -} - -static void wanpipe_tty_break(struct tty_struct *tty, int break_state) -{ - return; -} - -static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) -{ - return; -} - -static void wanpipe_tty_throttle(struct tty_struct * tty) -{ - return; -} - -static void wanpipe_tty_unthrottle(struct tty_struct * tty) -{ - return; -} - -int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - return 0; -} - -/* - * The serial driver boot-time initialization code! - */ -int wanpipe_tty_init(sdla_t *card) -{ - struct serial_state * state; - - /* Initialize the tty_driver structure */ - - if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ - printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", - card->devname,card->tty_minor); - return -EINVAL; - } - - if (WAN_CARD(card->tty_minor)){ - printk(KERN_INFO "%s: TTY Minor %i, already in use\n", - card->devname,card->tty_minor); - return -EBUSY; - } - - if (tty_init_cnt==0){ - - printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", - card->devname, - card->u.c.async_mode ? "ASYNC" : "SYNC", - WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); - - tty_driver_mode = card->u.c.async_mode; - - memset(&serial_driver, 0, sizeof(struct tty_driver)); - serial_driver.magic = TTY_DRIVER_MAGIC; - serial_driver.owner = THIS_MODULE; - serial_driver.driver_name = "wanpipe_tty"; - serial_driver.name = "ttyW"; - serial_driver.major = WAN_TTY_MAJOR; - serial_driver.minor_start = WAN_TTY_MINOR; - serial_driver.num = NR_PORTS; - serial_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_driver.subtype = SERIAL_TYPE_NORMAL; - - serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver.flags = TTY_DRIVER_REAL_RAW; - - serial_driver.refcount = 1; /* !@!@^#^&!! */ - - serial_driver.open = wanpipe_tty_open; - serial_driver.close = wanpipe_tty_close; - serial_driver.write = wanpipe_tty_write; - - serial_driver.put_char = wanpipe_tty_put_char; - serial_driver.flush_chars = wanpipe_tty_flush_chars; - serial_driver.write_room = wanpipe_tty_write_room; - serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; - serial_driver.flush_buffer = wanpipe_tty_flush_buffer; - //serial_driver.ioctl = wanpipe_tty_ioctl; - serial_driver.throttle = wanpipe_tty_throttle; - serial_driver.unthrottle = wanpipe_tty_unthrottle; - serial_driver.send_xchar = wanpipe_tty_send_xchar; - serial_driver.set_termios = wanpipe_tty_set_termios; - serial_driver.stop = wanpipe_tty_stop; - serial_driver.start = wanpipe_tty_start; - serial_driver.hangup = wanpipe_tty_hangup; - serial_driver.break_ctl = wanpipe_tty_break; - serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; - serial_driver.read_proc = wanpipe_tty_read_proc; - - if (tty_register_driver(&serial_driver)){ - printk(KERN_INFO "%s: Failed to register serial driver!\n", - card->devname); - } - } - - - /* The subsequent ports must comply to the initial configuration */ - if (tty_driver_mode != card->u.c.async_mode){ - printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", - card->devname); - printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", - card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); - return -EINVAL; - } - - tty_init_cnt++; - - printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n", - card->devname, - tty_driver_mode ? "ASYNC" : "SYNC", - card->tty_minor); - - tty_card_map[card->tty_minor] = card; - state = &rs_table[card->tty_minor]; - - state->magic = SSTATE_MAGIC; - state->line = 0; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - state->irq = card->wandev.irq; - - INIT_WORK(&card->tty_work, tty_poll_work, (void*)card); - return 0; -} - - -MODULE_LICENSE("GPL"); - -/****** End ****************************************************************/ diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c deleted file mode 100644 index 7f1ce9d4333..00000000000 --- a/drivers/net/wan/sdla_fr.c +++ /dev/null @@ -1,5061 +0,0 @@ -/***************************************************************************** -* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. -* -* Author(s): Nenad Corbic <ncorbic@sangoma.com> -* Gideon Hack -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels -* Nov 15, 2000 David Rokavarg -* Nenad Corbic o Added frame relay bridging support. -* Original code from Mark Wells and Kristian Hoffmann has -* been integrated into the frame relay driver. -* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. -* Tcpdump doesn't support Frame Relay inteface -* types, to fix this true type option will set -* the interface type to RAW IP mode. -* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: -* Deny all and specify allowed requests. -* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. -* Moved the if_header into the if_send() routine. -* The if_header() was breaking the libpcap -* support. i.e. support for tcpdump, ethereal ... -* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure -* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. -* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface -* when the channel gets disconnected. -* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate -* interface setups. -* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove -* new dlcis/interfaces. -* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. -* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support -* Mar 13, 2000 Nenad Corbic o Added new socket API support. -* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. -* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels -* -* Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function -* o Removed the ARP support. This has to be done -* in the next version. -* o Only a Node can implement NO signalling. -* Initialize DLCI during if_open() if NO -* signalling. -* o Took out IPX support, implement in next -* version -* Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update -* function to use timer interrupt. -* o Fixed the CIR bug: Set the value of BC -* to CIR when the CIR is enabled. -* o Updated comments, statistics and tracing. -* Jun 02, 1999 Gideon Hack o Updated for S514 support. -* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. -* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI -* status is received through an event interrupt. -* Jul 08, 1998 David Fong o Added inverse ARP support. -* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. -* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. -* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) -* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. -* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards -* o Added Cli() to protect enabling of interrupts -* while polling is called. -* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts -* when they have been disabled by another -* interface or routine (eg. wpf_poll). -* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling -* routine disable interrupts during interrupt -* testing. -* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. -* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow -* control by avoiding RACE conditions. The -* cli() and restore_flags() are taken out. -* The fr_channel structure is appended for -* Driver Statistics. -* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX -* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() -* o Abstracted the UDP management stuff -* o Now use tbusy and critical more intelligently -* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 -* through router.conf. -* o Protected calls to sdla_peek() by adDing -* save_flags(), cli() and restore_flags(). -* o Added error message for Inactive DLCIs in -* fr_event() and update_chan_state(). -* o Fixed freeing up of buffers using kfree() -* when packets are received. -* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets -* o Added ability to discard multicast and -* broadcast source addressed packets -* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities -* New case (0x44) statement in if_send routine -* Added a global variable rCount to keep track -* of FT1 status enabled on the board. -* May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem -* With multiple boards a problem was seen where -* the second board always stopped transmitting -* packet after running for a while. The code -* got into a stage where the interrupts were -* disabled and dev->tbusy was set to 1. -* This caused the If_send() routine to get into -* the if clause for it(0,dev->tbusy) -* forever. -* The code got into this stage due to an -* interrupt occurring within the if clause for -* set_bit(0,dev->tbusy). Since an interrupt -* disables furhter transmit interrupt and -* makes dev->tbusy = 0, this effect was undone -* by making dev->tbusy = 1 in the if clause. -* The Fix checks to see if Transmit interrupts -* are disabled then do not make dev->tbusy = 1 -* Introduced a global variable: int_occur and -* added tx_int_enabled in the wan_device -* structure. -* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple -* boards. -* -* Apr 25, 1997 Farhan Thawar o added UDP Management stuff -* o fixed bug in if_send() and tx_intr() to -* sleep and wakeup all devices -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o fixed (+1) bug in fr508_rx_intr() -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* o added tx_intr() routine -* Jan 30, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* o fixed a bug causing driver configured as -* a FR switch to be stuck in WAN_ -* mode -* Jan 02, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/wanrouter.h> /* WAN router definitions */ -#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <linux/workqueue.h> -#include <linux/if_arp.h> /* ARPHRD_* defines */ -#include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/io.h> /* for inb(), outb(), etc. */ -#include <linux/time.h> /* for do_gettimeofday */ -#include <linux/in.h> /* sockaddr_in */ -#include <linux/jiffies.h> /* time_after() macro */ -#include <asm/errno.h> - -#include <linux/ip.h> -#include <linux/if.h> - -#include <linux/if_wanpipe_common.h> /* Wanpipe Socket */ -#include <linux/if_wanpipe.h> - -#include <linux/sdla_fr.h> /* frame relay firmware API definitions */ - -#include <asm/uaccess.h> -#include <linux/inetdevice.h> -#include <linux/netdevice.h> - -#include <net/route.h> /* Dynamic Route Creation */ -#include <linux/etherdevice.h> /* eth_type_trans() used for bridging */ -#include <linux/random.h> - -/****** Defines & Macros ****************************************************/ - -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ - -/* Q.922 frame types */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF - -/* DLCI configured or not */ -#define DLCI_NOT_CONFIGURED 0x00 -#define DLCI_CONFIG_PENDING 0x01 -#define DLCI_CONFIGURED 0x02 - -/* CIR enabled or not */ -#define CIR_ENABLED 0x00 -#define CIR_DISABLED 0x01 - -#define FRAME_RELAY_API 1 -#define MAX_BH_BUFF 10 - -/* For handle_IPXWAN() */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/****** Data Structures *****************************************************/ - -/* This is an extention of the 'struct device' we create for each network - * interface to keep the rest of channel-specific data. - */ -typedef struct fr_channel -{ - wanpipe_common_t common; - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - unsigned dlci_configured ; /* check whether configured or not */ - unsigned cir_status; /* check whether CIR enabled or not */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - unsigned bc; /* committed burst size */ - unsigned be; /* excess burst size */ - unsigned mc; /* multicast support on or off */ - unsigned tx_int_status; /* Transmit Interrupt Status */ - unsigned short pkt_length; /* Packet Length */ - unsigned long router_start_time;/* Router start time in seconds */ - unsigned long tick_counter; /* counter for transmit time out */ - char dev_pending_devtint; /* interface pending dev_tint() */ - void *dlci_int_interface; /* pointer to the DLCI Interface */ - unsigned long IB_addr; /* physical address of Interface Byte */ - unsigned long state_tick; /* time of the last state change */ - unsigned char enable_IPX; /* Enable/Disable the use of IPX */ - unsigned long network_number; /* Internal Network Number for IPX*/ - sdla_t *card; /* -> owner */ - unsigned route_flag; /* Add/Rem dest addr in route tables */ - unsigned inarp; /* Inverse Arp Request status */ - long inarp_ready; /* Ready to send requests */ - int inarp_interval; /* Time between InArp Requests */ - unsigned long inarp_tick; /* InArp jiffies tick counter */ - long interface_down; /* Bring interface down on disconnect */ - struct net_device_stats ifstats; /* interface statistics */ - if_send_stat_t drvstats_if_send; - rx_intr_stat_t drvstats_rx_intr; - pipe_mgmt_stat_t drvstats_gen; - unsigned long router_up_time; - - unsigned short transmit_length; - struct sk_buff *delay_skb; - - bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - /* Polling task queue. Each interface - * has its own task queue, which is used - * to defer events from the interrupt */ - struct work_struct fr_poll_work; - struct timer_list fr_arp_timer; - - u32 ip_local; - u32 ip_remote; - long config_dlci; - long unconfig_dlci; - - /* Whether this interface should be setup as a gateway. - * Used by dynamic route setup code */ - u8 gateway; - - /* True interface type */ - u8 true_if_encoding; - u8 fr_header[FR_HEADER_LEN]; - char fr_header_len; - -} fr_channel_t; - -/* Route Flag options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 -#define ARP_REQ 0x04 - -/* inarp options */ -#define INARP_NONE 0x00 -#define INARP_REQUEST 0x01 -#define INARP_CONFIGURED 0x02 - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_ARP 0x04 -#define TMR_INT_ENABLED_UPDATE_STATE 0x08 -#define TMR_INT_ENABLED_CONFIG 0x10 -#define TMR_INT_ENABLED_UNCONFIG 0x20 - - -typedef struct dlci_status -{ - unsigned short dlci PACKED; - unsigned char state PACKED; -} dlci_status_t; - -typedef struct dlci_IB_mapping -{ - unsigned short dlci PACKED; - unsigned long addr_value PACKED; -} dlci_IB_mapping_t; - -/* This structure is used for DLCI list Tx interrupt mode. It is used to - enable interrupt bit and set the packet length for transmission - */ -typedef struct fr_dlci_interface -{ - unsigned char gen_interrupt PACKED; - unsigned short packet_length PACKED; - unsigned char reserved PACKED; -} fr_dlci_interface_t; - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/* variable for keeping track of number of interrupts generated during - * interrupt test routine - */ -static int Intr_test_counter; - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device *wandev); -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf); -static int del_if(struct wan_device *wandev, struct net_device *dev); -static void disable_comm (sdla_t *card); - -/* WANPIPE-specific entry points */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); - -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); - -static void if_tx_timeout(struct net_device *dev); - -static int if_rebuild_hdr (struct sk_buff *skb); - -static int if_send(struct sk_buff *skb, struct net_device *dev); -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); - -/* Interrupt handlers */ -static void fr_isr(sdla_t *card); -static void rx_intr(sdla_t *card); -static void tx_intr(sdla_t *card); -static void timer_intr(sdla_t *card); -static void spur_intr(sdla_t *card); - -/* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t *card, char *str); -static int fr_configure(sdla_t *card, fr_conf_t *conf); -static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); -static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); -static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); -static int fr_comm_enable(sdla_t *card); -static void fr_comm_disable(sdla_t *card); -static int fr_get_err_stats(sdla_t *card); -static int fr_get_stats(sdla_t *card); -static int fr_add_dlci(sdla_t *card, int dlci); -static int fr_activate_dlci(sdla_t *card, int dlci); -static int fr_delete_dlci (sdla_t* card, int dlci); -static int fr_issue_isf(sdla_t *card, int isf); -static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, - void *buf); -static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, - void *buf,unsigned char hdr_len); -static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); - -static int check_dlci_config (sdla_t *card, fr_channel_t *chan); -static void initialize_rx_tx_buffers (sdla_t *card); - - -/* Firmware asynchronous event handlers */ -static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); -static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); -static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); - -/* Miscellaneous functions */ -static int update_chan_state(struct net_device *dev); -static void set_chan_state(struct net_device *dev, int state); -static struct net_device *find_channel(sdla_t *card, unsigned dlci); -static int is_tx_ready(sdla_t *card, fr_channel_t *chan); -static unsigned int dec_to_uint(unsigned char *str, int len); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); - -static int intr_test( sdla_t* card ); -static void init_chan_statistics( fr_channel_t* chan ); -static void init_global_statistics( sdla_t* card ); -static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); -static int setup_for_delayed_transmit(struct net_device* dev, - struct sk_buff *skb); - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev); -static int check_tx_status(sdla_t *card, struct net_device *dev); - -/* Frame Relay Socket API */ -static void trigger_fr_bh (fr_channel_t *); -static void fr_bh(struct net_device *dev); -static int fr_bh_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - -static void trigger_fr_poll(struct net_device *dev); -static void fr_poll(struct net_device *dev); -//static void add_gateway(struct net_device *dev); - -static void trigger_unconfig_fr(struct net_device *dev); -static void unconfig_fr (sdla_t *); - -static void trigger_config_fr (sdla_t *); -static void config_fr (sdla_t *); - - -/* Inverse ARP and Dynamic routing functions */ -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); -int is_arp(void *buf); -int send_inarp_request(sdla_t *card, struct net_device *dev); - -static void trigger_fr_arp(struct net_device *dev); -static void fr_arp (unsigned long data); - - -/* Udp management functions */ -static int process_udp_mgmt_pkt(sdla_t *card); -static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, int dlci); - -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, - unsigned long network_number, unsigned char incoming); - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, - unsigned char enable_IPX, unsigned long network_number); - -/* Lock Functions: SMP supported */ -void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); -void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); - -unsigned short calc_checksum (char *, int); -static int setup_fr_header(struct sk_buff *skb, - struct net_device* dev, char op_mode); - - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Frame relay protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpf_init(sdla_t *card, wandev_conf_t *conf) -{ - - int err; - fr508_flags_t* flags; - - union - { - char str[80]; - fr_conf_t cfg; - } u; - - fr_buf_info_t* buf_info; - int i; - - - printk(KERN_INFO "\n"); - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) { - - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - - } - - /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) { - - case SFID_FR508: - card->mbox = (void*)(card->hw.dpmbase + - FR508_MBOX_OFFS); - card->flags = (void*)(card->hw.dpmbase + - FR508_FLAG_OFFS); - if(card->hw.type == SDLA_S514) { - card->mbox += FR_MB_VECTOR; - card->flags += FR_MB_VECTOR; - } - card->isr = &fr_isr; - break; - - default: - return -EINVAL; - } - - flags = card->flags; - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: running frame relay firmware v%s\n", - card->devname, u.str); - - /* Adjust configuration */ - conf->mtu += FR_HEADER_LEN; - conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? - min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : - FR_CHANNEL_MTU + FR_HEADER_LEN; - - conf->bps = min_t(unsigned int, conf->bps, 2048000); - - /* Initialze the configuration structure sent to the board to zero */ - memset(&u.cfg, 0, sizeof(u.cfg)); - - memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); - - /* Configure adapter firmware */ - - u.cfg.mtu = conf->mtu; - u.cfg.kbps = conf->bps / 1000; - - u.cfg.cir_fwd = u.cfg.cir_bwd = 16; - u.cfg.bc_fwd = u.cfg.bc_bwd = 16; - - u.cfg.options = 0x0000; - printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); - - switch (conf->u.fr.signalling) { - - case WANOPT_FR_ANSI: - u.cfg.options = 0x0000; - break; - - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; - - case WANOPT_NO: - u.cfg.options |= 0x0800; - break; - default: - printk(KERN_INFO "%s: Illegal Signalling option\n", - card->wandev.name); - return -EINVAL; - } - - - card->wandev.signalling = conf->u.fr.signalling; - - if (conf->station == WANOPT_CPE) { - - - if (conf->u.fr.signalling == WANOPT_NO){ - printk(KERN_INFO - "%s: ERROR - For NO signalling, station must be set to Node!", - card->devname); - return -EINVAL; - } - - u.cfg.station = 0; - u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - - } else { - - u.cfg.station = 1; /* switch emulation mode */ - - /* For switch emulation we have to create a list of dlci(s) - * that will be sent to be global SET_DLCI_CONFIGURATION - * command in fr_configure() routine. - */ - - card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100); - - for ( i = 0; i < card->u.f.dlci_num; i++) { - - card->u.f.node_dlci[i] = (unsigned short) - conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; - - } - } - - if (conf->clocking == WANOPT_INTERNAL) - u.cfg.port |= 0x0001; - - if (conf->interface == WANOPT_RS232) - u.cfg.port |= 0x0002; - - if (conf->u.fr.t391) - u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30); - else - u.cfg.t391 = 5; - - if (conf->u.fr.t392) - u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30); - else - u.cfg.t392 = 15; - - if (conf->u.fr.n391) - u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255); - else - u.cfg.n391 = 2; - - if (conf->u.fr.n392) - u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10); - else - u.cfg.n392 = 3; - - if (conf->u.fr.n393) - u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10); - else - u.cfg.n393 = 4; - - if (fr_configure(card, &u.cfg)) - return -EIO; - - if (card->hw.type == SDLA_S514) { - - buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + - FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + - card->hw.dpmbase); - }else{ - buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - - FR_MB_VECTOR + card->hw.dpmbase); - } - - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - - card->u.f.tx_interrupts_pending = 0; - - card->wandev.mtu = conf->mtu; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->poll = NULL; - card->exec = &wpf_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.ttl = conf->ttl; - card->wandev.udp_port = conf->udp_port; - card->disable_comm = &disable_comm; - card->u.f.arp_dev = NULL; - - /* Intialize global statistics for a card */ - init_global_statistics( card ); - - card->TracingEnabled = 0; - - /* Interrupt Test */ - Intr_test_counter = 0; - card->intr_mode = INTR_TEST_MODE; - err = intr_test( card ); - - printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", - card->devname,err,Intr_test_counter); - - if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "Please choose another interrupt\n"); - err = -EIO; - return err; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - - - /* Apr 28 2000. Nenad Corbic - * Enable commnunications here, not in if_open or new_if, since - * interfaces come down when the link is disconnected. - */ - - /* If you enable comms and then set ints, you get a Tx int as you - * perform the SET_INT_TRIGGERS command. So, we only set int - * triggers and then adjust the interrupt mask (to disable Tx ints) - * before enabling comms. - */ - if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | - FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , - card->wandev.mtu, 0)) { - return -EIO; - } - - flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); - - if (fr_comm_enable(card)) { - return -EIO; - } - wanpipe_set_state(card, WAN_CONNECTED); - spin_lock_init(&card->u.f.if_send_lock); - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update(struct wan_device* wandev) -{ - volatile sdla_t* card; - unsigned long timeout; - fr508_flags_t* flags; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - card = wandev->private; - flags = card->flags; - - - card->u.f.update_comms_stats = 1; - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - flags->imask |= FR_INTR_TIMER; - timeout = jiffies; - for(;;) { - if(card->u.f.update_comms_stats == 0) - break; - if (time_after(jiffies, timeout + 1 * HZ)){ - card->u.f.update_comms_stats = 0; - return -EAGAIN; - } - } - - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - fr_channel_t* chan; - int dlci = 0; - int err = 0; - - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); - - if (chan == NULL) - return -ENOMEM; - - memset(chan, 0, sizeof(fr_channel_t)); - strcpy(chan->name, conf->name); - chan->card = card; - - /* verify media address */ - if (isdigit(conf->addr[0])) { - - dlci = dec_to_uint(conf->addr, 0); - - if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { - - chan->dlci = dlci; - - } else { - - printk(KERN_ERR - "%s: Invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); - err = -EINVAL; - } - - } else { - printk(KERN_ERR - "%s: Invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - - if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ - printk(KERN_INFO - "%s: Enabling, true interface type encoding.\n", - card->devname); - } - - - - /* Setup wanpipe as a router (WANPIPE) even if it is - * a bridged DLCI, or as an API - */ - if (strcmp(conf->usedby, "WANPIPE") == 0 || - strcmp(conf->usedby, "BRIDGE") == 0 || - strcmp(conf->usedby, "BRIDGE_N") == 0){ - - if(strcmp(conf->usedby, "WANPIPE") == 0){ - chan->common.usedby = WANPIPE; - - printk(KERN_INFO "%s: Running in WANPIPE mode.\n", - card->devname); - - }else if(strcmp(conf->usedby, "BRIDGE") == 0){ - - chan->common.usedby = BRIDGE; - - printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", - card->devname); - }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ - - chan->common.usedby = BRIDGE_NODE; - - printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", - card->devname); - } - - if (!err){ - /* Dynamic interface configuration option. - * On disconnect, if the options is selected, - * the interface will be brought down */ - if (conf->if_down == WANOPT_YES){ - set_bit(DYN_OPT_ON,&chan->interface_down); - printk(KERN_INFO - "%s: Dynamic interface configuration enabled.\n", - card->devname); - } - } - - } else if(strcmp(conf->usedby, "API") == 0){ - - chan->common.usedby = API; - printk(KERN_INFO "%s: Running in API mode.\n", - wandev->name); - } - - if (err) { - - kfree(chan); - return err; - } - - /* place cir,be,bc and other channel specific information into the - * chan structure - */ - if (conf->cir) { - - chan->cir = max_t(unsigned int, 1, - min_t(unsigned int, conf->cir, 512)); - chan->cir_status = CIR_ENABLED; - - - /* If CIR is enabled, force BC to equal CIR - * this solves number of potential problems if CIR is - * set and BC is not - */ - chan->bc = chan->cir; - - if (conf->be){ - chan->be = max_t(unsigned int, - 0, min_t(unsigned int, conf->be, 511)); - }else{ - conf->be = 0; - } - - printk (KERN_INFO "%s: CIR enabled for DLCI %i \n", - wandev->name,chan->dlci); - printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", - wandev->name,chan->cir,chan->bc,chan->be); - - - }else{ - chan->cir_status = CIR_DISABLED; - printk (KERN_INFO "%s: CIR disabled for DLCI %i\n", - wandev->name,chan->dlci); - } - - chan->mc = conf->mc; - - if (conf->inarp == WANOPT_YES){ - printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); - chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; - chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; - }else{ - printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); - chan->inarp = INARP_NONE; - chan->inarp_interval = 10; - } - - - chan->dlci_configured = DLCI_NOT_CONFIGURED; - - - /*FIXME: IPX disabled in this WANPIPE version */ - if (conf->enable_IPX == WANOPT_YES){ - printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n", - card->devname); - kfree(chan); - return -EINVAL; - }else{ - chan->enable_IPX = WANOPT_NO; - } - - if (conf->network_number){ - chan->network_number = conf->network_number; - }else{ - chan->network_number = 0xDEADBEEF; - } - - chan->route_flag = NO_ROUTE; - - init_chan_statistics(chan); - - chan->transmit_length = 0; - - /* prepare network device data space for registration */ - strcpy(dev->name,chan->name); - - dev->init = &if_init; - dev->priv = chan; - - /* Initialize FR Polling Task Queue - * We need a poll routine for each network - * interface. - */ - INIT_WORK(&chan->fr_poll_work, (void *)fr_poll, dev); - - init_timer(&chan->fr_arp_timer); - chan->fr_arp_timer.data=(unsigned long)dev; - chan->fr_arp_timer.function = fr_arp; - - wandev->new_if_cnt++; - - /* Tells us that if this interface is a - * gateway or not */ - if ((chan->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,dev->name); - } - - /* M. Grant Patch Apr 28 2000 - * Disallow duplicate dlci configurations. */ - if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { - kfree(chan); - return -EBUSY; - } - - /* Configure this dlci at a later date, when - * the interface comes up. i.e. when if_open() - * executes */ - set_bit(0,&chan->config_dlci); - - printk(KERN_INFO "\n"); - - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - unsigned long smp_flags=0; - - /* This interface is dead, make sure the - * ARP timer is stopped */ - del_timer(&chan->fr_arp_timer); - - /* If we are a NODE, we must unconfigure this DLCI - * Trigger an unconfigure command that will - * be executed in timer interrupt. We must wait - * for the command to complete. */ - trigger_unconfig_fr(dev); - - lock_adapter_irq(&wandev->lock, &smp_flags); - wandev->new_if_cnt--; - unlock_adapter_irq(&wandev->lock, &smp_flags); - - return 0; -} - - -/*===================================================================== - * disable_comm - * - * Description: - * Disable communications. - * This code runs in shutdown (sdlamain.c) - * under critical flag. Therefore it is not - * necessary to set a critical flag here - * - * Usage: - * Commnunications are disabled only on a card - * shutdown. - */ - -static void disable_comm (sdla_t *card) -{ - printk(KERN_INFO "%s: Disabling Communications!\n", - card->devname); - fr_comm_disable(card); -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ -static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, len; - fr_cmd_t cmd; - - if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) - return -EFAULT; - - /* execute command */ - do - { - memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - - if (cmd.length){ - if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return -EFAULT; - } - - if (sdla_exec(mbox)) - err = mbox->cmd.result; - - else return -EIO; - - } while (err && retry-- && fr_event(card, err, mbox)); - - /* return result */ - if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) - return -EFAULT; - - len = mbox->cmd.length; - - if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = NULL; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ - - /* Initialize media-specific parameters */ - if (chan->true_if_encoding){ - dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ - }else{ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - } - - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Multicast addressing */ - if (chan->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - dev->mtu = wandev->mtu - FR_HEADER_LEN; - /* For an API, the maximum number of bytes that the stack will pass - to the driver is (dev->mtu + dev->hard_header_len). So, adjust the - mtu so that a frame of maximum size can be transmitted by the API. - */ - if(chan->common.usedby == API) { - dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); - } - - dev->hard_header_len = FR_HEADER_LEN;/* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short*)dev->dev_addr = htons(chan->dlci); - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - - }else{ - - /* Setup the interface for Bridging */ - int hw_addr=0; - ether_setup(dev); - - /* Use a random number to generate the MAC address */ - memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); - get_random_bytes(&hw_addr, sizeof(hw_addr)); - *(int *)(dev->dev_addr + 2) += hw_addr; - } - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o if this is the first open, then enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int err = 0; - struct timeval tv; - - if (netif_running(dev)) - return -EBUSY; - - /* Initialize the task queue */ - chan->tq_working=0; - - INIT_WORK(&chan->common.wanpipe_work, (void *)fr_bh, dev); - - /* Allocate and initialize BH circular buffer */ - chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); - memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); - atomic_set(&chan->bh_buff_used, 0); - - netif_start_queue(dev); - - wanpipe_open(card); - do_gettimeofday( &tv ); - chan->router_start_time = tv.tv_sec; - - if (test_bit(0,&chan->config_dlci)){ - trigger_config_fr (card); - }else if (chan->inarp == INARP_REQUEST){ - trigger_fr_arp(dev); - } - - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - netif_stop_queue(dev); - wanpipe_close(card); - - return 0; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff* skb) -{ - struct net_device *dev = skb->dev; - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - chan->drvstats_if_send.if_send_tbusy++; - ++chan->ifstats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", - card->devname, dev->name); - chan->drvstats_if_send.if_send_tbusy_timeout++; - netif_wake_queue (dev); - -} - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o set critical flag when accessing board. - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * - * 2. Using netif_start_queue() and netif_stop_queue() - * will inhibit further transmit requests from the protocol stack - * and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int err; - unsigned char *sendpacket; - fr508_flags_t* adptr_flags = card->flags; - int udp_type; - long delay_tx_queued = 0; - unsigned long smp_flags=0; - unsigned char attr = 0; - - chan->drvstats_if_send.if_send_entry++; - - netif_stop_queue(dev); - - if (skb == NULL) { - /* if we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - chan->drvstats_if_send.if_send_skb_null ++; - - netif_wake_queue(dev); - return 0; - } - - /* If a peripheral task is running just drop packets */ - if (test_bit(PERI_CRIT, &card->wandev.critical)){ - - printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", - card->devname); - - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - /* We must set the 'tbusy' flag if we already have a packet queued for - transmission in the transmit interrupt handler. However, we must - ensure that the transmit interrupt does not reset the 'tbusy' flag - just before we set it, as this will result in a "transmit timeout". - */ - set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - if(chan->transmit_length) { - netif_stop_queue(dev); - chan->tick_counter = jiffies; - clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - return 1; - } - clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - - /* Move the if_header() code to here. By inserting frame - * relay header in if_header() we would break the - * tcpdump and other packet sniffers */ - chan->fr_header_len = setup_fr_header(skb,dev,chan->common.usedby); - if (chan->fr_header_len < 0 ){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - sendpacket = skb->data; - - udp_type = udp_pkt_type(skb, card); - - if(udp_type != UDP_INVALID_TYPE) { - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, - chan->dlci)) { - adptr_flags->imask |= FR_INTR_TIMER; - if (udp_type == UDP_FPIPE_TYPE){ - chan->drvstats_if_send. - if_send_PIPE_request ++; - } - } - netif_start_queue(dev); - return 0; - } - - //FIXME: can we do better than sendpacket[2]? - if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { - - /* check to see if the source IP address is a broadcast or */ - /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - } - - - /* Lock the S514/S508 card: SMP Supported */ - s508_s514_lock(card,&smp_flags); - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - chan->drvstats_if_send.if_send_critical_non_ISR ++; - chan->ifstats.tx_dropped ++; - printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", - card->devname); - goto if_send_start_and_exit; - } - - /* API packet check: minimum packet size must be greater than - * 16 byte API header */ - if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - - goto if_send_start_and_exit; - - }else{ - /* During API transmission, get rid of the API header */ - if (chan->common.usedby == API) { - api_tx_hdr_t* api_tx_hdr; - api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; - attr = api_tx_hdr->attr; - skb_pull(skb,sizeof(api_tx_hdr_t)); - } - } - - if (card->wandev.state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_wan_disconnected ++; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else if (chan->common.state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_dlci_disconnected ++; - - /* Update the DLCI state in timer interrupt */ - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; - adptr_flags->imask |= FR_INTR_TIMER; - - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else if (!is_tx_ready(card, chan)) { - /* No tx buffers available, store for delayed transmit */ - if (!setup_for_delayed_transmit(dev, skb)){ - set_bit(1,&delay_tx_queued); - } - chan->drvstats_if_send.if_send_no_bfrs++; - - } else if (!skb->protocol) { - /* No protocols drop packet */ - chan->drvstats_if_send.if_send_protocol_error ++; - ++card->wandev.stats.tx_errors; - - } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ - /* We are trying to send an ARP Packet, block IP data until - * ARP is sent */ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else { - //FIXME: IPX is not implemented in this version of Frame Relay ? - if((chan->common.usedby == WANPIPE) && - sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) { - - if( chan->enable_IPX ) { - switch_net_numbers(sendpacket, - chan->network_number, 0); - } else { - //FIXME: Take this out when IPX is fixed - printk(KERN_INFO - "%s: WARNING: Unsupported IPX data in send, packet dropped\n", - card->devname); - } - - }else{ - err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); - if (err) { - switch(err) { - case FRRES_CIR_OVERFLOW: - case FRRES_BUFFER_OVERFLOW: - if (!setup_for_delayed_transmit(dev, skb)){ - set_bit(1,&delay_tx_queued); - } - chan->drvstats_if_send. - if_send_adptr_bfrs_full ++; - break; - - case FRRES_TOO_LONG: - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Error: Frame too long, transmission failed %i\n", - card->devname, (unsigned int)skb->len); - } - /* Drop down to default */ - default: - chan->drvstats_if_send. - if_send_dlci_disconnected ++; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - } else { - chan->drvstats_if_send. - if_send_bfr_passed_to_adptr++; - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; - - chan->ifstats.tx_bytes += skb->len; - card->wandev.stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - } - } - } - -if_send_start_and_exit: - - netif_start_queue(dev); - - /* If we queued the packet for transmission, we must not - * deallocate it. The packet is unlinked from the IP stack - * not copied. Therefore, we must keep the original packet */ - if (!test_bit(1,&delay_tx_queued)) { - dev_kfree_skb_any(skb); - }else{ - adptr_flags->imask |= FR_INTR_TXRDY; - card->u.f.tx_interrupts_pending ++; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - - s508_s514_unlock(card,&smp_flags); - - return 0; -} - - - -/*============================================================================ - * Setup so that a frame can be transmitted on the occurrence of a transmit - * interrupt. - */ -static int setup_for_delayed_transmit(struct net_device* dev, - struct sk_buff *skb) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - fr_dlci_interface_t* dlci_interface; - int len = skb->len; - - /* Check that the dlci is properly configured, - * before using tx interrupt */ - if (!chan->dlci_int_interface){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: ERROR on DLCI %i: Not configured properly !\n", - card->devname, chan->dlci); - printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", - card->devname); - } - return 1; - } - - dlci_interface = chan->dlci_int_interface; - - if(chan->transmit_length) { - printk(KERN_INFO "%s: Big mess in setup_for_del...\n", - card->devname); - return 1; - } - - if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { - //FIXME: increment some statistic */ - return 1; - } - - chan->transmit_length = len; - chan->delay_skb = skb; - - dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - dlci_interface->packet_length = len; - - /* Turn on TX interrupt at the end of if_send */ - return 0; -} - - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - * Return 0 if not broadcast/multicast address, otherwise return 1. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - fr_channel_t* chan = dev->priv; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 14); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO - "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO - "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - -/*============================================================================ - * Reply to UDP Management system. - * Return nothing. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - - - fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; - - /* Set length of packet */ - len = //sizeof(fr_encap_hdr_t)+ - sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* fill in UDP reply */ - fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - fr_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = fr_udp_pkt->udp_pkt.udp_src_port; - fr_udp_pkt->udp_pkt.udp_src_port = - fr_udp_pkt->udp_pkt.udp_dst_port; - fr_udp_pkt->udp_pkt.udp_dst_port = temp; - - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *) - (fr_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *) - (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - fr_udp_pkt->udp_pkt.udp_checksum = 0; - - fr_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], - udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = udp_length + sizeof(ip_pkt_t); - temp = (ip_length<<8)|(ip_length>>8); - fr_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; - fr_udp_pkt->ip_pkt.ip_src_address = - fr_udp_pkt->ip_pkt.ip_dst_address; - fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - - /* fill in IP checksum */ - fr_udp_pkt->ip_pkt.hdr_checksum = 0; - fr_udp_pkt->ip_pkt.hdr_checksum = - calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], - sizeof(ip_pkt_t)); - - return len; -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i <len; i+=2 ) { - memcpy(&temp,&data[i],2); - sum += (unsigned long)temp; - } - - while (sum >> 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[14] << 24) + - (sendpacket[15] << 16) + (sendpacket[16] << 8) + - sendpacket[17]); - - if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[14] = sendpacket[15] = sendpacket[16] = - sendpacket[17] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) { - sendpacket[14] = (unsigned char)(network_number >> 24); - sendpacket[15] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[16] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[17] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[26] << 24) + - (sendpacket[27] << 16) + (sendpacket[28] << 8) + - sendpacket[29]); - - if( !incoming ) { - /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[26] = sendpacket[27] = sendpacket[28] = - sendpacket[29] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) { - sendpacket[26] = (unsigned char)(network_number >> 24); - sendpacket[27] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[28] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[29] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats *if_stats(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - if(chan == NULL) - return NULL; - - return &chan->ifstats; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * fr_isr: S508 frame relay interrupt service routine. - * - * Description: - * Frame relay main interrupt service route. This - * function check the interrupt type and takes - * the appropriate action. - */ -static void fr_isr (sdla_t* card) -{ - fr508_flags_t* flags = card->flags; - char *ptr = &flags->iflag; - int i,err; - fr_mbox_t* mbox = card->mbox; - - /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. */ - card->in_isr = 1; - - ++card->statistics.isr_entry; - - - /* All peripheral (configuraiton, re-configuration) events - * take presidence over the ISR. Thus, retrigger */ - if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - ++card->statistics.isr_already_critical; - goto fr_isr_exit; - } - - if(card->hw.type != SDLA_S514) { - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", - card->devname); - ++card->statistics.isr_already_critical; - goto fr_isr_exit; - } - } - - switch (flags->iflag) { - - case FR_INTR_RXRDY: /* receive interrupt */ - ++card->statistics.isr_rx; - rx_intr(card); - break; - - - case FR_INTR_TXRDY: /* transmit interrupt */ - ++ card->statistics.isr_tx; - tx_intr(card); - break; - - case FR_INTR_READY: - Intr_test_counter++; - ++card->statistics.isr_intr_test; - break; - - case FR_INTR_DLC: /* Event interrupt occurred */ - mbox->cmd.command = FR_READ_STATUS; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - fr_event(card, err, mbox); - break; - - case FR_INTR_TIMER: /* Timer interrupt */ - timer_intr(card); - break; - - default: - ++card->statistics.isr_spurious; - spur_intr(card); - printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", - card->devname, flags->iflag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - break; - } - -fr_isr_exit: - - card->in_isr = 0; - flags->iflag = 0; - return; -} - - - -/*=========================================================== - * rx_intr Receive interrupt handler. - * - * Description - * Upon receiveing an interrupt: - * 1. Check that the firmware is in sync with - * the driver. - * 2. Find an appropriate network interface - * based on the received dlci number. - * 3. Check that the netowrk interface exists - * and that it's setup properly. - * 4. Copy the data into an skb buffer. - * 5. Check the packet type and take - * appropriate acton: UPD, API, ARP or Data. - */ - -static void rx_intr (sdla_t* card) -{ - fr_rx_buf_ctl_t* frbuf = card->rxmb; - fr508_flags_t* flags = card->flags; - fr_channel_t* chan; - char *ptr = &flags->iflag; - struct sk_buff* skb; - struct net_device* dev; - void* buf; - unsigned dlci, len, offs, len_incl_hdr; - int i, udp_type; - - - /* Check that firmware buffers are in sync */ - if (frbuf->flag != 0x01) { - - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)frbuf, frbuf->flag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - ++card->statistics.rx_intr_corrupt_rx_bfr; - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it means that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - fr_set_intr_mode(card, 0, 0, 0); - return; - } - - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - - /* Find the network interface for this packet */ - dev = find_channel(card, dlci); - - - /* Check that the network interface is active and - * properly setup */ - if (dev == NULL) { - if( net_ratelimit()) { - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", - card->devname, dlci); - } - ++card->statistics.rx_intr_on_orphaned_DLCI; - ++card->wandev.stats.rx_dropped; - goto rx_done; - } - - if ((chan = dev->priv) == NULL){ - if( net_ratelimit()) { - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", - card->devname, dlci); - } - ++card->statistics.rx_intr_on_orphaned_DLCI; - ++card->wandev.stats.rx_dropped; - goto rx_done; - } - - skb = dev_alloc_skb(len); - - if (!netif_running(dev) || (skb == NULL)){ - - ++chan->ifstats.rx_dropped; - - if(skb == NULL) { - if (net_ratelimit()) { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - } - chan->drvstats_rx_intr.rx_intr_no_socket ++; - } - - if (!netif_running(dev)){ - chan->drvstats_rx_intr. - rx_intr_dev_not_started ++; - if (skb){ - dev_kfree_skb_any(skb); - } - } - goto rx_done; - } - - /* Copy data from the board into the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs + 1; - - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - - - /* We got the packet from the bard. - * Check the packet type and take appropriate action */ - - udp_type = udp_pkt_type( skb, card ); - - if(udp_type != UDP_INVALID_TYPE) { - - /* UDP Debug packet received, store the - * packet and handle it in timer interrupt */ - - skb_pull(skb, 1); - if (wanrouter_type_trans(skb, dev)){ - if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ - - flags->imask |= FR_INTR_TIMER; - - if (udp_type == UDP_FPIPE_TYPE){ - ++chan->drvstats_rx_intr.rx_intr_PIPE_request; - } - } - } - - }else if (chan->common.usedby == API) { - - /* We are in API mode. - * Add an API header to the RAW packet - * and queue it into a circular buffer. - * Then kick the fr_bh() bottom half handler */ - - api_rx_hdr_t* api_rx_hdr; - chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; - chan->ifstats.rx_packets ++; - card->wandev.stats.rx_packets ++; - - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->attr = frbuf->attr; - api_rx_hdr->time_stamp = frbuf->tmstamp; - - skb->protocol = htons(ETH_P_IP); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->pkt_type = WAN_PACKET_DATA; - - bh_enqueue(dev, skb); - - trigger_fr_bh(chan); - - }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ - - //FIXME: Frame Relay IPX is not supported, Yet ! - //if (chan->enable_IPX) { - // fr_send(card, dlci, 0, skb->len,skb->data); - //} - dev_kfree_skb_any(skb); - - } else if (is_arp(skb->data)) { - - /* ARP support enabled Mar 16 2000 - * Process incoming ARP reply/request, setup - * dynamic routes. */ - - if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { - if (net_ratelimit()){ - printk (KERN_INFO - "%s: Error processing ARP Packet.\n", - card->devname); - } - } - dev_kfree_skb_any(skb); - - } else if (skb->data[0] != 0x03) { - - if (net_ratelimit()) { - printk(KERN_INFO "%s: Non IETF packet discarded.\n", - card->devname); - } - dev_kfree_skb_any(skb); - - } else { - - len_incl_hdr = skb->len; - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; - - if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ - - /* Make sure it's an Ethernet frame, otherwise drop it */ - if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { - skb_pull(skb, 8); - skb->protocol=eth_type_trans(skb,dev); - }else{ - ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - goto rx_done; - } - }else{ - - /* remove hardware header */ - buf = skb_pull(skb, 1); - - if (!wanrouter_type_trans(skb, dev)) { - - /* can't decapsulate packet */ - dev_kfree_skb_any(skb); - - ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - goto rx_done; - } - skb->mac.raw = skb->data; - } - - - /* Send a packet up the IP stack */ - skb->dev->last_rx = jiffies; - netif_rx(skb); - ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - - chan->ifstats.rx_bytes += len_incl_hdr; - card->wandev.stats.rx_bytes += len_incl_hdr; - } - -rx_done: - - /* Release buffer element and calculate a pointer to the next one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void*)frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base; - -} - -/*================================================================== - * tx_intr: Transmit interrupt handler. - * - * Rationale: - * If the board is busy transmitting, if_send() will - * buffers a single packet and turn on - * the tx interrupt. Tx interrupt will be called - * by the board, once the firmware can send more - * data. Thus, no polling is required. - * - * Description: - * Tx interrupt is called for each - * configured dlci channel. Thus: - * 1. Obtain the netowrk interface based on the - * dlci number. - * 2. Check that network interface is up and - * properly setup. - * 3. Check for a buffered packet. - * 4. Transmit the packet. - * 5. If we are in WANPIPE mode, mark the - * NET_BH handler. - * 6. If we are in API mode, kick - * the AF_WANPIPE socket for more data. - * - */ -static void tx_intr(sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - fr_tx_buf_ctl_t* bctl; - struct net_device* dev; - fr_channel_t* chan; - - if(card->hw.type == SDLA_S514){ - bctl = (void*)(flags->tse_offs + card->hw.dpmbase); - }else{ - bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); - } - - /* Find the structure and make it unbusy */ - dev = find_channel(card, flags->dlci); - if (dev == NULL){ - printk(KERN_INFO "NO DEV IN TX Interrupt\n"); - goto end_of_tx_intr; - } - - if ((chan = dev->priv) == NULL){ - printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); - goto end_of_tx_intr; - } - - if(!chan->transmit_length || !chan->delay_skb) { - printk(KERN_INFO "%s: tx int error - transmit length zero\n", - card->wandev.name); - goto end_of_tx_intr; - } - - /* If the 'if_send()' procedure is currently checking the 'tbusy' - status, then we cannot transmit. Instead, we configure the microcode - so as to re-issue this transmit interrupt at a later stage. - */ - if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { - - fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; - bctl->flag = 0xA0; - dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - return; - - }else{ - bctl->dlci = flags->dlci; - bctl->length = chan->transmit_length+chan->fr_header_len; - sdla_poke(&card->hw, - fr_send_hdr(card,bctl->dlci,bctl->offset), - chan->delay_skb->data, - chan->delay_skb->len); - bctl->flag = 0xC0; - - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += chan->transmit_length; - card->wandev.stats.tx_bytes += chan->transmit_length; - - /* We must free an sk buffer, which we used - * for delayed transmission; Otherwise, the sock - * will run out of memory */ - dev_kfree_skb_any(chan->delay_skb); - - chan->delay_skb = NULL; - chan->transmit_length = 0; - - dev->trans_start = jiffies; - - if (netif_queue_stopped(dev)){ - /* If using API, than wakeup socket BH handler */ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - } - -end_of_tx_intr: - - /* if any other interfaces have transmit interrupts pending, - * do not disable the global transmit interrupt */ - if(!(-- card->u.f.tx_interrupts_pending)) - flags->imask &= ~FR_INTR_TXRDY; - - -} - - -/*============================================================================ - * timer_intr: Timer interrupt handler. - * - * Rationale: - * All commans must be executed within the timer - * interrupt since no two commands should execute - * at the same time. - * - * Description: - * The timer interrupt is used to: - * 1. Processing udp calls from 'fpipemon'. - * 2. Processing update calls from /proc file system - * 3. Reading board-level statistics for - * updating the proc file system. - * 4. Sending inverse ARP request packets. - * 5. Configure a dlci/channel. - * 6. Unconfigure a dlci/channel. (Node only) - */ - -static void timer_intr(sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - - /* UDP Debuging: fpipemon call */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { - if(card->u.f.udp_type == UDP_FPIPE_TYPE) { - if(process_udp_mgmt_pkt(card)) { - card->u.f.timer_int_enabled &= - ~TMR_INT_ENABLED_UDP; - } - } - } - - /* /proc update call : triggered from update() */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - fr_get_err_stats(card); - fr_get_stats(card); - card->u.f.update_comms_stats = 0; - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - } - - /* Update the channel state call. This is call is - * triggered by if_send() function */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ - struct net_device *dev; - if (card->wandev.state == WAN_CONNECTED){ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - fr_channel_t *chan = dev->priv; - if (chan->common.state != WAN_CONNECTED){ - update_chan_state(dev); - } - } - } - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; - } - - /* configure a dlci/channel */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ - config_fr(card); - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - - /* unconfigure a dlci/channel */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ - unconfig_fr(card); - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; - } - - - /* Transmit ARP packets */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ - int i=0; - struct net_device *dev; - - if (card->u.f.arp_dev == NULL) - card->u.f.arp_dev = card->wandev.dev; - - dev = card->u.f.arp_dev; - - for (;;){ - - fr_channel_t *chan = dev->priv; - - /* If the interface is brought down cancel sending In-ARPs */ - if (!(dev->flags&IFF_UP)){ - clear_bit(0,&chan->inarp_ready); - } - - if (test_bit(0,&chan->inarp_ready)){ - - if (check_tx_status(card,dev)){ - set_bit(ARP_CRIT,&card->wandev.critical); - break; - } - - if (!send_inarp_request(card,dev)){ - trigger_fr_arp(dev); - chan->inarp_tick = jiffies; - } - - clear_bit(0,&chan->inarp_ready); - dev = move_dev_to_next(card,dev); - break; - } - dev = move_dev_to_next(card,dev); - - if (++i == card->wandev.new_if_cnt){ - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; - break; - } - } - card->u.f.arp_dev = dev; - } - - if(!card->u.f.timer_int_enabled) - flags->imask &= ~FR_INTR_TIMER; -} - - -/*============================================================================ - * spur_intr: Spurious interrupt handler. - * - * Description: - * We don't know this interrupt. - * Print a warning. - */ - -static void spur_intr (sdla_t* card) -{ - if (net_ratelimit()){ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); - } -} - - -//FIXME: Fix the IPX in next version -/*=========================================================================== - * Return 0 for non-IPXWAN packet - * 1 for IPXWAN packet or IPX is not enabled! - * FIXME: Use a IPX structure here not offsets - */ -static int handle_IPXWAN(unsigned char *sendpacket, - char *devname, unsigned char enable_IPX, - unsigned long network_number) -{ - int i; - - if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { - - /* It's an IPX packet */ - if (!enable_IPX){ - /* Return 1 so we don't pass it up the stack. */ - //FIXME: Take this out when IPX is fixed - if (net_ratelimit()){ - printk (KERN_INFO - "%s: WARNING: Unsupported IPX packet received and dropped\n", - devname); - } - return 1; - } - } else { - /* It's not IPX so return and pass it up the stack. */ - return 0; - } - - if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ - /* It's IPXWAN */ - - if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ - - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", - devname); - - /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP - */ - for(i = 49; sendpacket[i] == 0x00; i += 5){ - /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02){ - sendpacket[i + 1] = 0; - } - } - - /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ){ - i += 8; - } - - /* We also want to turn off all header compression opt. - */ - for(; sendpacket[i] == 0x80 ;){ - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - /* Set the packet type to timer response */ - sendpacket[42] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", - devname); - - } else if( sendpacket[42] == 0x02 ){ - - /* This is an information request packet */ - printk(KERN_INFO - "%s: Received IPXWAN Information Request packet\n", - devname); - - /* Set the packet type to information response */ - sendpacket[42] = 0x03; - - /* Set the router name */ - sendpacket[59] = 'F'; - sendpacket[60] = 'P'; - sendpacket[61] = 'I'; - sendpacket[62] = 'P'; - sendpacket[63] = 'E'; - sendpacket[64] = '-'; - sendpacket[65] = CVHexToAscii(network_number >> 28); - sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); - for(i = 73; i < 107; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", - devname); - } else { - - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - /* Set the WNodeID to our network address */ - sendpacket[43] = (unsigned char)(network_number >> 24); - sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[46] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } - - /* If we get here, it's an IPX-data packet so it'll get passed up the - * stack. - * switch the network numbers - */ - switch_net_numbers(sendpacket, network_number ,1); - return 0; -} -/*============================================================================ - * process_route - * - * Rationale: - * If the interface goes down, or we receive an ARP request, - * we have to change the network interface ip addresses. - * This cannot be done within the interrupt. - * - * Description: - * - * This routine is called as a polling routine to dynamically - * add/delete routes negotiated by inverse ARP. It is in this - * "task" because we don't want routes to be added while in - * interrupt context. - * - * Usage: - * This function is called by fr_poll() polling funtion. - */ - -static void process_route(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - - struct ifreq if_info; - struct sockaddr_in *if_data; - mm_segment_t fs = get_fs(); - u32 ip_tmp; - int err; - - - switch(chan->route_flag){ - - case ADD_ROUTE: - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = chan->ip_remote; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO - "%s: Route Add failed. Error: %d\n", - card->devname,err); - printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", - chan->name, NIPQUAD(chan->ip_remote)); - - }else { - printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", - card->devname,NIPQUAD(chan->ip_remote)); - chan->route_flag = ROUTE_ADDED; - } - break; - - case REMOVE_ROUTE: - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = 0; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); - - if (err) { - printk(KERN_INFO - "%s: Deleting of route failed. Error: %d\n", - card->devname,err); - printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", - dev->name,NIPQUAD(chan->ip_remote) ); - - } else { - printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", - card->devname,NIPQUAD(ip_tmp)); - chan->route_flag = NO_ROUTE; - } - break; - - } /* Case Statement */ - -} - - - -/****** Frame Relay Firmware-Specific Functions *****************************/ - -/*============================================================================ - * Read firmware code version. - * o fill string str with firmware version info. - */ -static int fr_read_version (sdla_t* card, char* str) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_READ_CODE_VERSION; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err && str) { - int len = mbox->cmd.length; - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} - -/*============================================================================ - * Set global configuration. - */ -static int fr_configure (sdla_t* card, fr_conf_t *conf) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int dlci_num = card->u.f.dlci_num; - int err, i; - - do - { - memcpy(mbox->data, conf, sizeof(fr_conf_t)); - - if (dlci_num) for (i = 0; i < dlci_num; ++i) - ((fr_conf_t*)mbox->data)->dlci[i] = - card->u.f.node_dlci[i]; - - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = - sizeof(fr_conf_t) + dlci_num * sizeof(short); - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - /*NC Oct 12 2000 */ - if (err != CMD_OK){ - printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", - card->devname,err); - } - - return err; -} - -/*============================================================================ - * Set DLCI configuration. - */ -static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); - mbox->cmd.dlci = (unsigned short) dlci; - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = sizeof(fr_dlc_conf_t); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - return err; -} -/*============================================================================ - * Set interrupt mode. - */ -static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, - unsigned short timeout) -{ - fr_mbox_t* mbox = card->mbox; - fr508_intr_ctl_t* ictl = (void*)mbox->data; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - ictl->irq = card->hw.irq; - - /* indicate timeout on timer */ - if (mode & 0x20) ictl->timeout = timeout; - - mbox->cmd.length = sizeof(fr508_intr_ctl_t); - mbox->cmd.command = FR_SET_INTR_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Enable communications. - */ -static int fr_comm_enable (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_COMM_ENABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * fr_comm_disable - * - * Warning: This functin is called by the shutdown() procedure. It is void - * since dev->priv are has already been deallocated and no - * error checking is possible using fr_event() function. - */ -static void fr_comm_disable (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do { - mbox->cmd.command = FR_SET_MODEM_STATUS; - mbox->cmd.length = 1; - mbox->data[0] = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - retry = MAX_CMD_RETRY; - - do - { - mbox->cmd.command = FR_COMM_DISABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - return; -} - - - -/*============================================================================ - * Get communications error statistics. - */ -static int fr_get_err_stats (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - - do - { - mbox->cmd.command = FR_READ_ERROR_STATS; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_comm_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; - card->wandev.stats.tx_aborted_errors = stats->tx_aborts; - - } - - return err; -} - -/*============================================================================ - * Get statistics. - */ -static int fr_get_stats (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - - do - { - mbox->cmd.command = FR_READ_STATISTICS; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_link_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_frame_errors = stats->rx_bad_format; - card->wandev.stats.rx_dropped = - stats->rx_dropped + stats->rx_dropped2; - } - - return err; -} - -/*============================================================================ - * Add DLCI(s) (Access Node only!). - * This routine will perform the ADD_DLCIs command for the specified DLCI. - */ -static int fr_add_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_ADD_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Activate DLCI(s) (Access Node only!). - * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. - */ -static int fr_activate_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_ACTIVATE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Delete DLCI(s) (Access Node only!). - * This routine will perform the DELETE_DLCIs command with a DLCI number. - */ -static int fr_delete_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_DELETE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - - - -/*============================================================================ - * Issue in-channel signalling frame. - */ -static int fr_issue_isf (sdla_t* card, int isf) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->data[0] = isf; - mbox->cmd.length = 1; - mbox->cmd.command = FR_ISSUE_IS_FRAME; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - - -static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) -{ - struct net_device *dev = find_channel(card,dlci); - fr_channel_t *chan; - - if (!dev || !(chan=dev->priv)) - return offset; - - if (chan->fr_header_len){ - sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); - } - - return offset+chan->fr_header_len; -} - -/*============================================================================ - * Send a frame on a selected DLCI. - */ -static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, - void *buf, unsigned char hdr_len) -{ - fr_mbox_t* mbox = card->mbox + 0x800; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len+hdr_len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_tx_buf_ctl_t* frbuf; - - if(card->hw.type == SDLA_S514) - frbuf = (void*)(*(unsigned long*)mbox->data + - card->hw.dpmbase); - else - frbuf = (void*)(*(unsigned long*)mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); - - sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); - frbuf->flag = 0x01; - } - - return err; -} - -static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, - void *buf) -{ - fr_mbox_t* mbox = card->mbox + 0x800; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_tx_buf_ctl_t* frbuf; - - if(card->hw.type == SDLA_S514) - frbuf = (void*)(*(unsigned long*)mbox->data + - card->hw.dpmbase); - else - frbuf = (void*)(*(unsigned long*)mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); - - sdla_poke(&card->hw, frbuf->offset, buf, len); - frbuf->flag = 0x01; - } - - return err; -} - - -/****** Firmware Asynchronous Event Handlers ********************************/ - -/*============================================================================ - * Main asyncronous event/error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) -{ - fr508_flags_t* flags = card->flags; - char *ptr = &flags->iflag; - int i; - - switch (event) { - - case FRRES_MODEM_FAILURE: - return fr_modem_failure(card, mbox); - - case FRRES_CHANNEL_DOWN: { - struct net_device *dev; - - /* Remove all routes from associated DLCI's */ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan = dev->priv; - if (chan->route_flag == ROUTE_ADDED) { - chan->route_flag = REMOVE_ROUTE; - } - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - /* If the link becomes disconnected then, - * all channels will be disconnected - * as well. - */ - set_chan_state(dev,WAN_DISCONNECTED); - } - - wanpipe_set_state(card, WAN_DISCONNECTED); - return 1; - } - - case FRRES_CHANNEL_UP: { - struct net_device *dev; - - /* FIXME: Only startup devices that are on the list */ - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - - set_chan_state(dev,WAN_CONNECTED); - } - - wanpipe_set_state(card, WAN_CONNECTED); - return 1; - } - - case FRRES_DLCI_CHANGE: - return fr_dlci_change(card, mbox); - - case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", - card->devname); - return 1; - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i)); - printk(KERN_INFO "\n"); - - break; - - case FRRES_DLCI_INACTIVE: - break; - - case FRRES_CIR_OVERFLOW: - break; - - case FRRES_BUFFER_OVERFLOW: - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - , card->devname, mbox->cmd.command, event); - } - - return 0; -} - -/*============================================================================ - * Handle modem error. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) -{ - printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", - card->devname, mbox->data[0]); - - switch (mbox->cmd.command){ - case FR_WRITE: - - case FR_READ: - return 0; - } - - return 1; -} - -/*============================================================================ - * Handle DLCI status change. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) -{ - dlci_status_t* status = (void*)mbox->data; - int cnt = mbox->cmd.length / sizeof(dlci_status_t); - fr_channel_t *chan; - struct net_device* dev2; - - - for (; cnt; --cnt, ++status) { - - unsigned short dlci= status->dlci; - struct net_device* dev = find_channel(card, dlci); - - if (dev == NULL){ - printk(KERN_INFO - "%s: CPE contains unconfigured DLCI= %d\n", - card->devname, dlci); - - printk(KERN_INFO - "%s: unconfigured DLCI %d reported by network\n" - , card->devname, dlci); - - }else{ - if (status->state == FR_LINK_INOPER) { - printk(KERN_INFO - "%s: DLCI %u is inactive!\n", - card->devname, dlci); - - if (dev && netif_running(dev)) - set_chan_state(dev, WAN_DISCONNECTED); - } - - if (status->state & FR_DLCI_DELETED) { - - printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); - - if (dev && netif_running(dev)){ - - fr_channel_t *chan = dev->priv; - - if (chan->route_flag == ROUTE_ADDED) { - chan->route_flag = REMOVE_ROUTE; - /* The state change will trigger - * the fr polling routine */ - } - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - set_chan_state(dev, WAN_DISCONNECTED); - } - - } else if (status->state & FR_DLCI_ACTIVE) { - - chan = dev->priv; - - /* This flag is used for configuring specific - DLCI(s) when they become active. - */ - chan->dlci_configured = DLCI_CONFIG_PENDING; - - set_chan_state(dev, WAN_CONNECTED); - - } - } - } - - for (dev2 = card->wandev.dev; dev2; - dev2 = *((struct net_device **)dev2->priv)){ - - chan = dev2->priv; - - if (chan->dlci_configured == DLCI_CONFIG_PENDING) { - if (fr_init_dlci(card, chan)){ - return 1; - } - } - - } - return 1; -} - - -static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) -{ - fr_dlc_conf_t cfg; - - memset(&cfg, 0, sizeof(cfg)); - - if ( chan->cir_status == CIR_DISABLED) { - - cfg.cir_fwd = cfg.cir_bwd = 16; - cfg.bc_fwd = cfg.bc_bwd = 16; - cfg.conf_flags = 0x0001; - - }else if (chan->cir_status == CIR_ENABLED) { - - cfg.cir_fwd = cfg.cir_bwd = chan->cir; - cfg.bc_fwd = cfg.bc_bwd = chan->bc; - cfg.be_fwd = cfg.be_bwd = chan->be; - cfg.conf_flags = 0x0000; - } - - if (fr_dlci_configure( card, &cfg , chan->dlci)){ - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); - return 1; - } - - chan->dlci_configured = DLCI_CONFIGURED; - - /* Read the interface byte mapping into the channel - * structure. - */ - read_DLCI_IB_mapping( card, chan ); - - return 0; -} -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Update channel state. - */ -static int update_chan_state(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_LIST_ACTIVE_DLCI; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - - unsigned short* list = (void*)mbox->data; - int cnt = mbox->cmd.length / sizeof(short); - - err=1; - - for (; cnt; --cnt, ++list) { - - if (*list == chan->dlci) { - set_chan_state(dev, WAN_CONNECTED); - - - /* May 23 2000. NC - * When a dlci is added or restarted, - * the dlci_int_interface pointer must - * be reinitialized. */ - if (!chan->dlci_int_interface){ - err=fr_init_dlci (card,chan); - } - break; - } - } - } - - return err; -} - -/*============================================================================ - * Set channel state. - */ -static void set_chan_state(struct net_device* dev, int state) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->common.state != state) { - - switch (state) { - - case WAN_CONNECTED: - printk(KERN_INFO - "%s: Interface %s: DLCI %d connected\n", - card->devname, dev->name, chan->dlci); - - /* If the interface was previoulsy down, - * bring it up, since the channel is active */ - - trigger_fr_poll (dev); - trigger_fr_arp (dev); - break; - - case WAN_CONNECTING: - printk(KERN_INFO - "%s: Interface %s: DLCI %d connecting\n", - card->devname, dev->name, chan->dlci); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO - "%s: Interface %s: DLCI %d disconnected!\n", - card->devname, dev->name, chan->dlci); - - /* If the interface is up, bring it down, - * since the channel is now disconnected */ - trigger_fr_poll (dev); - break; - } - - chan->common.state = state; - } - - chan->state_tick = jiffies; -} - -/*============================================================================ - * Find network device by its channel number. - * - * We need this critical flag because we change - * the dlci_to_dev_map outside the interrupt. - * - * NOTE: del_if() functions updates this array, it uses - * the spin locks to avoid corruption. - */ -static struct net_device* find_channel(sdla_t* card, unsigned dlci) -{ - if(dlci > HIGHEST_VALID_DLCI) - return NULL; - - return(card->u.f.dlci_to_dev_map[dlci]); -} - -/*============================================================================ - * Check to see if a frame can be sent. If no transmit buffers available, - * enable transmit interrupts. - * - * Return: 1 - Tx buffer(s) available - * 0 - no buffers available - */ -static int is_tx_ready (sdla_t* card, fr_channel_t* chan) -{ - unsigned char sb; - - if(card->hw.type == SDLA_S514) - return 1; - - sb = inb(card->hw.port); - if (sb & 0x02) - return 1; - - return 0; -} - -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ -static unsigned int dec_to_uint (unsigned char* str, int len) -{ - unsigned val; - - if (!len) - len = strlen(str); - - for (val = 0; len && isdigit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - - return val; -} - - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, int dlci) -{ - int udp_pkt_stored = 0; - - struct net_device *dev = find_channel(card, dlci); - fr_channel_t *chan; - - if (!dev || !(chan=dev->priv)) - return 1; - - if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; - card->u.f.udp_type = udp_type; - card->u.f.udp_pkt_src = udp_pkt_src; - card->u.f.udp_dlci = dlci; - memcpy(card->u.f.udp_pkt_data, skb->data, skb->len); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - - }else{ - printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", - dlci); - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - -/*============================================================================== - * Process UDP call of type FPIPE8ND - */ -static int process_udp_mgmt_pkt(sdla_t* card) -{ - - int c_retry = MAX_CMD_RETRY; - unsigned char *buf; - unsigned char frames; - unsigned int len; - unsigned short buffer_length; - struct sk_buff *new_skb; - fr_mbox_t* mbox = card->mbox; - int err; - struct timeval tv; - int udp_mgmt_req_valid = 1; - struct net_device* dev; - fr_channel_t* chan; - fr_udp_pkt_t *fr_udp_pkt; - unsigned short num_trc_els; - fr_trc_el_t* ptr_trc_el; - fr_trc_el_t trc_el; - fpipemon_trc_t* fpipemon_trc; - - char udp_pkt_src = card->u.f.udp_pkt_src; - int dlci = card->u.f.udp_dlci; - - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (!dev){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - if ((chan = dev->priv) == NULL){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - - /* If the UDP packet is from the network, we are going to have to - transmit a response. Before doing so, we must check to see that - we are not currently transmitting a frame (in 'if_send()') and - that we are not already in a 'delayed transmit' state. - */ - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if (check_tx_status(card,dev)){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - } - - fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; - - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(fr_udp_pkt->cblock.command) { - - case FR_READ_MODEM_STATUS: - case FR_READ_STATUS: - case FPIPE_ROUTER_UP_TIME: - case FR_READ_ERROR_STATS: - case FPIPE_DRIVER_STAT_GEN: - case FR_READ_STATISTICS: - case FR_READ_ADD_DLC_STATS: - case FR_READ_CONFIG: - case FR_READ_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - /* set length to 0 */ - fr_udp_pkt->cblock.length = 0; - /* set return code */ - fr_udp_pkt->cblock.result = 0xCD; - - chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,fr_udp_pkt->cblock.command); - } - - } else { - - switch(fr_udp_pkt->cblock.command) { - - case FPIPE_ENABLE_TRACING: - if(!card->TracingEnabled) { - do { - mbox->cmd.command = FR_SET_TRACE_CONFIG; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = fr_udp_pkt->data[0] | - RESET_TRC; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, - mbox)); - - if(err) { - card->TracingEnabled = 0; - /* set the return code */ - fr_udp_pkt->cblock.result = - mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - - sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF, - &num_trc_els, 2); - sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF, - &card->u.f.trc_el_base, 4); - card->u.f.curr_trc_el = card->u.f.trc_el_base; - card->u.f.trc_el_last = card->u.f.curr_trc_el + - ((num_trc_els - 1) * - sizeof(fr_trc_el_t)); - - /* Calculate the maximum trace data area in */ - /* the UDP packet */ - card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - - //sizeof(fr_encap_hdr_t) - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t)); - - /* set return code */ - fr_udp_pkt->cblock.result = 0; - - } else { - /* set return code to line trace already - enabled */ - fr_udp_pkt->cblock.result = 1; - } - - mbox->cmd.length = 0; - card->TracingEnabled = 1; - break; - - - case FPIPE_DISABLE_TRACING: - if(card->TracingEnabled) { - - do { - mbox->cmd.command = FR_SET_TRACE_CONFIG; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = ~ACTIVATE_TRC; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, mbox)); - } - - /* set return code */ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 0; - break; - - case FPIPE_GET_TRACE_INFO: - - /* Line trace cannot be performed on the 502 */ - if(!card->TracingEnabled) { - /* set return code */ - fr_udp_pkt->cblock.result = 1; - mbox->cmd.length = 0; - break; - } - - ptr_trc_el = (void *)card->u.f.curr_trc_el; - - buffer_length = 0; - fr_udp_pkt->data[0x00] = 0x00; - - for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { - - sdla_peek(&card->hw, (unsigned long)ptr_trc_el, - (void *)&trc_el.flag, - sizeof(fr_trc_el_t)); - if(trc_el.flag == 0x00) { - break; - } - if((card->u.f.trc_bfr_space - buffer_length) - < sizeof(fpipemon_trc_hdr_t)) { - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - break; - } - - fpipemon_trc = - (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; - fpipemon_trc->fpipemon_trc_hdr.status = - trc_el.attr; - fpipemon_trc->fpipemon_trc_hdr.tmstamp = - trc_el.tmstamp; - fpipemon_trc->fpipemon_trc_hdr.length = - trc_el.length; - - if(!trc_el.offset || !trc_el.length) { - - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; - - }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > - (card->u.f.trc_bfr_space - buffer_length)){ - - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - - }else { - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; - sdla_peek(&card->hw, trc_el.offset, - fpipemon_trc->data, - trc_el.length); - } - - trc_el.flag = 0x00; - sdla_poke(&card->hw, (unsigned long)ptr_trc_el, - &trc_el.flag, 1); - - ptr_trc_el ++; - if((void *)ptr_trc_el > card->u.f.trc_el_last) - ptr_trc_el = (void*)card->u.f.trc_el_base; - - buffer_length += sizeof(fpipemon_trc_hdr_t); - if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { - buffer_length += trc_el.length; - } - - if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) { - break; - } - } - - if(frames == MAX_FRMS_TRACED) { - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - } - - card->u.f.curr_trc_el = (void *)ptr_trc_el; - - /* set the total number of frames passed */ - fr_udp_pkt->data[0x00] |= - ((frames << 1) & (MAX_FRMS_TRACED << 1)); - - /* set the data length and return code */ - fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, - &fr_udp_pkt->data[0x00] , 2); - fr_udp_pkt->cblock.length = mbox->cmd.length = 2; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_FLUSH_DRIVER_STATS: - init_chan_statistics(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - - case FPIPE_ROUTER_UP_TIME: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - - chan->router_start_time; - *(unsigned long *)&fr_udp_pkt->data = - chan->router_up_time; - mbox->cmd.length = fr_udp_pkt->cblock.length = 4; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_IFSEND: - memcpy(fr_udp_pkt->data, - &chan->drvstats_if_send.if_send_entry, - sizeof(if_send_stat_t)); - mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_INTR: - - memcpy(fr_udp_pkt->data, - &card->statistics.isr_entry, - sizeof(global_stats_t)); - - memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], - &chan->drvstats_rx_intr.rx_intr_no_socket, - sizeof(rx_intr_stat_t)); - - mbox->cmd.length = fr_udp_pkt->cblock.length = - sizeof(global_stats_t) + - sizeof(rx_intr_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_GEN: - memcpy(fr_udp_pkt->data, - &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], - &card->statistics, sizeof(global_stats_t)); - - mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - - case FR_FT1_STATUS_CTRL: - if(fr_udp_pkt->data[0] == 1) { - if(rCount++ != 0 ){ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if(fr_udp_pkt->data[0] == 0) { - if( --rCount != 0) { - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - goto udp_mgmt_dflt; - - - default: -udp_mgmt_dflt: - do { - memcpy(&mbox->cmd, - &fr_udp_pkt->cblock.command, - sizeof(fr_cmd_t)); - if(mbox->cmd.length) { - memcpy(&mbox->data, - (char *)fr_udp_pkt->data, - mbox->cmd.length); - } - - err = sdla_exec(mbox) ? mbox->cmd.result : - CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, mbox)); - - if(!err) - chan->drvstats_gen. - UDP_PIPE_mgmt_adptr_cmnd_OK ++; - else - chan->drvstats_gen. - UDP_PIPE_mgmt_adptr_cmnd_timeout ++; - - /* copy the result back to our buffer */ - memcpy(&fr_udp_pkt->cblock.command, - &mbox->cmd, sizeof(fr_cmd_t)); - - if(mbox->cmd.length) { - memcpy(&fr_udp_pkt->data, - &mbox->data, mbox->cmd.length); - } - } - } - - /* Fill UDP TTL */ - fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); - - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - chan->fr_header_len=2; - chan->fr_header[0]=Q922_UI; - chan->fr_header[1]=NLPID_IP; - - err = fr_send_data_header(card, dlci, 0, len, - card->u.f.udp_pkt_data,chan->fr_header_len); - if (err){ - chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; - }else{ - chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; - } - - } else { - /* Allocate socket buffer */ - if((new_skb = dev_alloc_skb(len)) != NULL) { - - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, card->u.f.udp_pkt_data, len); - - chan->drvstats_gen. - UDP_PIPE_mgmt_passed_to_stack ++; - new_skb->dev = dev; - new_skb->protocol = htons(ETH_P_IP); - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - - } else { - chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - - card->u.f.udp_pkt_lgth = 0; - - return 1; -} - -/*============================================================================== - * Send Inverse ARP Request - */ - -int send_inarp_request(sdla_t *card, struct net_device *dev) -{ - int err=0; - - arphdr_1490_t *ArpPacket; - arphdr_fr_t *arphdr; - fr_channel_t *chan = dev->priv; - struct in_device *in_dev; - - in_dev = dev->ip_ptr; - - if(in_dev != NULL ) { - - ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); - /* SNAP Header indicating ARP */ - ArpPacket->control = 0x03; - ArpPacket->pad = 0x00; - ArpPacket->NLPID = 0x80; - ArpPacket->OUI[0] = 0; - ArpPacket->OUI[1] = 0; - ArpPacket->OUI[2] = 0; - ArpPacket->PID = 0x0608; - - arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet - - /* InARP request */ - arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ - arphdr->ar_pro = 0x0008; /* IP Protocol */ - arphdr->ar_hln = 2; /* HW addr length */ - arphdr->ar_pln = 4; /* IP addr length */ - arphdr->ar_op = htons(0x08); /* InARP Request */ - arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ - if(in_dev->ifa_list != NULL) - arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else - arphdr->ar_sip = 0; - arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ - arphdr->ar_tip = 0; /* Remote Address -- what we want */ - - err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), - (void *)ArpPacket); - - if (!err){ - printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", - card->devname, chan->dlci); - clear_bit(ARP_CRIT,&card->wandev.critical); - } - - kfree(ArpPacket); - }else{ - printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", - card->devname,dev->name); - return 1; - } - - return 0; -} - - -/*============================================================================== - * Check packet for ARP Type - */ - -int is_arp(void *buf) -{ - arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; - - if (arphdr->pad == 0x00 && - arphdr->NLPID == 0x80 && - arphdr->PID == 0x0608) - return 1; - else return 0; -} - -/*============================================================================== - * Process ARP Packet Type - */ - -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) -{ - - - arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ - fr_rx_buf_ctl_t* frbuf = card->rxmb; - struct in_device *in_dev; - fr_channel_t *chan = dev->priv; - - /* Before we transmit ARP packet, we must check - * to see that we are not currently transmitting a - * frame (in 'if_send()') and that we are not - * already in a 'delayed transmit' state. */ - if (check_tx_status(card,dev)){ - if (net_ratelimit()){ - printk(KERN_INFO "%s: Disabling comminication to process ARP\n", - card->devname); - } - set_bit(ARP_CRIT,&card->wandev.critical); - return 0; - } - - in_dev = dev->ip_ptr; - - /* Check that IP addresses exist for our network address */ - if (in_dev == NULL || in_dev->ifa_list == NULL) - return -1; - - switch (ntohs(arphdr->ar_op)) { - - case 0x08: // Inverse ARP request -- Send Reply, add route. - - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", - card->devname, NIPQUAD(arphdr->ar_sip)); - - - /* Check that the network address is the same as ours, only - * if the netowrk mask is not 255.255.255.255. Otherwise - * this check would not make sense */ - - if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && - (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != - (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ - printk(KERN_INFO - "%s: Invalid PtP address. %u.%u.%u.%u InARP ignored.\n", - card->devname,NIPQUAD(arphdr->ar_sip)); - - printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", - card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); - printk(KERN_INFO "%s: local %u.%u.%u.%u\n", - card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); - return -1; - } - - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ - printk(KERN_INFO - "%s: Local addr = PtP addr. InARP ignored.\n", - card->devname); - return -1; - } - - arphdr->ar_op = htons(0x09); /* InARP Reply */ - - /* Set addresses */ - arphdr->ar_tip = arphdr->ar_sip; - arphdr->ar_sip = in_dev->ifa_list->ifa_local; - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); - - if (test_bit(ARP_CRIT,&card->wandev.critical)){ - if (net_ratelimit()){ - printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", - card->devname); - } - } - clear_bit(ARP_CRIT,&card->wandev.critical); - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ - - chan->route_flag = ADD_ROUTE; - trigger_fr_poll (dev); - - break; - - case 0x09: // Inverse ARP reply - - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", - card->devname, NIPQUAD(arphdr->ar_sip)); - - - /* Compare network addresses, only if network mask - * is not 255.255.255.255 It would not make sense - * to perform this test if the mask was all 1's */ - - if (in_dev->ifa_list->ifa_mask != 0xffffffff && - (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != - (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - - printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", - card->devname); - return -1; - } - - /* Make sure that the received IP address is not - * the same as our own local address */ - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { - printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", - card->devname); - return -1; - } - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ - - chan->route_flag = ADD_ROUTE; - chan->inarp = INARP_CONFIGURED; - trigger_fr_poll(dev); - - break; - default: - break; // ARP's and RARP's -- Shouldn't happen. - } - - return 0; -} - - -/*============================================================ - * trigger_fr_arp - * - * Description: - * Add an fr_arp() task into a arp - * timer handler for a specific dlci/interface. - * This will kick the fr_arp() routine - * within the specified time interval. - * - * Usage: - * This timer is used to send ARP requests at - * certain time intervals. - * Called by an interrupt to request an action - * at a later date. - */ - -static void trigger_fr_arp(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - mod_timer(&chan->fr_arp_timer, jiffies + chan->inarp_interval * HZ); - return; -} - - - -/*============================================================================== - * ARP Request Action - * - * This funciton is called by timer interrupt to send an arp request - * to the remote end. - */ - -static void fr_arp (unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - fr_channel_t *chan = dev->priv; - volatile sdla_t *card = chan->card; - fr508_flags_t* flags = card->flags; - - /* Send ARP packets for all devs' until - * ARP state changes to CONFIGURED */ - - if (chan->inarp == INARP_REQUEST && - chan->common.state == WAN_CONNECTED && - card->wandev.state == WAN_CONNECTED){ - set_bit(0,&chan->inarp_ready); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; - flags->imask |= FR_INTR_TIMER; - } - - return; -} - - -/*============================================================================== - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ - * TEST_COUNTER times. - */ -static int intr_test( sdla_t* card ) -{ - fr_mbox_t* mb = card->mbox; - int err,i; - - err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); - - if (err == CMD_OK) { - - for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { - /* Run command READ_CODE_VERSION */ - mb->cmd.length = 0; - mb->cmd.command = FR_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - fr_event(card, err, mb); - } - - } else { - return err; - } - - err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); - - if( err != CMD_OK ) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. FPIPE8ND ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) -{ - fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; - - /* Quick HACK */ - - - if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && - (fr_udp_pkt->udp_pkt.udp_dst_port == - ntohs(card->wandev.udp_port)) && - (fr_udp_pkt->wp_mgmt.request_reply == - UDPMGMT_REQUEST)) { - if(!strncmp(fr_udp_pkt->wp_mgmt.signature, - UDPMGMT_FPIPE_SIGNATURE, 8)){ - return UDP_FPIPE_TYPE; - } - } - return UDP_INVALID_TYPE; -} - - -/*============================================================================== - * Initializes the Statistics values in the fr_channel structure. - */ -void init_chan_statistics( fr_channel_t* chan) -{ - memset(&chan->drvstats_if_send.if_send_entry, 0, - sizeof(if_send_stat_t)); - memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, - sizeof(rx_intr_stat_t)); - memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, - sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================== - * Initializes the Statistics values in the Sdla_t structure. - */ -void init_global_statistics( sdla_t* card ) -{ - /* Intialize global statistics for a card */ - memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); -} - -static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - dlci_IB_mapping_t* result; - int err, counter, found; - - do { - mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if( mbox->cmd.result != 0){ - printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", - chan->name); - } - - counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); - result = (void *)mbox->data; - - found = 0; - for (; counter; --counter, ++result) { - if ( result->dlci == chan->dlci ) { - chan->IB_addr = result->addr_value; - if(card->hw.type == SDLA_S514){ - chan->dlci_int_interface = - (void*)(card->hw.dpmbase + - chan->IB_addr); - }else{ - chan->dlci_int_interface = - (void*)(card->hw.dpmbase + - (chan->IB_addr & 0x00001FFF)); - - } - found = 1; - break; - } - } - if (!found) - printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); -} - - - -void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) -{ - if (card->hw.type != SDLA_S514){ - - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - }else{ - spin_lock(&card->u.f.if_send_lock); - } - return; -} - - -void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) -{ - if (card->hw.type != SDLA_S514){ - - spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); - }else{ - spin_unlock(&card->u.f.if_send_lock); - } - return; -} - - - -/*---------------------------------------------------------------------- - RECEIVE INTERRUPT: BOTTOM HALF HANDLERS - ----------------------------------------------------------------------*/ - - -/*======================================================== - * bh_enqueue - * - * Description: - * Insert a received packet into a circular - * rx queue. This packet will be picked up - * by fr_bh() and sent up the stack to the - * user. - * - * Usage: - * This function is called by rx interrupt, - * in API mode. - * - */ - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - /* Check for full */ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - - if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == (MAX_BH_BUFF-1)){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - return 0; -} - - -/*======================================================== - * trigger_fr_bh - * - * Description: - * Kick the fr_bh() handler - * - * Usage: - * rx interrupt calls this function during - * the API mode. - */ - -static void trigger_fr_bh (fr_channel_t *chan) -{ - if (!test_and_set_bit(0,&chan->tq_working)){ - wanpipe_queue_work(&chan->common.wanpipe_work); - } -} - - -/*======================================================== - * fr_bh - * - * Description: - * Frame relay receive BH handler. - * Dequeue data from the BH circular - * buffer and pass it up the API sock. - * - * Rationale: - * This fuction is used to offload the - * rx_interrupt during API operation mode. - * The fr_bh() function executes for each - * dlci/interface. - * - * Once receive interrupt copies data from the - * card into an skb buffer, the skb buffer - * is appended to a circular BH buffer. - * Then the interrupt kicks fr_bh() to finish the - * job at a later time (not within the interrupt). - * - * Usage: - * Interrupts use this to defer a task to - * a polling routine. - * - */ - -static void fr_bh(struct net_device * dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - clear_bit(0, &chan->tq_working); - return; - } - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb != NULL){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - ++card->wandev.stats.rx_dropped; - ++chan->ifstats.rx_dropped; - dev_kfree_skb_any(skb); - fr_bh_cleanup(dev); - continue; - } - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for - * another try */ - atomic_set(&chan->common.receive_block,1); - return; - }else{ - fr_bh_cleanup(dev); - } - }else{ - fr_bh_cleanup(dev); - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -static int fr_bh_cleanup(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == (MAX_BH_BUFF-1)){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - -/*---------------------------------------------------------------------- - POLL BH HANDLERS AND KICK ROUTINES - ----------------------------------------------------------------------*/ - -/*============================================================ - * trigger_fr_poll - * - * Description: - * Add a fr_poll() task into a tq_scheduler bh handler - * for a specific dlci/interface. This will kick - * the fr_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ -static void trigger_fr_poll(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - schedule_work(&chan->fr_poll_work); - return; -} - - -/*============================================================ - * fr_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * Frame relay polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each frame relay - * dlci/interface through a tq_schedule bottom half. - * - * trigger_fr_poll() function is used to kick - * the fr_poll routine. - */ - -static void fr_poll(struct net_device *dev) -{ - - fr_channel_t* chan; - sdla_t *card; - u8 check_gateway=0; - - if (!dev || (chan = dev->priv) == NULL) - return; - - card = chan->card; - - /* (Re)Configuraiton is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - - switch (chan->common.state){ - - case WAN_DISCONNECTED: - - if (test_bit(DYN_OPT_ON,&chan->interface_down) && - !test_bit(DEV_DOWN, &chan->interface_down) && - dev->flags&IFF_UP){ - - printk(KERN_INFO "%s: Interface %s is Down.\n", - card->devname,dev->name); - change_dev_flags(dev,dev->flags&~IFF_UP); - set_bit(DEV_DOWN, &chan->interface_down); - chan->route_flag = NO_ROUTE; - - }else{ - if (chan->inarp != INARP_NONE) - process_route(dev); - } - break; - - case WAN_CONNECTED: - - if (test_bit(DYN_OPT_ON,&chan->interface_down) && - test_bit(DEV_DOWN, &chan->interface_down) && - !(dev->flags&IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s is Up.\n", - card->devname,dev->name); - - change_dev_flags(dev,dev->flags|IFF_UP); - clear_bit(DEV_DOWN, &chan->interface_down); - check_gateway=1; - } - - if (chan->inarp != INARP_NONE){ - process_route(dev); - check_gateway=1; - } - - if (chan->gateway && check_gateway) - add_gateway(card,dev); - - break; - - } - - return; -} - -/*============================================================== - * check_tx_status - * - * Rationale: - * We cannot transmit from an interrupt while - * the if_send is transmitting data. Therefore, - * we must check whether the tx buffers are - * begin used, before we transmit from an - * interrupt. - * - * Description: - * Checks whether it's safe to use the transmit - * buffers. - * - * Usage: - * ARP and UDP handling routines use this function - * because, they need to transmit data during - * an interrupt. - */ - -static int check_tx_status(sdla_t *card, struct net_device *dev) -{ - - if (card->hw.type == SDLA_S514){ - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || - test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { - return 1; - } - } - - if (netif_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) - return 1; - - return 0; -} - -/*=============================================================== - * move_dev_to_next - * - * Description: - * Move the dev pointer to the next location in the - * link list. Check if we are at the end of the - * list, if so start from the begining. - * - * Usage: - * Timer interrupt uses this function to efficiently - * step through the devices that need to send ARP data. - * - */ - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) -{ - if (card->wandev.new_if_cnt != 1){ - if (!*((struct net_device **)dev->priv)) - return card->wandev.dev; - else - return *((struct net_device **)dev->priv); - } - return dev; -} - -/*============================================================== - * trigger_config_fr - * - * Rationale: - * All commands must be performed inside of a - * interrupt. - * - * Description: - * Kick the config_fr() routine throught the - * timer interrupt. - */ - - -static void trigger_config_fr (sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->imask |= FR_INTR_TIMER; -} - - -/*============================================================== - * config_fr - * - * Rationale: - * All commands must be performed inside of a - * interrupt. - & - * Description: - * Configure a DLCI. This function is executed - * by a timer_interrupt. The if_open() function - * triggers it. - * - * Usage: - * new_if() collects all data necessary to - * configure the DLCI. It sets the chan->dlci_ready - * bit. When the if_open() function is executed - * it checks this bit, and if its set it triggers - * the timer interrupt to execute the config_fr() - * function. - */ - -static void config_fr (sdla_t *card) -{ - struct net_device *dev; - fr_channel_t *chan; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - - if ((chan=dev->priv) == NULL) - continue; - - if (!test_bit(0,&chan->config_dlci)) - continue; - - clear_bit(0,&chan->config_dlci); - - /* If signalling is set to NO, then setup - * DLCI addresses right away. Don't have to wait for - * link to connect. - */ - if (card->wandev.signalling == WANOPT_NO){ - printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", - card->wandev.name); - if (fr_init_dlci(card,chan)){ - printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", - card->devname, chan->dlci); - return; - } - } - - if (card->wandev.station == WANOPT_CPE) { - - update_chan_state(dev); - - /* CPE: issue full status enquiry */ - fr_issue_isf(card, FR_ISF_FSE); - - } else { - /* FR switch: activate DLCI(s) */ - - /* For Switch emulation we have to ADD and ACTIVATE - * the DLCI(s) that were configured with the SET_DLCI_ - * CONFIGURATION command. Add and Activate will fail if - * DLCI specified is not included in the list. - * - * Also If_open is called once for each interface. But - * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add - * activate routines. - */ - - if (!check_dlci_config (card, chan)){ - fr_add_dlci(card, chan->dlci); - fr_activate_dlci(card, chan->dlci); - } - } - - card->u.f.dlci_to_dev_map[chan->dlci] = dev; - } - return; -} - - -/*============================================================== - * config_fr - * - * Rationale: - * All commands must be executed during an interrupt. - * - * Description: - * Trigger uncofig_fr() function through - * the timer interrupt. - * - */ - -static void trigger_unconfig_fr(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - volatile sdla_t *card = chan->card; - unsigned long timeout; - fr508_flags_t* flags = card->flags; - int reset_critical=0; - - if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ - clear_bit(PERI_CRIT,(void*)&card->wandev.critical); - reset_critical=1; - } - - /* run unconfig_dlci() function - * throught the timer interrupt */ - set_bit(0,(void*)&chan->unconfig_dlci); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; - flags->imask |= FR_INTR_TIMER; - - /* Wait for the command to complete */ - timeout = jiffies; - for(;;) { - - if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) - break; - - if (time_after(jiffies, timeout + 1 * HZ)){ - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; - printk(KERN_INFO "%s: Failed to delete DLCI %i\n", - card->devname,chan->dlci); - break; - } - } - - if (reset_critical){ - set_bit(PERI_CRIT,(void*)&card->wandev.critical); - } -} - -/*============================================================== - * unconfig_fr - * - * Rationale: - * All commands must be executed during an interrupt. - * - * Description: - * Remove the dlci from firmware. - * This funciton is used in NODE shutdown. - */ - -static void unconfig_fr (sdla_t *card) -{ - struct net_device *dev; - fr_channel_t *chan; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - - if ((chan=dev->priv) == NULL) - continue; - - if (!test_bit(0,&chan->unconfig_dlci)) - continue; - - clear_bit(0,&chan->unconfig_dlci); - - if (card->wandev.station == WANOPT_NODE){ - printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", - card->devname,chan->dlci); - fr_delete_dlci(card,chan->dlci); - } - card->u.f.dlci_to_dev_map[chan->dlci] = NULL; - } -} - -static int setup_fr_header(struct sk_buff *skb, struct net_device* dev, - char op_mode) -{ - fr_channel_t *chan=dev->priv; - - if (op_mode == WANPIPE) { - chan->fr_header[0]=Q922_UI; - - switch (htons(skb->protocol)){ - case ETH_P_IP: - chan->fr_header[1]=NLPID_IP; - break; - default: - return -EINVAL; - } - - return 2; - } - - /* If we are in bridging mode, we must apply - * an Ethernet header - */ - if (op_mode == BRIDGE || op_mode == BRIDGE_NODE) { - /* Encapsulate the packet as a bridged Ethernet frame. */ -#ifdef DEBUG - printk(KERN_INFO "%s: encapsulating skb for frame relay\n", - dev->name); -#endif - chan->fr_header[0] = 0x03; - chan->fr_header[1] = 0x00; - chan->fr_header[2] = 0x80; - chan->fr_header[3] = 0x00; - chan->fr_header[4] = 0x80; - chan->fr_header[5] = 0xC2; - chan->fr_header[6] = 0x00; - chan->fr_header[7] = 0x07; - - /* Yuck. */ - skb->protocol = ETH_P_802_3; - return 8; - } - - return 0; -} - - -static int check_dlci_config (sdla_t *card, fr_channel_t *chan) -{ - fr_mbox_t* mbox = card->mbox; - int err=0; - fr_conf_t *conf=NULL; - unsigned short dlci_num = chan->dlci; - int dlci_offset=0; - struct net_device *dev = NULL; - - mbox->cmd.command = FR_READ_CONFIG; - mbox->cmd.length = 0; - mbox->cmd.dlci = dlci_num; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err == CMD_OK){ - return 0; - } - - for (dev = card->wandev.dev; dev; - dev=*((struct net_device **)dev->priv)) - set_chan_state(dev,WAN_DISCONNECTED); - - printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); - - mbox->cmd.command = FR_COMM_DISABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - printk(KERN_INFO "Disabled Communications \n"); - - mbox->cmd.command = FR_READ_CONFIG; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - conf = (fr_conf_t *)mbox->data; - - dlci_offset=0; - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan_tmp = dev->priv; - conf->dlci[dlci_offset] = chan_tmp->dlci; - dlci_offset++; - } - - printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", - mbox->cmd.length, - mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, - dlci_offset ); - - mbox->cmd.length = 0x20 + dlci_offset*2; - - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.dlci = 0; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - initialize_rx_tx_buffers (card); - - - printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); - - if (fr_comm_enable (card)){ - return 2; - } - - printk(KERN_INFO "Enabling Communications \n"); - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan_tmp = dev->priv; - fr_init_dlci(card,chan_tmp); - fr_add_dlci(card, chan_tmp->dlci); - fr_activate_dlci(card, chan_tmp->dlci); - } - - printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); - - return 1; -} - -static void initialize_rx_tx_buffers (sdla_t *card) -{ - fr_buf_info_t* buf_info; - - if (card->hw.type == SDLA_S514) { - - buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + - FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + - card->hw.dpmbase); - }else{ - buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - - FR_MB_VECTOR + card->hw.dpmbase); - } - - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - - card->u.f.tx_interrupts_pending = 0; - - return; -} - - - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c deleted file mode 100644 index 9d6528a50f7..00000000000 --- a/drivers/net/wan/sdla_ft1.c +++ /dev/null @@ -1,345 +0,0 @@ -/***************************************************************************** -* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. -* -* Authors: Nenad Corbic <ncorbic@sangoma.com> -* Gideon Hack -* -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. -* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing -* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). -* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. -* Aug 07, 1998 David Fong Initial version. -*****************************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/wanrouter.h> /* WAN router definitions */ -#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <linux/if_arp.h> /* ARPHRD_* defines */ -#include <linux/jiffies.h> /* time_after() macro */ - -#include <linux/inetdevice.h> -#include <asm/uaccess.h> - -#include <linux/in.h> /* sockaddr_in */ -#include <linux/inet.h> -#include <linux/if.h> -#include <asm/byteorder.h> /* htons(), etc. */ -#include <linux/sdlapci.h> -#include <asm/io.h> - -#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ - -/****** Defines & Macros ****************************************************/ - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x0001 -#define TMR_INT_ENABLED_UPDATE 0x0002 - -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define IFF_POINTTOPOINT 0x10 - -#define WANPIPE 0x00 -#define API 0x01 -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) - - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - struct net_device *slave; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpft1_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_CHDLC) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Use primary port */ - card->u.c.comm_port = 0; - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if (time_after(jiffies, timeout + 1*HZ)) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", - card->devname, u.str); - - card->isr = NULL; - card->poll = NULL; - card->exec = &wpft1_exec; - card->wandev.update = NULL; - card->wandev.new_if = NULL; - card->wandev.del_if = NULL; - card->wandev.state = WAN_DUALPORT; - card->wandev.udp_port = conf->udp_port; - - card->wandev.new_if_cnt = 0; - - /* This is for the ports link state */ - card->u.c.state = WAN_DISCONNECTED; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = 0x7F; - card->wandev.interface = 0; - - card->wandev.clocking = 0; - - port_num = card->u.c.comm_port; - - /* Setup Port Bps */ - - card->wandev.bps = 0; - - card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - card->wandev.state = WAN_FT1_READY; - printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); - - return 0; -} - -static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int len; - - if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){ - return -EFAULT; - } - - len = mbox->buffer_length; - - if (len) { - if( copy_from_user((void*)&mbox->data, u_data, len)){ - return -EFAULT; - } - } - - /* execute command */ - if (!sdla_exec(mbox)){ - return -EIO; - } - - /* return result */ - if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){ - return -EFAULT; - } - - len = mbox->buffer_length; - - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){ - return -EFAULT; - } - - return 0; - -} - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c deleted file mode 100644 index a4b489cccbb..00000000000 --- a/drivers/net/wan/sdla_ppp.c +++ /dev/null @@ -1,3430 +0,0 @@ -/***************************************************************************** -* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. -* -* Author: Nenad Corbic <ncorbic@sangoma.com> -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for -* 2.4.X kernels. -* Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: -* get_ip_address() function has moved -* into the ppp_poll() routine. It cannot -* be called from an interrupt. -* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: -* Deny all and specify allowed requests. -* May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown -* option. When the link goes down, the -* network interface IFF_UP flag is reset. -* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. -* Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called -* with NULL dev pointer: no check. -* Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. -* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels -* Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels -* Moved dynamic route processing into -* a polling routine. -* Oct 07, 1999 Nenad Corbic o Support for S514 PCI card. -* Gideon Hack o UPD and Updates executed using timer interrupt -* Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics -* Jul 20, 1999 Nenad Corbic o Remove the polling routines and use -* interrupts instead. -* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. -* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. -* Jun 22, 1998 David Fong o Added remote IP address assignment -* Mar 15, 1998 Alan Cox o 2.1.8x basic port. -* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. -* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. -* o Implemented new routines like -* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), -* tokenize() and strstrip(). -* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs -* while they have been disabled. -* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by -* disabling and enabling of irqs. -* o Added new counters for stats on disable/enable -* IRQs. -* Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' -* before every netif_rx(). -* o Free up the device structure in del_if(). -* Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing -* command. -* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. -* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow -* control by avoiding RACE conditions. The -* cli() and restore_flags() are taken out. -* A new structure, "ppp_private_area", is added -* to provide Driver Statistics. -* Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding -* save_flags(), cli() and restore_flags(). -* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets -* o Added ability to discard mulitcast and -* broacast source addressed packets. -* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities -* New case (0x25) statement in if_send routine. -* Added a global variable rCount to keep track -* of FT1 status enabled on the board. -* May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for -* 508 card to reflect changes in the new -* ppp508.sfm for supporting:continous transmission -* of Configure-Request packets without receiving a -* reply -* OR-ed 0x300 to conf_flags -* o Changed connect_tmout from 900 to 0 -* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards -* Apr 25, 1997 Farhan Thawar o added UDP Management stuff -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o fixed (+1) bug in rx_intr() -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* Jan 06, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/wanrouter.h> /* WAN router definitions */ -#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <linux/if_arp.h> /* ARPHRD_* defines */ -#include <asm/byteorder.h> /* htons(), etc. */ -#include <linux/in.h> /* sockaddr_in */ -#include <linux/jiffies.h> /* time_after() macro */ - - -#include <asm/uaccess.h> -#include <linux/inetdevice.h> -#include <linux/netdevice.h> - -#include <linux/if.h> -#include <linux/sdla_ppp.h> /* PPP firmware API definitions */ -#include <linux/sdlasfm.h> /* S514 Type Definition */ -/****** Defines & Macros ****************************************************/ - -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ -#define PPP_HDR_LEN 1 - -#define MAX_IP_ERRORS 100 - -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ - -/* For handle_IPXWAN() */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/* Macro for enabling/disabling debugging comments */ -//#define NEX_DEBUG -#ifdef NEX_DEBUG -#define NEX_PRINTK(format, a...) printk(format, ## a) -#else -#define NEX_PRINTK(format, a...) -#endif /* NEX_DEBUG */ - -#define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" ) -#define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" ) -#define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) -#define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) - -#define TMR_INT_ENABLED_UPDATE 0x01 -#define TMR_INT_ENABLED_PPP_EVENT 0x02 -#define TMR_INT_ENABLED_UDP 0x04 -#define TMR_INT_ENABLED_CONFIG 0x20 - -/* Set Configuraton Command Definitions */ -#define PERCENT_TX_BUFF 60 -#define TIME_BETWEEN_CONF_REQ 30 -#define TIME_BETWEEN_PAP_CHAP_REQ 30 -#define WAIT_PAP_CHAP_WITHOUT_REPLY 300 -#define WAIT_AFTER_DCD_CTS_LOW 5 -#define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10 -#define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900 -#define MAX_CONF_REQ_WITHOUT_REPLY 10 -#define MAX_TERM_REQ_WITHOUT_REPLY 2 -#define NUM_CONF_NAK_WITHOUT_REPLY 5 -#define NUM_AUTH_REQ_WITHOUT_REPLY 10 - -#define END_OFFSET 0x1F0 - - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with PPP specific data - */ - -typedef struct ppp_private_area -{ - struct net_device *slave; - sdla_t* card; - unsigned long router_start_time; /*router start time in sec */ - unsigned long tick_counter; /*used for 5 second counter*/ - unsigned mc; /*multicast support on or off*/ - unsigned char enable_IPX; - unsigned long network_number; - unsigned char pap; - unsigned char chap; - unsigned char sysname[31]; /* system name for in-bnd auth*/ - unsigned char userid[511]; /* list of user ids */ - unsigned char passwd[511]; /* list of passwords */ - unsigned protocol; /* SKB Protocol */ - u32 ip_local; /* Local IP Address */ - u32 ip_remote; /* remote IP Address */ - - u32 ip_local_tmp; - u32 ip_remote_tmp; - - unsigned char timer_int_enabled; /* Who enabled the timer inter*/ - unsigned char update_comms_stats; /* Used by update function */ - unsigned long curr_trace_addr; /* Trace information */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - - unsigned char interface_down; /* Brind down interface when channel - goes down */ - unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, - wait a few seconds before configuring */ - - unsigned short udp_pkt_lgth; - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - - /* PPP specific statistics */ - - if_send_stat_t if_send_stat; - rx_intr_stat_t rx_intr_stat; - pipe_mgmt_stat_t pipe_mgmt_stat; - - unsigned long router_up_time; - - /* Polling work queue entry. Each interface - * has its own work queue entry, which is used - * to defer events from the interrupt */ - struct work_struct poll_work; - struct timer_list poll_delay_timer; - - u8 gateway; - u8 config_ppp; - u8 ip_error; - -}ppp_private_area_t; - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device *wandev); -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf); -static int del_if(struct wan_device *wandev, struct net_device *dev); - -/* WANPIPE-specific entry points */ -static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); - -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - void *daddr, void *saddr, unsigned len); - -static void if_tx_timeout(struct net_device *dev); - -static int if_rebuild_hdr(struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); -static int if_send(struct sk_buff *skb, struct net_device *dev); - - -/* PPP firmware interface functions */ -static int ppp_read_version(sdla_t *card, char *str); -static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); -static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); -static int ppp_configure(sdla_t *card, void *data); -static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); -static int ppp_comm_enable(sdla_t *card); -static int ppp_comm_disable(sdla_t *card); -static int ppp_comm_disable_shutdown(sdla_t *card); -static int ppp_get_err_stats(sdla_t *card); -static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); - -static void wpp_isr(sdla_t *card); -static void rx_intr(sdla_t *card); -static void event_intr(sdla_t *card); -static void timer_intr(sdla_t *card); - -/* Background polling routines */ -static void process_route(sdla_t *card); -static void retrigger_comm(sdla_t *card); - -/* Miscellaneous functions */ -static int read_info( sdla_t *card ); -static int read_connection_info (sdla_t *card); -static void remove_route( sdla_t *card ); -static int config508(struct net_device *dev, sdla_t *card); -static void show_disc_cause(sdla_t * card, unsigned cause); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, - ppp_private_area_t *ppp_priv_area); -static void init_ppp_tx_rx_buff( sdla_t *card ); -static int intr_test( sdla_t *card ); -static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); -static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); -static void init_global_statistics( sdla_t *card ); -static int tokenize(char *str, char **tokens); -static char* strstrip(char *str, char *s); -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, - struct sk_buff *skb); - -static int config_ppp (sdla_t *); -static void ppp_poll(struct net_device *dev); -static void trigger_ppp_poll(struct net_device *dev); -static void ppp_poll_delay (unsigned long dev_ptr); - - -static int Read_connection_info; -static int Intr_test_counter; -static unsigned short available_buffer_space; - - -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, - unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, - unsigned long network_number, unsigned short proto); - -/* Lock Functions */ -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - ppp_private_area_t* ppp_priv_area ); -static unsigned short calc_checksum (char *data, int len); -static void disable_comm (sdla_t *card); -static int detect_and_fix_tx_bug (sdla_t *card); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * PPP protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpp_init(sdla_t *card, wandev_conf_t *conf) -{ - ppp_flags_t *flags; - union - { - char str[80]; - } u; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_PPP) { - - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - - } - - /* Initialize miscellaneous pointers to structures on the adapter */ - switch (card->hw.type) { - - case SDLA_S508: - card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); - card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); - break; - - case SDLA_S514: - card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS); - card->flags=(void*)(card->hw.dpmbase + PPP514_FLG_OFFS); - break; - - default: - return -EINVAL; - - } - flags = card->flags; - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); - /* Adjust configuration and set defaults */ - card->wandev.mtu = (conf->mtu) ? - min_t(unsigned int, conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; - - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = NULL; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.udp_port = conf->udp_port; - card->wandev.ttl = conf->ttl; - card->wandev.state = WAN_DISCONNECTED; - card->disable_comm = &disable_comm; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->u.p.authenticator = conf->u.ppp.authenticator; - card->u.p.ip_mode = conf->u.ppp.ip_mode ? - conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; - card->TracingEnabled = 0; - Read_connection_info = 1; - - /* initialize global statistics */ - init_global_statistics( card ); - - - - if (!card->configured){ - int err; - - Intr_test_counter = 0; - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk("%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk( "%s: Please choose another interrupt\n",card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - card->configured = 1; - } - - ppp_set_intr_mode(card, PPP_INTR_TIMER); - - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~PPP_INTR_TIMER; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update(struct wan_device *wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile ppp_private_area_t *ppp_priv_area; - ppp_flags_t *flags = card->flags; - unsigned long timeout; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* Shutdown bug fix. This function can be - * called with NULL dev pointer during - * shutdown - */ - if ((dev=card->wandev.dev) == NULL){ - return -ENODEV; - } - - if ((ppp_priv_area=dev->priv) == NULL){ - return -ENODEV; - } - - ppp_priv_area->update_comms_stats = 2; - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - flags->imask |= PPP_INTR_TIMER; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies; - for(;;) { - if(ppp_priv_area->update_comms_stats == 0){ - break; - } - if (time_after(jiffies, timeout + 1 * HZ)){ - ppp_priv_area->update_comms_stats = 0; - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf) -{ - sdla_t *card = wandev->private; - ppp_private_area_t *ppp_priv_area; - - if (wandev->ndev) - return -EEXIST; - - - printk(KERN_INFO "%s: Configuring Interface: %s\n", - card->devname, conf->name); - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - - } - - /* allocate and initialize private data */ - ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); - - if( ppp_priv_area == NULL ) - return -ENOMEM; - - memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - - ppp_priv_area->card = card; - - /* initialize data */ - strcpy(card->u.p.if_name, conf->name); - - /* initialize data in ppp_private_area structure */ - - init_ppp_priv_struct( ppp_priv_area ); - - ppp_priv_area->mc = conf->mc; - ppp_priv_area->pap = conf->pap; - ppp_priv_area->chap = conf->chap; - - /* Option to bring down the interface when - * the link goes down */ - if (conf->if_down){ - set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); - printk("%s: Dynamic interface configuration enabled\n", - card->devname); - } - - /* If no user ids are specified */ - if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* If no passwords are specified */ - if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - if(strlen(conf->sysname) > 31){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* If no system name is specified */ - if(!strlen(conf->sysname) && (card->u.p.authenticator)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* copy the data into the ppp private structure */ - memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); - memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); - memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); - - - ppp_priv_area->enable_IPX = conf->enable_IPX; - if (conf->network_number){ - ppp_priv_area->network_number = conf->network_number; - }else{ - ppp_priv_area->network_number = 0xDEADBEEF; - } - - /* Tells us that if this interface is a - * gateway or not */ - if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,card->u.p.if_name); - } - - /* prepare network device data space for registration */ - strcpy(dev->name,card->u.p.if_name); - - dev->init = &if_init; - dev->priv = ppp_priv_area; - dev->mtu = min_t(unsigned int, dev->mtu, card->wandev.mtu); - - /* Initialize the polling work routine */ - INIT_WORK(&ppp_priv_area->poll_work, (void*)(void*)ppp_poll, dev); - - /* Initialize the polling delay timer */ - init_timer(&ppp_priv_area->poll_delay_timer); - ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; - ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; - - - /* Since we start with dummy IP addresses we can say - * that route exists */ - printk(KERN_INFO "\n"); - - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device *wandev, struct net_device *dev) -{ - return 0; -} - -static void disable_comm (sdla_t *card) -{ - ppp_comm_disable_shutdown(card); - return; -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ - -//FIXME: Why do we need this ???? -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) -{ - ppp_mbox_t *mbox = card->mbox; - int len; - - if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - - len = mbox->cmd.length; - - if (len) { - - if( copy_from_user((void*)&mbox->data, u_data, len)) - return -EFAULT; - - } - - /* execute command */ - if (!sdla_exec(mbox)) - return -EIO; - - /* return result */ - if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - len = mbox->cmd.length; - - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - struct wan_device *wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Mulitcasting if specified by user*/ - if (ppp_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - struct timeval tv; - //unsigned long smp_flags; - - if (netif_running(dev)) - return -EBUSY; - - wanpipe_open(card); - - netif_start_queue(dev); - - do_gettimeofday( &tv ); - ppp_priv_area->router_start_time = tv.tv_sec; - - /* We cannot configure the card here because we don't - * have access to the interface IP addresses. - * Once the interface initilization is complete, we will be - * able to access the IP addresses. Therefore, - * configure the ppp link in the poll routine */ - set_bit(0,&ppp_priv_area->config_ppp); - ppp_priv_area->config_wait_timeout=jiffies; - - /* Start the PPP configuration after 1sec delay. - * This will give the interface initilization time - * to finish its configuration */ - mod_timer(&ppp_priv_area->poll_delay_timer, jiffies + HZ); - return 0; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - netif_stop_queue(dev); - wanpipe_close(card); - - del_timer (&ppp_priv_area->poll_delay_timer); - return 0; -} - -/*============================================================================ - * Build media header. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If packet type is not - * supported, set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - switch (type) - { - case ETH_P_IP: - case ETH_P_IPX: - skb->protocol = htons(type); - break; - - default: - skb->protocol = 0; - } - - return PPP_HDR_LEN; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - ppp_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++ chan->if_send_stat.if_send_tbusy; - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - ++chan->if_send_stat.if_send_tbusy_timeout; - netif_wake_queue (dev); -} - - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send (struct sk_buff *skb, struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - unsigned char *sendpacket; - unsigned long smp_flags; - ppp_flags_t *flags = card->flags; - int udp_type; - int err=0; - - ++ppp_priv_area->if_send_stat.if_send_entry; - - netif_stop_queue(dev); - - if (skb == NULL) { - - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - - ++ppp_priv_area->if_send_stat.if_send_skb_null; - - netif_wake_queue(dev); - return 0; - } - - sendpacket = skb->data; - - udp_type = udp_pkt_type( skb, card ); - - - if (udp_type == UDP_PTPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - ppp_priv_area)){ - flags->imask |= PPP_INTR_TIMER; - } - ++ppp_priv_area->if_send_stat.if_send_PIPE_request; - netif_start_queue(dev); - return 0; - } - - /* Check for broadcast and multicast addresses - * If found, drop (deallocate) a packet and return. - */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - - ++card->wandev.stats.tx_dropped; - ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - if (card->wandev.state != WAN_CONNECTED) { - - ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - - } else if (!skb->protocol) { - ++ppp_priv_area->if_send_stat.if_send_protocol_error; - ++card->wandev.stats.tx_errors; - netif_start_queue(dev); - - } else { - - /*If it's IPX change the network numbers to 0 if they're ours.*/ - if( skb->protocol == htons(ETH_P_IPX) ) { - if(ppp_priv_area->enable_IPX) { - switch_net_numbers( skb->data, - ppp_priv_area->network_number, 0); - } else { - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - } - - if (ppp_send(card, skb->data, skb->len, skb->protocol)) { - netif_stop_queue(dev); - ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; - ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; - } else { - ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - netif_start_queue(dev); - dev->trans_start = jiffies; - } - } - -if_send_exit_crit: - - if (!(err=netif_queue_stopped(dev))){ - dev_kfree_skb_any(skb); - }else{ - ppp_priv_area->tick_counter = jiffies; - flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ - } - - clear_bit(SEND_CRIT,&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - ppp_private_area_t* ppp_priv_area ) -{ - int udp_pkt_stored = 0; - - if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ - ppp_priv_area->udp_pkt_lgth = skb->len; - ppp_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; - ppp_priv_area->protocol = skb->protocol; - udp_pkt_stored = 1; - }else{ - if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ - printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", - card->devname, skb->len); - }else{ - printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", - card->devname); - } - ppp_priv_area->udp_pkt_lgth = 0; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - /* fill in UDP reply */ - p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound=1; - } - - temp = (udp_length<<8)|(udp_length>>8); - p_udp_pkt->udp_pkt.udp_length = temp; - - - /* swap UDP ports */ - temp = p_udp_pkt->udp_pkt.udp_src_port; - p_udp_pkt->udp_pkt.udp_src_port = - p_udp_pkt->udp_pkt.udp_dst_port; - p_udp_pkt->udp_pkt.udp_dst_port = temp; - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - p_udp_pkt->udp_pkt.udp_checksum = 0; - p_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = udp_length + sizeof(ip_pkt_t); - temp = (ip_length<<8)|(ip_length>>8); - p_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = p_udp_pkt->ip_pkt.ip_src_address; - p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address; - p_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - p_udp_pkt->ip_pkt.hdr_checksum = 0; - p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i <len; i+=2 ) { - memcpy(&temp,&data[i],2); - sum += (unsigned long)temp; - } - - while (sum >> 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - - if (!incoming) { - //If the destination network number is ours, make it 0 - if( pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } else { - //If the incoming network is 0, make it ours - if( pnetwork_number == 0) { - sendpacket[6] = (unsigned char)(network_number >> 24); - sendpacket[7] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - - if( !incoming ) { - //If the source network is ours, make it 0 - if( pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } else { - //If the source network is 0, make it ours - if( pnetwork_number == 0 ) { - sendpacket[18] = (unsigned char)(network_number >> 24); - sendpacket[19] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. - */ -static struct net_device_stats *if_stats(struct net_device *dev) -{ - - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t* card; - - if( ppp_priv_area == NULL ) - return NULL; - - card = ppp_priv_area->card; - return &card->wandev.stats; -} - -/****** PPP Firmware Interface Functions ************************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int ppp_read_version(sdla_t *card, char *str) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - - ppp_error(card, err, mb); - - else if (str) { - - int len = mb->cmd.length; - - memcpy(str, mb->data, len); - str[len] = '\0'; - - } - - return err; -} -/*=========================================================================== - * Set Out-Bound Authentication. -*/ -static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + - strlen(ppp_priv_area->passwd) + 2 ) ); - memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); - memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), - ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); - - mb->cmd.length = strlen(ppp_priv_area->userid) + - strlen(ppp_priv_area->passwd) + 2 ; - - mb->cmd.command = PPP_SET_OUTBOUND_AUTH; - - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - -/*=========================================================================== - * Set In-Bound Authentication. -*/ -static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) -{ - ppp_mbox_t *mb = card->mbox; - int err, i; - char* user_tokens[32]; - char* pass_tokens[32]; - int userids, passwds; - int add_ptr; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memset(&mb->data, 0, 1008); - memcpy(mb->data, ppp_priv_area->sysname, - strlen(ppp_priv_area->sysname)); - - /* Parse the userid string and the password string and build a string - to copy it to the data area of the command structure. The string - will look like "SYS_NAME<NULL>USER1<NULL>PASS1<NULL>USER2<NULL>PASS2 - ....<NULL> " - */ - userids = tokenize( ppp_priv_area->userid, user_tokens); - passwds = tokenize( ppp_priv_area->passwd, pass_tokens); - - if (userids != passwds){ - printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); - return 1; - } - - add_ptr = strlen(ppp_priv_area->sysname) + 1; - for (i=0; i<userids; i++){ - memcpy((mb->data + add_ptr), user_tokens[i], - strlen(user_tokens[i])); - memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), - pass_tokens[i], strlen(pass_tokens[i])); - add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + - strlen(pass_tokens[i]) + 1; - } - - mb->cmd.length = add_ptr + 1; - mb->cmd.command = PPP_SET_INBOUND_AUTH; - - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - - -/*============================================================================ - * Tokenize string. - * Parse a string of the following syntax: - * <arg1>,<arg2>,... - * and fill array of tokens with pointers to string elements. - * - */ -static int tokenize (char *str, char **tokens) -{ - int cnt = 0; - - tokens[0] = strsep(&str, "/"); - while (tokens[cnt] && (cnt < 32 - 1)) - { - tokens[cnt] = strstrip(tokens[cnt], " \t"); - tokens[++cnt] = strsep(&str, "/"); - } - return cnt; -} - -/*============================================================================ - * Strip leading and trailing spaces off the string str. - */ -static char* strstrip (char *str, char* s) -{ - char *eos = str + strlen(str); /* -> end of string */ - - while (*str && strchr(s, *str)) - ++str /* strip leading spaces */ - ; - while ((eos > str) && strchr(s, *(eos - 1))) - --eos /* strip trailing spaces */ - ; - *eos = '\0'; - return str; -} -/*============================================================================ - * Configure PPP firmware. - */ -static int ppp_configure(sdla_t *card, void *data) -{ - ppp_mbox_t *mb = card->mbox; - int data_len = sizeof(ppp508_conf_t); - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; - mb->cmd.command = PPP_SET_CONFIG; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - -/*============================================================================ - * Set interrupt mode. - */ -static int ppp_set_intr_mode(sdla_t *card, unsigned char mode) -{ - ppp_mbox_t *mb = card->mbox; - ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - ppp_intr_data->i_enable = mode; - - ppp_intr_data->irq = card->hw.irq; - mb->cmd.length = 2; - - /* If timer has been enabled, set the timer delay to 1sec */ - if (mode & 0x80){ - ppp_intr_data->timer_len = 250; //5;//100; //250; - mb->cmd.length = 4; - } - - mb->cmd.command = PPP_SET_INTR_FLAGS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - - return err; -} - -/*============================================================================ - * Enable communications. - */ -static int ppp_comm_enable(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_ENABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - else - card->u.p.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Disable communications. - */ -static int ppp_comm_disable(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_DISABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - else - card->u.p.comm_enabled = 0; - - return err; -} - -static int ppp_comm_disable_shutdown(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - ppp_intr_info_t *ppp_intr_data; - int err; - - if (!mb){ - return 1; - } - - ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; - - /* Disable all interrupts */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - ppp_intr_data->i_enable = 0; - - ppp_intr_data->irq = card->hw.irq; - mb->cmd.length = 2; - - mb->cmd.command = PPP_SET_INTR_FLAGS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - /* Disable communicatinons */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_DISABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - card->u.p.comm_enabled = 0; - - return 0; -} - - - -/*============================================================================ - * Get communications error statistics. - */ -static int ppp_get_err_stats(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_ERROR_STATS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err == CMD_OK) { - - ppp_err_stats_t* stats = (void*)mb->data; - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; - card->wandev.stats.tx_aborted_errors = stats->tx_abort; - - } else - ppp_error(card, err, mb); - - return err; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) -{ - ppp_buf_ctl_t *txbuf = card->u.p.txbuf; - - if (txbuf->flag) - return 1; - - sdla_poke(&card->hw, txbuf->buf.ptr, data, len); - - txbuf->length = len; /* frame length */ - - if (proto == htons(ETH_P_IPX)) - txbuf->proto = 0x01; /* protocol ID */ - else - txbuf->proto = 0x00; /* protocol ID */ - - txbuf->flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.p.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.p.txbuf_last) - card->u.p.txbuf = card->u.p.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) -{ - unsigned cmd = mb->cmd.command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - , card->devname, cmd, err); - } - - return 0; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * PPP interrupt service routine. - */ -static void wpp_isr (sdla_t *card) -{ - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - struct net_device *dev = card->wandev.dev; - int i; - - card->in_isr = 1; - ++card->statistics.isr_entry; - - if (!dev && flags->iflag != PPP_INTR_CMD){ - card->in_isr = 0; - flags->iflag = 0; - return; - } - - if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - card->in_isr = 0; - flags->iflag = 0; - return; - } - - - if(card->hw.type != SDLA_S514){ - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - ++card->statistics.isr_already_critical; - printk (KERN_INFO "%s: Critical while in ISR!\n", - card->devname); - card->in_isr = 0; - flags->iflag = 0; - return; - } - } - - switch (flags->iflag) { - - case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ - ++card->statistics.isr_rx; - rx_intr(card); - break; - - case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ - ++card->statistics.isr_tx; - flags->imask &= ~PPP_INTR_TXRDY; - netif_wake_queue(dev); - break; - - case PPP_INTR_CMD: /* interface command completed */ - ++Intr_test_counter; - ++card->statistics.isr_intr_test; - break; - - case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ - case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ - case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ - event_intr(card); - break; - - case PPP_INTR_TIMER: - timer_intr(card); - break; - - default: /* unexpected interrupt */ - ++card->statistics.isr_spurious; - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - } - - card->in_isr = 0; - flags->iflag = 0; - return; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr(sdla_t *card) -{ - ppp_buf_ctl_t *rxbuf = card->rxmb; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area; - struct sk_buff *skb; - unsigned len; - void *buf; - int i; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - int udp_type; - - - if (rxbuf->flag != 0x01) { - - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->flag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - ++card->statistics.rx_intr_corrupt_rx_bfr; - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it means that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - ppp_set_intr_mode(card,0); - return; - } - - if (dev && netif_running(dev) && dev->priv){ - - len = rxbuf->length; - ppp_priv_area = dev->priv; - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb != NULL) { - - /* Copy data to the socket buffer */ - unsigned addr = rxbuf->buf.ptr; - - if ((addr + len) > card->u.p.rx_top + 1) { - - unsigned tmp = card->u.p.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.p.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - /* Decapsulate packet */ - switch (rxbuf->proto) { - - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; - } - - udp_type = udp_pkt_type( skb, card ); - - if (udp_type == UDP_PTPIPE_TYPE){ - - /* Handle a UDP Request in Timer Interrupt */ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, - ppp_priv_area)){ - flags->imask |= PPP_INTR_TIMER; - } - ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request; - - - } else if (handle_IPXWAN(skb->data,card->devname, - ppp_priv_area->enable_IPX, - ppp_priv_area->network_number, - skb->protocol)) { - - /* Handle an IPXWAN packet */ - if( ppp_priv_area->enable_IPX) { - - /* Make sure we are not already sending */ - if (!test_bit(SEND_CRIT, &card->wandev.critical)){ - ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); - } - dev_kfree_skb_any(skb); - - } else { - ++card->wandev.stats.rx_dropped; - } - } else { - /* Pass data up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - - ++card->wandev.stats.rx_packets; - card->wandev.stats.rx_bytes += skb->len; - ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; - netif_rx(skb); - dev->last_rx = jiffies; - } - - } else { - - if (net_ratelimit()){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - ++card->wandev.stats.rx_dropped; - ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; - } - - } else { - ++card->statistics.rx_intr_dev_not_started; - } - - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->flag = 0x00; - card->rxmb = ++rxbuf; - if ((void*)rxbuf > card->u.p.rxbuf_last) - card->rxmb = card->u.p.rxbuf_base; -} - - -void event_intr (sdla_t *card) -{ - - struct net_device* dev = card->wandev.dev; - ppp_private_area_t* ppp_priv_area = dev->priv; - volatile ppp_flags_t *flags = card->flags; - - switch (flags->iflag){ - - case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - - if (net_ratelimit()){ - printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", - card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); - } - break; - - case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ - - NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n", - flags->disc_cause); - - if (flags->disc_cause & - (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | - PPP_REMOTE_TERMINATION)) { - - if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - set_bit(0,&Read_connection_info); - } - wanpipe_set_state(card, WAN_DISCONNECTED); - - show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - trigger_ppp_poll(dev); - } - break; - - case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ - - NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n", - card->devname,LCP(flags->lcp_state), - IP(flags->ip_state)); - - if (flags->lcp_state == 0x09 && - (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ - - /* Initialize the polling timer and set the state - * to WAN_CONNNECTED */ - - - /* BUG FIX: When the protocol restarts, during heavy - * traffic, board tx buffers and driver tx buffers - * can go out of sync. This checks the condition - * and if the tx buffers are out of sync, the - * protocols are restarted. - * I don't know why the board tx buffer is out - * of sync. It could be that a packets is tx - * while the link is down, but that is not - * possible. The other possiblility is that the - * firmware doesn't reinitialize properly. - * FIXME: A better fix should be found. - */ - if (detect_and_fix_tx_bug(card)){ - - ppp_comm_disable(card); - - wanpipe_set_state(card, WAN_DISCONNECTED); - - ppp_priv_area->timer_int_enabled |= - TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - break; - } - - card->state_tick = jiffies; - wanpipe_set_state(card, WAN_CONNECTED); - - NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", - (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next, - (unsigned long)card->rxmb, *card->u.p.rxbuf_next); - - /* Tell timer interrupt that PPP event occurred */ - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - - /* If we are in PEER mode, we must first obtain the - * IP information and then go into the poll routine */ - if (card->u.p.ip_mode != WANOPT_PPP_PEER){ - trigger_ppp_poll(dev); - } - } - break; - - case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ - - NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); - - if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - set_bit(0,&Read_connection_info); - } - - wanpipe_set_state(card, WAN_DISCONNECTED); - - show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - trigger_ppp_poll(dev); - break; - - default: - printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname); - } -} - - - -/* TIMER INTERRUPT */ - -void timer_intr (sdla_t *card) -{ - - struct net_device* dev = card->wandev.dev; - ppp_private_area_t* ppp_priv_area = dev->priv; - ppp_flags_t *flags = card->flags; - - - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ - if (!config_ppp(card)){ - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_CONFIG; - } - } - - /* Update statistics */ - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ - ppp_get_err_stats(card); - if(!(--ppp_priv_area->update_comms_stats)){ - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* PPIPEMON UDP request */ - - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){ - process_udp_mgmt_pkt(card,dev, ppp_priv_area); - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - /* PPP Event */ - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ - - if (card->wandev.state == WAN_DISCONNECTED){ - retrigger_comm(card); - } - - /* If the state is CONNECTING, it means that communicatins were - * enabled. When the remote side enables its comminication we - * should get an interrupt PPP_INTR_OPEN, thus turn off polling - */ - - else if (card->wandev.state == WAN_CONNECTING){ - /* Turn off the timer interrupt */ - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } - - /* If state is connected and we are in PEER mode - * poll for an IP address which will be provided by remote end. - */ - else if ((card->wandev.state == WAN_CONNECTED && - card->u.p.ip_mode == WANOPT_PPP_PEER) && - test_bit(0,&Read_connection_info)){ - - card->state_tick = jiffies; - if (read_connection_info (card)){ - printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", - card->devname); - }else{ - clear_bit(0,&Read_connection_info); - set_bit(1,&Read_connection_info); - trigger_ppp_poll(dev); - } - }else{ - //FIXME Put the comment back int - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } - - }/* End of PPP_EVENT */ - - - /* Only disable the timer interrupt if there are no udp, statistic */ - /* updates or events pending */ - if(!ppp_priv_area->timer_int_enabled) { - flags->imask &= ~PPP_INTR_TIMER; - } -} - - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - - if( proto == htons(ETH_P_IPX) ) { - //It's an IPX packet - if(!enable_IPX) { - //Return 1 so we don't pass it up the stack. - return 1; - } - } else { - //It's not IPX so pass it up the stack. - return 0; - } - - if( sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) - { - //It's IPXWAN - - if( sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) - { - //It's a timer request packet - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); - - //Go through the routing options and answer no to every - //option except Unnumbered RIP/SAP - for(i = 41; sendpacket[i] == 0x00; i += 5) - { - //0x02 is the option for Unnumbered RIP/SAP - if( sendpacket[i + 4] != 0x02) - { - sendpacket[i + 1] = 0; - } - } - - //Skip over the extended Node ID option - if( sendpacket[i] == 0x04 ) - { - i += 8; - } - - //We also want to turn off all header compression opt. - for(; sendpacket[i] == 0x80 ;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - //Set the packet type to timer response - sendpacket[34] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[34] == 0x02 ) - { - //This is an information request packet - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); - - //Set the packet type to information response - sendpacket[34] = 0x03; - - //Set the router name - sendpacket[51] = 'P'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for(i = 66; i < 99; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - //Set the WNodeID to our network address - sendpacket[35] = (unsigned char)(network_number >> 24); - sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } else { - //If we get here it's an IPX-data packet, so it'll get passed up the stack. - - //switch the network numbers - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/****** Background Polling Routines ****************************************/ - -/* All polling functions are invoked by the TIMER interrupt in the wpp_isr - * routine. - */ - -/*============================================================================ - * Monitor active link phase. - */ -static void process_route (sdla_t *card) -{ - ppp_flags_t *flags = card->flags; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - (flags->ip_state == 0x09)){ - - /* We get ip_local from the firmware in PEER mode. - * Therefore, if ip_local is 0, we failed to obtain - * the remote IP address. */ - if (ppp_priv_area->ip_local == 0) - return; - - printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); - if (read_info( card )) { - printk(KERN_INFO - "%s: An error occurred in IP assignment.\n", - card->devname); - } else { - struct in_device *in_dev = dev->ip_ptr; - if (in_dev != NULL ) { - struct in_ifaddr *ifa = in_dev->ifa_list; - - printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(ifa->ifa_local)); - printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(ifa->ifa_address)); - }else{ - printk(KERN_INFO - "%s: Error: Failed to add a route for PPP interface %s\n", - card->devname,dev->name); - } - } - } -} - -/*============================================================================ - * Monitor physical link disconnected phase. - * o if interface is up and the hold-down timeout has expired, then retry - * connection. - */ -static void retrigger_comm(sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - - if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - - wanpipe_set_state(card, WAN_CONNECTING); - - if(ppp_comm_enable(card) == CMD_OK){ - init_ppp_tx_rx_buff( card ); - } - } -} - -/****** Miscellaneous Functions *********************************************/ - -/*============================================================================ - * Configure S508 adapter. - */ -static int config508(struct net_device *dev, sdla_t *card) -{ - ppp508_conf_t cfg; - struct in_device *in_dev = dev->ip_ptr; - ppp_private_area_t *ppp_priv_area = dev->priv; - - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp508_conf_t)); - - if (card->wandev.clocking) - cfg.line_speed = card->wandev.bps; - - if (card->wandev.interface == WANOPT_RS232) - cfg.conf_flags |= INTERFACE_LEVEL_RS232; - - - cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ - cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; /* Default */ - cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */ - cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */ - cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */ - cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */ - cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */ - cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */ - cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */ - cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */ - cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */ - cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */ - - - if( !card->u.p.authenticator ) { - printk(KERN_INFO "%s: Device is not configured as an authenticator\n", - card->devname); - cfg.auth_options = NO_AUTHENTICATION; - }else{ - printk(KERN_INFO "%s: Device is configured as an authenticator\n", - card->devname); - cfg.auth_options = INBOUND_AUTH; - } - - if( ppp_priv_area->pap == WANOPT_YES){ - cfg.auth_options |=PAP_AUTH; - printk(KERN_INFO "%s: Pap enabled\n", card->devname); - } - if( ppp_priv_area->chap == WANOPT_YES){ - cfg.auth_options |= CHAP_AUTH; - printk(KERN_INFO "%s: Chap enabled\n", card->devname); - } - - - if (ppp_priv_area->enable_IPX == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); - cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; - }else{ - cfg.ipx_options = DISABLE_IPX; - } - - switch (card->u.p.ip_mode) { - - case WANOPT_PPP_STATIC: - - printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); - cfg.ip_options = L_AND_R_IP_NO_ASSIG | - ENABLE_IP; - cfg.ip_local = in_dev->ifa_list->ifa_local; - cfg.ip_remote = in_dev->ifa_list->ifa_address; - /* Debugging code used to check that IP addresses - * obtained from the kernel are correct */ - - NEX_PRINTK(KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", - NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); - break; - - case WANOPT_PPP_HOST: - - printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); - cfg.ip_options = L_IP_LOCAL_ASSIG | - R_IP_LOCAL_ASSIG | - ENABLE_IP; - cfg.ip_local = in_dev->ifa_list->ifa_local; - cfg.ip_remote = in_dev->ifa_list->ifa_address; - /* Debugging code used to check that IP addresses - * obtained from the kernel are correct */ - NEX_PRINTK (KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", - NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); - - break; - - case WANOPT_PPP_PEER: - - printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); - cfg.ip_options = L_IP_REMOTE_ASSIG | - R_IP_REMOTE_ASSIG | - ENABLE_IP; - cfg.ip_local = 0x00; - cfg.ip_remote = 0x00; - break; - - default: - printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", - card->devname); - printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", - card->devname); - return 1; - } - - return ppp_configure(card, &cfg); -} - -/*============================================================================ - * Show disconnection cause. - */ -static void show_disc_cause(sdla_t *card, unsigned cause) -{ - if (cause & 0x0802) - - printk(KERN_INFO "%s: link terminated by peer\n", - card->devname); - - else if (cause & 0x0004) - - printk(KERN_INFO "%s: link terminated by user\n", - card->devname); - - else if (cause & 0x0008) - - printk(KERN_INFO "%s: authentication failed\n", card->devname); - - else if (cause & 0x0010) - - printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - - else if (cause & 0x0020) - - printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - - else if (cause & 0x0040) - - printk(KERN_INFO "%s: MRU option rejected by peer\n", - card->devname); - - else if (cause & 0x0080) - - printk(KERN_INFO "%s: peer's MRU was too small\n", - card->devname); - - else if (cause & 0x0100) - - printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", - card->devname); - - else if (cause & 0x0200) - - printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" - , card->devname); - - else if (cause & 0x0400) - - printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); -} - -/*============================================================================= - * Process UDP call of type PTPIPEAB. - */ -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, - ppp_private_area_t *ppp_priv_area ) -{ - unsigned char buf2[5]; - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short data_length, buffer_length, real_len; - unsigned long data_ptr; - int udp_mgmt_req_valid = 1; - ppp_mbox_t *mbox = card->mbox; - struct timeval tv; - int err; - ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data; - - memcpy(&buf2, &card->wandev.udp_port, 2 ); - - - if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(ppp_udp_pkt->cblock.command) { - - case PPIPE_GET_IBA_DATA: - case PPP_READ_CONFIG: - case PPP_GET_CONNECTION_INFO: - case PPIPE_ROUTER_UP_TIME: - case PPP_READ_STATISTICS: - case PPP_READ_ERROR_STATS: - case PPP_READ_PACKET_STATS: - case PPP_READ_LCP_STATS: - case PPP_READ_IPCP_STATS: - case PPP_READ_IPXCP_STATS: - case PPP_READ_PAP_STATS: - case PPP_READ_CHAP_STATS: - case PPP_READ_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - ppp_udp_pkt->cblock.length = 0x00; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0xCD; - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,ppp_udp_pkt->cblock.command); - } - } else { - /* Initialize the trace element */ - trace_element_t trace_element; - - switch (ppp_udp_pkt->cblock.command){ - - /* PPIPE_ENABLE_TRACING */ - case PPIPE_ENABLE_TRACING: - if (!card->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = PPP_DATALINE_MONITOR; - mbox->cmd.length = 0x01; - mbox->data[0] = ppp_udp_pkt->data[0]; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - - ppp_error(card, err, mbox); - card->TracingEnabled = 0; - - /* set the return code */ - - ppp_udp_pkt->cblock.result = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - - sdla_peek(&card->hw, 0xC000, &buf2, 2); - - ppp_priv_area->curr_trace_addr = 0; - memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2); - ppp_priv_area->start_trace_addr = - ppp_priv_area->curr_trace_addr; - ppp_priv_area->end_trace_addr = - ppp_priv_area->start_trace_addr + END_OFFSET; - - /* MAX_SEND_BUFFER_SIZE - 28 (IP header) - - 32 (ppipemon CBLOCK) */ - available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - - sizeof(ip_pkt_t)- - sizeof(udp_pkt_t)- - sizeof(wp_mgmt_t)- - sizeof(cblock_t); - } - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 1; - break; - - /* PPIPE_DISABLE_TRACING */ - case PPIPE_DISABLE_TRACING: - - if(card->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x33; - mbox->cmd.length = 1; - mbox->data[0] = 0x00; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - - } - - /*set return code*/ - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 0; - break; - - /* PPIPE_GET_TRACE_INFO */ - case PPIPE_GET_TRACE_INFO: - - if(!card->TracingEnabled) { - /* set return code */ - ppp_udp_pkt->cblock.result = 1; - mbox->cmd.length = 0; - } - - buffer_length = 0; - - /* frames < 62, where 62 is the number of trace - information elements. There is in total 496 - bytes of space and each trace information - element is 8 bytes. - */ - for ( frames=0; frames<62; frames++) { - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &ppp_udp_pkt->data[buffer_length]; - - /* Read the whole trace packet */ - sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr, - &trace_element, sizeof(trace_element_t)); - - /* no data on board so exit */ - if( trace_element.opp_flag == 0x00 ) - break; - - data_ptr = trace_element.trace_data_ptr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element.trace_length; - }else{ - data_length = 0; - ppp_udp_pkt->data[0] |= 0x02; - } - - //FIXME: Do we need this check - if ((available_buffer_space - buffer_length) - < (sizeof(trace_element_t)+1)){ - - /*indicate we have more frames - * on board and exit - */ - ppp_udp_pkt->data[0] |= 0x02; - break; - } - - trace_pkt->status = trace_element.trace_type; - trace_pkt->time_stamp = trace_element.trace_time_stamp; - trace_pkt->real_length = trace_element.trace_length; - - real_len = trace_element.trace_length; - - if(data_ptr == 0){ - trace_pkt->data_avail = 0x00; - }else{ - /* we can take it next time */ - if ((available_buffer_space - buffer_length)< - (real_len + sizeof(trace_pkt_t))){ - - ppp_udp_pkt->data[0] |= 0x02; - break; - } - trace_pkt->data_avail = 0x01; - - /* get the data */ - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data, - real_len); - } - /* zero the opp flag to - show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr, - &buf2, 1); - - /* now move onto the next - frame */ - ppp_priv_area->curr_trace_addr += 8; - - /* check if we passed the last address */ - if ( ppp_priv_area->curr_trace_addr >= - ppp_priv_area->end_trace_addr){ - - ppp_priv_area->curr_trace_addr = - ppp_priv_area->start_trace_addr; - } - - /* update buffer length and make sure its even */ - - if ( trace_pkt->data_avail == 0x01 ) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += 8; - - if( buffer_length & 0x0001 ) - buffer_length += 1; - } - - /* ok now set the total number of frames passed - in the high 5 bits */ - ppp_udp_pkt->data[0] |= (frames << 2); - - /* set the data length */ - mbox->cmd.length = buffer_length; - ppp_udp_pkt->cblock.length = buffer_length; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_GET_IBA_DATA */ - case PPIPE_GET_IBA_DATA: - - mbox->cmd.length = 0x09; - - sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data, - mbox->cmd.length); - - /* set the length of the data */ - ppp_udp_pkt->cblock.length = 0x09; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0x00; - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_FT1_READ_STATUS */ - case PPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2); - ppp_udp_pkt->cblock.length = mbox->cmd.length = 2; - ppp_udp_pkt->cblock.result = 0; - break; - - case PPIPE_FLUSH_DRIVER_STATS: - init_ppp_priv_struct( ppp_priv_area ); - init_global_statistics( card ); - mbox->cmd.length = 0; - ppp_udp_pkt->cblock.result = 0; - break; - - - case PPIPE_ROUTER_UP_TIME: - - do_gettimeofday( &tv ); - ppp_priv_area->router_up_time = tv.tv_sec - - ppp_priv_area->router_start_time; - *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; - mbox->cmd.length = 4; - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_DRIVER_STATISTICS */ - case PPIPE_DRIVER_STAT_IFSEND: - memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, - sizeof(if_send_stat_t)); - - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t); - mbox->cmd.length = sizeof(if_send_stat_t); - break; - - case PPIPE_DRIVER_STAT_INTR: - memcpy(&ppp_udp_pkt->data, &card->statistics, - sizeof(global_stats_t)); - - memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t), - &ppp_priv_area->rx_intr_stat, - sizeof(rx_intr_stat_t)); - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = ppp_udp_pkt->cblock.length; - break; - - case PPIPE_DRIVER_STAT_GEN: - memcpy( &ppp_udp_pkt->data, - &ppp_priv_area->pipe_mgmt_stat, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t), - &card->statistics, sizeof(global_stats_t)); - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = ppp_udp_pkt->cblock.length; - break; - - - /* FT1 MONITOR STATUS */ - case FT1_MONITOR_STATUS_CTRL: - - /* Enable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 1) { - - if( rCount++ != 0 ) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - goto udp_dflt_cmd; - - /* WARNING: FIXME: This should be fixed. - * The FT1 Status Ctrl doesn't have a break - * statment. Thus, no code must be inserted - * HERE: between default and above case statement */ - - default: -udp_dflt_cmd: - - /* it's a board command */ - mbox->cmd.command = ppp_udp_pkt->cblock.command; - mbox->cmd.length = ppp_udp_pkt->cblock.length; - - if(mbox->cmd.length) { - memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data, - mbox->cmd.length); - } - - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - - ppp_error(card, err, mbox); - ++ppp_priv_area->pipe_mgmt_stat. - UDP_PIPE_mgmt_adptr_cmnd_timeout; - break; - } - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; - - /* copy the result back to our buffer */ - memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t)); - - if(mbox->cmd.length) { - memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); - - if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - /* Make sure we are not already sending */ - if (!test_bit(SEND_CRIT,&card->wandev.critical)){ - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; - ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); - } - - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf,ppp_priv_area->udp_pkt_data, len); - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; - - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - dev->last_rx = jiffies; - - } else { - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; - printk(KERN_INFO "no socket buffers available!\n"); - } - } - - ppp_priv_area->udp_pkt_lgth = 0; - - return; -} - -/*============================================================================= - * Initial the ppp_private_area structure. - */ -static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) -{ - - memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t)); - memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t)); - memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================ - * Initialize Global Statistics - */ -static void init_global_statistics( sdla_t *card ) -{ - memset(&card->statistics, 0, sizeof(global_stats_t)); -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ -static void init_ppp_tx_rx_buff( sdla_t *card ) -{ - ppp508_buf_info_t* info; - - if (card->hw.type == SDLA_S514) { - - info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS); - - card->u.p.txbuf_base = (void*)(card->hw.dpmbase + - info->txb_ptr); - - card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + - (info->txb_num - 1); - - card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + - info->rxb_ptr); - - card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + - (info->rxb_num - 1); - - } else { - - info = (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); - - card->u.p.txbuf_base = (void*)(card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - - card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + - (info->txb_num - 1); - - card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - - card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + - (info->rxb_num - 1); - } - - card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; - card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr; - - card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; - - card->u.p.txbuf = card->u.p.txbuf_base; - card->rxmb = card->u.p.rxbuf_base; - -} - -/*============================================================================= - * Read Connection Information (ie for Remote IP address assginment). - * Called when ppp interface connected. - */ -static int read_info( sdla_t *card ) -{ - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - int err; - - struct ifreq if_info; - struct sockaddr_in *if_data1, *if_data2; - mm_segment_t fs; - - /* Set Local and remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - - fs = get_fs(); - set_fs(get_ds()); /* get user space block */ - - /* Change the local and remote ip address of the interface. - * This will also add in the destination route. - */ - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = ppp_priv_area->ip_local; - if_data1->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFADDR, &if_info ); - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote; - if_data2->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - if (err) { - printk (KERN_INFO "%s: Adding of route failed: %i\n", - card->devname,err); - printk (KERN_INFO "%s: Local : %u.%u.%u.%u\n", - card->devname,NIPQUAD(ppp_priv_area->ip_local)); - printk (KERN_INFO "%s: Remote: %u.%u.%u.%u\n", - card->devname,NIPQUAD(ppp_priv_area->ip_remote)); - } - return err; -} - -/*============================================================================= - * Remove Dynamic Route. - * Called when ppp interface disconnected. - */ - -static void remove_route( sdla_t *card ) -{ - - struct net_device *dev = card->wandev.dev; - long ip_addr; - int err; - - mm_segment_t fs; - struct ifreq if_info; - struct sockaddr_in *if_data1; - struct in_device *in_dev = dev->ip_ptr; - struct in_ifaddr *ifa = in_dev->ifa_list; - - ip_addr = ifa->ifa_local; - - /* Set Local and remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - fs = get_fs(); - set_fs(get_ds()); /* get user space block */ - - /* Change the local ip address of the interface to 0. - * This will also delete the destination route. - */ - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = 0; - if_data1->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - - if (err) { - printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", - card->devname, err); - return; - }else{ - printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n", - card->devname, NIPQUAD(ip_addr)); - } - return; -} - -/*============================================================================= - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t *card ) -{ - ppp_mbox_t *mb = card->mbox; - int err,i; - - err = ppp_set_intr_mode( card, 0x08 ); - - if (err == CMD_OK) { - - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - /* Run command READ_CODE_VERSION */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = PPP_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - } - } - else return err; - - err = ppp_set_intr_mode( card, 0 ); - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; - - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - - if( ppp_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45 && /* IP packet */ - sendpacket[9] == 0x11 && /* UDP packet */ - sendpacket[22] == buf2[1] && /* UDP Port */ - sendpacket[23] == buf2[0] && - sendpacket[36] == 0x01 ) { - - if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ - sendpacket[29] == 0x54 && - sendpacket[30] == 0x50 && - sendpacket[31] == 0x49 && - sendpacket[32] == 0x50 && - sendpacket[33] == 0x45 && - sendpacket[34] == 0x41 && - sendpacket[35] == 0x42 ){ - - return UDP_PTPIPE_TYPE; - - } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[29] == 0x52 && - sendpacket[30] == 0x56 && - sendpacket[31] == 0x53 && - sendpacket[32] == 0x54 && - sendpacket[33] == 0x41 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x53 ){ - - return UDP_DRVSTATS_TYPE; - - } else - return UDP_INVALID_TYPE; - - } else - return UDP_INVALID_TYPE; - -} - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 12); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -static int read_connection_info (sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - ppp508_connect_info_t *ppp508_connect_info; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = PPP_GET_CONNECTION_INFO; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - ppp_error(card, err, mb); - ppp_priv_area->ip_remote = 0; - ppp_priv_area->ip_local = 0; - } - else { - ppp508_connect_info = (ppp508_connect_info_t *)mb->data; - ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; - ppp_priv_area->ip_local = ppp508_connect_info->ip_local; - - NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", - ppp_priv_area->ip_remote, - ppp_priv_area->ip_local); - } - - return err; -} - -/*=============================================================================== - * config_ppp - * - * Configure the ppp protocol and enable communications. - * - * The if_open function binds this function to the poll routine. - * Therefore, this function will run every time the ppp interface - * is brought up. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - */ -static int config_ppp (sdla_t *card) -{ - - struct net_device *dev = card->wandev.dev; - ppp_flags_t *flags = card->flags; - ppp_private_area_t *ppp_priv_area = dev->priv; - - if (card->u.p.comm_enabled){ - - if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || - ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ - - /* The IP addersses have changed, we must - * stop the communications and reconfigure - * the card. Reason: the firmware must know - * the local and remote IP addresses. */ - disable_comm(card); - wanpipe_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO - "%s: IP addresses changed!\n", - card->devname); - printk(KERN_INFO "%s: Restarting communications ...\n", - card->devname); - }else{ - /* IP addresses are the same and the link is up, - * we don't have to do anything here. Therefore, exit */ - return 0; - } - } - - /* Record the new IP addreses */ - ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; - ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; - - if (config508(dev, card)){ - printk(KERN_INFO "%s: Failed to configure PPP device\n", - card->devname); - return 0; - } - - if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| - PPP_INTR_TXRDY| - PPP_INTR_MODEM| - PPP_INTR_DISC | - PPP_INTR_OPEN | - PPP_INTR_DROP_DTR | - PPP_INTR_TIMER)) { - - printk(KERN_INFO "%s: Failed to configure board interrupts !\n", - card->devname); - return 0; - } - - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; - - - /* If you are not the authenticator and any one of the protocol is - * enabled then we call the set_out_bound_authentication. - */ - if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { - if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ - printk(KERN_INFO "%s: Outbound authentication failed !\n", - card->devname); - return 0; - } - } - - /* If you are the authenticator and any one of the protocol is enabled - * then we call the set_in_bound_authentication. - */ - if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ - if (ppp_set_inbnd_auth(card, ppp_priv_area)){ - printk(KERN_INFO "%s: Inbound authentication failed !\n", - card->devname); - return 0; - } - } - - /* If we fail to enable communications here it's OK, - * since the DTR timer will cause a disconnected, which - * will retrigger communication in timer_intr() */ - if (ppp_comm_enable(card) == CMD_OK) { - wanpipe_set_state(card, WAN_CONNECTING); - init_ppp_tx_rx_buff(card); - } - - return 0; -} - -/*============================================================ - * ppp_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * PPP polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each ppp - * interface through a tq_schedule bottom half. - * - * trigger_ppp_poll() function is used to kick - * the ppp_poll routine. - */ -static void ppp_poll(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area; - sdla_t *card; - u8 check_gateway=0; - ppp_flags_t *flags; - - if (!dev || (ppp_priv_area = dev->priv) == NULL) - return; - - card = ppp_priv_area->card; - flags = card->flags; - - /* Shutdown is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* if_open() function has triggered the polling routine - * to determine the configured IP addresses. Once the - * addresses are found, trigger the chdlc configuration */ - if (test_bit(0,&ppp_priv_area->config_ppp)){ - - ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); - ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && - card->u.p.ip_mode == WANOPT_PPP_HOST){ - - if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ - printk(KERN_INFO "\n%s: --- WARNING ---\n", - card->devname); - printk(KERN_INFO "%s: The local IP address is the same as the\n", - card->devname); - printk(KERN_INFO "%s: Point-to-Point IP address.\n", - card->devname); - printk(KERN_INFO "%s: --- WARNING ---\n\n", - card->devname); - }else{ - clear_bit(POLL_CRIT,&card->wandev.critical); - ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; - add_timer(&ppp_priv_area->poll_delay_timer); - return; - } - } - - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->imask |= PPP_INTR_TIMER; - ppp_priv_area->ip_error=0; - - clear_bit(0,&ppp_priv_area->config_ppp); - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* Dynamic interface implementation, as well as dynamic - * routing. */ - - switch (card->wandev.state) { - - case WAN_DISCONNECTED: - - /* If the dynamic interface configuration is on, and interface - * is up, then bring down the netowrk interface */ - - if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && - !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && - card->wandev.dev->flags & IFF_UP){ - - printk(KERN_INFO "%s: Interface %s down.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev, - (card->wandev.dev->flags&~IFF_UP)); - set_bit(DEV_DOWN,&ppp_priv_area->interface_down); - }else{ - /* We need to check if the local IP address is - * zero. If it is, we shouldn't try to remove it. - * For some reason the kernel crashes badly if - * we try to remove the route twice */ - - if (card->wandev.dev->flags & IFF_UP && - get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && - card->u.p.ip_mode == WANOPT_PPP_PEER){ - - remove_route(card); - } - } - break; - - case WAN_CONNECTED: - - /* In SMP machine this code can execute before the interface - * comes up. In this case, we must make sure that we do not - * try to bring up the interface before dev_open() is finished */ - - - /* DEV_DOWN will be set only when we bring down the interface - * for the very first time. This way we know that it was us - * that brought the interface down */ - - if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && - test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && - !(card->wandev.dev->flags & IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s up.\n", - card->devname,card->wandev.dev->name); - - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); - clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); - check_gateway=1; - } - - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - test_bit(1,&Read_connection_info)) { - - process_route(card); - clear_bit(1,&Read_connection_info); - check_gateway=1; - } - - if (ppp_priv_area->gateway && check_gateway) - add_gateway(card,dev); - - break; - } - clear_bit(POLL_CRIT,&card->wandev.critical); - return; -} - -/*============================================================ - * trigger_ppp_poll - * - * Description: - * Add a ppp_poll() task into a tq_scheduler bh handler - * for a specific interface. This will kick - * the ppp_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ - -static void trigger_ppp_poll(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area; - if ((ppp_priv_area=dev->priv) != NULL){ - - sdla_t *card = ppp_priv_area->card; - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - - if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - return; - } - - schedule_work(&ppp_priv_area->poll_work); - } - return; -} - -static void ppp_poll_delay (unsigned long dev_ptr) -{ - struct net_device *dev = (struct net_device *)dev_ptr; - trigger_ppp_poll(dev); -} - -/*============================================================ - * detect_and_fix_tx_bug - * - * Description: - * On connect, if the board tx buffer ptr is not the same - * as the driver tx buffer ptr, we found a firmware bug. - * Report the bug to the above layer. To fix the - * error restart communications again. - * - * Usage: - * - */ - -static int detect_and_fix_tx_bug (sdla_t *card) -{ - if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){ - NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); - return 1; - } - return 0; -} - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c deleted file mode 100644 index 63f846d6f3a..00000000000 --- a/drivers/net/wan/sdla_x25.c +++ /dev/null @@ -1,5497 +0,0 @@ -/***************************************************************************** -* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. -* -* Author: Nenad Corbic <ncorbic@sangoma.com> -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). -* Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses -* a kernel timer (more efficient). -* Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel -* Jul 26, 2000 Nenad Corbic o Increased the local packet buffering -* for API to 4096+header_size. -* Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable -* communications only after all interfaces -* come up. HIGH SVC/PVC is used to calculate -* the number of channels. -* Enable protocol only after all interfaces -* are enabled. -* Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. -* Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. -* Disable idle timeout in X25 API. -* Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. -* Maximum LCN number is 4095. -* Maximum number of X25 channels is 255. -* Apr 06, 2000 Nenad Corbic o Added SMP Support. -* Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card -* Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. -* Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling -* routines. Bug Fix. -* Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. -* Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. -* Application must bring the link up -* before tx/rx, and bring the -* link down on close(). -* Mar 06, 2000 Nenad Corbic o Added an option for logging call setup -* information. -* Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API -* Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. -* No Modem OOB message will be passed -* to the user. -* Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support -* Dec 30, 1999 Nenad Corbic o Socket based X25API -* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel -* Mar 15, 1998 Alan Cox o 2.1.x porting -* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support -* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs -* when they are disabled. -* Nov 17, 1997 Farhan Thawar o Added IPX support -* o Changed if_send() to now buffer packets when -* the board is busy -* o Removed queueing of packets via the polling -* routing -* o Changed if_send() critical flags to properly -* handle race conditions -* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts -* o Changed PVC encapsulation to ETH_P_IP -* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree() -* when packets are received. -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o added support for V35 -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* o added support for single '@' address to -* accept all incoming calls -* o fixed bug in set_chan_state() to disconnect -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* Jan 07, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -/*====================================================== - * Includes - *=====================================================*/ - -#include <linux/module.h> -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/ctype.h> -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/wanrouter.h> /* WAN router definitions */ -#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <linux/workqueue.h> -#include <linux/jiffies.h> /* time_after() macro */ -#include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/atomic.h> -#include <linux/delay.h> /* Experimental delay */ - -#include <asm/uaccess.h> - -#include <linux/if.h> -#include <linux/if_arp.h> -#include <linux/sdla_x25.h> /* X.25 firmware API definitions */ -#include <linux/if_wanpipe_common.h> -#include <linux/if_wanpipe.h> - - -/*====================================================== - * Defines & Macros - *=====================================================*/ - - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ -#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ -#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ -#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ -#define MAX_BH_BUFF 10 -#define M_BIT 0x01 - -//#define PRINT_DEBUG 1 -#ifdef PRINT_DEBUG -#define DBG_PRINTK(format, a...) printk(format, ## a) -#else -#define DBG_PRINTK(format, a...) -#endif - -#define TMR_INT_ENABLED_POLL_ACTIVE 0x01 -#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 -#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 -#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 -#define TMR_INT_ENABLED_CMD_EXEC 0x10 -#define TMR_INT_ENABLED_UPDATE 0x20 -#define TMR_INT_ENABLED_UDP_PKT 0x40 - -#define MAX_X25_ADDR_SIZE 16 -#define MAX_X25_DATA_SIZE 129 -#define MAX_X25_FACL_SIZE 110 - -#define TRY_CMD_AGAIN 2 -#define DELAY_RESULT 1 -#define RETURN_RESULT 0 - -#define DCD(x) (x & 0x03 ? "HIGH" : "LOW") -#define CTS(x) (x & 0x05 ? "HIGH" : "LOW") - - -/* Driver will not write log messages about - * modem status if defined.*/ -#define MODEM_NOT_LOG 1 - -/*==================================================== - * For IPXWAN - *===================================================*/ - -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - - -/*==================================================== - * MEMORY DEBUGGING FUNCTION - *==================================================== - -#define KMEM_SAFETYZONE 8 - -static void * dbg_kmalloc(unsigned int size, int prio, int line) { - int i = 0; - void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); - char * c1 = v; - c1 += sizeof(unsigned int); - *((unsigned int *)v) = size; - - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; - c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; - c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; - c1 += 8; - } - v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; - printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); - return v; -} -static void dbg_kfree(void * v, int line) { - unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); - unsigned int size = *sp; - char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; - int i = 0; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' - || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { - printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' - || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' - ) { - printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - printk(KERN_INFO "line %d kfree(%p)\n",line,v); - v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); - kfree(v); -} - -#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) -#define kfree(x) dbg_kfree(x,__LINE__) - -==============================================================*/ - - - -/*=============================================== - * Data Structures - *===============================================*/ - - -/*======================================================== - * Name: x25_channel - * - * Purpose: To hold private informaton for each - * logical channel. - * - * Rationale: Per-channel debugging is possible if each - * channel has its own private area. - * - * Assumptions: - * - * Description: This is an extention of the struct net_device - * we create for each network interface to keep - * the rest of X.25 channel-specific data. - * - * Construct: Typedef - */ -typedef struct x25_channel -{ - wanpipe_common_t common; /* common area for x25api and socket */ - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - unsigned tx_pkt_size; - unsigned short protocol; /* ethertype, 0 - multiplexed */ - char drop_sequence; /* mark sequence for dropping */ - unsigned long state_tick; /* time of the last state change */ - unsigned idle_timeout; /* sec, before disconnecting */ - unsigned long i_timeout_sofar; /* # of sec's we've been idle */ - unsigned hold_timeout; /* sec, before re-connecting */ - unsigned long tick_counter; /* counter for transmit time out */ - char devtint; /* Weather we should dev_tint() */ - struct sk_buff* rx_skb; /* receive socket buffer */ - struct sk_buff* tx_skb; /* transmit socket buffer */ - - bh_data_t *bh_head; /* Circular buffer for x25api_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - sdla_t* card; /* -> owner */ - struct net_device *dev; /* -> bound devce */ - - int ch_idx; - unsigned char enable_IPX; - unsigned long network_number; - struct net_device_stats ifstats; /* interface statistics */ - unsigned short transmit_length; - unsigned short tx_offset; - char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; - - if_send_stat_t if_send_stat; - rx_intr_stat_t rx_intr_stat; - pipe_mgmt_stat_t pipe_mgmt_stat; - - unsigned long router_start_time; /* Router start time in seconds */ - unsigned long router_up_time; - -} x25_channel_t; - -/* FIXME Take this out */ - -#ifdef NEX_OLD_CALL_INFO -typedef struct x25_call_info -{ - char dest[17]; PACKED;/* ASCIIZ destination address */ - char src[17]; PACKED;/* ASCIIZ source address */ - char nuser; PACKED;/* number of user data bytes */ - unsigned char user[127]; PACKED;/* user data */ - char nfacil; PACKED;/* number of facilities */ - struct - { - unsigned char code; PACKED; - unsigned char parm; PACKED; - } facil[64]; /* facilities */ -} x25_call_info_t; -#else -typedef struct x25_call_info -{ - char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ - char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ - unsigned char nuser PACKED; - unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ - unsigned char nfacil PACKED; - unsigned char facil[MAX_X25_FACL_SIZE] PACKED; - unsigned short lcn PACKED; -} x25_call_info_t; -#endif - - - -/*=============================================== - * Private Function Prototypes - *==============================================*/ - - -/*================================================= - * WAN link driver entry points. These are - * called by the WAN router module. - */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if(struct wan_device* wandev, struct net_device* dev); -static void disable_comm (sdla_t* card); -static void disable_comm_shutdown(sdla_t *card); - - - -/*================================================= - * WANPIPE-specific entry points - */ -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); -static void x25api_bh(struct net_device *dev); -static int x25api_bh_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - - -/*================================================= - * Network device interface - */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, unsigned len); -static int if_rebuild_hdr (struct sk_buff* skb); -static int if_send(struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats *if_stats(struct net_device* dev); - -static void if_tx_timeout(struct net_device *dev); - -/*================================================= - * Interrupt handlers - */ -static void wpx_isr (sdla_t *); -static void rx_intr (sdla_t *); -static void tx_intr (sdla_t *); -static void status_intr (sdla_t *); -static void event_intr (sdla_t *); -static void spur_intr (sdla_t *); -static void timer_intr (sdla_t *); - -static int tx_intr_send(sdla_t *card, struct net_device *dev); -static struct net_device *move_dev_to_next(sdla_t *card, - struct net_device *dev); - -/*================================================= - * Background polling routines - */ -static void wpx_poll (sdla_t* card); -static void poll_disconnected (sdla_t* card); -static void poll_connecting (sdla_t* card); -static void poll_active (sdla_t* card); -static void trigger_x25_poll(sdla_t *card); -static void x25_timer_routine(unsigned long data); - - - -/*================================================= - * X.25 firmware interface functions - */ -static int x25_get_version (sdla_t* card, char* str); -static int x25_configure (sdla_t* card, TX25Config* conf); -static int hdlc_configure (sdla_t* card, TX25Config* conf); -static int set_hdlc_level (sdla_t* card); -static int x25_get_err_stats (sdla_t* card); -static int x25_get_stats (sdla_t* card); -static int x25_set_intr_mode (sdla_t* card, int mode); -static int x25_close_hdlc (sdla_t* card); -static int x25_open_hdlc (sdla_t* card); -static int x25_setup_hdlc (sdla_t* card); -static int x25_set_dtr (sdla_t* card, int dtr); -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); -static int x25_place_call (sdla_t* card, x25_channel_t* chan); -static int x25_accept_call (sdla_t* card, int lcn, int qdm); -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); -static int x25_fetch_events (sdla_t* card); -static int x25_error (sdla_t* card, int err, int cmd, int lcn); - -/*================================================= - * X.25 asynchronous event handlers - */ -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); - - -/*================================================= - * Miscellaneous functions - */ -static int connect (sdla_t* card); -static int disconnect (sdla_t* card); -static struct net_device* get_dev_by_lcn(struct wan_device* wandev, - unsigned lcn); -static int chan_connect(struct net_device* dev); -static int chan_disc(struct net_device* dev); -static void set_chan_state(struct net_device* dev, int state); -static int chan_send(struct net_device *dev, void* buff, unsigned data_len, - unsigned char tx_intr); -static unsigned char bps_to_speed_code (unsigned long bps); -static unsigned int dec_to_uint (unsigned char* str, int len); -static unsigned int hex_to_uint (unsigned char*, int); -static void parse_call_info (unsigned char*, x25_call_info_t*); -static struct net_device *find_channel(sdla_t *card, unsigned lcn); -static void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn); -static void setup_for_delayed_transmit(struct net_device *dev, - void *buf, unsigned len); - - -/*================================================= - * X25 API Functions - */ -static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, - struct sk_buff **); -static void timer_intr_exec(sdla_t *, unsigned char); -static int execute_delayed_cmd(sdla_t *card, struct net_device *dev, - mbox_cmd_t *usr_cmd, char bad_cmd); -static int api_incoming_call (sdla_t*, TX25Mbox *, int); -static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); -static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, - TX25Mbox* mbox); -static int clear_confirm_event (sdla_t *, TX25Mbox*); -static void send_oob_msg (sdla_t *card, struct net_device *dev, TX25Mbox *mbox); -static int timer_intr_cmd_exec(sdla_t *card); -static void api_oob_event (sdla_t *card,TX25Mbox *mbox); -static int check_bad_command(sdla_t *card, struct net_device *dev); -static int channel_disconnect(sdla_t* card, struct net_device *dev); -static void hdlc_link_down (sdla_t*); - -/*================================================= - * XPIPEMON Functions - */ -static int process_udp_mgmt_pkt(sdla_t *); -static int udp_pkt_type( struct sk_buff *, sdla_t*); -static int reply_udp( unsigned char *, unsigned int); -static void init_x25_channel_struct( x25_channel_t *); -static void init_global_statistics( sdla_t *); -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t *card, - struct net_device *dev, - struct sk_buff *skb, int lcn); -static unsigned short calc_checksum (char *, int); - - - -/*================================================= - * IPX functions - */ -static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); -static int handle_IPXWAN(unsigned char *, char *, unsigned char , - unsigned long , unsigned short ); - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -static void S508_S514_lock(sdla_t *, unsigned long *); -static void S508_S514_unlock(sdla_t *, unsigned long *); - - -/*================================================= - * Global Variables - *=================================================*/ - - - -/*================================================= - * Public Functions - *=================================================*/ - - - - -/*=================================================================== - * wpx_init: X.25 Protocol Initialization routine. - * - * Purpose: To initialize the protocol/firmware. - * - * Rationale: This function is called by setup() function, in - * sdlamain.c, to dynamically setup the x25 protocol. - * This is the first protocol specific function, which - * executes once on startup. - * - * Description: This procedure initializes the x25 firmware and - * sets up the mailbox, transmit and receive buffer - * pointers. It also initializes all debugging structures - * and sets up the X25 environment. - * - * Sets up hardware options defined by user in [wanpipe#] - * section of wanpipe#.conf configuration file. - * - * At this point adapter is completely initialized - * and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the - * adapter data space. - * - * Called by: setup() function in sdlamain.c - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 o.k. - * < 0 failure. - */ - -int wpx_init (sdla_t* card, wandev_conf_t* conf) -{ - union{ - char str[80]; - TX25Config cfg; - } u; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_X25){ - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id) - ; - return -EINVAL; - } - - /* Initialize protocol-specific fields */ - card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); - card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); - card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); - - /* Initialize for S514 Card */ - if(card->hw.type == SDLA_S514) { - card->mbox += X25_MB_VECTOR; - card->flags += X25_MB_VECTOR; - card->rxmb += X25_MB_VECTOR; - } - - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) - return -EIO; - - - /* X25 firmware can run ether in X25 or LAPB HDLC mode. - * Check the user defined option and configure accordingly */ - if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ - if (set_hdlc_level(card) != CMD_OK){ - return -EIO; - }else{ - printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", - card->devname, u.str); - } - card->u.x.LAPB_hdlc = 1; - }else{ - printk(KERN_INFO "%s: running X.25 firmware v%s\n", - card->devname, u.str); - card->u.x.LAPB_hdlc = 0; - } - - /* Configure adapter. Here we set resonable defaults, then parse - * device configuration structure and set configuration options. - * Most configuration options are verified and corrected (if - * necessary) since we can't rely on the adapter to do so. - */ - memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.t1 = 3; - u.cfg.n2 = 10; - u.cfg.autoHdlc = 1; /* automatic HDLC connection */ - u.cfg.hdlcWindow = 7; - u.cfg.pktWindow = 2; - u.cfg.station = 1; /* DTE */ - u.cfg.options = 0x0090; /* disable D-bit pragmatics */ - u.cfg.ccittCompat = 1988; - u.cfg.t10t20 = 30; - u.cfg.t11t21 = 30; - u.cfg.t12t22 = 30; - u.cfg.t13t23 = 30; - u.cfg.t16t26 = 30; - u.cfg.t28 = 30; - u.cfg.r10r20 = 5; - u.cfg.r12r22 = 5; - u.cfg.r13r23 = 5; - u.cfg.responseOpt = 1; /* RR's after every packet */ - - if (card->u.x.LAPB_hdlc){ - u.cfg.hdlcMTU = 1027; - } - - if (conf->u.x25.x25_conf_opt){ - u.cfg.options = conf->u.x25.x25_conf_opt; - } - - if (conf->clocking != WANOPT_EXTERNAL) - u.cfg.baudRate = bps_to_speed_code(conf->bps); - - if (conf->station != WANOPT_DTE){ - u.cfg.station = 0; /* DCE mode */ - } - - if (conf->interface != WANOPT_RS232 ){ - u.cfg.hdlcOptions |= 0x80; /* V35 mode */ - } - - /* adjust MTU */ - if (!conf->mtu || (conf->mtu >= 1024)) - card->wandev.mtu = 1024; - else if (conf->mtu >= 512) - card->wandev.mtu = 512; - else if (conf->mtu >= 256) - card->wandev.mtu = 256; - else if (conf->mtu >= 128) - card->wandev.mtu = 128; - else - card->wandev.mtu = 64; - - u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; - - if (conf->u.x25.hi_pvc){ - card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, MAX_LCN_NUM); - card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc); - } - - if (conf->u.x25.hi_svc){ - card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, MAX_LCN_NUM); - card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc); - } - - /* Figure out the total number of channels to configure */ - card->u.x.num_of_ch = 0; - if (card->u.x.hi_svc != 0){ - card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1; - } - if (card->u.x.hi_pvc != 0){ - card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1; - } - - if (card->u.x.num_of_ch == 0){ - printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" - "%s: Please set the Lowest/Highest PVC/SVC values !\n", - card->devname,card->devname); - return -ECHRNG; - } - - u.cfg.loPVC = card->u.x.lo_pvc; - u.cfg.hiPVC = card->u.x.hi_pvc; - u.cfg.loTwoWaySVC = card->u.x.lo_svc; - u.cfg.hiTwoWaySVC = card->u.x.hi_svc; - - if (conf->u.x25.hdlc_window) - u.cfg.hdlcWindow = min_t(unsigned int, conf->u.x25.hdlc_window, 7); - if (conf->u.x25.pkt_window) - u.cfg.pktWindow = min_t(unsigned int, conf->u.x25.pkt_window, 7); - - if (conf->u.x25.t1) - u.cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30); - if (conf->u.x25.t2) - u.cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 29); - if (conf->u.x25.t4) - u.cfg.t4 = min_t(unsigned int, conf->u.x25.t4, 240); - if (conf->u.x25.n2) - u.cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30); - - if (conf->u.x25.t10_t20) - u.cfg.t10t20 = min_t(unsigned int, conf->u.x25.t10_t20,255); - if (conf->u.x25.t11_t21) - u.cfg.t11t21 = min_t(unsigned int, conf->u.x25.t11_t21,255); - if (conf->u.x25.t12_t22) - u.cfg.t12t22 = min_t(unsigned int, conf->u.x25.t12_t22,255); - if (conf->u.x25.t13_t23) - u.cfg.t13t23 = min_t(unsigned int, conf->u.x25.t13_t23,255); - if (conf->u.x25.t16_t26) - u.cfg.t16t26 = min_t(unsigned int, conf->u.x25.t16_t26, 255); - if (conf->u.x25.t28) - u.cfg.t28 = min_t(unsigned int, conf->u.x25.t28, 255); - - if (conf->u.x25.r10_r20) - u.cfg.r10r20 = min_t(unsigned int, conf->u.x25.r10_r20,250); - if (conf->u.x25.r12_r22) - u.cfg.r12r22 = min_t(unsigned int, conf->u.x25.r12_r22,250); - if (conf->u.x25.r13_r23) - u.cfg.r13r23 = min_t(unsigned int, conf->u.x25.r13_r23,250); - - - if (conf->u.x25.ccitt_compat) - u.cfg.ccittCompat = conf->u.x25.ccitt_compat; - - /* initialize adapter */ - if (card->u.x.LAPB_hdlc){ - if (hdlc_configure(card, &u.cfg) != CMD_OK) - return -EIO; - }else{ - if (x25_configure(card, &u.cfg) != CMD_OK) - return -EIO; - } - - if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ - (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ - return -EIO; - - /* Initialize protocol-specific fields of adapter data space */ - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpx_isr; - card->poll = NULL; //&wpx_poll; - card->disable_comm = &disable_comm; - card->exec = &wpx_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - - /* WARNING: This function cannot exit with an error - * after the change of state */ - card->wandev.state = WAN_DISCONNECTED; - - card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->u.x.tx_dev = NULL; - card->u.x.no_dev = 0; - - - /* Configure for S514 PCI Card */ - if (card->hw.type == SDLA_S514) { - card->u.x.hdlc_buf_status = - (volatile unsigned char *) - (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS); - }else{ - card->u.x.hdlc_buf_status = - (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); - } - - card->u.x.poll_device=NULL; - card->wandev.udp_port = conf->udp_port; - - /* Enable or disable call setup logging */ - if (conf->u.x25.logging == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling Call Logging.\n", - card->devname); - card->u.x.logging = 1; - }else{ - card->u.x.logging = 0; - } - - /* Enable or disable modem status reporting */ - if (conf->u.x25.oob_on_modem == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", - card->devname); - card->u.x.oob_on_modem = 1; - }else{ - card->u.x.oob_on_modem = 0; - } - - init_global_statistics(card); - - INIT_WORK(&card->u.x.x25_poll_work, (void *)wpx_poll, card); - - init_timer(&card->u.x.x25_timer); - card->u.x.x25_timer.data = (unsigned long)card; - card->u.x.x25_timer.function = x25_timer_routine; - - return 0; -} - -/*========================================================= - * WAN Device Driver Entry Points - *========================================================*/ - -/*============================================================ - * Name: update(), Update device status & statistics. - * - * Purpose: To provide debugging and statitical - * information to the /proc file system. - * /proc/net/wanrouter/wanpipe# - * - * Rationale: The /proc file system is used to collect - * information about the kernel and drivers. - * Using the /proc file system the user - * can see exactly what the sangoma drivers are - * doing. And in what state they are in. - * - * Description: Collect all driver statistical information - * and pass it to the top laywer. - * - * Since we have to execute a debugging command, - * to obtain firmware statitics, we trigger a - * UPDATE function within the timer interrtup. - * We wait until the timer update is complete. - * Once complete return the appropriate return - * code to indicate that the update was successful. - * - * Called by: device_stat() in wanmain.c - * - * Assumptions: - * - * Warnings: This function will degrade the performance - * of the router, since it uses the mailbox. - * - * Return: 0 OK - * <0 Failed (or busy). - */ - -static int update(struct wan_device* wandev) -{ - volatile sdla_t* card; - TX25Status* status; - unsigned long timeout; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - if (test_bit(SEND_CRIT, (void*)&wandev->critical)) - return -EAGAIN; - - if (!wandev->dev) - return -ENODEV; - - card = wandev->private; - status = card->flags; - - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - status->imask |= INTR_ON_TIMER; - timeout = jiffies; - - for (;;){ - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){ - break; - } - if (time_after(jiffies, timeout + 1*HZ)){ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - return 0; -} - - -/*=================================================================== - * Name: new_if - * - * Purpose: To allocate and initialize resources for a - * new logical channel. - * - * Rationale: A new channel can be added dynamically via - * ioctl call. - * - * Description: Allocate a private channel structure, x25_channel_t. - * Parse the user interface options from wanpipe#.conf - * configuration file. - * Bind the private are into the network device private - * area pointer (dev->priv). - * Prepare the network device structure for registration. - * - * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() - * (wanmain.c) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failed (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - x25_channel_t* chan; - int err = 0; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - - if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { - printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", - card->devname); - printk(KERN_INFO - "%s: Maximum number of network interfaces must be one !\n", - card->devname); - return -EEXIST; - } - - /* allocate and initialize private data */ - chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); - if (chan == NULL){ - return -ENOMEM; - } - - memset(chan, 0, sizeof(x25_channel_t)); - - /* Bug Fix: Seg Err on PVC startup - * It must be here since bind_lcn_to_dev expects - * it bellow */ - dev->priv = chan; - - strcpy(chan->name, conf->name); - chan->card = card; - chan->dev = dev; - chan->common.sk = NULL; - chan->common.func = NULL; - chan->common.rw_bind = 0; - chan->tx_skb = chan->rx_skb = NULL; - - /* verify media address */ - if (conf->addr[0] == '@'){ /* SVC */ - chan->common.svc = 1; - strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); - - /* Set channel timeouts (default if not specified) */ - chan->idle_timeout = (conf->idle_timeout) ? - conf->idle_timeout : 90; - chan->hold_timeout = (conf->hold_timeout) ? - conf->hold_timeout : 10; - - }else if (isdigit(conf->addr[0])){ /* PVC */ - int lcn = dec_to_uint(conf->addr, 0); - - if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ - bind_lcn_to_dev (card, dev, lcn); - }else{ - printk(KERN_ERR - "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name); - err = -EINVAL; - } - }else{ - printk(KERN_ERR - "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - - if(strcmp(conf->usedby, "WANPIPE") == 0){ - printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", - wandev->name, chan->name); - chan->common.usedby = WANPIPE; - chan->protocol = htons(ETH_P_IP); - - }else if(strcmp(conf->usedby, "API") == 0){ - chan->common.usedby = API; - printk(KERN_INFO "%s: Running in API mode %s\n", - wandev->name, chan->name); - chan->protocol = htons(X25_PROT); - } - - - if (err){ - kfree(chan); - dev->priv = NULL; - return err; - } - - chan->enable_IPX = conf->enable_IPX; - - if (chan->enable_IPX) - chan->protocol = htons(ETH_P_IPX); - - if (conf->network_number) - chan->network_number = conf->network_number; - else - chan->network_number = 0xDEADBEEF; - - /* prepare network device data space for registration */ - strcpy(dev->name,chan->name); - - dev->init = &if_init; - - init_x25_channel_struct(chan); - - return 0; -} - -/*=================================================================== - * Name: del_if(), Remove a logical channel. - * - * Purpose: To dynamically remove a logical channel. - * - * Rationale: Each logical channel should be dynamically - * removable. This functin is called by an - * IOCTL_IFDEL ioctl call or shutdown(). - * - * Description: Do nothing. - * - * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c - * shutdown() from sdlamain.c - * - * Assumptions: - * - * Warnings: - * - * Return: 0 Ok. Void function. - */ - -//FIXME Del IF Should be taken out now. - -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - return 0; -} - - -/*============================================================ - * Name: wpx_exec - * - * Description: Execute adapter interface command. - * This option is currently dissabled. - *===========================================================*/ - -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) -{ - return 0; -} - -/*============================================================ - * Name: disable_comm - * - * Description: Disable communications during shutdown. - * Dont check return code because there is - * nothing we can do about it. - * - * Warning: Dev and private areas are gone at this point. - *===========================================================*/ - -static void disable_comm(sdla_t* card) -{ - disable_comm_shutdown(card); - del_timer(&card->u.x.x25_timer); - return; -} - - -/*============================================================ - * Network Device Interface - *===========================================================*/ - -/*=================================================================== - * Name: if_init(), Netowrk Interface Initialization - * - * Purpose: To initialize a network interface device structure. - * - * Rationale: During network interface startup, the if_init - * is called by the kernel to initialize the - * netowrk device structure. Thus a driver - * can customze a network device. - * - * Description: Initialize the netowrk device call back - * routines. This is where we tell the kernel - * which function to use when it wants to send - * via our interface. - * Furthermore, we initialize the device flags, - * MTU and physical address of the board. - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->init()) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok : Void function. - */ -static int if_init(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - if (chan->common.usedby == API){ - dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); - }else{ - dev->mtu = card->wandev.mtu; - } - - dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - - if (!chan->common.svc){ - *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); - } - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - /* FIXME Why are we doing this */ - set_chan_state(dev, WAN_DISCONNECTED); - return 0; -} - - -/*=================================================================== - * Name: if_open(), Open/Bring up the Netowrk Interface - * - * Purpose: To bring up a network interface. - * - * Rationale: - * - * Description: Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->open()) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failure: Interface will not come up. - */ - -static int if_open(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct timeval tv; - unsigned long smp_flags; - - if (netif_running(dev)) - return -EBUSY; - - chan->tq_working = 0; - - /* Initialize the workqueue */ - INIT_WORK(&chan->common.wanpipe_work, (void *)x25api_bh, dev); - - /* Allocate and initialize BH circular buffer */ - /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ - chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); - - if (chan->bh_head == NULL){ - printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n", - card->devname); - - return -ENOBUFS; - } - memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); - atomic_set(&chan->bh_buff_used, 0); - - /* Increment the number of interfaces */ - ++card->u.x.no_dev; - - wanpipe_open(card); - - /* LAPB protocol only uses one interface, thus - * start the protocol after it comes up. */ - if (card->u.x.LAPB_hdlc){ - if (card->open_cnt == 1){ - TX25Status* status = card->flags; - S508_S514_lock(card, &smp_flags); - x25_set_intr_mode(card, INTR_ON_TIMER); - status->imask &= ~INTR_ON_TIMER; - S508_S514_unlock(card, &smp_flags); - } - }else{ - /* X25 can have multiple interfaces thus, start the - * protocol once all interfaces are up */ - - //FIXME: There is a bug here. If interface is - //brought down and up, it will try to enable comm. - if (card->open_cnt == card->u.x.num_of_ch){ - - S508_S514_lock(card, &smp_flags); - connect(card); - S508_S514_unlock(card, &smp_flags); - - mod_timer(&card->u.x.x25_timer, jiffies + HZ); - } - } - /* Device is not up until the we are in connected state */ - do_gettimeofday( &tv ); - chan->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - return 0; -} - -/*=================================================================== - * Name: if_close(), Close/Bring down the Netowrk Interface - * - * Purpose: To bring down a network interface. - * - * Rationale: - * - * Description: Close network interface. - * o decrement use module use count - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->close()) - * ifconfig <name> down: will trigger the kernel - * which will call this function. - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failure: Interface will not exit properly. - */ -static int if_close(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - unsigned long smp_flags; - - netif_stop_queue(dev); - - if ((chan->common.state == WAN_CONNECTED) || - (chan->common.state == WAN_CONNECTING)){ - S508_S514_lock(card, &smp_flags); - chan_disc(dev); - S508_S514_unlock(card, &smp_flags); - } - - wanpipe_close(card); - - S508_S514_lock(card, &smp_flags); - if (chan->bh_head){ - int i; - struct sk_buff *skb; - - for (i=0; i<(MAX_BH_BUFF+1); i++){ - skb = ((bh_data_t *)&chan->bh_head[i])->skb; - if (skb != NULL){ - dev_kfree_skb_any(skb); - } - } - kfree(chan->bh_head); - chan->bh_head=NULL; - } - S508_S514_unlock(card, &smp_flags); - - /* If this is the last close, disconnect physical link */ - if (!card->open_cnt){ - S508_S514_lock(card, &smp_flags); - disconnect(card); - x25_set_intr_mode(card, 0); - S508_S514_unlock(card, &smp_flags); - } - - /* Decrement the number of interfaces */ - --card->u.x.no_dev; - return 0; -} - -/*====================================================================== - * Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' - * field of the socket buffer, so that we don't forget it. - * If encapsulation fails, set skb->protocol to 0 and discard - * packet later. - * - * Return: media header length. - *======================================================================*/ - -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len) -{ - x25_channel_t* chan = dev->priv; - int hdr_len = dev->hard_header_len; - - skb->protocol = htons(type); - if (!chan->protocol){ - hdr_len = wanrouter_encapsulate(skb, dev, type); - if (hdr_len < 0){ - hdr_len = 0; - skb->protocol = htons(0); - } - } - return hdr_len; -} - -/*=============================================================== - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - *==============================================================*/ - -static int if_rebuild_hdr (struct sk_buff* skb) -{ - struct net_device *dev = skb->dev; - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++chan->if_send_stat.if_send_tbusy_timeout; - printk (KERN_INFO "%s: Transmit timed out on %s\n", - card->devname, dev->name); - netif_wake_queue (dev); -} - - -/*========================================================================= - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - * - *========================================================================*/ - -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - int udp_type; - unsigned long smp_flags=0; - - ++chan->if_send_stat.if_send_entry; - - netif_stop_queue(dev); - - /* No need to check frame length, since socket code - * will perform the check for us */ - - chan->tick_counter = jiffies; - - /* Critical region starts here */ - S508_S514_lock(card, &smp_flags); - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); - goto if_send_crit_exit; - } - - udp_type = udp_pkt_type(skb, card); - - if(udp_type != UDP_INVALID_TYPE) { - - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, - chan->common.lcn)) { - - status->imask |= INTR_ON_TIMER; - if (udp_type == UDP_XPIPE_TYPE){ - chan->if_send_stat.if_send_PIPE_request++; - } - } - netif_start_queue(dev); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 0; - } - - if (chan->transmit_length){ - //FIXME: This check doesn't make sense any more - if (chan->common.state != WAN_CONNECTED){ - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - }else{ - netif_stop_queue(dev); - ++card->u.x.tx_interrupts_pending; - status->imask |= INTR_ON_TX_FRAME; - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 1; - } - } - - if (card->wandev.state != WAN_CONNECTED){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_wan_disconnected; - - }else if ( chan->protocol && (chan->protocol != skb->protocol)){ - printk(KERN_INFO - "%s: unsupported Ethertype 0x%04X on interface %s!\n", - chan->name, htons(skb->protocol), dev->name); - - printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); - ++chan->ifstats.tx_errors; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_protocol_error; - - }else switch (chan->common.state){ - - case WAN_DISCONNECTED: - /* Try to establish connection. If succeded, then start - * transmission, else drop a packet. - */ - if (chan->common.usedby == API){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - }else{ - if (chan_connect(dev) != 0){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - } - /* fall through */ - - case WAN_CONNECTED: - if( skb->protocol == htons(ETH_P_IPX)) { - if(chan->enable_IPX) { - switch_net_numbers( skb->data, - chan->network_number, 0); - } else { - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - ++chan->if_send_stat.if_send_protocol_error; - goto if_send_crit_exit; - } - } - /* We never drop here, if cannot send than, copy - * a packet into a transmit buffer - */ - chan_send(dev, skb->data, skb->len, 0); - break; - - default: - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - - -if_send_crit_exit: - - dev_kfree_skb_any(skb); - - netif_start_queue(dev); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 0; -} - -/*============================================================================ - * Setup so that a frame can be transmitted on the occurrence of a transmit - * interrupt. - *===========================================================================*/ - -static void setup_for_delayed_transmit(struct net_device* dev, void* buf, - unsigned len) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - - ++chan->if_send_stat.if_send_adptr_bfrs_full; - - if(chan->transmit_length) { - printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", - card->devname); - return; - } - - if (chan->common.usedby == API){ - if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - printk(KERN_INFO "%s: Length is too big for delayed transmit\n", - card->devname); - return; - } - }else{ - if (len > X25_MAX_DATA) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - printk(KERN_INFO "%s: Length is too big for delayed transmit\n", - card->devname); - return; - } - } - - chan->transmit_length = len; - atomic_set(&chan->common.driver_busy,1); - memcpy(chan->transmit_buffer, buf, len); - - ++chan->if_send_stat.if_send_tx_int_enabled; - - /* Enable Transmit Interrupt */ - ++card->u.x.tx_interrupts_pending; - status->imask |= INTR_ON_TX_FRAME; -} - - -/*=============================================================== - * net_device_stats - * - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - * - *==============================================================*/ -static struct net_device_stats *if_stats(struct net_device* dev) -{ - x25_channel_t *chan = dev->priv; - - if(chan == NULL) - return NULL; - - return &chan->ifstats; -} - - -/* - * Interrupt Handlers - */ - -/* - * X.25 Interrupt Service Routine. - */ - -static void wpx_isr (sdla_t* card) -{ - TX25Status* status = card->flags; - - card->in_isr = 1; - ++card->statistics.isr_entry; - - if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ - card->in_isr=0; - status->iflags = 0; - return; - } - - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - - printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", - card->devname, card->wandev.critical, status->iflags); - card->in_isr = 0; - status->iflags = 0; - return; - } - - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - switch (status->iflags){ - - case RX_INTR_PENDING: /* receive interrupt */ - rx_intr(card); - break; - - case TX_INTR_PENDING: /* transmit interrupt */ - tx_intr(card); - break; - - case MODEM_INTR_PENDING: /* modem status interrupt */ - status_intr(card); - break; - - case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ - event_intr(card); - break; - - case TIMER_INTR_PENDING: - timer_intr(card); - break; - - default: /* unwanted interrupt */ - spur_intr(card); - } - - card->in_isr = 0; - status->iflags = 0; /* clear interrupt condition */ -} - -/* - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. - * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * coming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. - */ - -static void rx_intr (sdla_t* card) -{ - TX25Mbox* rxmb = card->rxmb; - unsigned lcn = rxmb->cmd.lcn; - struct net_device* dev = find_channel(card,lcn); - x25_channel_t* chan; - struct sk_buff* skb=NULL; - - if (dev == NULL){ - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", - card->devname, lcn); - return; - } - - chan = dev->priv; - chan->i_timeout_sofar = jiffies; - - - /* Copy the data from the board, into an - * skb buffer - */ - if (wanpipe_pull_data_in_skb(card,dev,&skb)){ - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_no_socket; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - return; - } - - dev->last_rx = jiffies; /* timestamp */ - - - /* ------------ API ----------------*/ - - if (chan->common.usedby == API){ - - if (bh_enqueue(dev, skb)){ - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - dev_kfree_skb_any(skb); - return; - } - - ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - - - chan->rx_skb = NULL; - if (!test_and_set_bit(0, &chan->tq_working)){ - wanpipe_queue_work(&chan->common.wanpipe_work); - } - return; - } - - - /* ------------- WANPIPE -------------------*/ - - /* set rx_skb to NULL so we won't access it later when kernel already owns it */ - chan->rx_skb=NULL; - - /* Decapsulate packet, if necessary */ - if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ - /* can't decapsulate packet */ - dev_kfree_skb_any(skb); - ++chan->ifstats.rx_errors; - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - - }else{ - if( handle_IPXWAN(skb->data, chan->name, - chan->enable_IPX, chan->network_number, - skb->protocol)){ - - if( chan->enable_IPX ){ - if(chan_send(dev, skb->data, skb->len,0)){ - chan->tx_skb = skb; - }else{ - dev_kfree_skb_any(skb); - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - } - }else{ - /* increment IPX packet dropped statistic */ - ++chan->ifstats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - } - }else{ - skb->mac.raw = skb->data; - chan->ifstats.rx_bytes += skb->len; - ++chan->ifstats.rx_packets; - ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; - netif_rx(skb); - } - } - - return; -} - - -static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, - struct sk_buff **skb) -{ - void *bufptr; - TX25Mbox* rxmb = card->rxmb; - unsigned len = rxmb->cmd.length; /* packet length */ - unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ - x25_channel_t *chan = dev->priv; - struct sk_buff *new_skb = *skb; - - if (chan->common.usedby == WANPIPE){ - if (chan->drop_sequence){ - if (!(qdm & 0x01)){ - chan->drop_sequence = 0; - } - return 1; - } - new_skb = chan->rx_skb; - }else{ - /* Add on the API header to the received - * data - */ - len += sizeof(x25api_hdr_t); - } - - if (new_skb == NULL){ - int bufsize; - - if (chan->common.usedby == WANPIPE){ - bufsize = (qdm & 0x01) ? dev->mtu : len; - }else{ - bufsize = len; - } - - /* Allocate new socket buffer */ - new_skb = dev_alloc_skb(bufsize + dev->hard_header_len); - if (new_skb == NULL){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - chan->drop_sequence = 1; /* set flag */ - ++chan->ifstats.rx_dropped; - return 1; - } - } - - if (skb_tailroom(new_skb) < len){ - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb_any(new_skb); - if (chan->common.usedby == WANPIPE){ - chan->rx_skb = NULL; - if (qdm & 0x01){ - chan->drop_sequence = 1; - } - } - - printk(KERN_INFO "%s: unexpectedly long packet sequence " - "on interface %s!\n", card->devname, dev->name); - ++chan->ifstats.rx_length_errors; - return 1; - } - - bufptr = skb_put(new_skb,len); - - - if (chan->common.usedby == API){ - /* Fill in the x25api header - */ - x25api_t * api_data = (x25api_t*)bufptr; - api_data->hdr.qdm = rxmb->cmd.qdm; - api_data->hdr.cause = rxmb->cmd.cause; - api_data->hdr.diagn = rxmb->cmd.diagn; - api_data->hdr.length = rxmb->cmd.length; - memcpy(api_data->data, rxmb->data, rxmb->cmd.length); - }else{ - memcpy(bufptr, rxmb->data, len); - } - - new_skb->dev = dev; - - if (chan->common.usedby == API){ - new_skb->mac.raw = new_skb->data; - new_skb->protocol = htons(X25_PROT); - new_skb->pkt_type = WAN_PACKET_DATA; - }else{ - new_skb->protocol = chan->protocol; - chan->rx_skb = new_skb; - } - - /* If qdm bit is set, more data is coming - * thus, exit and wait for more data before - * sending the packet up. (Used by router only) - */ - if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) - return 1; - - *skb = new_skb; - - return 0; -} - -/*=============================================================== - * tx_intr - * - * Transmit interrupt handler. - * For each dev, check that there is something to send. - * If data available, transmit. - * - *===============================================================*/ - -static void tx_intr (sdla_t* card) -{ - struct net_device *dev; - TX25Status* status = card->flags; - unsigned char more_to_tx=0; - x25_channel_t *chan=NULL; - int i=0; - - if (card->u.x.tx_dev == NULL){ - card->u.x.tx_dev = card->wandev.dev; - } - - dev = card->u.x.tx_dev; - - for (;;){ - - chan = dev->priv; - if (chan->transmit_length){ - /* Device was set to transmit, check if the TX - * buffers are available - */ - if (chan->common.state != WAN_CONNECTED){ - chan->transmit_length = 0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - if (netif_queue_stopped(dev)){ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - dev = move_dev_to_next(card,dev); - break; - } - - if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && - (*card->u.x.hdlc_buf_status & 0x40) ){ - /* Tx buffer available, we can send */ - - if (tx_intr_send(card, dev)){ - more_to_tx=1; - } - - /* If more than one interface present, move the - * device pointer to the next interface, so on the - * next TX interrupt we will try sending from it. - */ - dev = move_dev_to_next(card,dev); - break; - }else{ - /* Tx buffers not available, but device set - * the TX interrupt. Set more_to_tx and try - * to transmit for other devices. - */ - more_to_tx=1; - dev = move_dev_to_next(card,dev); - } - - }else{ - /* This device was not set to transmit, - * go to next - */ - dev = move_dev_to_next(card,dev); - } - - if (++i == card->u.x.no_dev){ - if (!more_to_tx){ - DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", - card->devname); - } - break; - } - - } //End of FOR - - card->u.x.tx_dev = dev; - - if (!more_to_tx){ - /* if any other interfaces have transmit interrupts pending, */ - /* do not disable the global transmit interrupt */ - if (!(--card->u.x.tx_interrupts_pending)){ - status->imask &= ~INTR_ON_TX_FRAME; - } - } - return; -} - -/*=============================================================== - * move_dev_to_next - * - * - *===============================================================*/ - - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) -{ - if (card->u.x.no_dev != 1){ - if (!*((struct net_device **)dev->priv)) - return card->wandev.dev; - else - return *((struct net_device **)dev->priv); - } - return dev; -} - -/*=============================================================== - * tx_intr_send - * - * - *===============================================================*/ - -static int tx_intr_send(sdla_t *card, struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - - if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ - - /* Packet was split up due to its size, do not disable - * tx_intr - */ - return 1; - } - - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - - /* If we are in API mode, wakeup the - * sock BH handler, not the NET_BH */ - if (netif_queue_stopped(dev)){ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - return 0; -} - - -/*=============================================================== - * timer_intr - * - * Timer interrupt handler. - * Check who called the timer interrupt and perform - * action accordingly. - * - *===============================================================*/ - -static void timer_intr (sdla_t *card) -{ - TX25Status* status = card->flags; - - if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ - - if (timer_intr_cmd_exec(card) == 0){ - card->u.x.timer_int_enabled &= - ~TMR_INT_ENABLED_CMD_EXEC; - } - - }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { - - if ((*card->u.x.hdlc_buf_status & 0x40) && - card->u.x.udp_type == UDP_XPIPE_TYPE){ - - if(process_udp_mgmt_pkt(card)) { - card->u.x.timer_int_enabled &= - ~TMR_INT_ENABLED_UDP_PKT; - } - } - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { - - struct net_device *dev = card->u.x.poll_device; - x25_channel_t *chan = NULL; - - if (!dev){ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; - return; - } - chan = dev->priv; - - printk(KERN_INFO - "%s: Closing down Idle link %s on LCN %d\n", - card->devname,chan->name,chan->common.lcn); - chan->i_timeout_sofar = jiffies; - chan_disc(dev); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; - card->u.x.poll_device=NULL; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { - - wanpipe_set_state(card, WAN_CONNECTED); - if (card->u.x.LAPB_hdlc){ - struct net_device *dev = card->wandev.dev; - set_chan_state(dev,WAN_CONNECTED); - send_delayed_cmd_result(card,dev,card->mbox); - } - - /* 0x8F enable all interrupts */ - x25_set_intr_mode(card, INTR_ON_RX_FRAME| - INTR_ON_TX_FRAME| - INTR_ON_MODEM_STATUS_CHANGE| - //INTR_ON_COMMAND_COMPLETE| - X25_ASY_TRANS_INTR_PENDING | - INTR_ON_TIMER | - DIRECT_RX_INTR_USAGE - ); - - status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { - - //printk(KERN_INFO "Poll connect, Turning OFF\n"); - disconnect(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { - - //printk(KERN_INFO "POll disconnect, trying to connect\n"); - connect(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ - - if (*card->u.x.hdlc_buf_status & 0x40){ - x25_get_err_stats(card); - x25_get_stats(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - } - } - - if(!card->u.x.timer_int_enabled){ - //printk(KERN_INFO "Turning Timer Off \n"); - status->imask &= ~INTR_ON_TIMER; - } -} - -/*==================================================================== - * Modem status interrupt handler. - *===================================================================*/ -static void status_intr (sdla_t* card) -{ - - /* Added to avoid Modem status message flooding */ - static TX25ModemStatus last_stat; - - TX25Mbox* mbox = card->mbox; - TX25ModemStatus *modem_status; - struct net_device *dev; - x25_channel_t *chan; - int err; - - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_MODEM_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err){ - x25_error(card, err, X25_READ_MODEM_STATUS, 0); - }else{ - - modem_status = (TX25ModemStatus*)mbox->data; - - /* Check if the last status was the same - * if it was, do NOT print message again */ - - if (last_stat.status != modem_status->status){ - - printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", - card->devname,DCD(modem_status->status),CTS(modem_status->status)); - - last_stat.status = modem_status->status; - - if (card->u.x.oob_on_modem){ - - mbox->cmd.pktType = mbox->cmd.command; - mbox->cmd.result = 0x08; - - /* Send a OOB to all connected sockets */ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device**)dev->priv)) { - chan=dev->priv; - if (chan->common.usedby == API){ - send_oob_msg(card,dev,mbox); - } - } - - /* The modem OOB message will probably kill the - * the link. If we don't clear the flag here, - * a deadlock could occur */ - if (atomic_read(&card->u.x.command_busy)){ - atomic_set(&card->u.x.command_busy,0); - } - } - } - } - - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err){ - x25_error(card, err, X25_HDLC_LINK_STATUS, 0); - } - -} - -/*==================================================================== - * Network event interrupt handler. - *===================================================================*/ -static void event_intr (sdla_t* card) -{ - x25_fetch_events(card); -} - -/*==================================================================== - * Spurious interrupt handler. - * o print a warning - * o - *====================================================================*/ - -static void spur_intr (sdla_t* card) -{ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); -} - - -/* - * Background Polling Routines - */ - -/*==================================================================== - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - *====================================================================*/ - -static void wpx_poll (sdla_t *card) -{ - if (!card->wandev.dev){ - goto wpx_poll_exit; - } - - if (card->open_cnt != card->u.x.num_of_ch){ - goto wpx_poll_exit; - } - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - goto wpx_poll_exit; - } - - if (test_bit(SEND_CRIT,&card->wandev.critical)){ - goto wpx_poll_exit; - } - - switch(card->wandev.state){ - case WAN_CONNECTED: - poll_active(card); - break; - - case WAN_CONNECTING: - poll_connecting(card); - break; - - case WAN_DISCONNECTED: - poll_disconnected(card); - break; - } - -wpx_poll_exit: - clear_bit(POLL_CRIT,&card->wandev.critical); - return; -} - -static void trigger_x25_poll(sdla_t *card) -{ - schedule_work(&card->u.x.x25_poll_work); -} - -/*==================================================================== - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. - *===================================================================*/ - -static void poll_connecting (sdla_t* card) -{ - volatile TX25Status* status = card->flags; - - if (status->gflags & X25_HDLC_ABM){ - - timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); - - }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ - - timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); - - } -} - -/*==================================================================== - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, - * connect link. - *===================================================================*/ - -static void poll_disconnected (sdla_t* card) -{ - struct net_device *dev; - x25_channel_t *chan; - TX25Status* status = card->flags; - - if (!card->u.x.LAPB_hdlc && card->open_cnt && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ - timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); - } - - - if ((dev=card->wandev.dev) == NULL) - return; - - if ((chan=dev->priv) == NULL) - return; - - if (chan->common.usedby == API && - atomic_read(&chan->common.command) && - card->u.x.LAPB_hdlc){ - - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - -} - -/*==================================================================== - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. - *===================================================================*/ - -static void poll_active (sdla_t* card) -{ - struct net_device* dev; - TX25Status* status = card->flags; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - x25_channel_t* chan = dev->priv; - - /* If SVC has been idle long enough, close virtual circuit */ - if ( chan->common.svc && - chan->common.state == WAN_CONNECTED && - chan->common.usedby == WANPIPE ){ - - if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ - /* Close svc */ - card->u.x.poll_device=dev; - timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); - } - } - -#ifdef PRINT_DEBUG - chan->ifstats.tx_compressed = atomic_read(&chan->common.command); - chan->ifstats.tx_errors = chan->common.state; - chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy); - ++chan->ifstats.tx_bytes; - - chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect); - chan->ifstats.multicast=atomic_read(&chan->bh_buff_used); - chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status; -#endif - - if (chan->common.usedby == API && - atomic_read(&chan->common.command) && - !card->u.x.LAPB_hdlc){ - - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - - if ((chan->common.usedby == API) && - atomic_read(&chan->common.disconnect)){ - - if (chan->common.state == WAN_DISCONNECTED){ - atomic_set(&chan->common.disconnect,0); - return; - } - - atomic_set(&chan->common.command,X25_CLEAR_CALL); - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - } -} - -static void timer_intr_exec(sdla_t *card, unsigned char TYPE) -{ - TX25Status* status = card->flags; - card->u.x.timer_int_enabled |= TYPE; - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; -} - - -/*==================================================================== - * SDLA Firmware-Specific Functions - * - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be delt with - * immediately. To tackle with this problem we execute each interface - * command in a loop until good return code is received or maximum number - * of retries is reached. Each interface command returns non-zero return - * code, an asynchronous event/error handler x25_error() is called. - *====================================================================*/ - -/*==================================================================== - * Read X.25 firmware version. - * Put code version as ASCII string in str. - *===================================================================*/ - -static int x25_get_version (sdla_t* card, char* str) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_CODE_VERSION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && - x25_error(card, err, X25_READ_CODE_VERSION, 0)); - - if (!err && str) - { - int len = mbox->cmd.length; - - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} - -/*==================================================================== - * Configure adapter. - *===================================================================*/ - -static int x25_configure (sdla_t* card, TX25Config* conf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); - mbox->cmd.length = sizeof(TX25Config); - mbox->cmd.command = X25_SET_CONFIGURATION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); - return err; -} - -/*==================================================================== - * Configure adapter for HDLC only. - *===================================================================*/ - -static int hdlc_configure (sdla_t* card, TX25Config* conf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); - mbox->cmd.length = sizeof(TX25Config); - mbox->cmd.command = X25_HDLC_SET_CONFIG; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); - - return err; -} - -static int set_hdlc_level (sdla_t* card) -{ - - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = SET_PROTOCOL_LEVEL; - mbox->cmd.length = 1; - mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0)); - - return err; -} - - - -/*==================================================================== - * Get communications error statistics. - *====================================================================*/ - -static int x25_get_err_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_READ_COMM_ERR; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - - if (!err) - { - THdlcCommErr* stats = (void*)mbox->data; - - card->wandev.stats.rx_over_errors = stats->rxOverrun; - card->wandev.stats.rx_crc_errors = stats->rxBadCrc; - card->wandev.stats.rx_missed_errors = stats->rxAborted; - card->wandev.stats.tx_aborted_errors = stats->txAborted; - } - return err; -} - -/*==================================================================== - * Get protocol statistics. - *===================================================================*/ - -static int x25_get_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_STATISTICS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; - - if (!err) - { - TX25Stats* stats = (void*)mbox->data; - - card->wandev.stats.rx_packets = stats->rxData; - card->wandev.stats.tx_packets = stats->txData; - } - return err; -} - -/*==================================================================== - * Close HDLC link. - *===================================================================*/ - -static int x25_close_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_CLOSE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - - return err; -} - - -/*==================================================================== - * Open HDLC link. - *===================================================================*/ - -static int x25_open_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_OPEN; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - - return err; -} - -/*===================================================================== - * Setup HDLC link. - *====================================================================*/ -static int x25_setup_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_SETUP; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); - - return err; -} - -/*==================================================================== - * Set (raise/drop) DTR. - *===================================================================*/ - -static int x25_set_dtr (sdla_t* card, int dtr) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = 0; - mbox->data[2] = 0; - mbox->data[1] = dtr ? 0x02 : 0x01; - mbox->cmd.length = 3; - mbox->cmd.command = X25_SET_GLOBAL_VARS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - - return err; -} - -/*==================================================================== - * Set interrupt mode. - *===================================================================*/ - -static int x25_set_intr_mode (sdla_t* card, int mode) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = mode; - if (card->hw.fwid == SFID_X25_508){ - mbox->data[1] = card->hw.irq; - mbox->data[2] = 2; - mbox->cmd.length = 3; - }else { - mbox->cmd.length = 1; - } - mbox->cmd.command = X25_SET_INTERRUPT_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); - - return err; -} - -/*==================================================================== - * Read X.25 channel configuration. - *===================================================================*/ - -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int lcn = chan->common.lcn; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.command = X25_READ_CHANNEL_CONFIG; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); - - if (!err) - { - TX25Status* status = card->flags; - - /* calculate an offset into the array of status bytes */ - if (card->u.x.hi_svc <= X25_MAX_CHAN){ - - chan->ch_idx = lcn - 1; - - }else{ - int offset; - - /* FIX: Apr 14 2000 : Nenad Corbic - * The data field was being compared to 0x1F using - * '&&' instead of '&'. - * This caused X25API to fail for LCNs greater than 255. - */ - switch (mbox->data[0] & 0x1F) - { - case 0x01: - offset = status->pvc_map; break; - case 0x03: - offset = status->icc_map; break; - case 0x07: - offset = status->twc_map; break; - case 0x0B: - offset = status->ogc_map; break; - default: - offset = 0; - } - chan->ch_idx = lcn - 1 - offset; - } - - /* get actual transmit packet size on this channel */ - switch(mbox->data[1] & 0x38) - { - case 0x00: - chan->tx_pkt_size = 16; - break; - case 0x08: - chan->tx_pkt_size = 32; - break; - case 0x10: - chan->tx_pkt_size = 64; - break; - case 0x18: - chan->tx_pkt_size = 128; - break; - case 0x20: - chan->tx_pkt_size = 256; - break; - case 0x28: - chan->tx_pkt_size = 512; - break; - case 0x30: - chan->tx_pkt_size = 1024; - break; - } - if (card->u.x.logging) - printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", - card->devname, lcn, chan->tx_pkt_size); - } - return err; -} - -/*==================================================================== - * Place X.25 call. - *====================================================================*/ - -static int x25_place_call (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - char str[64]; - - - if (chan->protocol == htons(ETH_P_IP)){ - sprintf(str, "-d%s -uCC", chan->addr); - - }else if (chan->protocol == htons(ETH_P_IPX)){ - sprintf(str, "-d%s -u800000008137", chan->addr); - - } - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - strcpy(mbox->data, str); - mbox->cmd.length = strlen(str); - mbox->cmd.command = X25_PLACE_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); - - if (!err){ - bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn); - } - return err; -} - -/*==================================================================== - * Accept X.25 call. - *====================================================================*/ - -static int x25_accept_call (sdla_t* card, int lcn, int qdm) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.qdm = qdm; - mbox->cmd.command = X25_ACCEPT_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - - return err; -} - -/*==================================================================== - * Clear X.25 call. - *====================================================================*/ - -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.cause = cause; - mbox->cmd.diagn = diagn; - mbox->cmd.command = X25_CLEAR_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - - return err; -} - -/*==================================================================== - * Send X.25 data packet. - *====================================================================*/ - -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - unsigned char cmd; - - if (card->u.x.LAPB_hdlc) - cmd = X25_HDLC_WRITE; - else - cmd = X25_WRITE; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, buf, len); - mbox->cmd.length = len; - mbox->cmd.lcn = lcn; - - if (card->u.x.LAPB_hdlc){ - mbox->cmd.pf = qdm; - }else{ - mbox->cmd.qdm = qdm; - } - - mbox->cmd.command = cmd; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, cmd , lcn)); - - - /* If buffers are busy the return code for LAPB HDLC is - * 1. The above functions are looking for return code - * of X25RES_NOT_READY if busy. */ - - if (card->u.x.LAPB_hdlc && err == 1){ - err = X25RES_NOT_READY; - } - - return err; -} - -/*==================================================================== - * Fetch X.25 asynchronous events. - *===================================================================*/ - -static int x25_fetch_events (sdla_t* card) -{ - TX25Status* status = card->flags; - TX25Mbox* mbox = card->mbox; - int err = 0; - - if (status->gflags & 0x20) - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_IS_DATA_AVAILABLE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); - } - return err; -} - -/*==================================================================== - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns - * non-zero return code to handle X.25 asynchronous events and - * common errors. Return non-zero to repeat command or zero to - * cancel it. - * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. - *====================================================================*/ - -static int x25_error (sdla_t* card, int err, int cmd, int lcn) -{ - int retry = 1; - unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; - TX25Mbox* mb; - - mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); - if (mb == NULL) - { - printk(KERN_ERR "%s: x25_error() out of memory!\n", - card->devname); - return 0; - } - memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); - switch (err){ - - case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ - - mb->data[dlen] = '\0'; - - switch (mb->cmd.pktType & 0x7F){ - - case ASE_CALL_RQST: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; - - case ASE_CALL_ACCEPTED: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; - - case ASE_CLEAR_RQST: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case ASE_RESET_RQST: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - api_oob_event (card,mb); - break; - - case ASE_RESTART_RQST: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - case ASE_CLEAR_CONFRM: - if (clear_confirm_event (card,mb)) - break; - - /* I use the goto statement here so if - * somebody inserts code between the - * case and default, we will not have - * ghost problems */ - - goto dflt_1; - - default: -dflt_1: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } - break; - - case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ - - /* Bug Fix: Mar 14 2000 - * The Protocol violation error conditions were - * not handled previously */ - - switch (mb->cmd.pktType & 0x7F){ - - case PVE_CLEAR_RQST: /* Clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case PVE_RESET_RQST: /* Reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - api_oob_event (card,mb); - break; - - case PVE_RESTART_RQST: /* Restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - default : - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); - api_oob_event(card,mb); - } - break; - - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); - break; - - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) - ; - break; - - case 0x08: /* modem failure */ -#ifndef MODEM_NOT_LOG - printk(KERN_INFO "%s: modem failure!\n", card->devname); -#endif /* MODEM_NOT_LOG */ - api_oob_event(card,mb); - break; - - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); - api_oob_event(card,mb); - break; - - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); - api_oob_event(card,mb); - break; - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd) - ; - retry = 0; /* abort command */ - break; - - case X25RES_NOT_READY: - retry = 1; - break; - - case 0x01: - if (card->u.x.LAPB_hdlc) - break; - - if (mb->cmd.command == 0x16) - break; - /* I use the goto statement here so if - * somebody inserts code between the - * case and default, we will not have - * ghost problems */ - goto dflt_2; - - default: -dflt_2: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", - card->devname, cmd, err, mb->cmd.lcn) - ; - retry = 0; /* abort command */ - } - kfree(mb); - return retry; -} - -/*==================================================================== - * X.25 Asynchronous Event Handlers - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. - *====================================================================*/ - - - -/*==================================================================== - *Handle X.25 incoming call request. - * RFC 1356 establishes the following rules: - * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used - * when clearing a call because protocol encapsulation is not - * supported. - * 4. If an incoming call is received while a call request is - * pending (i.e. call collision has occurred), the incoming call - * shall be rejected and call request shall be retried. - *====================================================================*/ - -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - struct wan_device* wandev = &card->wandev; - int new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); - x25_channel_t* chan = NULL; - int accept = 0; /* set to '1' if o.k. to accept call */ - unsigned int user_data; - x25_call_info_t* info; - - /* Make sure there is no call collision */ - if (dev != NULL) - { - printk(KERN_INFO - "%s: X.25 incoming call collision on LCN %d!\n", - card->devname, new_lcn); - - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - /* Make sure D bit is not set in call request */ -//FIXME: THIS IS NOT TURE !!!! TAKE IT OUT -// if (mb->cmd.qdm & 0x02) -// { -// printk(KERN_INFO -// "%s: X.25 incoming call on LCN %d with D-bit set!\n", -// card->devname, new_lcn); -// -// x25_clear_call(card, new_lcn, 0, 0); -// return 1; -// } - - /* Parse call request data */ - info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); - if (info == NULL) - { - printk(KERN_ERR - "%s: not enough memory to parse X.25 incoming call " - "on LCN %d!\n", card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - parse_call_info(mb->data, info); - - if (card->u.x.logging) - printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n", - card->devname, new_lcn); - - /* Conver the first two ASCII characters into an - * interger. Used to check the incoming protocol - */ - user_data = hex_to_uint(info->user,2); - - /* Find available channel */ - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { - chan = dev->priv; - - if (chan->common.usedby == API) - continue; - - if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)) - continue; - - if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ - printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", - htons(chan->protocol), info->user[0]); - continue; - } - - if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ - printk(KERN_INFO "IPX packet but configured for IP: %x\n", - htons(chan->protocol)); - continue; - } - if (strcmp(info->src, chan->addr) == 0) - break; - - /* If just an '@' is specified, accept all incoming calls */ - if (strcmp(chan->addr, "") == 0) - break; - } - - if (dev == NULL){ - - /* If the call is not for any WANPIPE interfaces - * check to see if there is an API listening queue - * waiting for data. If there is send the packet - * up the stack. - */ - if (card->sk != NULL && card->func != NULL){ - if (api_incoming_call(card,mb,new_lcn)){ - x25_clear_call(card, new_lcn, 0, 0); - } - accept = 0; - }else{ - printk(KERN_INFO "%s: no channels available!\n", - card->devname); - - x25_clear_call(card, new_lcn, 0, 0); - } - - }else if (info->nuser == 0){ - - printk(KERN_INFO - "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn) - ; - x25_clear_call(card, new_lcn, 0, 0); - - }else switch (info->user[0]){ - - case 0: /* multiplexed */ - chan->protocol = htons(0); - accept = 1; - break; - - case NLPID_IP: /* IP datagrams */ - accept = 1; - break; - - case NLPID_SNAP: /* IPX datagrams */ - accept = 1; - break; - - default: - printk(KERN_INFO - "%s: unsupported NLPID 0x%02X in incoming call " - "on LCN %d!\n", card->devname, info->user[0], new_lcn); - x25_clear_call(card, new_lcn, 0, 249); - } - - if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){ - - bind_lcn_to_dev (card, chan->dev, new_lcn); - - if (x25_get_chan_conf(card, chan) == CMD_OK) - set_chan_state(dev, WAN_CONNECTED); - else - x25_clear_call(card, new_lcn, 0, 0); - } - kfree(info); - return 1; -} - -/*==================================================================== - * Handle accepted call. - *====================================================================*/ - -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = find_channel(card, new_lcn); - x25_channel_t* chan; - - if (dev == NULL){ - printk(KERN_INFO - "%s: clearing orphaned connection on LCN %d!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - if (card->u.x.logging) - printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n", - card->devname, dev->name, new_lcn); - - /* Get channel configuration and notify router */ - chan = dev->priv; - if (x25_get_chan_conf(card, chan) != CMD_OK) - { - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - set_chan_state(dev, WAN_CONNECTED); - - if (chan->common.usedby == API){ - send_delayed_cmd_result(card,dev,mb); - bind_lcn_to_dev (card, dev, new_lcn); - } - - return 1; -} - -/*==================================================================== - * Handle cleared call. - *====================================================================*/ - -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = find_channel(card, new_lcn); - x25_channel_t *chan; - unsigned char old_state; - - if (card->u.x.logging){ - printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " - "Diagn:0x%02X\n", - card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - } - - if (dev == NULL){ - printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", - card->devname); - return 1; - } - - chan=dev->priv; - - old_state = chan->common.state; - - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - - switch (old_state){ - - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - } - - return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; -} - -/*==================================================================== - * Handle X.25 restart event. - *====================================================================*/ - -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - struct wan_device* wandev = &card->wandev; - struct net_device* dev; - x25_channel_t *chan; - unsigned char old_state; - - printk(KERN_INFO - "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.cause, mb->cmd.diagn); - - /* down all logical channels */ - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { - chan=dev->priv; - old_state = chan->common.state; - - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - switch (old_state){ - - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - } - } - return (cmd == X25_WRITE) ? 0 : 1; -} - -/*==================================================================== - * Handle timeout event. - *====================================================================*/ - -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - - if (mb->cmd.pktType == 0x05) /* call request time out */ - { - struct net_device* dev = find_channel(card,new_lcn); - - printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", - card->devname, new_lcn); - - if (dev){ - x25_channel_t *chan = dev->priv; - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - send_delayed_cmd_result(card,dev,card->mbox); - } - } - }else{ - printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", - card->devname, mb->cmd.pktType, new_lcn); - } - return 1; -} - -/* - * Miscellaneous - */ - -/*==================================================================== - * Establish physical connection. - * o open HDLC and raise DTR - * - * Return: 0 connection established - * 1 connection is in progress - * <0 error - *===================================================================*/ - -static int connect (sdla_t* card) -{ - TX25Status* status = card->flags; - - if (x25_open_hdlc(card) || x25_setup_hdlc(card)) - return -EIO; - - wanpipe_set_state(card, WAN_CONNECTING); - - x25_set_intr_mode(card, INTR_ON_TIMER); - status->imask &= ~INTR_ON_TIMER; - - return 1; -} - -/* - * Tear down physical connection. - * o close HDLC link - * o drop DTR - * - * Return: 0 - * <0 error - */ - -static int disconnect (sdla_t* card) -{ - wanpipe_set_state(card, WAN_DISCONNECTED); - x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ - x25_close_hdlc(card); /* close HDLC link */ - x25_set_dtr(card, 0); /* drop DTR */ - return 0; -} - -/* - * Find network device by its channel number. - */ - -static struct net_device* get_dev_by_lcn(struct wan_device* wandev, - unsigned lcn) -{ - struct net_device* dev; - - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) - if (((x25_channel_t*)dev->priv)->common.lcn == lcn) - break; - return dev; -} - -/* - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call - * - * Return: 0 connected - * >0 connection in progress - * <0 failure - */ - -static int chan_connect(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->common.svc && chan->common.usedby == WANPIPE){ - if (!chan->addr[0]){ - printk(KERN_INFO "%s: No Destination Address\n", - card->devname); - return -EINVAL; /* no destination address */ - } - printk(KERN_INFO "%s: placing X.25 call to %s ...\n", - card->devname, chan->addr); - - if (x25_place_call(card, chan) != CMD_OK) - return -EIO; - - set_chan_state(dev, WAN_CONNECTING); - return 1; - }else{ - if (x25_get_chan_conf(card, chan) != CMD_OK) - return -EIO; - - set_chan_state(dev, WAN_CONNECTED); - } - return 0; -} - -/* - * Disconnect logical channel. - * o if SVC then clear X.25 call - */ - -static int chan_disc(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - - if (chan->common.svc){ - x25_clear_call(chan->card, chan->common.lcn, 0, 0); - - /* For API we disconnect on clear - * confirmation. - */ - if (chan->common.usedby == API) - return 0; - } - - set_chan_state(dev, WAN_DISCONNECTED); - - return 0; -} - -/* - * Set logical channel state. - */ - -static void set_chan_state(struct net_device* dev, int state) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - unsigned long flags; - - save_flags(flags); - cli(); - if (chan->common.state != state) - { - switch (state) - { - case WAN_CONNECTED: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s connected, lcn %i !\n", - card->devname, dev->name,chan->common.lcn); - } - *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); - chan->i_timeout_sofar = jiffies; - - /* LAPB is PVC Based */ - if (card->u.x.LAPB_hdlc) - chan->common.svc=0; - break; - - case WAN_CONNECTING: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s connecting, lcn %i ...\n", - card->devname, dev->name, chan->common.lcn); - } - break; - - case WAN_DISCONNECTED: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s disconnected, lcn %i !\n", - card->devname, dev->name,chan->common.lcn); - } - atomic_set(&chan->common.disconnect,0); - - if (chan->common.svc) { - *(unsigned short*)dev->dev_addr = 0; - card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; - chan->common.lcn = 0; - } - - if (chan->transmit_length){ - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - if (netif_queue_stopped(dev)){ - netif_wake_queue(dev); - } - } - atomic_set(&chan->common.command,0); - break; - - case WAN_DISCONNECTING: - if (card->u.x.logging){ - printk (KERN_INFO - "\n%s: interface %s disconnecting, lcn %i ...\n", - card->devname, dev->name,chan->common.lcn); - } - atomic_set(&chan->common.disconnect,0); - break; - } - chan->common.state = state; - } - chan->state_tick = jiffies; - restore_flags(flags); -} - -/* - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data - * space points to the transmit socket buffer. When transmission - * is complete, release socket buffer and reset 'tbusy' flag. - * - * Return: 0 - transmission complete - * 1 - busy - * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. - */ - -static int chan_send(struct net_device* dev, void* buff, unsigned data_len, - unsigned char tx_intr) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - unsigned len=0, qdm=0, res=0, orig_len = 0; - void *data; - - /* Check to see if channel is ready */ - if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || - !(*card->u.x.hdlc_buf_status & 0x40)){ - - if (!tx_intr){ - setup_for_delayed_transmit (dev, buff, data_len); - return 0; - }else{ - /* By returning 0 to tx_intr the packet will be dropped */ - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", - card->devname,dev->name); - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - return 0; - } - } - - if (chan->common.usedby == API){ - /* Remove the API Header */ - x25api_hdr_t *api_data = (x25api_hdr_t *)buff; - - /* Set the qdm bits from the packet header - * User has the option to set the qdm bits - */ - qdm = api_data->qdm; - - orig_len = len = data_len - sizeof(x25api_hdr_t); - data = (unsigned char*)buff + sizeof(x25api_hdr_t); - }else{ - data = buff; - orig_len = len = data_len; - } - - if (tx_intr){ - /* We are in tx_intr, minus the tx_offset from - * the total length. The tx_offset part of the - * data has already been sent. Also, move the - * data pointer to proper offset location. - */ - len -= chan->tx_offset; - data = (unsigned char*)data + chan->tx_offset; - } - - /* Check if the packet length is greater than MTU - * If YES: Cut the len to MTU and set the M bit - */ - if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ - len = chan->tx_pkt_size; - qdm |= M_BIT; - } - - - /* Pass only first three bits of the qdm byte to the send - * routine. In case user sets any other bit which might - * cause errors. - */ - - switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ - case 0x00: /* success */ - chan->i_timeout_sofar = jiffies; - - dev->trans_start=jiffies; - - if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ - if (!tx_intr){ - /* The M bit was set, which means that part of the - * packet has been sent. Copy the packet into a buffer - * and set the offset to len, so on next tx_inter - * the packet will be sent using the below offset. - */ - chan->tx_offset += len; - - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - - if (chan->tx_offset < orig_len){ - setup_for_delayed_transmit (dev, buff, data_len); - } - res=0; - }else{ - /* We are already in tx_inter, thus data is already - * in the buffer. Update the offset and wait for - * next tx_intr. We add on to the offset, since data can - * be X number of times larger than max data size. - */ - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - - ++chan->if_send_stat.if_send_bfr_passed_to_adptr; - chan->tx_offset += len; - - /* The user can set the qdm bit as well. - * If the entire packet was sent and qdm is still - * set, than it's the user who has set the M bit. In that, - * case indicate that the packet was send by returning - * 0 and wait for a new packet. Otherwise, wait for next - * tx interrupt to send the rest of the packet */ - - if (chan->tx_offset < orig_len){ - res=1; - }else{ - res=0; - } - } - }else{ - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - ++chan->if_send_stat.if_send_bfr_passed_to_adptr; - res=0; - } - break; - - case 0x33: /* Tx busy */ - if (tx_intr){ - printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", - card->devname,dev->name); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - res=0; - }else{ - DBG_PRINTK(KERN_INFO - "%s: Send: Big Error should have tx: storring %s\n", - card->devname,dev->name); - setup_for_delayed_transmit (dev, buff, data_len); - res=1; - } - break; - - default: /* failure */ - ++chan->ifstats.tx_errors; - if (tx_intr){ - printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", - card->devname,dev->name); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - res=0; - }else{ - DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", - card->devname,dev->name); - setup_for_delayed_transmit (dev, buff, data_len); - res=1; - } - break; - } - return res; -} - - -/* - * Parse X.25 call request data and fill x25_call_info_t structure. - */ - -static void parse_call_info (unsigned char* str, x25_call_info_t* info) -{ - memset(info, 0, sizeof(x25_call_info_t)); - for (; *str; ++str) - { - int i; - unsigned char ch; - - if (*str == '-') switch (str[1]) { - - /* Take minus 2 off the maximum size so that - * last byte is 0. This way we can use string - * manipulaton functions on call information. - */ - - case 'd': /* destination address */ - for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->dest[i] = ch; - } - break; - - case 's': /* source address */ - for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->src[i] = ch; - } - break; - - case 'u': /* user data */ - for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->user[i] = ch; - } - info->nuser = i; - break; - - case 'f': /* facilities */ - for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->facil[i] = ch; - } - info->nfacil = i; - break; - } - } -} - -/* - * Convert line speed in bps to a number used by S502 code. - */ - -static unsigned char bps_to_speed_code (unsigned long bps) -{ - unsigned char number; - - if (bps <= 1200) number = 0x01; - else if (bps <= 2400) number = 0x02; - else if (bps <= 4800) number = 0x03; - else if (bps <= 9600) number = 0x04; - else if (bps <= 19200) number = 0x05; - else if (bps <= 38400) number = 0x06; - else if (bps <= 45000) number = 0x07; - else if (bps <= 56000) number = 0x08; - else if (bps <= 64000) number = 0x09; - else if (bps <= 74000) number = 0x0A; - else if (bps <= 112000) number = 0x0B; - else if (bps <= 128000) number = 0x0C; - else number = 0x0D; - - return number; -} - -/* - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ - -static unsigned int dec_to_uint (unsigned char* str, int len) -{ - unsigned val; - - if (!len) - len = strlen(str); - - for (val = 0; len && isdigit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - - return val; -} - -/* - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. - */ - -static unsigned int hex_to_uint (unsigned char* str, int len) -{ - unsigned val, ch; - - if (!len) - len = strlen(str); - - for (val = 0; len; ++str, --len) - { - ch = *str; - if (isdigit(ch)) - val = (val << 4) + (ch - (unsigned)'0'); - else if (isxdigit(ch)) - val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else break; - } - return val; -} - - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - - if( proto == ETH_P_IPX) { - /* It's an IPX packet */ - if(!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ - return 1; - } - } else { - /* It's not IPX so pass it up the stack.*/ - return 0; - } - - if( sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) - { - /* It's IPXWAN */ - - if( sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) - { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); - - /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP - */ - for(i = 41; sendpacket[i] == 0x00; i += 5) - { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02) - { - sendpacket[i + 1] = 0; - } - } - - /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ) - { - i += 8; - } - - /* We also want to turn off all header compression opt. */ - for(; sendpacket[i] == 0x80 ;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - /* Set the packet type to timer response */ - sendpacket[34] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[34] == 0x02 ) - { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); - - /* Set the packet type to information response */ - sendpacket[34] = 0x03; - - /* Set the router name */ - sendpacket[51] = 'X'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for(i = 66; i < 99; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char)(network_number >> 24); - sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } else { - /*If we get here it's an IPX-data packet, so it'll get passed up the stack. - */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/* - * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - * if incoming is 1 - if the net number is 0 make it ours - */ - -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - - - if (!incoming) { - /*If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) { - sendpacket[6] = (unsigned char)(network_number >> 24); - sendpacket[7] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - - - if( !incoming ) { - /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) { - sendpacket[18] = (unsigned char)(network_number >> 24); - sendpacket[19] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - - - - -/********************* X25API SPECIFIC FUNCTIONS ****************/ - - -/*=============================================================== - * find_channel - * - * Manages the lcn to device map. It increases performance - * because it eliminates the need to search through the link - * list for a device which is bounded to a specific lcn. - * - *===============================================================*/ - - -struct net_device *find_channel(sdla_t *card, unsigned lcn) -{ - if (card->u.x.LAPB_hdlc){ - - return card->wandev.dev; - - }else{ - /* We don't know whether the incoming lcn - * is a PVC or an SVC channel. But we do know that - * the lcn cannot be for both the PVC and the SVC - * channel. - - * If the lcn number is greater or equal to 255, - * take the modulo 255 of that number. We only have - * 255 locations, thus higher numbers must be mapped - * to a number between 0 and 245. - - * We must separate pvc's and svc's since two don't - * have to be contiguous. Meaning pvc's can start - * from 1 to 10 and svc's can start from 256 to 266. - * But 256%255 is 1, i.e. CONFLICT. - */ - - - /* Highest LCN number must be less or equal to 4096 */ - if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ - - if (lcn < X25_MAX_CHAN){ - if (card->u.x.svc_to_dev_map[lcn]) - return card->u.x.svc_to_dev_map[lcn]; - - if (card->u.x.pvc_to_dev_map[lcn]) - return card->u.x.pvc_to_dev_map[lcn]; - - }else{ - int new_lcn = lcn%X25_MAX_CHAN; - if (card->u.x.svc_to_dev_map[new_lcn]) - return card->u.x.svc_to_dev_map[new_lcn]; - - if (card->u.x.pvc_to_dev_map[new_lcn]) - return card->u.x.pvc_to_dev_map[new_lcn]; - } - } - return NULL; - } -} - -void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn) -{ - x25_channel_t *chan = dev->priv; - - /* Modulo the lcn number by X25_MAX_CHAN (255) - * because the lcn number can be greater than 255 - * - * We need to split svc and pvc since they don't have - * to be contigous. - */ - - if (chan->common.svc){ - card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; - }else{ - card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; - } - chan->common.lcn = lcn; -} - - - -/*=============================================================== - * x25api_bh - * - * - *==============================================================*/ - -static void x25api_bh(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - printk(KERN_INFO "%s: BH Buffer Empty in BH\n", - card->devname); - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - clear_bit(0, &chan->tq_working); - return; - } - - /* If LAPB HDLC, do not drop packets if socket is - * not connected. Let the buffer fill up and - * turn off rx interrupt */ - if (card->u.x.LAPB_hdlc){ - if (chan->common.sk == NULL || chan->common.func == NULL){ - clear_bit(0, &chan->tq_working); - return; - } - } - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb == NULL){ - printk(KERN_INFO "%s: BH Skb empty for read %i\n", - card->devname,chan->bh_read); - }else{ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n", - card->devname); - dev_kfree_skb_any(skb); - x25api_bh_cleanup(dev); - ++chan->ifstats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - continue; - } - - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for another - * try - */ - printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n", - card->devname); - atomic_set(&chan->common.receive_block,1); - return; - }else{ - x25api_bh_cleanup(dev); - ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; - } - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -/*=============================================================== - * x25api_bh_cleanup - * - * - *==============================================================*/ - -static int x25api_bh_cleanup(struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - TX25Status* status = card->flags; - - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == MAX_BH_BUFF){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - /* If the Receive interrupt was off, it means - * that we filled up our circular buffer. Check - * that we have space in the buffer. If so - * turn the RX interrupt back on. - */ - if (!(status->imask & INTR_ON_RX_FRAME)){ - if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: BH: Turning on the interrupt\n", - card->devname); - status->imask |= INTR_ON_RX_FRAME; - } - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - -/*=============================================================== - * bh_enqueue - * - * - *==============================================================*/ - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - TX25Status* status = card->flags; - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: Bottom half buffer FULL\n", - card->devname); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == MAX_BH_BUFF){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n", - card->devname); - status->imask &= ~INTR_ON_RX_FRAME; - } - - return 0; -} - - -/*=============================================================== - * timer_intr_cmd_exec - * - * Called by timer interrupt to execute a command - *===============================================================*/ - -static int timer_intr_cmd_exec (sdla_t* card) -{ - struct net_device *dev; - unsigned char more_to_exec=0; - volatile x25_channel_t *chan=NULL; - int i=0,bad_cmd=0,err=0; - - if (card->u.x.cmd_dev == NULL){ - card->u.x.cmd_dev = card->wandev.dev; - } - - dev = card->u.x.cmd_dev; - - for (;;){ - - chan = dev->priv; - - if (atomic_read(&chan->common.command)){ - - bad_cmd = check_bad_command(card,dev); - - if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && - !bad_cmd){ - - /* Socket has died or exited, We must bring the - * channel down before anybody else tries to - * use it */ - err = channel_disconnect(card,dev); - }else{ - err = execute_delayed_cmd(card, dev, - (mbox_cmd_t*)chan->common.mbox, - bad_cmd); - } - - switch (err){ - - case RETURN_RESULT: - - /* Return the result to the socket without - * delay. NO_WAIT Command */ - atomic_set(&chan->common.command,0); - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - - send_delayed_cmd_result(card,dev,card->mbox); - - more_to_exec=0; - break; - case DELAY_RESULT: - - /* Wait for the remote to respond, before - * sending the result up to the socket. - * WAIT command */ - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - - atomic_set(&chan->common.command,0); - more_to_exec=0; - break; - default: - - /* If command could not be executed for - * some reason (i.e return code 0x33 busy) - * set the more_to_exec bit which will - * indicate that this command must be exectued - * again during next timer interrupt - */ - more_to_exec=1; - if (atomic_read(&card->u.x.command_busy) == 0) - atomic_set(&card->u.x.command_busy,1); - break; - } - - bad_cmd=0; - - /* If flags is set, there are no hdlc buffers, - * thus, wait for the next pass and try the - * same command again. Otherwise, start searching - * from next device on the next pass. - */ - if (!more_to_exec){ - dev = move_dev_to_next(card,dev); - } - break; - }else{ - /* This device has nothing to execute, - * go to next. - */ - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - dev = move_dev_to_next(card,dev); - } - - if (++i == card->u.x.no_dev){ - if (!more_to_exec){ - DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n", - card->devname); - if (atomic_read(&card->u.x.command_busy)){ - atomic_set(&card->u.x.command_busy,0); - } - } - break; - } - - } //End of FOR - - card->u.x.cmd_dev = dev; - - if (more_to_exec){ - /* If more commands are pending, do not turn off timer - * interrupt */ - return 1; - }else{ - /* No more commands, turn off timer interrupt */ - return 0; - } -} - -/*=============================================================== - * execute_delayed_cmd - * - * Execute an API command which was passed down from the - * sock. Sock is very limited in which commands it can - * execute. Wait and No Wait commands are supported. - * Place Call, Clear Call and Reset wait commands, where - * Accept Call is a no_wait command. - * - *===============================================================*/ - -static int execute_delayed_cmd(sdla_t* card, struct net_device *dev, - mbox_cmd_t *usr_cmd, char bad_cmd) -{ - TX25Mbox* mbox = card->mbox; - int err; - x25_channel_t *chan = dev->priv; - int delay=RETURN_RESULT; - - if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){ - return TRY_CMD_AGAIN; - } - - /* This way a command is guaranteed to be executed for - * a specific lcn, the network interface is bound to. */ - usr_cmd->cmd.lcn = chan->common.lcn; - - - /* If channel is pvc, instead of place call - * run x25_channel configuration. If running LAPB HDLC - * enable communications. - */ - if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){ - - if (card->u.x.LAPB_hdlc){ - DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); - connect(card); - set_chan_state(dev,WAN_CONNECTING); - return DELAY_RESULT; - }else{ - DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); - if (x25_get_chan_conf(card, chan) == CMD_OK){ - set_chan_state(dev, WAN_CONNECTED); - }else{ - set_chan_state(dev, WAN_DISCONNECTED); - } - return RETURN_RESULT; - } - } - - /* Copy the socket mbox command onto the board */ - - memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd)); - if (usr_cmd->cmd.length){ - memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length); - } - - /* Check if command is bad. We need to copy the cmd into - * the buffer regardless since we return the, mbox to - * the user */ - if (bad_cmd){ - mbox->cmd.result=0x01; - return RETURN_RESULT; - } - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK && err != X25RES_NOT_READY) - x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn); - - if (mbox->cmd.result == X25RES_NOT_READY){ - return TRY_CMD_AGAIN; - } - - switch (mbox->cmd.command){ - - case X25_PLACE_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - - /* Check if Place call is a wait command or a - * no wait command */ - if (atomic_read(&chan->common.command) & 0x80) - delay=RETURN_RESULT; - else - delay=DELAY_RESULT; - - - DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n", - card->devname,dev->name, mbox->cmd.lcn); - - bind_lcn_to_dev (card, dev, mbox->cmd.lcn); - set_chan_state(dev, WAN_CONNECTING); - break; - - - default: - delay=RETURN_RESULT; - set_chan_state(dev, WAN_DISCONNECTED); - break; - } - break; - - case X25_ACCEPT_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - - DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n", - card->devname,dev->name,mbox->cmd.lcn); - - bind_lcn_to_dev (card, dev, mbox->cmd.lcn); - - if (x25_get_chan_conf(card, chan) == CMD_OK){ - - set_chan_state(dev, WAN_CONNECTED); - delay=RETURN_RESULT; - - }else{ - if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ - /* if clear is successful, wait for clear confirm - */ - delay=DELAY_RESULT; - }else{ - /* Do not change the state here. If we fail - * the accept the return code is send up - *the stack, which will ether retry - * or clear the call - */ - DBG_PRINTK(KERN_INFO - "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", - card->devname); - delay=RETURN_RESULT; - } - } - break; - - - case X25RES_ASYNC_PACKET: - delay=TRY_CMD_AGAIN; - break; - - default: - DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); - if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ - delay=DELAY_RESULT; - }else{ - /* Do not change the state here. If we fail the accept. The - * return code is send up the stack, which will ether retry - * or clear the call */ - DBG_PRINTK(KERN_INFO - "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", - card->devname); - delay=RETURN_RESULT; - } - } - break; - - case X25_CLEAR_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - DBG_PRINTK(KERN_INFO - "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n", - dev->name,mbox->cmd.lcn,chan->common.lcn); - set_chan_state(dev, WAN_DISCONNECTING); - delay = DELAY_RESULT; - break; - - case X25RES_CHANNEL_IN_USE: - case X25RES_ASYNC_PACKET: - delay = TRY_CMD_AGAIN; - break; - - case X25RES_LINK_NOT_IN_ABM: - case X25RES_INVAL_LCN: - case X25RES_INVAL_STATE: - set_chan_state(dev, WAN_DISCONNECTED); - delay = RETURN_RESULT; - break; - - default: - /* If command did not execute because of user - * fault, do not change the state. This will - * signal the socket that clear command failed. - * User can retry or close the socket. - * When socket gets killed, it will set the - * chan->disconnect which will signal - * driver to clear the call */ - printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n", - card->devname,mbox->cmd.command); - delay = RETURN_RESULT; - } - break; - } - - return delay; -} - -/*=============================================================== - * api_incoming_call - * - * Pass an incoming call request up the listening - * sock. If the API sock is not listening reject the - * call. - * - *===============================================================*/ - -static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn) -{ - struct sk_buff *skb; - int len = sizeof(TX25Cmd)+mbox->cmd.length; - - if (alloc_and_init_skb_buf(card, &skb, len)){ - printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); - return 1; - } - - memcpy(skb_put(skb,len),&mbox->cmd,len); - - skb->mac.raw = skb->data; - skb->protocol = htons(X25_PROT); - skb->pkt_type = WAN_PACKET_ASYNC; - - if (card->func(skb,card->sk) < 0){ - printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname); - dev_kfree_skb_any(skb); - return 1; - } - - return 0; -} - -/*=============================================================== - * send_delayed_cmd_result - * - * Wait commands like PLEACE CALL or CLEAR CALL must wait - * until the result arrives. This function passes - * the result to a waiting sock. - * - *===============================================================*/ -static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, - TX25Mbox* mbox) -{ - x25_channel_t *chan = dev->priv; - mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; - struct sk_buff *skb; - int len=sizeof(unsigned char); - - atomic_set(&chan->common.command,0); - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - return; - } - - if (!usr_cmd || !chan->common.sk || !chan->common.func){ - DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n", - (unsigned int)chan->common.sk, - (unsigned int)chan->common.func, - (unsigned int)usr_cmd); - return; - } - - memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); - if (mbox->cmd.length > 0){ - memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); - } - - if (alloc_and_init_skb_buf(card,&skb,len)){ - printk(KERN_INFO "Delay result: No sock buffers\n"); - return; - } - - memcpy(skb_put(skb,len),&mbox->cmd.command,len); - - skb->mac.raw = skb->data; - skb->pkt_type = WAN_PACKET_CMD; - - chan->common.func(skb,dev,chan->common.sk); -} - -/*=============================================================== - * clear_confirm_event - * - * Pass the clear confirmation event up the sock. The - * API will disconnect only after the clear confirmation - * has been received. - * - * Depending on the state, clear confirmation could - * be an OOB event, or a result of an API command. - *===============================================================*/ - -static int clear_confirm_event (sdla_t *card, TX25Mbox* mb) -{ - struct net_device *dev; - x25_channel_t *chan; - unsigned char old_state; - - dev = find_channel(card,mb->cmd.lcn); - if (!dev){ - DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n", - card->devname,mb->cmd.lcn); - return 0; - } - - chan=dev->priv; - DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n", - card->devname, dev->name, mb->cmd.lcn, chan->common.lcn); - - /* If not API fall through to default. - * If API, send the result to a waiting - * socket. - */ - - old_state = chan->common.state; - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - switch (old_state) { - - case WAN_DISCONNECTING: - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - return 1; - } - - return 0; -} - -/*=============================================================== - * send_oob_msg - * - * Construct an NEM Message and pass it up the connected - * sock. If the sock is not bounded discard the NEM. - * - *===============================================================*/ - -static void send_oob_msg(sdla_t *card, struct net_device *dev, TX25Mbox *mbox) -{ - x25_channel_t *chan = dev->priv; - mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; - struct sk_buff *skb; - int len=sizeof(x25api_hdr_t)+mbox->cmd.length; - x25api_t *api_hdr; - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - return; - } - - if (!usr_cmd || !chan->common.sk || !chan->common.func){ - DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); - return; - } - - memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); - if (mbox->cmd.length > 0){ - memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); - } - - if (alloc_and_init_skb_buf(card,&skb,len)){ - printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname); - return; - } - - api_hdr = (x25api_t*)skb_put(skb,len); - api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F; - api_hdr->hdr.qdm = mbox->cmd.qdm; - api_hdr->hdr.cause = mbox->cmd.cause; - api_hdr->hdr.diagn = mbox->cmd.diagn; - api_hdr->hdr.length = mbox->cmd.length; - api_hdr->hdr.result = mbox->cmd.result; - api_hdr->hdr.lcn = mbox->cmd.lcn; - - if (mbox->cmd.length > 0){ - memcpy(api_hdr->data,mbox->data,mbox->cmd.length); - } - - skb->mac.raw = skb->data; - skb->pkt_type = WAN_PACKET_ERR; - - if (chan->common.func(skb,dev,chan->common.sk) < 0){ - if (bh_enqueue(dev,skb)){ - printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname); - dev_kfree_skb_any(skb); - } - } - - DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n", - card->devname, dev->name, mbox->cmd.lcn); -} - -/*=============================================================== - * alloc_and_init_skb_buf - * - * Allocate and initialize an skb buffer. - * - *===============================================================*/ - -static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) -{ - struct sk_buff *new_skb = *skb; - - new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); - if (new_skb == NULL){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - return 1; - } - - if (skb_tailroom(new_skb) < len){ - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb_any(new_skb); - printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" - ,card->devname); - *skb = NULL; - return 1; - } - - *skb = new_skb; - return 0; - -} - -/*=============================================================== - * api_oob_event - * - * Send an OOB event up to the sock - * - *===============================================================*/ - -static void api_oob_event (sdla_t *card,TX25Mbox *mbox) -{ - struct net_device *dev = find_channel(card, mbox->cmd.lcn); - x25_channel_t *chan; - - if (!dev) - return; - - chan=dev->priv; - - if (chan->common.usedby == API) - send_oob_msg(card,dev,mbox); - -} - - - - -static int channel_disconnect(sdla_t* card, struct net_device *dev) -{ - - int err; - x25_channel_t *chan = dev->priv; - - DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n", - card->devname,dev->name); - - if (chan->common.svc){ - err = x25_clear_call(card,chan->common.lcn,0,0); - }else{ - /* If channel is PVC or LAPB HDLC, there is no call - * to be cleared, thus drop down to the default - * area - */ - err = 1; - } - - switch (err){ - - case X25RES_CHANNEL_IN_USE: - case X25RES_NOT_READY: - err = TRY_CMD_AGAIN; - break; - case CMD_OK: - DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n", - dev->name,chan->common.lcn); - - set_chan_state(dev,WAN_DISCONNECTING); - atomic_set(&chan->common.command,0); - err = DELAY_RESULT; - break; - default: - /* If LAPB HDLC protocol, bring the whole link down - * once the application terminates - */ - - set_chan_state(dev,WAN_DISCONNECTED); - - if (card->u.x.LAPB_hdlc){ - DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n"); - hdlc_link_down (card); - } - atomic_set(&chan->common.command,0); - err = RETURN_RESULT; - break; - } - - return err; -} - -static void hdlc_link_down (sdla_t *card) -{ - TX25Mbox* mbox = card->mbox; - int retry = 5; - int err=0; - - do { - memset(mbox,0,sizeof(TX25Mbox)); - mbox->cmd.command = X25_HDLC_LINK_DISC; - mbox->cmd.length = 1; - mbox->data[0]=0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0)); - - if (err) - printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); - - disconnect (card); - -} - -static int check_bad_command(sdla_t* card, struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - int bad_cmd = 0; - - switch (atomic_read(&chan->common.command)&0x7F){ - - case X25_PLACE_CALL: - if (chan->common.state != WAN_DISCONNECTED) - bad_cmd=1; - break; - case X25_CLEAR_CALL: - if (chan->common.state == WAN_DISCONNECTED) - bad_cmd=1; - break; - case X25_ACCEPT_CALL: - if (chan->common.state != WAN_CONNECTING) - bad_cmd=1; - break; - case X25_RESET: - if (chan->common.state != WAN_CONNECTED) - bad_cmd=1; - break; - default: - bad_cmd=1; - break; - } - - if (bad_cmd){ - printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", - card->devname,atomic_read(&chan->common.command),dev->name, - chan->common.lcn, chan->common.state); - } - - return bad_cmd; -} - - - -/*************************** XPIPEMON FUNCTIONS **************************/ - -/*============================================================================== - * Process UDP call of type XPIPE - */ - -static int process_udp_mgmt_pkt(sdla_t *card) -{ - int c_retry = MAX_CMD_RETRY; - unsigned int len; - struct sk_buff *new_skb; - TX25Mbox *mbox = card->mbox; - int err; - int udp_mgmt_req_valid = 1; - struct net_device *dev; - x25_channel_t *chan; - unsigned short lcn; - struct timeval tv; - - - x25_udp_pkt_t *x25_udp_pkt; - x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data; - - dev = card->u.x.udp_dev; - chan = dev->priv; - lcn = chan->common.lcn; - - switch(x25_udp_pkt->cblock.command) { - - /* XPIPE_ENABLE_TRACE */ - case XPIPE_ENABLE_TRACING: - - /* XPIPE_GET_TRACE_INFO */ - case XPIPE_GET_TRACE_INFO: - - /* SET FT1 MODE */ - case XPIPE_SET_FT1_MODE: - - if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; - udp_mgmt_req_valid = 0; - break; - } - - /* XPIPE_FT1_READ_STATUS */ - case XPIPE_FT1_READ_STATUS: - - /* FT1 MONITOR STATUS */ - case XPIPE_FT1_STATUS_CTRL: - if(card->hw.fwid != SFID_X25_508) { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; - udp_mgmt_req_valid = 0; - break; - } - default: - break; - } - - if(!udp_mgmt_req_valid) { - /* set length to 0 */ - x25_udp_pkt->cblock.length = 0; - /* set return code */ - x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; - - } else { - - switch (x25_udp_pkt->cblock.command) { - - - case XPIPE_FLUSH_DRIVER_STATS: - init_x25_channel_struct(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - - - case XPIPE_DRIVER_STAT_IFSEND: - memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t)); - mbox->cmd.length = sizeof(if_send_stat_t); - x25_udp_pkt->cblock.length = mbox->cmd.length; - break; - - case XPIPE_DRIVER_STAT_INTR: - memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t)); - memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)], - &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); - - mbox->cmd.length = sizeof(global_stats_t) + - sizeof(rx_intr_stat_t); - x25_udp_pkt->cblock.length = mbox->cmd.length; - break; - - case XPIPE_DRIVER_STAT_GEN: - memcpy(x25_udp_pkt->data, - &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], - &card->statistics, sizeof(global_stats_t)); - - x25_udp_pkt->cblock.result = 0; - x25_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = x25_udp_pkt->cblock.length; - break; - - case XPIPE_ROUTER_UP_TIME: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - chan->router_start_time; - *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time; - x25_udp_pkt->cblock.length = mbox->cmd.length = 4; - x25_udp_pkt->cblock.result = 0; - break; - - default : - - do { - memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd)); - if(mbox->cmd.length){ - memcpy(&mbox->data, - (char *)x25_udp_pkt->data, - mbox->cmd.length); - } - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0)); - - - if ( err == CMD_OK || - (err == 1 && - (mbox->cmd.command == 0x06 || - mbox->cmd.command == 0x16) ) ){ - - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; - } else { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; - } - - /* copy the result back to our buffer */ - memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd)); - - if(mbox->cmd.length) { - memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length); - } - break; - - } //switch - - } - - /* Fill UDP TTL */ - - x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length); - - - if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data); - if (!err) - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; - else - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; - - } else { - - /* Allocate socket buffer */ - if((new_skb = dev_alloc_skb(len)) != NULL) { - void *buf; - - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, card->u.x.udp_pkt_data, len); - - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->dev = dev; - - if (chan->common.usedby == API) - new_skb->protocol = htons(X25_PROT); - else - new_skb->protocol = htons(ETH_P_IP); - - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; - - } else { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - - card->u.x.udp_pkt_lgth = 0; - - return 1; -} - - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) -{ - x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data; - - if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && - (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - - if(!strncmp(x25_udp_pkt->wp_mgmt.signature, - UDPMGMT_XPIPE_SIGNATURE, 8)){ - return UDP_XPIPE_TYPE; - }else{ - printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", - card->devname); - } - } - - return UDP_INVALID_TYPE; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return nothing. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - - - x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* fill in UDP reply */ - x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - x25_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = x25_udp_pkt->udp_pkt.udp_src_port; - x25_udp_pkt->udp_pkt.udp_src_port = - x25_udp_pkt->udp_pkt.udp_dst_port; - x25_udp_pkt->udp_pkt.udp_dst_port = temp; - - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *) - (x25_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *) - (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - x25_udp_pkt->udp_pkt.udp_checksum = 0; - - x25_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - x25_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = x25_udp_pkt->ip_pkt.ip_src_address; - x25_udp_pkt->ip_pkt.ip_src_address = - x25_udp_pkt->ip_pkt.ip_dst_address; - x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - - /* fill in IP checksum */ - x25_udp_pkt->ip_pkt.hdr_checksum = 0; - x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t)); - - return len; -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i <len; i+=2 ) { - memcpy(&temp,&data[i],2); - sum += (unsigned long)temp; - } - - while (sum >> 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct net_device *dev, struct sk_buff *skb, - int lcn) -{ - int udp_pkt_stored = 0; - - if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.x.udp_pkt_lgth = skb->len; - card->u.x.udp_type = udp_type; - card->u.x.udp_pkt_src = udp_pkt_src; - card->u.x.udp_lcn = lcn; - card->u.x.udp_dev = dev; - memcpy(card->u.x.udp_pkt_data, skb->data, skb->len); - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; - udp_pkt_stored = 1; - - }else{ - printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", - card->devname,lcn); - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - - -/*============================================================================= - * Initial the ppp_private_area structure. - */ -static void init_x25_channel_struct( x25_channel_t *chan ) -{ - memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); - memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); - memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================ - * Initialize Global Statistics - */ -static void init_global_statistics( sdla_t *card ) -{ - memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); -} - - -/*=============================================================== - * SMP Support - * ==============================================================*/ - -static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); -} -static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) -{ - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -/*=============================================================== - * x25_timer_routine - * - * A more efficient polling routine. Each half a second - * queue a polling task. We want to do the polling in a - * task not timer, because timer runs in interrupt time. - * - * FIXME Polling should be rethinked. - *==============================================================*/ - -static void x25_timer_routine(unsigned long data) -{ - sdla_t *card = (sdla_t*)data; - - if (!card->wandev.dev){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", - card->devname); - return; - } - - if (card->open_cnt != card->u.x.num_of_ch){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", - card->devname); - return; - } - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", - card->devname); - return; - } - - if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - trigger_x25_poll(card); - } - - card->u.x.x25_timer.expires=jiffies+(HZ>>1); - add_timer(&card->u.x.x25_timer); - return; -} - -void disable_comm_shutdown(sdla_t *card) -{ - TX25Mbox* mbox = card->mbox; - int err; - - /* Turn of interrutps */ - mbox->data[0] = 0; - if (card->hw.fwid == SFID_X25_508){ - mbox->data[1] = card->hw.irq; - mbox->data[2] = 2; - mbox->cmd.length = 3; - }else { - mbox->cmd.length = 1; - } - mbox->cmd.command = X25_SET_INTERRUPT_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); - - /* Bring down HDLC */ - mbox->cmd.command = X25_HDLC_LINK_CLOSE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); - - - /* Brind down DTR */ - mbox->data[0] = 0; - mbox->data[2] = 0; - mbox->data[1] = 0x01; - mbox->cmd.length = 3; - mbox->cmd.command = X25_SET_GLOBAL_VARS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "DTR DOWN FAILED %x\n",err); - -} - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c deleted file mode 100644 index 032c0f81928..00000000000 --- a/drivers/net/wan/sdladrv.c +++ /dev/null @@ -1,2314 +0,0 @@ -/***************************************************************************** -* sdladrv.c SDLA Support Module. Main module. -* -* This module is a library of common hardware-specific functions -* used by all Sangoma drivers. -* -* Author: Gideon Hack -* -* Copyright: (c) 1995-2000 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support -* the PCISLOT #0. -* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. -* The memory test at address 0xC8000. -* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci -* interrupt flags on initial load. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Updates for Linux 2.2.X kernels. -* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels -* Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. -* Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. -* Jun 12, 1996 Gene Kozin Added support for S503 card. -* Apr 30, 1996 Gene Kozin SDLA hardware interrupt is acknowledged before -* calling protocolspecific ISR. -* Register I/O ports with Linux kernel. -* Miscellaneous bug fixes. -* Dec 20, 1995 Gene Kozin Fixed a bug in interrupt routine. -* Oct 14, 1995 Gene Kozin Initial version. -*****************************************************************************/ - -/***************************************************************************** - * Notes: - * ------ - * 1. This code is ment to be system-independent (as much as possible). To - * achive this, various macros are used to hide system-specific interfaces. - * To compile this code, one of the following constants must be defined: - * - * Platform Define - * -------- ------ - * Linux _LINUX_ - * SCO Unix _SCO_UNIX_ - * - * 2. Supported adapter types: - * - * S502A - * ES502A (S502E) - * S503 - * S507 - * S508 (S509) - * - * 3. S502A Notes: - * - * There is no separate DPM window enable/disable control in S502A. It - * opens immediately after a window number it written to the HMCR - * register. To close the window, HMCR has to be written a value - * ????1111b (e.g. 0x0F or 0xFF). - * - * S502A DPM window cannot be located at offset E000 (e.g. 0xAE000). - * - * There should be a delay of ??? before reading back S502A status - * register. - * - * 4. S502E Notes: - * - * S502E has a h/w bug: although default IRQ line state is HIGH, enabling - * interrupts by setting bit 1 of the control register (BASE) to '1' - * causes it to go LOW! Therefore, disabling interrupts by setting that - * bit to '0' causes low-to-high transition on IRQ line (ghosty - * interrupt). The same occurs when disabling CPU by resetting bit 0 of - * CPU control register (BASE+3) - see the next note. - * - * S502E CPU and DPM control is limited: - * - * o CPU cannot be stopped independently. Resetting bit 0 of the CPUi - * control register (BASE+3) shuts the board down entirely, including - * DPM; - * - * o DPM access cannot be controlled dynamically. Ones CPU is started, - * bit 1 of the control register (BASE) is used to enable/disable IRQ, - * so that access to shared memory cannot be disabled while CPU is - * running. - ****************************************************************************/ - -#define _LINUX_ - -#if defined(_LINUX_) /****** Linux *******************************/ - -#include <linux/config.h> -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/module.h> /* support for loadable modules */ -#include <linux/jiffies.h> /* for jiffies, HZ, etc. */ -#include <linux/sdladrv.h> /* API definitions */ -#include <linux/sdlasfm.h> /* SDLA firmware module definitions */ -#include <linux/sdlapci.h> /* SDLA PCI hardware definitions */ -#include <linux/pci.h> /* PCI defines and function prototypes */ -#include <asm/io.h> /* for inb(), outb(), etc. */ - -#define _INB(port) (inb(port)) -#define _OUTB(port, byte) (outb((byte),(port))) -#define SYSTEM_TICK jiffies - -#include <linux/init.h> - - -#elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ - -#if !defined(INKERNEL) -#error This code MUST be compiled in kernel mode! -#endif -#include <sys/sdladrv.h> /* API definitions */ -#include <sys/sdlasfm.h> /* SDLA firmware module definitions */ -#include <sys/inline.h> /* for inb(), outb(), etc. */ -#define _INB(port) (inb(port)) -#define _OUTB(port, byte) (outb((port),(byte))) -#define SYSTEM_TICK lbolt - -#else -#error Unknown system type! -#endif - -#define MOD_VERSION 3 -#define MOD_RELEASE 0 - -#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ -#define EXEC_DELAY 20 /* shared memory access delay, mks */ -#define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ - -/* I/O port address range */ -#define S502A_IORANGE 3 -#define S502E_IORANGE 4 -#define S503_IORANGE 3 -#define S507_IORANGE 4 -#define S508_IORANGE 4 - -/* Maximum amount of memory */ -#define S502_MAXMEM 0x10000L -#define S503_MAXMEM 0x10000L -#define S507_MAXMEM 0x40000L -#define S508_MAXMEM 0x40000L - -/* Minimum amount of memory */ -#define S502_MINMEM 0x8000L -#define S503_MINMEM 0x8000L -#define S507_MINMEM 0x20000L -#define S508_MINMEM 0x20000L -#define NO_PORT -1 - - - - - -/****** Function Prototypes *************************************************/ - -/* Hardware-specific functions */ -static int sdla_detect (sdlahw_t* hw); -static int sdla_autodpm (sdlahw_t* hw); -static int sdla_setdpm (sdlahw_t* hw); -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); -static int sdla_init (sdlahw_t* hw); -static unsigned long sdla_memtest (sdlahw_t* hw); -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); -static unsigned char make_config_byte (sdlahw_t* hw); -static int sdla_start (sdlahw_t* hw, unsigned addr); - -static int init_s502a (sdlahw_t* hw); -static int init_s502e (sdlahw_t* hw); -static int init_s503 (sdlahw_t* hw); -static int init_s507 (sdlahw_t* hw); -static int init_s508 (sdlahw_t* hw); - -static int detect_s502a (int port); -static int detect_s502e (int port); -static int detect_s503 (int port); -static int detect_s507 (int port); -static int detect_s508 (int port); -static int detect_s514 (sdlahw_t* hw); -static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card); - -/* Miscellaneous functions */ -static void peek_by_4 (unsigned long src, void* buf, unsigned len); -static void poke_by_4 (unsigned long dest, void* buf, unsigned len); -static int calibrate_delay (int mks); -static int get_option_index (unsigned* optlist, unsigned optval); -static unsigned check_memregion (void* ptr, unsigned len); -static unsigned test_memregion (void* ptr, unsigned len); -static unsigned short checksum (unsigned char* buf, unsigned len); -static int init_pci_slot(sdlahw_t *); - -static int pci_probe(sdlahw_t *hw); - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -static struct pci_device_id sdladrv_pci_tbl[] = { - { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); - -MODULE_LICENSE("GPL"); - -/* private data */ -static char modname[] = "sdladrv"; -static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; -static unsigned exec_idle; - -/* Hardware configuration options. - * These are arrays of configuration options used by verification routines. - * The first element of each array is its size (i.e. number of options). - */ -static unsigned s502_port_options[] = - { 4, 0x250, 0x300, 0x350, 0x360 } -; -static unsigned s503_port_options[] = - { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } -; -static unsigned s508_port_options[] = - { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } -; - -static unsigned s502a_irq_options[] = { 0 }; -static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; -static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; -static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; - -static unsigned s502a_dpmbase_options[] = -{ - 28, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, -}; -static unsigned s507_dpmbase_options[] = -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; -static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; - -/* -static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; -static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; -static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; -*/ - -static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; -static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; -static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; -static unsigned s507_pclk_options[] = { 1, 12288 }; -static unsigned s508_pclk_options[] = { 1, 16000 }; - -/* Host memory control register masks */ -static unsigned char s502a_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ -}; -static unsigned char s502e_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ -}; -static unsigned char s507_hmcr[] = -{ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ - 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ - 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ - 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ -}; -static unsigned char s508_hmcr[] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ -}; - -static unsigned char s507_irqmask[] = -{ - 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 -}; - -static int pci_slot_ar[MAX_S514_CARDS]; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o initialize static data - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -static int __init sdladrv_init(void) -{ - int i=0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, MOD_VERSION, MOD_RELEASE, copyright); - exec_idle = calibrate_delay(EXEC_DELAY); -#ifdef WANDEBUG - printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); -#endif - - /* Initialize the PCI Card array, which - * will store flags, used to mark - * card initialization state */ - for (i=0; i<MAX_S514_CARDS; i++) - pci_slot_ar[i] = 0xFF; - - return 0; -} - -/*============================================================================ - * Module 'remove' entry point. - * o release all remaining system resources - */ -static void __exit sdladrv_cleanup(void) -{ -} - -module_init(sdladrv_init); -module_exit(sdladrv_cleanup); - -/******* Kernel APIs ********************************************************/ - -/*============================================================================ - * Set up adapter. - * o detect adapter type - * o verify hardware configuration options - * o check for hardware conflicts - * o set up adapter shared memory - * o test adapter memory - * o load firmware - * Return: 0 ok. - * < 0 error - */ - -EXPORT_SYMBOL(sdla_setup); - -int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) -{ - unsigned* irq_opt = NULL; /* IRQ options */ - unsigned* dpmbase_opt = NULL; /* DPM window base options */ - unsigned* pclk_opt = NULL; /* CPU clock rate options */ - int err=0; - - if (sdla_detect(hw)) { - if(hw->type != SDLA_S514) - printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n", - modname, hw->port); - return -EINVAL; - } - - if(hw->type != SDLA_S514) { - printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", - modname, hw->type, hw->port); - - hw->dpmsize = SDLA_WINDOWSIZE; - switch (hw->type) { - case SDLA_S502A: - hw->io_range = S502A_IORANGE; - irq_opt = s502a_irq_options; - dpmbase_opt = s502a_dpmbase_options; - pclk_opt = s502a_pclk_options; - break; - - case SDLA_S502E: - hw->io_range = S502E_IORANGE; - irq_opt = s502e_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s502e_pclk_options; - break; - - case SDLA_S503: - hw->io_range = S503_IORANGE; - irq_opt = s503_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s503_pclk_options; - break; - - case SDLA_S507: - hw->io_range = S507_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s507_dpmbase_options; - pclk_opt = s507_pclk_options; - break; - - case SDLA_S508: - hw->io_range = S508_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s508_pclk_options; - break; - } - - /* Verify IRQ configuration options */ - if (!get_option_index(irq_opt, hw->irq)) { - printk(KERN_INFO "%s: IRQ %d is invalid!\n", - modname, hw->irq); - return -EINVAL; - } - - /* Verify CPU clock rate configuration options */ - if (hw->pclk == 0) - hw->pclk = pclk_opt[1]; /* use default */ - - else if (!get_option_index(pclk_opt, hw->pclk)) { - printk(KERN_INFO "%s: CPU clock %u is invalid!\n", - modname, hw->pclk); - return -EINVAL; - } - printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", - modname, hw->pclk); - - /* Setup adapter dual-port memory window and test memory */ - if (hw->dpmbase == 0) { - err = sdla_autodpm(hw); - if (err) { - printk(KERN_INFO - "%s: can't find available memory region!\n", - modname); - return err; - } - } - else if (!get_option_index(dpmbase_opt, - virt_to_phys(hw->dpmbase))) { - printk(KERN_INFO - "%s: memory address 0x%lX is invalid!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - else if (sdla_setdpm(hw)) { - printk(KERN_INFO - "%s: 8K memory region at 0x%lX is not available!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - printk(KERN_INFO - "%s: dual-port memory window is set at 0x%lX.\n", - modname, virt_to_phys(hw->dpmbase)); - - - /* If we find memory in 0xE**** Memory region, - * warn the user to disable the SHADOW RAM. - * Since memory corruption can occur if SHADOW is - * enabled. This can causes random crashes ! */ - if (virt_to_phys(hw->dpmbase) >= 0xE0000){ - printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname); - printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n", - modname, virt_to_phys(hw->dpmbase)); - printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n"); - printk(KERN_WARNING " your system might crash randomly from time to time !\n"); - printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname); - } - } - - else { - hw->memory = test_memregion((void*)hw->dpmbase, - MAX_SIZEOF_S514_MEMORY); - if(hw->memory < (256 * 1024)) { - printk(KERN_INFO - "%s: error in testing S514 memory (0x%lX)\n", - modname, hw->memory); - sdla_down(hw); - return -EINVAL; - } - } - - printk(KERN_INFO "%s: found %luK bytes of on-board memory\n", - modname, hw->memory / 1024); - - /* Load firmware. If loader fails then shut down adapter */ - err = sdla_load(hw, sfm, len); - if (err) sdla_down(hw); /* shutdown adapter */ - - return err; -} - -/*============================================================================ - * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. - */ - -EXPORT_SYMBOL(sdla_down); - -int sdla_down (sdlahw_t* hw) -{ - unsigned port = hw->port; - int i; - unsigned char CPU_no; - u32 int_config, int_status; - - if(!port && (hw->type != SDLA_S514)) - return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - hw->regs[0] = 0x08; - _OUTB(port + 1, 0xFF); /* close memory window */ - hw->regs[1] = 0xFF; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0); /* stop CPU */ - _OUTB(port, 0); /* reset board */ - for (i = 0; i < S502E_IORANGE; ++i) - hw->regs[i] = 0 - ; - break; - - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - _OUTB(port, 0); /* reset board logic */ - hw->regs[0] = 0; - break; - - case SDLA_S514: - /* halt the adapter */ - *(char *)hw->vector = S514_CPU_HALT; - CPU_no = hw->S514_cpu_no[0]; - - /* disable the PCI IRQ and disable memory access */ - pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); - int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; - pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); - read_S514_int_stat(hw, &int_status); - S514_intack(hw, int_status); - if(CPU_no == S514_CPU_A) - pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD, - PCI_CPU_A_MEM_DISABLE); - else - pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, - PCI_CPU_B_MEM_DISABLE); - - /* free up the allocated virtual memory */ - iounmap((void *)hw->dpmbase); - iounmap((void *)hw->vector); - break; - - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Map shared memory window into SDLA address space. - */ - -EXPORT_SYMBOL(sdla_mapmem); - -int sdla_mapmem (sdlahw_t* hw, unsigned long addr) -{ - unsigned port = hw->port; - register int tmp; - - switch (hw->type) { - case SDLA_S502A: - case SDLA_S502E: - if (addr < S502_MAXMEM) { /* verify parameter */ - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S503: - if (addr < S503_MAXMEM) { /* verify parameter */ - tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S507: - if (addr < S507_MAXMEM) { - if (!(_INB(port) & 0x02)) - return -EIO; - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S508: - if (addr < S508_MAXMEM) { - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S514: - return 0; - - default: - return -EINVAL; - } - hw->vector = addr & 0xFFFFE000L; - return 0; -} - -/*============================================================================ - * Enable interrupt generation. - */ - -static int sdla_inten (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) { - case SDLA_S502E: - /* Note thar interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 0 of status register is set). - */ - if (_INB(port) & 0x01) { - _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ - _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ - hw->regs[0] = 0x06; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x02)) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port + 1) & 0x10)) /* verify */ - return -EIO; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - case SDLA_S514: - break; - - default: - return -EINVAL; - - } - return 0; -} - -/*============================================================================ - * Disable interrupt generation. - */ - -#if 0 -int sdla_intde (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) { - case SDLA_S502E: - /* Notes: - * 1) interrupt control operations are allowed only if CPU is - * enabled (bit 0 of status register is set). - * 2) disabling interrupts using bit 1 of control register - * causes IRQ line go high, therefore we are going to use - * 0x04 instead: lower it to inhibit interrupts to PC. - */ - if (_INB(port) & 0x01) { - _OUTB(port, hw->regs[0] & ~0x04); - hw->regs[0] &= ~0x04; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x02) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] & ~0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x10) /* verify */ - return -EIO; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - default: - return -EINVAL; - } - return 0; -} -#endif /* 0 */ - -/*============================================================================ - * Acknowledge SDLA hardware interrupt. - */ - -static int sdla_intack (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp; - - switch (hw->type) { - case SDLA_S502E: - /* To acknoledge hardware interrupt we have to toggle bit 3 of - * control register: \_/ - * Note that interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 1 of status register is set). - */ - if (_INB(port) & 0x01) { - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - tmp |= 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EIO; - break; - - case SDLA_S503: - if (_INB(port) & 0x04) { - tmp = hw->regs[0] & ~0x08; - _OUTB(port, tmp); - tmp |= 0x08; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - break; - - case SDLA_S502A: - case SDLA_S507: - case SDLA_S508: - break; - - default: - return -EINVAL; - } - return 0; -} - - -/*============================================================================ - * Acknowledge S514 hardware interrupt. - */ - -EXPORT_SYMBOL(S514_intack); - -void S514_intack (sdlahw_t* hw, u32 int_status) -{ - pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); -} - - -/*============================================================================ - * Read the S514 hardware interrupt status. - */ - -EXPORT_SYMBOL(read_S514_int_stat); - -void read_S514_int_stat (sdlahw_t* hw, u32* int_status) -{ - pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); -} - - -/*============================================================================ - * Generate an interrupt to adapter's CPU. - */ - -#if 0 -int sdla_intr (sdlahw_t* hw) -{ - unsigned port = hw->port; - - switch (hw->type) { - case SDLA_S502A: - if (!(_INB(port) & 0x40)) { - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - } - else return -EIO; - break; - - case SDLA_S507: - if ((_INB(port) & 0x06) == 0x06) { - _OUTB(port + 3, 0); - } - else return -EIO; - break; - - case SDLA_S508: - if (_INB(port + 1) & 0x02) { - _OUTB(port, 0x08); - } - else return -EIO; - break; - - case SDLA_S502E: - case SDLA_S503: - default: - return -EINVAL; - } - return 0; -} -#endif /* 0 */ - -/*============================================================================ - * Execute Adapter Command. - * o Set exec flag. - * o Busy-wait until flag is reset. - * o Return number of loops made, or 0 if command timed out. - */ - -EXPORT_SYMBOL(sdla_exec); - -int sdla_exec (void* opflag) -{ - volatile unsigned char* flag = opflag; - unsigned long tstop; - int nloops; - - if(readb(flag) != 0x00) { - printk(KERN_INFO - "WANPIPE: opp flag set on entry to sdla_exec\n"); - return 0; - } - - writeb(0x01, flag); - - tstop = SYSTEM_TICK + EXEC_TIMEOUT; - - for (nloops = 1; (readb(flag) == 0x01); ++ nloops) { - unsigned delay = exec_idle; - while (-- delay); /* delay */ - if (SYSTEM_TICK > tstop) return 0; /* time is up! */ - } - return nloops; -} - -/*============================================================================ - * Read absolute adapter memory. - * Transfer data from adapter's memory to data buffer. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_peek); - -int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL; - - if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ - peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); - return 0; - } - - else { /* copy data for the S508 adapter */ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - while (len && !err) { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? - (winsize - curpos) : len; - /* Relocate window and copy block of data */ - err = sdla_mapmem(hw, curvec); - peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, - curlen); - addr += curlen; - buf = (char*)buf + curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; - } -} - - -/*============================================================================ - * Read data from adapter's memory to a data buffer in 4-byte chunks. - * Note that we ensure that the SDLA memory address is on a 4-byte boundary - * before we begin moving the data in 4-byte chunks. -*/ - -static void peek_by_4 (unsigned long src, void* buf, unsigned len) -{ - - /* byte copy data until we get to a 4-byte boundary */ - while (len && (src & 0x03)) { - *(char *)buf ++ = readb(src ++); - len --; - } - - /* copy data in 4-byte chunks */ - while (len >= 4) { - *(unsigned long *)buf = readl(src); - buf += 4; - src += 4; - len -= 4; - } - - /* byte copy any remaining data */ - while (len) { - *(char *)buf ++ = readb(src ++); - len --; - } -} - - -/*============================================================================ - * Write Absolute Adapter Memory. - * Transfer data from data buffer to adapter's memory. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_poke); - -int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL; - - if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ - poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); - return 0; - } - - else { /* copy data for the S508 adapter */ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - while (len && !err) { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? - (winsize - curpos) : len; - /* Relocate window and copy block of data */ - sdla_mapmem(hw, curvec); - poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, - curlen); - addr += curlen; - buf = (char*)buf + curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; - } -} - - -/*============================================================================ - * Write from a data buffer to adapter's memory in 4-byte chunks. - * Note that we ensure that the SDLA memory address is on a 4-byte boundary - * before we begin moving the data in 4-byte chunks. -*/ - -static void poke_by_4 (unsigned long dest, void* buf, unsigned len) -{ - - /* byte copy data until we get to a 4-byte boundary */ - while (len && (dest & 0x03)) { - writeb (*(char *)buf ++, dest ++); - len --; - } - - /* copy data in 4-byte chunks */ - while (len >= 4) { - writel (*(unsigned long *)buf, dest); - dest += 4; - buf += 4; - len -= 4; - } - - /* byte copy any remaining data */ - while (len) { - writeb (*(char *)buf ++ , dest ++); - len --; - } -} - - -#ifdef DONT_COMPIPLE_THIS -#endif /* DONT_COMPIPLE_THIS */ - -/****** Hardware-Specific Functions *****************************************/ - -/*============================================================================ - * Detect adapter type. - * o if adapter type is specified then call detection routine for that adapter - * type. Otherwise call detection routines for every adapter types until - * adapter is detected. - * - * Notes: - * 1) Detection tests are destructive! Adapter will be left in shutdown state - * after the test. - */ -static int sdla_detect (sdlahw_t* hw) -{ - unsigned port = hw->port; - int err = 0; - - if (!port && (hw->type != SDLA_S514)) - return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - if (!detect_s502a(port)) err = -ENODEV; - break; - - case SDLA_S502E: - if (!detect_s502e(port)) err = -ENODEV; - break; - - case SDLA_S503: - if (!detect_s503(port)) err = -ENODEV; - break; - - case SDLA_S507: - if (!detect_s507(port)) err = -ENODEV; - break; - - case SDLA_S508: - if (!detect_s508(port)) err = -ENODEV; - break; - - case SDLA_S514: - if (!detect_s514(hw)) err = -ENODEV; - break; - - default: - if (detect_s502a(port)) - hw->type = SDLA_S502A; - else if (detect_s502e(port)) - hw->type = SDLA_S502E; - else if (detect_s503(port)) - hw->type = SDLA_S503; - else if (detect_s507(port)) - hw->type = SDLA_S507; - else if (detect_s508(port)) - hw->type = SDLA_S508; - else err = -ENODEV; - } - return err; -} - -/*============================================================================ - * Autoselect memory region. - * o try all available DMP address options from the top down until success. - */ -static int sdla_autodpm (sdlahw_t* hw) -{ - int i, err = -EINVAL; - unsigned* opt; - - switch (hw->type) { - case SDLA_S502A: - opt = s502a_dpmbase_options; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S508: - opt = s508_dpmbase_options; - break; - - case SDLA_S507: - opt = s507_dpmbase_options; - break; - - default: - return -EINVAL; - } - - /* Start testing from 8th position, address - * 0xC8000 from the 508 address table. - * We don't want to test A**** addresses, since - * they are usually used for Video */ - for (i = 8; i <= opt[0] && err; i++) { - hw->dpmbase = phys_to_virt(opt[i]); - err = sdla_setdpm(hw); - } - return err; -} - -/*============================================================================ - * Set up adapter dual-port memory window. - * o shut down adapter - * o make sure that no physical memory exists in this region, i.e entire - * region reads 0xFF and is not writable when adapter is shut down. - * o initialize adapter hardware - * o make sure that region is usable with SDLA card, i.e. we can write to it - * when adapter is configured. - */ -static int sdla_setdpm (sdlahw_t* hw) -{ - int err; - - /* Shut down card and verify memory region */ - sdla_down(hw); - if (check_memregion(hw->dpmbase, hw->dpmsize)) - return -EINVAL; - - /* Initialize adapter and test on-board memory segment by segment. - * If memory size appears to be less than shared memory window size, - * assume that memory region is unusable. - */ - err = sdla_init(hw); - if (err) return err; - - if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */ - sdla_down(hw); - return -EIO; - } - sdla_mapmem(hw, 0L); /* set window vector at bottom */ - return 0; -} - -/*============================================================================ - * Load adapter from the memory image of the SDLA firmware module. - * o verify firmware integrity and compatibility - * o start adapter up - */ -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) -{ - - int i; - - /* Verify firmware signature */ - if (strcmp(sfm->signature, SFM_SIGNATURE)) { - printk(KERN_INFO "%s: not SDLA firmware!\n", - modname); - return -EINVAL; - } - - /* Verify firmware module format version */ - if (sfm->version != SFM_VERSION) { - printk(KERN_INFO - "%s: firmware format %u rejected! Expecting %u.\n", - modname, sfm->version, SFM_VERSION); - return -EINVAL; - } - - /* Verify firmware module length and checksum */ - if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || - (checksum((void*)&sfm->info, - sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { - printk(KERN_INFO "%s: firmware corrupted!\n", modname); - return -EINVAL; - } - - /* Announce */ - printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, - (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", - sfm->info.codeid); - - if(hw->type == SDLA_S514) - printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n", - modname, hw->S514_cpu_no[0]); - - /* Scan through the list of compatible adapters and make sure our - * adapter type is listed. - */ - for (i = 0; - (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); - ++i); - - if (i == SFM_MAX_SDLA) { - printk(KERN_INFO "%s: firmware is not compatible with S%u!\n", - modname, hw->type); - return -EINVAL; - } - - - /* Make sure there is enough on-board memory */ - if (hw->memory < sfm->info.memsize) { - printk(KERN_INFO - "%s: firmware needs %lu bytes of on-board memory!\n", - modname, sfm->info.memsize); - return -EINVAL; - } - - /* Move code onto adapter */ - if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { - printk(KERN_INFO "%s: failed to load code segment!\n", - modname); - return -EIO; - } - - /* Prepare boot-time configuration data and kick-off CPU */ - sdla_bootcfg(hw, &sfm->info); - if (sdla_start(hw, sfm->info.startoffs)) { - printk(KERN_INFO "%s: Damn... Adapter won't start!\n", - modname); - return -EIO; - } - - /* position DPM window over the mailbox and enable interrupts */ - if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { - printk(KERN_INFO "%s: adapter hardware failure!\n", - modname); - return -EIO; - } - hw->fwid = sfm->info.codeid; /* set firmware ID */ - return 0; -} - -/*============================================================================ - * Initialize SDLA hardware: setup memory window, IRQ, etc. - */ -static int sdla_init (sdlahw_t* hw) -{ - int i; - - for (i = 0; i < SDLA_MAXIORANGE; ++i) - hw->regs[i] = 0; - - switch (hw->type) { - case SDLA_S502A: return init_s502a(hw); - case SDLA_S502E: return init_s502e(hw); - case SDLA_S503: return init_s503(hw); - case SDLA_S507: return init_s507(hw); - case SDLA_S508: return init_s508(hw); - } - return -EINVAL; -} - -/*============================================================================ - * Test adapter on-board memory. - * o slide DPM window from the bottom up and test adapter memory segment by - * segment. - * Return adapter memory size. - */ -static unsigned long sdla_memtest (sdlahw_t* hw) -{ - unsigned long memsize; - unsigned winsize; - - for (memsize = 0, winsize = hw->dpmsize; - !sdla_mapmem(hw, memsize) && - (test_memregion(hw->dpmbase, winsize) == winsize) - ; - memsize += winsize) - ; - hw->memory = memsize; - return memsize; -} - -/*============================================================================ - * Prepare boot-time firmware configuration data. - * o position DPM window - * o initialize configuration data area - */ -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) -{ - unsigned char* data; - - if (!sfminfo->datasize) return 0; /* nothing to do */ - - if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) - return -EIO; - - if(hw->type == SDLA_S514) - data = (void*)(hw->dpmbase + sfminfo->dataoffs); - else - data = (void*)((u8 *)hw->dpmbase + - (sfminfo->dataoffs - hw->vector)); - - memset_io (data, 0, sfminfo->datasize); - - writeb (make_config_byte(hw), &data[0x00]); - - switch (sfminfo->codeid) { - case SFID_X25_502: - case SFID_X25_508: - writeb (3, &data[0x01]); /* T1 timer */ - writeb (10, &data[0x03]); /* N2 */ - writeb (7, &data[0x06]); /* HDLC window size */ - writeb (1, &data[0x0B]); /* DTE */ - writeb (2, &data[0x0C]); /* X.25 packet window size */ - writew (128, &data[0x0D]); /* default X.25 data size */ - writew (128, &data[0x0F]); /* maximum X.25 data size */ - break; - } - return 0; -} - -/*============================================================================ - * Prepare configuration byte identifying adapter type and CPU clock rate. - */ -static unsigned char make_config_byte (sdlahw_t* hw) -{ - unsigned char byte = 0; - - switch (hw->pclk) { - case 5000: byte = 0x01; break; - case 7200: byte = 0x02; break; - case 8000: byte = 0x03; break; - case 10000: byte = 0x04; break; - case 16000: byte = 0x05; break; - } - - switch (hw->type) { - case SDLA_S502E: byte |= 0x80; break; - case SDLA_S503: byte |= 0x40; break; - } - return byte; -} - -/*============================================================================ - * Start adapter's CPU. - * o calculate a pointer to adapter's cold boot entry point - * o position DPM window - * o place boot instruction (jp addr) at cold boot entry point - * o start CPU - */ -static int sdla_start (sdlahw_t* hw, unsigned addr) -{ - unsigned port = hw->port; - unsigned char *bootp; - int err, tmp, i; - - if (!port && (hw->type != SDLA_S514)) return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - bootp = hw->dpmbase; - bootp += 0x66; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - case SDLA_S514: - bootp = hw->dpmbase; - break; - - default: - return -EINVAL; - } - - err = sdla_mapmem(hw, 0); - if (err) return err; - - writeb (0xC3, bootp); /* Z80: 'jp' opcode */ - bootp ++; - writew (addr, bootp); - - switch (hw->type) { - case SDLA_S502A: - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0x01); /* start CPU */ - hw->regs[3] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); - if (_INB(port) & 0x01) { /* verify */ - /* - * Enabling CPU changes functionality of the - * control register, so we have to reset its - * mirror. - */ - _OUTB(port, 0); /* disable interrupts */ - hw->regs[0] = 0; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x01)) /* verify */ - return -EIO; - break; - - case SDLA_S507: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x04)) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port + 1) & 0x02)) /* verify */ - return -EIO; - break; - - case SDLA_S514: - writeb (S514_CPU_START, hw->vector); - break; - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Initialize S502A adapter. - */ -static int init_s502a (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502a(port)) - return -ENODEV; - - hw->regs[0] = 0x08; - hw->regs[1] = 0xFF; - - /* Verify configuration options */ - i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502a_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window (this also enables memory access) */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - hw->regs[0] = 0x08; - return 0; -} - -/*============================================================================ - * Initialize S502E adapter. - */ -static int init_s502e (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502e(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x02) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S503 adapter. - * --------------------------------------------------------------------------- - */ -static int init_s503 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s503(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; /* update mirror */ - return 0; -} - -/*============================================================================ - * Initialize S507 adapter. - */ -static int init_s507 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s507(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s507_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Enable adapter's logic */ - _OUTB(port, 0x01); - hw->regs[0] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x20)) - return -EIO; - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - tmp = hw->regs[0] | 0x04; - if (hw->irq) { - i = get_option_index(s508_irq_options, hw->irq); - if (i) tmp |= s507_irqmask[i - 1]; - } - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x08) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S508 adapter. - */ -static int init_s508 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s508(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - /* Setup memory configuration */ - tmp = s508_hmcr[i - 1]; - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x04); - hw->regs[0] = 0x04; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port + 1) & 0x04) ? 0 : -EIO; -} - -/*============================================================================ - * Detect S502A adapter. - * Following tests are used to detect S502A adapter: - * 1. All registers other than status (BASE) should read 0xFF - * 2. After writing 00001000b to control register, status register should - * read 01000000b. - * 3. After writing 0 to control register, status register should still - * read 01000000b. - * 4. After writing 00000100b to control register, status register should - * read 01000100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502a (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0; - - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0; - _OUTB(port, 0x04); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x44) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port + 1, 0xFF); - return 1; -} - -/*============================================================================ - * Detect S502E adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to CPU control register (BASE+3), status register - * (BASE) should read 11111000b. - * 3. After writing 00000100b to port BASE (set bit 2), status register - * (BASE) should read 11111100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502e (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0; - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port + 3, 0); /* CPU control reg. */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF8) /* read status */ - return 0; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xFC) /* verify */ - return 0; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s503 adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to control register (BASE), status register (BASE) - * should read 11110000b. - * 3. After writing 00000100b (set bit 2) to control register (BASE), - * status register should read 11110010b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s503 (int port) -{ - int i, j; - - if (!get_option_index(s503_port_options, port)) - return 0; - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0); /* reset control reg.*/ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF0) /* read status */ - return 0; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF2) /* verify */ - return 0; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s507 adapter. - * Following tests are used to detect s507 adapter: - * 1. All ports should read the same value. - * 2. After writing 0x00 to control register, status register should read - * ?011000?b. - * 3. After writing 0x01 to control register, status register should read - * ?011001?b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s507 (int port) -{ - int tmp, i, j; - - if (!get_option_index(s508_port_options, port)) - return 0; - tmp = _INB(port); - for (j = 1; j < S507_IORANGE; ++j) { - if (_INB(port + j) != tmp) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x30) - return 0; - _OUTB(port, 0x01); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x32) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/*============================================================================ - * Detect s508 adapter. - * Following tests are used to detect s508 adapter: - * 1. After writing 0x00 to control register, status register should read - * ??000000b. - * 2. After writing 0x10 to control register, status register should read - * ??010000b - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s508 (int port) -{ - int i; - - if (!get_option_index(s508_port_options, port)) - return 0; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x00) - return 0; - _OUTB(port, 0x10); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x10) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/*============================================================================ - * Detect s514 PCI adapter. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s514 (sdlahw_t* hw) -{ - unsigned char CPU_no, slot_no, auto_slot_cfg; - int number_S514_cards = 0; - u32 S514_mem_base_addr = 0; - u32 ut_u32; - struct pci_dev *pci_dev; - - -#ifndef CONFIG_PCI - printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname); - return 0; -#endif - - /* - The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the - slot number defined in 'router.conf' via the 'port' definition. - */ - CPU_no = hw->S514_cpu_no[0]; - slot_no = hw->S514_slot_no; - auto_slot_cfg = hw->auto_pci_cfg; - - if (auto_slot_cfg){ - printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n", - modname, CPU_no); - - }else{ - printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n", - modname, CPU_no, slot_no); - } - - /* check to see that CPU A or B has been selected in 'router.conf' */ - switch(CPU_no) { - case S514_CPU_A: - case S514_CPU_B: - break; - - default: - printk(KERN_INFO "%s: S514 CPU definition invalid.\n", - modname); - printk(KERN_INFO "Must be 'A' or 'B'\n"); - return 0; - } - - number_S514_cards = find_s514_adapter(hw, 0); - if(!number_S514_cards) - return 0; - - /* we are using a single S514 adapter with a slot of 0 so re-read the */ - /* location of this adapter */ - if((number_S514_cards == 1) && auto_slot_cfg) { - number_S514_cards = find_s514_adapter(hw, 1); - if(!number_S514_cards) { - printk(KERN_INFO "%s: Error finding PCI card\n", - modname); - return 0; - } - } - - pci_dev = hw->pci_dev; - /* read the physical memory base address */ - S514_mem_base_addr = (CPU_no == S514_CPU_A) ? - (pci_dev->resource[1].start) : - (pci_dev->resource[2].start); - - printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", - modname, S514_mem_base_addr); - if(!S514_mem_base_addr) { - if(CPU_no == S514_CPU_B) - printk(KERN_INFO "%s: CPU #B not present on the card\n", modname); - else - printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname); - return 0; - } - - /* enable the PCI memory */ - pci_read_config_dword(pci_dev, - (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, - &ut_u32); - pci_write_config_dword(pci_dev, - (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, - (ut_u32 | PCI_MEMORY_ENABLE)); - - /* check the IRQ allocated and enable IRQ usage */ - if(!(hw->irq = pci_dev->irq)) { - printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", - modname); - return 0; - } - - /* BUG FIX : Mar 6 2000 - * On a initial loading of the card, we must check - * and clear PCI interrupt bits, due to a reset - * problem on some other boards. i.e. An interrupt - * might be pending, even after system bootup, - * in which case, when starting wanrouter the machine - * would crash. - */ - if (init_pci_slot(hw)) - return 0; - - pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); - ut_u32 |= (CPU_no == S514_CPU_A) ? - PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; - pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); - - printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", - modname, hw->irq); - - /* map the physical PCI memory to virtual memory */ - hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, - (unsigned long)MAX_SIZEOF_S514_MEMORY); - /* map the physical control register memory to virtual memory */ - hw->vector = (unsigned long)ioremap( - (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), - (unsigned long)16); - - if(!hw->dpmbase || !hw->vector) { - printk(KERN_INFO "%s: PCI virtual memory allocation failed\n", - modname); - return 0; - } - - /* halt the adapter */ - writeb (S514_CPU_HALT, hw->vector); - - return 1; -} - -/*============================================================================ - * Find the S514 PCI adapter in the PCI bus. - * Return the number of S514 adapters found (0 if no adapter found). - */ -static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card) -{ - unsigned char slot_no; - int number_S514_cards = 0; - char S514_found_in_slot = 0; - u16 PCI_subsys_vendor; - - struct pci_dev *pci_dev = NULL; - - slot_no = hw->S514_slot_no; - - while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) - != NULL) { - - pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, - &PCI_subsys_vendor); - - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) - continue; - - hw->pci_dev = pci_dev; - - if(find_first_S514_card) - return(1); - - number_S514_cards ++; - - printk(KERN_INFO - "%s: S514 card found, slot #%d (devfn 0x%X)\n", - modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->devfn); - - if (hw->auto_pci_cfg){ - hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); - slot_no = hw->S514_slot_no; - - }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){ - S514_found_in_slot = 1; - break; - } - } - - /* if no S514 adapter has been found, then exit */ - if (!number_S514_cards) { - printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname); - return 0; - } - /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ - else if ((number_S514_cards > 1) && hw->auto_pci_cfg) { - printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n" - "%s: More than one S514 adapter found.\n" - "%s: Disable the Autodetect feature and supply\n" - "%s: the PCISLOT numbers for each card.\n", - modname,modname,modname,modname); - return 0; - } - /* if the user has specified a slot number and the S514 adapter has */ - /* not been found in that slot, then exit */ - else if (!hw->auto_pci_cfg && !S514_found_in_slot) { - printk(KERN_INFO - "%s: Error, S514 card not found in specified slot #%d\n", - modname, slot_no); - return 0; - } - - return (number_S514_cards); -} - - - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Calibrate SDLA memory access delay. - * Count number of idle loops made within 1 second and then calculate the - * number of loops that should be made to achive desired delay. - */ -static int calibrate_delay (int mks) -{ - unsigned int delay; - unsigned long stop; - - for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); - return (delay/(1000000L/mks) + 1); -} - -/*============================================================================ - * Get option's index into the options list. - * Return option's index (1 .. N) or zero if option is invalid. - */ -static int get_option_index (unsigned* optlist, unsigned optval) -{ - int i; - - for (i = 1; i <= optlist[0]; ++i) - if ( optlist[i] == optval) - return i; - return 0; -} - -/*============================================================================ - * Check memory region to see if it's available. - * Return: 0 ok. - */ -static unsigned check_memregion (void* ptr, unsigned len) -{ - volatile unsigned char* p = ptr; - - for (; len && (readb (p) == 0xFF); --len, ++p) { - writeb (0, p); /* attempt to write 0 */ - if (readb(p) != 0xFF) { /* still has to read 0xFF */ - writeb (0xFF, p);/* restore original value */ - break; /* not good */ - } - } - - return len; -} - -/*============================================================================ - * Test memory region. - * Return: size of the region that passed the test. - * Note: Region size must be multiple of 2 ! - */ -static unsigned test_memregion (void* ptr, unsigned len) -{ - volatile unsigned short* w_ptr; - unsigned len_w = len >> 1; /* region len in words */ - unsigned i; - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0xAA55, w_ptr); - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (readw (w_ptr) != 0xAA55) { - len_w = i; - break; - } - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0x55AA, w_ptr); - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (readw(w_ptr) != 0x55AA) { - len_w = i; - break; - } - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0, w_ptr); - - return len_w << 1; -} - -/*============================================================================ - * Calculate 16-bit CRC using CCITT polynomial. - */ -static unsigned short checksum (unsigned char* buf, unsigned len) -{ - unsigned short crc = 0; - unsigned mask, flag; - - for (; len; --len, ++buf) { - for (mask = 0x80; mask; mask >>= 1) { - flag = (crc & 0x8000); - crc <<= 1; - crc |= ((*buf & mask) ? 1 : 0); - if (flag) crc ^= 0x1021; - } - } - return crc; -} - -static int init_pci_slot(sdlahw_t *hw) -{ - - u32 int_status; - int volatile found=0; - int i=0; - - /* Check if this is a very first load for a specific - * pci card. If it is, clear the interrput bits, and - * set the flag indicating that this card was initialized. - */ - - for (i=0; (i<MAX_S514_CARDS) && !found; i++){ - if (pci_slot_ar[i] == hw->S514_slot_no){ - found=1; - break; - } - if (pci_slot_ar[i] == 0xFF){ - break; - } - } - - if (!found){ - read_S514_int_stat(hw,&int_status); - S514_intack(hw,int_status); - if (i == MAX_S514_CARDS){ - printk(KERN_INFO "%s: Critical Error !!!\n",modname); - printk(KERN_INFO - "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", - modname); - printk(KERN_INFO "Please contact Sangoma Technologies\n"); - return 1; - } - pci_slot_ar[i] = hw->S514_slot_no; - } - return 0; -} - -static int pci_probe(sdlahw_t *hw) -{ - - unsigned char slot_no; - int number_S514_cards = 0; - u16 PCI_subsys_vendor; - u16 PCI_card_type; - - struct pci_dev *pci_dev = NULL; - struct pci_bus *bus = NULL; - - slot_no = 0; - - while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) - != NULL) { - - pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, - &PCI_subsys_vendor); - - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) - continue; - - pci_read_config_word(pci_dev, PCI_CARD_TYPE, - &PCI_card_type); - - bus = pci_dev->bus; - - /* A dual cpu card can support up to 4 physical connections, - * where a single cpu card can support up to 2 physical - * connections. The FT1 card can only support a single - * connection, however we cannot distinguish between a Single - * CPU card and an FT1 card. */ - if (PCI_card_type == S514_DUAL_CPU){ - number_S514_cards += 4; - printk(KERN_INFO - "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", - bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->irq); - }else{ - number_S514_cards += 2; - printk(KERN_INFO - "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", - bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->irq); - } - } - - return number_S514_cards; - -} - - - -EXPORT_SYMBOL(wanpipe_hw_probe); - -unsigned wanpipe_hw_probe(void) -{ - sdlahw_t hw; - unsigned* opt = s508_port_options; - unsigned cardno=0; - int i; - - memset(&hw, 0, sizeof(hw)); - - for (i = 1; i <= opt[0]; i++) { - if (detect_s508(opt[i])){ - /* S508 card can support up to two physical links */ - cardno+=2; - printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]); - } - } - - #ifdef CONFIG_PCI - hw.S514_slot_no = 0; - cardno += pci_probe(&hw); - #else - printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n"); - printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n"); - #endif - - return cardno; -} - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c deleted file mode 100644 index 7a8b22a7ea3..00000000000 --- a/drivers/net/wan/sdlamain.c +++ /dev/null @@ -1,1346 +0,0 @@ -/**************************************************************************** -* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. -* -* Author: Nenad Corbic <ncorbic@sangoma.com> -* Gideon Hack -* -* Copyright: (c) 1995-2000 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. -* Removed the polling routine. -* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic -* device allocation. -* Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels -* 2.2.16 and above. -* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on -* kernels 2.2.16 or greater. The SyncPPP -* has changed. -* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. -* Jul 13, 2000 Nenad Corbic Added Multi-PPP support. -* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. -* Sep 23, 1999 Nenad Corbic Added support for SMP -* Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Updates for Linux 2.2.X kernels. -* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel -* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 -* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); -* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 -* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr -* assignments are taken out and placed in the -* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr -* routines. Took out 'wandev->tx_int_enabled' and -* replaced it with 'wandev->enable_tx_int'. -* May 29, 1997 Jaspreet Singh Flow Control Problem -* added "wandev->tx_int_enabled=1" line in the -* init module. This line initializes the flag for -* preventing Interrupt disabled with device set to -* busy -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o added UDP management stuff -* Jan 02, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include <linux/config.h> /* OS configuration options */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/init.h> -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/module.h> /* support for loadable modules */ -#include <linux/ioport.h> /* request_region(), release_region() */ -#include <linux/wanrouter.h> /* WAN router definitions */ -#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <linux/rcupdate.h> - -#include <linux/in.h> -#include <asm/io.h> /* phys_to_virt() */ -#include <linux/pci.h> -#include <linux/sdlapci.h> -#include <linux/if_wanpipe_common.h> - -#include <asm/uaccess.h> /* kernel <-> user copy */ -#include <linux/inetdevice.h> - -#include <linux/ip.h> -#include <net/route.h> - -#define KMEM_SAFETYZONE 8 - - -#ifndef CONFIG_WANPIPE_FR - #define wpf_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_CHDLC - #define wpc_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_X25 - #define wpx_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_PPP - #define wpp_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_MULTPPP - #define wsppp_init(a,b) (-EPROTONOSUPPORT) -#endif - - -/***********FOR DEBUGGING PURPOSES********************************************* -static void * dbg_kmalloc(unsigned int size, int prio, int line) { - int i = 0; - void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); - char * c1 = v; - c1 += sizeof(unsigned int); - *((unsigned int *)v) = size; - - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; - c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; - c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; - c1 += 8; - } - v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; - printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); - return v; -} -static void dbg_kfree(void * v, int line) { - unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); - unsigned int size = *sp; - char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; - int i = 0; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' - || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { - printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' - || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' - ) { - printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - printk(KERN_INFO "line %d kfree(%p)\n",line,v); - v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); - kfree(v); -} - -#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) -#define kfree(x) dbg_kfree(x,__LINE__) -******************************************************************************/ - - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -#define DRV_VERSION 5 /* version number */ -#define DRV_RELEASE 0 /* release (minor version) number */ -#define MAX_CARDS 16 /* max number of adapters */ - -#ifndef CONFIG_WANPIPE_CARDS /* configurable option */ -#define CONFIG_WANPIPE_CARDS 1 -#endif - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -/****** Function Prototypes *************************************************/ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/* WAN link driver entry points */ -static int setup(struct wan_device* wandev, wandev_conf_t* conf); -static int shutdown(struct wan_device* wandev); -static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg); - -/* IOCTL handlers */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); - -/* Miscellaneous functions */ -STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs); -static void release_hw (sdla_t *card); - -static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); -static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); - - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -/* private data */ -static char drvname[] = "wanpipe"; -static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; -static int ncards; -static sdla_t* card_array; /* adapter data space */ - -/* Wanpipe's own workqueue, used for all API's. - * All protocol specific tasks will be inserted - * into the "wanpipe_wq" workqueue. - - * The kernel workqueue mechanism will execute - * all pending tasks in the "wanpipe_wq" workqueue. - */ - -struct workqueue_struct *wanpipe_wq; -DECLARE_WORK(wanpipe_work, NULL, NULL); - -static int wanpipe_bh_critical; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o allocate adapter data space - * o initialize static data - * o register all cards with WAN router - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -static int __init wanpipe_init(void) -{ - int cnt, err = 0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, DRV_VERSION, DRV_RELEASE, copyright); - - wanpipe_wq = create_workqueue("wanpipe_wq"); - if (!wanpipe_wq) - return -ENOMEM; - - /* Probe for wanpipe cards and return the number found */ - printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); - ncards = wanpipe_hw_probe(); - if (ncards){ - printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); - }else{ - printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); - destroy_workqueue(wanpipe_wq); - return -ENODEV; - } - - /* Verify number of cards and allocate adapter data space */ - card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); - if (card_array == NULL) { - destroy_workqueue(wanpipe_wq); - return -ENOMEM; - } - - memset(card_array, 0, sizeof(sdla_t) * ncards); - - /* Register adapters with WAN router */ - for (cnt = 0; cnt < ncards; ++ cnt) { - sdla_t* card = &card_array[cnt]; - struct wan_device* wandev = &card->wandev; - - card->next = NULL; - sprintf(card->devname, "%s%d", drvname, cnt + 1); - wandev->magic = ROUTER_MAGIC; - wandev->name = card->devname; - wandev->private = card; - wandev->enable_tx_int = 0; - wandev->setup = &setup; - wandev->shutdown = &shutdown; - wandev->ioctl = &ioctl; - err = register_wan_device(wandev); - if (err) { - printk(KERN_INFO - "%s: %s registration failed with error %d!\n", - drvname, card->devname, err); - break; - } - } - if (cnt){ - ncards = cnt; /* adjust actual number of cards */ - }else { - kfree(card_array); - destroy_workqueue(wanpipe_wq); - printk(KERN_INFO "IN Init Module: NO Cards registered\n"); - err = -ENODEV; - } - - return err; -} - -/*============================================================================ - * Module 'remove' entry point. - * o unregister all adapters from the WAN router - * o release all remaining system resources - */ -static void __exit wanpipe_cleanup(void) -{ - int i; - - if (!ncards) - return; - - for (i = 0; i < ncards; ++i) { - sdla_t* card = &card_array[i]; - unregister_wan_device(card->devname); - } - destroy_workqueue(wanpipe_wq); - kfree(card_array); - - printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); -} - -module_init(wanpipe_init); -module_exit(wanpipe_cleanup); - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Setup/configure WAN link driver. - * o check adapter state - * o make sure firmware is present in configuration - * o make sure I/O port and IRQ are specified - * o make sure I/O region is available - * o allocate interrupt vector - * o setup SDLA hardware - * o call appropriate routine to perform protocol-specific initialization - * o mark I/O region as used - * o if this is the first active card, then schedule background task - * - * This function is called when router handles ROUTER_SETUP IOCTL. The - * configuration structure is in kernel memory (including extended data, if - * any). - */ - -static int setup(struct wan_device* wandev, wandev_conf_t* conf) -{ - sdla_t* card; - int err = 0; - int irq=0; - - /* Sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ - printk(KERN_INFO - "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", - wandev->name, - (unsigned int)wandev,(unsigned int)wandev->private, - (unsigned int)conf); - return -EFAULT; - } - - printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); - - card = wandev->private; - if (wandev->state != WAN_UNCONFIGURED){ - printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", - wandev->name); - return -EBUSY; /* already configured */ - } - - printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); - - /* Initialize the counters for each wandev - * Used for counting number of times new_if and - * del_if get called. - */ - wandev->del_if_cnt = 0; - wandev->new_if_cnt = 0; - wandev->config_id = conf->config_id; - - if (!conf->data_size || (conf->data == NULL)) { - printk(KERN_INFO - "%s: firmware not found in configuration data!\n", - wandev->name); - return -EINVAL; - } - - /* Check for resource conflicts and setup the - * card for piggibacking if necessary */ - if(!conf->S514_CPU_no[0]) { - if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ - return err; - } - }else { - if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ - return err; - } - } - - /* If the current card has already been configured - * or it's a piggyback card, do not try to allocate - * resources. - */ - if (!card->wandev.piggyback && !card->configured){ - - /* Configure hardware, load firmware, etc. */ - memset(&card->hw, 0, sizeof(sdlahw_t)); - - /* for an S514 adapter, pass the CPU number and the slot number read */ - /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ - /* parameter */ - if (conf->S514_CPU_no[0]){ - - card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; - card->hw.S514_slot_no = conf->PCI_slot_no; - card->hw.auto_pci_cfg = conf->auto_pci_cfg; - - if (card->hw.auto_pci_cfg == WANOPT_YES){ - printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", - card->devname, card->hw.S514_cpu_no[0]); - }else{ - printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", - card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); - } - - }else{ - /* 508 Card io port and irq initialization */ - card->hw.port = conf->ioport; - card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; - } - - - /* Compute the virtual address of the card in kernel space */ - if(conf->maddr){ - card->hw.dpmbase = phys_to_virt(conf->maddr); - }else{ - card->hw.dpmbase = (void *)conf->maddr; - } - - card->hw.dpmsize = SDLA_WINDOWSIZE; - - /* set the adapter type if using an S514 adapter */ - card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; - card->hw.pclk = conf->hw_opt[1]; - - err = sdla_setup(&card->hw, conf->data, conf->data_size); - if (err){ - printk(KERN_INFO "%s: Hardware setup Failed %i\n", - card->devname,err); - return err; - } - - if(card->hw.type != SDLA_S514) - irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ - else - irq = card->hw.irq; - - /* request an interrupt vector - note that interrupts may be shared */ - /* when using the S514 PCI adapter */ - - if(request_irq(irq, sdla_isr, - (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, - wandev->name, card)){ - - printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); - return -EINVAL; - } - - }else{ - printk(KERN_INFO "%s: Card Configured %lu or Piggybacking %i!\n", - wandev->name,card->configured,card->wandev.piggyback); - } - - - if (!card->configured){ - - /* Initialize the Spin lock */ - printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); - - /* Piggyback spin lock has already been initialized, - * in check_s514/s508_conflicts() */ - if (!card->wandev.piggyback){ - spin_lock_init(&card->wandev.lock); - } - - /* Intialize WAN device data space */ - wandev->irq = irq; - wandev->dma = 0; - if(card->hw.type != SDLA_S514){ - wandev->ioport = card->hw.port; - }else{ - wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0]; - wandev->S514_slot_no = card->hw.S514_slot_no; - } - wandev->maddr = (unsigned long)card->hw.dpmbase; - wandev->msize = card->hw.dpmsize; - wandev->hw_opt[0] = card->hw.type; - wandev->hw_opt[1] = card->hw.pclk; - wandev->hw_opt[2] = card->hw.memory; - wandev->hw_opt[3] = card->hw.fwid; - } - - /* Protocol-specific initialization */ - switch (card->hw.fwid) { - - case SFID_X25_502: - case SFID_X25_508: - printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n", - card->devname); - err = wpx_init(card, conf); - break; - case SFID_FR502: - case SFID_FR508: - printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", - card->devname); - err = wpf_init(card, conf); - break; - case SFID_PPP502: - case SFID_PPP508: - printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", - card->devname); - err = wpp_init(card, conf); - break; - - case SFID_CHDLC508: - case SFID_CHDLC514: - if (conf->ft1){ - printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", - card->devname); - err = wpft1_init(card, conf); - break; - - }else if (conf->config_id == WANCONFIG_MPPP){ - printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", - card->devname); - err = wsppp_init(card,conf); - break; - - }else{ - printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", - card->devname); - err = wpc_init(card, conf); - break; - } - default: - printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", - wandev->name,card->hw.fwid,SFID_CHDLC508); - err = -EPROTONOSUPPORT; - } - - if (err != 0){ - if (err == -EPROTONOSUPPORT){ - printk(KERN_INFO - "%s: Error, Protocol selected has not been compiled!\n", - card->devname); - printk(KERN_INFO - "%s: Re-configure the kernel and re-build the modules!\n", - card->devname); - } - - release_hw(card); - wandev->state = WAN_UNCONFIGURED; - return err; - } - - - /* Reserve I/O region and schedule background task */ - if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) - if (!request_region(card->hw.port, card->hw.io_range, - wandev->name)) { - printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port); - release_hw(card); - wandev->state = WAN_UNCONFIGURED; - return -EBUSY; - } - - /* Only use the polling routine for the X25 protocol */ - - card->wandev.critical=0; - return 0; -} - -/*================================================================== - * configure_s508_card - * - * For a S508 adapter, check for a possible configuration error in that - * we are loading an adapter in the same IO port as a previously loaded S508 - * card. - */ - -static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) -{ - unsigned long smp_flags; - int i; - - if (conf->ioport <= 0) { - printk(KERN_INFO - "%s: can't configure without I/O port address!\n", - card->wandev.name); - return -EINVAL; - } - - if (conf->irq <= 0) { - printk(KERN_INFO "%s: can't configure without IRQ!\n", - card->wandev.name); - return -EINVAL; - } - - if (test_bit(0,&card->configured)) - return 0; - - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - - for (i = 0; i < ncards; i++) { - sdla_t *nxt_card = &card_array[i]; - - /* Skip the current card ptr */ - if (nxt_card == card) - continue; - - - /* Find a card that is already configured with the - * same IO Port */ - if ((nxt_card->hw.type == SDLA_S508) && - (nxt_card->hw.port == conf->ioport) && - (nxt_card->next == NULL)){ - - /* We found a card the card that has same configuration - * as us. This means, that we must setup this card in - * piggibacking mode. However, only CHDLC and MPPP protocol - * support this setup */ - - if ((conf->config_id == WANCONFIG_CHDLC || - conf->config_id == WANCONFIG_MPPP) && - (nxt_card->wandev.config_id == WANCONFIG_CHDLC || - nxt_card->wandev.config_id == WANCONFIG_MPPP)){ - - *irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - - /* The master could already be running, we must - * set this as a critical area */ - lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); - - nxt_card->next = card; - card->next = nxt_card; - - card->wandev.piggyback = WANOPT_YES; - - /* We must initialise the piggiback spin lock here - * since isr will try to lock card->next if it - * exists */ - spin_lock_init(&card->wandev.lock); - - unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); - break; - }else{ - /* Trying to run piggibacking with a wrong protocol */ - printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" - "%s: This protocol doesn't support\n" - "%s: multi-port operation!\n", - card->devname,nxt_card->hw.port, - card->devname,card->devname); - return -EEXIST; - } - } - } - - - /* Make sure I/O port region is available only if we are the - * master device. If we are running in piggybacking mode, - * we will use the resources of the master card. */ - if (!card->wandev.piggyback) { - struct resource *rr = - request_region(conf->ioport, SDLA_MAXIORANGE, "sdlamain"); - release_region(conf->ioport, SDLA_MAXIORANGE); - - if (!rr) { - printk(KERN_INFO - "%s: I/O region 0x%X - 0x%X is in use!\n", - card->wandev.name, conf->ioport, - conf->ioport + SDLA_MAXIORANGE - 1); - return -EINVAL; - } - } - - return 0; -} - -/*================================================================== - * configure_s514_card - * - * For a S514 adapter, check for a possible configuration error in that - * we are loading an adapter in the same slot as a previously loaded S514 - * card. - */ - - -static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) -{ - unsigned long smp_flags; - int i; - - if (test_bit(0,&card->configured)) - return 0; - - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - - for (i = 0; i < ncards; i ++) { - - sdla_t* nxt_card = &card_array[i]; - if(nxt_card == card) - continue; - - if((nxt_card->hw.type == SDLA_S514) && - (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && - (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& - (nxt_card->next == NULL)){ - - - if ((conf->config_id == WANCONFIG_CHDLC || - conf->config_id == WANCONFIG_MPPP) && - (nxt_card->wandev.config_id == WANCONFIG_CHDLC || - nxt_card->wandev.config_id == WANCONFIG_MPPP)){ - - *irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - - /* The master could already be running, we must - * set this as a critical area */ - lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); - nxt_card->next = card; - card->next = nxt_card; - - card->wandev.piggyback = WANOPT_YES; - - /* We must initialise the piggiback spin lock here - * since isr will try to lock card->next if it - * exists */ - spin_lock_init(&card->wandev.lock); - - unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); - - }else{ - /* Trying to run piggibacking with a wrong protocol */ - printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" - "%s: This protocol doesn't support\n" - "%s: multi-port operation!\n", - card->devname, - conf->S514_CPU_no[0],conf->PCI_slot_no, - card->devname,card->devname); - return -EEXIST; - } - } - } - - return 0; -} - - - -/*============================================================================ - * Shut down WAN link driver. - * o shut down adapter hardware - * o release system resources. - * - * This function is called by the router when device is being unregistered or - * when it handles ROUTER_DOWN IOCTL. - */ -static int shutdown(struct wan_device* wandev) -{ - sdla_t *card; - int err=0; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)){ - return -EFAULT; - } - - if (wandev->state == WAN_UNCONFIGURED){ - return 0; - } - - card = wandev->private; - - if (card->tty_opt){ - if (card->tty_open){ - printk(KERN_INFO - "%s: Shutdown Failed: TTY is still open\n", - card->devname); - return -EBUSY; - } - } - - wandev->state = WAN_UNCONFIGURED; - - set_bit(PERI_CRIT,(void*)&wandev->critical); - - /* In case of piggibacking, make sure that - * we never try to shutdown both devices at the same - * time, because they depend on one another */ - - if (card->disable_comm){ - card->disable_comm(card); - } - - /* Release Resources */ - release_hw(card); - - /* only free the allocated I/O range if not an S514 adapter */ - if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){ - release_region(card->hw.port, card->hw.io_range); - } - - if (!card->configured){ - memset(&card->hw, 0, sizeof(sdlahw_t)); - if (card->next){ - memset(&card->next->hw, 0, sizeof(sdlahw_t)); - } - } - - - clear_bit(PERI_CRIT,(void*)&wandev->critical); - return err; -} - -static void release_hw (sdla_t *card) -{ - sdla_t *nxt_card; - - - /* Check if next device exists */ - if (card->next){ - nxt_card = card->next; - /* If next device is down then release resources */ - if (nxt_card->wandev.state == WAN_UNCONFIGURED){ - if (card->wandev.piggyback){ - /* If this device is piggyback then use - * information of the master device - */ - printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname); - sdla_down(&card->next->hw); - free_irq(card->wandev.irq, card->next); - card->configured = 0; - card->next->configured = 0; - card->wandev.piggyback = 0; - }else{ - /* Master device shutting down */ - printk(KERN_INFO "%s: Master shutting down\n",card->devname); - sdla_down(&card->hw); - free_irq(card->wandev.irq, card); - card->configured = 0; - card->next->configured = 0; - } - }else{ - printk(KERN_INFO "%s: Device still running %i\n", - nxt_card->devname,nxt_card->wandev.state); - - card->configured = 1; - } - }else{ - printk(KERN_INFO "%s: Master shutting down\n",card->devname); - sdla_down(&card->hw); - free_irq(card->wandev.irq, card); - card->configured = 0; - } - return; -} - - -/*============================================================================ - * Driver I/O control. - * o verify arguments - * o perform requested action - * - * This function is called when router handles one of the reserved user - * IOCTLs. Note that 'arg' stil points to user address space. - */ -static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg) -{ - sdla_t* card; - int err; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - card = wandev->private; - - if(card->hw.type != SDLA_S514){ - disable_irq(card->hw.irq); - } - - if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { - return -EAGAIN; - } - - switch (cmd) { - case WANPIPE_DUMP: - err = ioctl_dump(wandev->private, (void*)arg); - break; - - case WANPIPE_EXEC: - err = ioctl_exec(wandev->private, (void*)arg, cmd); - break; - default: - err = -EINVAL; - } - - return err; -} - -/****** Driver IOCTL Handlers ***********************************************/ - -/*============================================================================ - * Dump adapter memory to user buffer. - * o verify request structure - * o copy request structure to kernel data space - * o verify length/offset - * o verify user buffer - * o copy adapter memory image to user buffer - * - * Note: when dumping memory, this routine switches curent dual-port memory - * vector, so care must be taken to avoid racing conditions. - */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) -{ - sdla_dump_t dump; - unsigned winsize; - unsigned long oldvec; /* DPM window vector */ - unsigned long smp_flags; - int err = 0; - - if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) - return -EFAULT; - - if ((dump.magic != WANPIPE_MAGIC) || - (dump.offset + dump.length > card->hw.memory)) - return -EINVAL; - - winsize = card->hw.dpmsize; - - if(card->hw.type != SDLA_S514) { - - lock_adapter_irq(&card->wandev.lock, &smp_flags); - - oldvec = card->hw.vector; - while (dump.length) { - /* current offset */ - unsigned pos = dump.offset % winsize; - /* current vector */ - unsigned long vec = dump.offset - pos; - unsigned len = (dump.length > (winsize - pos)) ? - (winsize - pos) : dump.length; - /* relocate window */ - if (sdla_mapmem(&card->hw, vec) != 0) { - err = -EIO; - break; - } - - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + pos, len)){ - - unlock_adapter_irq(&card->wandev.lock, &smp_flags); - return -EFAULT; - } - - dump.length -= len; - dump.offset += len; - dump.ptr = (char*)dump.ptr + len; - } - - sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ - unlock_adapter_irq(&card->wandev.lock, &smp_flags); - - }else { - - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + dump.offset, dump.length)){ - return -EFAULT; - } - } - - return err; -} - -/*============================================================================ - * Execute adapter firmware command. - * o verify request structure - * o copy request structure to kernel data space - * o call protocol-specific 'exec' function - */ -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) -{ - sdla_exec_t exec; - int err=0; - - if (card->exec == NULL && cmd == WANPIPE_EXEC){ - return -ENODEV; - } - - if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) - return -EFAULT; - - if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) - return -EINVAL; - - switch (cmd) { - case WANPIPE_EXEC: - err = card->exec(card, exec.cmd, exec.data); - break; - } - return err; -} - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * SDLA Interrupt Service Routine. - * o acknowledge SDLA hardware interrupt. - * o call protocol-specific interrupt service routine, if any. - */ -STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs) -{ -#define card ((sdla_t*)dev_id) - - if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */ - u32 int_status; - unsigned char CPU_no = card->hw.S514_cpu_no[0]; - unsigned char card_found_for_IRQ; - u8 IRQ_count = 0; - - for(;;) { - - read_S514_int_stat(&card->hw, &int_status); - - /* check if the interrupt is for this device */ - if(!((unsigned char)int_status & - (IRQ_CPU_A | IRQ_CPU_B))) - return IRQ_HANDLED; - - /* if the IRQ is for both CPUs on the same adapter, */ - /* then alter the interrupt status so as to handle */ - /* one CPU at a time */ - if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) - == (IRQ_CPU_A | IRQ_CPU_B)) { - int_status &= (CPU_no == S514_CPU_A) ? - ~IRQ_CPU_B : ~IRQ_CPU_A; - } - - card_found_for_IRQ = 0; - - /* check to see that the CPU number for this device */ - /* corresponds to the interrupt status read */ - switch (CPU_no) { - case S514_CPU_A: - if((unsigned char)int_status & - IRQ_CPU_A) - card_found_for_IRQ = 1; - break; - - case S514_CPU_B: - if((unsigned char)int_status & - IRQ_CPU_B) - card_found_for_IRQ = 1; - break; - } - - /* exit if the interrupt is for another CPU on the */ - /* same IRQ */ - if(!card_found_for_IRQ) - return IRQ_HANDLED; - - if (!card || - (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ - printk(KERN_INFO - "Received IRQ %d for CPU #%c\n", - irq, CPU_no); - printk(KERN_INFO - "IRQ for unconfigured adapter\n"); - S514_intack(&card->hw, int_status); - return IRQ_HANDLED; - } - - if (card->in_isr) { - printk(KERN_INFO - "%s: interrupt re-entrancy on IRQ %d\n", - card->devname, card->wandev.irq); - S514_intack(&card->hw, int_status); - return IRQ_HANDLED; - } - - spin_lock(&card->wandev.lock); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } - - S514_intack(&card->hw, int_status); - if (card->isr) - card->isr(card); - - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock(&card->wandev.lock); - - /* handle a maximum of two interrupts (one for each */ - /* CPU on the adapter) before returning */ - if((++ IRQ_count) == 2) - return IRQ_HANDLED; - } - } - - else { /* handle interrupt on S508 adapter */ - - if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) - return IRQ_HANDLED; - - if (card->in_isr) { - printk(KERN_INFO - "%s: interrupt re-entrancy on IRQ %d!\n", - card->devname, card->wandev.irq); - return IRQ_HANDLED; - } - - spin_lock(&card->wandev.lock); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } - - sdla_intack(&card->hw); - if (card->isr) - card->isr(card); - - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock(&card->wandev.lock); - - } - return IRQ_HANDLED; -#undef card -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being open. The only reason we need this, is because we - * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_open (sdla_t* card) -{ - ++card->open_cnt; -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being closed. The only reason we need this, is because we - * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_close (sdla_t* card) -{ - --card->open_cnt; -} - -/*============================================================================ - * Set WAN device state. - */ -void wanpipe_set_state (sdla_t* card, int state) -{ - if (card->wandev.state != state) { - switch (state) { - case WAN_CONNECTED: - printk (KERN_INFO "%s: link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: link disconnected!\n", - card->devname); - break; - } - card->wandev.state = state; - } - card->state_tick = jiffies; -} - -sdla_t * wanpipe_find_card (char *name) -{ - int cnt; - for (cnt = 0; cnt < ncards; ++ cnt) { - sdla_t* card = &card_array[cnt]; - if (!strcmp(card->devname,name)) - return card; - } - return NULL; -} - -sdla_t * wanpipe_find_card_num (int num) -{ - if (num < 1 || num > ncards) - return NULL; - num--; - return &card_array[num]; -} - -/* - * @work_pointer: work_struct to be done; - * should already have PREPARE_WORK() or - * INIT_WORK() done on it by caller; - */ -void wanpipe_queue_work (struct work_struct *work_pointer) -{ - if (test_and_set_bit(1, (void*)&wanpipe_bh_critical)) - printk(KERN_INFO "CRITICAL IN QUEUING WORK\n"); - - queue_work(wanpipe_wq, work_pointer); - clear_bit(1,(void*)&wanpipe_bh_critical); -} - -void wakeup_sk_bh(struct net_device *dev) -{ - wanpipe_common_t *chan = dev->priv; - - if (test_bit(0,&chan->common_critical)) - return; - - if (chan->sk && chan->tx_timer){ - chan->tx_timer->expires=jiffies+1; - add_timer(chan->tx_timer); - } -} - -int change_dev_flags(struct net_device *dev, unsigned flags) -{ - struct ifreq if_info; - mm_segment_t fs = get_fs(); - int err; - - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - if_info.ifr_flags = flags; - - set_fs(get_ds()); /* get user space block */ - err = devinet_ioctl(SIOCSIFFLAGS, &if_info); - set_fs(fs); - - return err; -} - -unsigned long get_ip_address(struct net_device *dev, int option) -{ - - struct in_ifaddr *ifaddr; - struct in_device *in_dev; - unsigned long addr = 0; - - rcu_read_lock(); - if ((in_dev = __in_dev_get_rcu(dev)) == NULL){ - goto out; - } - - if ((ifaddr = in_dev->ifa_list)== NULL ){ - goto out; - } - - switch (option){ - - case WAN_LOCAL_IP: - addr = ifaddr->ifa_local; - break; - - case WAN_POINTOPOINT_IP: - addr = ifaddr->ifa_address; - break; - - case WAN_NETMASK_IP: - addr = ifaddr->ifa_mask; - break; - - case WAN_BROADCAST_IP: - addr = ifaddr->ifa_broadcast; - break; - default: - break; - } - -out: - rcu_read_unlock(); - return addr; -} - -void add_gateway(sdla_t *card, struct net_device *dev) -{ - mm_segment_t oldfs; - struct rtentry route; - int res; - - memset((char*)&route,0,sizeof(struct rtentry)); - - ((struct sockaddr_in *) - &(route.rt_dst))->sin_addr.s_addr = 0; - ((struct sockaddr_in *) - &(route.rt_dst))->sin_family = AF_INET; - - ((struct sockaddr_in *) - &(route.rt_genmask))->sin_addr.s_addr = 0; - ((struct sockaddr_in *) - &(route.rt_genmask)) ->sin_family = AF_INET; - - - route.rt_flags = 0; - route.rt_dev = dev->name; - - oldfs = get_fs(); - set_fs(get_ds()); - res = ip_rt_ioctl(SIOCADDRT,&route); - set_fs(oldfs); - - if (res == 0){ - printk(KERN_INFO "%s: Gateway added for %s\n", - card->devname,dev->name); - } - - return; -} - -MODULE_LICENSE("GPL"); - -/****** End *********************************************************/ diff --git a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c deleted file mode 100644 index 812a1183c50..00000000000 --- a/drivers/net/wan/wanpipe_multppp.c +++ /dev/null @@ -1,2358 +0,0 @@ -/***************************************************************************** -* wanpipe_multppp.c Multi-Port PPP driver module. -* -* Authors: Nenad Corbic <ncorbic@sangoma.com> -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Dec 15 2000 Updated for 2.4.X kernel -* Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. -* The pppstruct has changed. -* Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC -* module. -*****************************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> /* printk(), and other useful stuff */ -#include <linux/stddef.h> /* offsetof(), etc. */ -#include <linux/errno.h> /* return codes */ -#include <linux/string.h> /* inline memset(), etc. */ -#include <linux/slab.h> /* kmalloc(), kfree() */ -#include <linux/wanrouter.h> /* WAN router definitions */ -#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ -#include <linux/if_arp.h> /* ARPHRD_* defines */ -#include <linux/jiffies.h> /* time_after() macro */ - -#include <linux/in.h> /* sockaddr_in */ -#include <linux/inet.h> -#include <linux/if.h> -#include <asm/byteorder.h> /* htons(), etc. */ -#include <linux/sdlapci.h> -#include <asm/io.h> - -#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ -#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */ - -#include <linux/if_wanpipe_common.h> /* Socket Driver common area */ -#include <linux/if_wanpipe.h> - - -#include <linux/inetdevice.h> -#include <asm/uaccess.h> - -#include <net/syncppp.h> - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_CONFIG 0x04 - -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define IFF_POINTTOPOINT 0x10 - -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) -#define MAX_BH_BUFF 10 - -#define CRC_LENGTH 2 -#define PPP_HEADER_LEN 4 - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - void *if_ptr; /* General Pointer used by SPPP */ - wanpipe_common_t common; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -/* variable for tracking how many interfaces to open for WANPIPE on the - two ports */ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if(struct wan_device* wandev, struct net_device* dev); - -/* Network device interface */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_send(struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats* if_stats(struct net_device* dev); - -static void if_tx_timeout(struct net_device *dev); - -/* CHDLC Firmware interface functions */ -static int chdlc_configure (sdla_t* card, void* data); -static int chdlc_comm_enable (sdla_t* card); -static int chdlc_comm_disable (sdla_t* card); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); -static int chdlc_send (sdla_t* card, void* data, unsigned len); -static int chdlc_read_comm_err_stats (sdla_t* card); -static int chdlc_read_op_stats (sdla_t* card); -static int config_chdlc (sdla_t *card); - - -/* Miscellaneous CHDLC Functions */ -static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); -static int process_chdlc_exception(sdla_t *card); -static int process_global_exception(sdla_t *card); -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area); -static void port_set_state (sdla_t *card, int); - -/* Interrupt handlers */ -static void wsppp_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void timer_intr(sdla_t *); - -/* Miscellaneous functions */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card); -static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static unsigned short calc_checksum (char *, int); -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); -static void send_ppp_term_request(struct net_device *dev); - - -static int Intr_test_counter; -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wsppp_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - unsigned long max_permitted_baud = 0; - SHARED_MEMORY_INFO_STRUCT *flags; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_MPPP) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Find out which Port to use */ - if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ - if (card->next){ - - if (conf->comm_port != card->next->u.c.comm_port){ - card->u.c.comm_port = conf->comm_port; - }else{ - printk(KERN_ERR "%s: ERROR - %s port used!\n", - card->wandev.name, PORT(conf->comm_port)); - return -EINVAL; - } - }else{ - card->u.c.comm_port = conf->comm_port; - } - }else{ - printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", - card->wandev.name); - return -EINVAL; - } - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + - SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; - } - }else{ - /* for a S514 adapter, set a pointer to the actual mailbox in the */ - /* allocated virtual memory area */ - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - }else{ - card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; - } - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies + 1 * HZ; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if (time_after(jiffies, timeout)) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" - "%s: for Multi-Port PPP protocol.\n", - card->devname,u.str,card->devname); - - card->isr = &wsppp_isr; - card->poll = NULL; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.udp_port = conf->udp_port; - - card->wandev.new_if_cnt = 0; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = conf->ttl; - card->wandev.interface = conf->interface; - - if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& - card->hw.type != SDLA_S514){ - printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", - card->devname, PORT(card->u.c.comm_port)); - return -EIO; - } - - - card->wandev.clocking = conf->clocking; - - port_num = card->u.c.comm_port; - - /* Setup Port Bps */ - - if(card->wandev.clocking) { - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - /* For Primary Port 0 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - PRI_MAX_BAUD_RATE_S514 : - PRI_MAX_BAUD_RATE_S508; - } - else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - SEC_MAX_BAUD_RATE_S514 : - SEC_MAX_BAUD_RATE_S508; - } - - if(conf->bps > max_permitted_baud) { - conf->bps = max_permitted_baud; - printk(KERN_INFO "%s: Baud too high!\n", - card->wandev.name); - printk(KERN_INFO "%s: Baud rate set to %lu bps\n", - card->wandev.name, max_permitted_baud); - } - - card->wandev.bps = conf->bps; - }else{ - card->wandev.bps = 0; - } - - /* Setup the Port MTU */ - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - - /* For Primary Port 0 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } - - /* Add on a PPP Header */ - card->wandev.mtu += PPP_HEADER_LEN; - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - clear_bit(1, (void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - enable_irq(card->hw.irq); - - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - flags = card->u.c.flags; - - /* This is for the ports link state */ - card->wandev.state = WAN_DUALPORT; - card->u.c.state = WAN_DISCONNECTED; - - - if (!card->wandev.piggyback){ - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "%s: Please choose another interrupt\n", - card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - } - - - if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return -EIO; - } - - /* Mask the Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics - * This procedure is called when updating the PROC file system and returns - * various communications statistics. These statistics are accumulated from 3 - * different locations: - * 1) The 'if_stats' recorded for the device. - * 2) Communication error statistics on the adapter. - * 3) CHDLC operational statistics on the adapter. - * The board level statistics are read during a timer interrupt. Note that we - * read the error and operational statistics during consecitive timer ticks so - * as to minimize the time that we are inside the interrupt handler. - * - */ -static int update(struct wan_device* wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile chdlc_private_area_t* chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags; - unsigned long timeout; - - /* sanity checks */ - if((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if(wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* more sanity checks */ - if(!card->u.c.flags) - return -ENODEV; - - if((dev=card->wandev.dev) == NULL) - return -ENODEV; - - if((chdlc_priv_area=dev->priv) == NULL) - return -ENODEV; - - flags = card->u.c.flags; - - if(chdlc_priv_area->update_comms_stats){ - return -EAGAIN; - } - - /* we will need 2 timer interrupts to complete the */ - /* reading of the statistics */ - chdlc_priv_area->update_comms_stats = 2; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies + 1 * HZ; - for(;;) { - if(chdlc_priv_area->update_comms_stats == 0) - break; - if (time_after(jiffies, timeout)){ - chdlc_priv_area->update_comms_stats = 0; - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* pdev, - wanif_conf_t* conf) -{ - - struct ppp_device *pppdev = (struct ppp_device *)pdev; - struct net_device *dev = NULL; - struct sppp *sp; - sdla_t* card = wandev->private; - chdlc_private_area_t* chdlc_priv_area; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); - - if(chdlc_priv_area == NULL) - return -ENOMEM; - - memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - - chdlc_priv_area->card = card; - - /* initialize data */ - strcpy(card->u.c.if_name, conf->name); - - if(card->wandev.new_if_cnt > 0) { - kfree(chdlc_priv_area); - return -EEXIST; - } - - card->wandev.new_if_cnt++; - - chdlc_priv_area->TracingEnabled = 0; - - //We don't need this any more - chdlc_priv_area->route_status = NO_ROUTE; - chdlc_priv_area->route_removed = 0; - - printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", - wandev->name); - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", - wandev->name); - card->u.c.usedby = WANPIPE; - } else { - printk(KERN_INFO - "%s: API Mode is not supported for SyncPPP!\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - /* Get Multicast Information */ - chdlc_priv_area->mc = conf->mc; - - - chdlc_priv_area->if_ptr = pppdev; - - /* prepare network device data space for registration */ - - strcpy(dev->name,card->u.c.if_name); - - /* Attach PPP protocol layer to pppdev - * The sppp_attach() will initilize the dev structure - * and setup ppp layer protocols. - * All we have to do is to bind in: - * if_open(), if_close(), if_send() and get_stats() functions. - */ - sppp_attach(pppdev); - dev = pppdev->dev; - sp = &pppdev->sppp; - - /* Enable PPP Debugging */ - // FIXME Fix this up somehow - //sp->pp_flags |= PP_DEBUG; - sp->pp_flags &= ~PP_CISCO; - - dev->init = &if_init; - dev->priv = chdlc_priv_area; - - return 0; -} - - - - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - unsigned long smp_lock; - - /* Detach the PPP layer */ - printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", - wandev->name,dev->name); - - lock_adapter_irq(&wandev->lock,&smp_lock); - - sppp_detach(dev); - chdlc_priv_area->if_ptr=NULL; - - chdlc_set_intr_mode(card, 0); - if (card->u.c.comm_enabled) - chdlc_comm_disable(card); - unlock_adapter_irq(&wandev->lock,&smp_lock); - - port_set_state(card, WAN_DISCONNECTED); - - return 0; -} - - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct wan_device* wandev = &card->wandev; - - /* NOTE: Most of the dev initialization was - * done in sppp_attach(), called by new_if() - * function. All we have to do here is - * to link four major routines below. - */ - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - - /* Initialize hardware parameters */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length - * If we over fill this queue the packets will - * be droped by the kernel. - * sppp_attach() sets this to 10, but - * 100 will give us more room at low speeds. - */ - dev->tx_queue_len = 100; - - return 0; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - netif_wake_queue (dev); -} - - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct timeval tv; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - /* Only one open per interface is allowed */ - if (netif_running(dev)) - return -EBUSY; - - /* Start PPP Layer */ - if (sppp_open(dev)){ - return -EIO; - } - - do_gettimeofday(&tv); - chdlc_priv_area->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - wanpipe_open(card); - - chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - return 0; -} - -/*============================================================================ - * Close network interface. - * o if this is the last close, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - - /* Stop the PPP Layer */ - sppp_close(dev); - netif_stop_queue(dev); - - wanpipe_close(card); - - return 0; -} - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - int udp_type = 0; - unsigned long smp_flags; - int err=0; - - netif_stop_queue(dev); - - - if (skb == NULL){ - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", - card->devname, dev->name); - - netif_wake_queue(dev); - return 0; - } - - if (ntohs(skb->protocol) != htons(PVC_PROT)){ - /* check the udp packet type */ - - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_CPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)){ - chdlc_int->interrupt_permission |= - APP_INT_ON_TIMER; - } - netif_start_queue(dev); - return 0; - } - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (card->wandev.state != WAN_CONNECTED){ - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (chdlc_send(card, skb->data, skb->len)){ - netif_stop_queue(dev); - - }else{ - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - netif_start_queue(dev); - } - -if_send_crit_exit: - if (!(err=netif_queue_stopped(dev))){ - dev_kfree_skb_any(skb); - }else{ - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* fill in UDP reply */ - c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - c_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = c_udp_pkt->udp_pkt.udp_src_port; - c_udp_pkt->udp_pkt.udp_src_port = - c_udp_pkt->udp_pkt.udp_dst_port; - c_udp_pkt->udp_pkt.udp_dst_port = temp; - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - - /* calculate UDP checksum */ - c_udp_pkt->udp_pkt.udp_checksum = 0; - c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - c_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = c_udp_pkt->ip_pkt.ip_src_address; - c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; - c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - c_udp_pkt->ip_pkt.hdr_checksum = 0; - c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i <len; i+=2 ) { - memcpy(&temp,&data[i],2); - sum += (unsigned long)temp; - } - - while (sum >> 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats* if_stats(struct net_device* dev) -{ - sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area; - - /* Shutdown bug fix. In del_if() we kill - * dev->priv pointer. This function, gets - * called after del_if(), thus check - * if pointer has been deleted */ - if ((chdlc_priv_area=dev->priv) == NULL) - return NULL; - - my_card = chdlc_priv_area->card; - return &my_card->wandev.stats; -} - - -/****** Cisco HDLC Firmware Interface Functions *******************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*----------------------------------------------------------------------------- - * Configure CHDLC firmware. - */ -static int chdlc_configure (sdla_t* card, void* data) -{ - int err; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); - - mailbox->buffer_length = data_length; - memcpy(mailbox->data, data, data_length); - mailbox->command = SET_CHDLC_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) chdlc_error (card, err, mailbox); - - return err; -} - - -/*============================================================================ - * Set interrupt mode -- HDLC Version. - */ - -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - int_data->CHDLC_interrupt_triggers = mode; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - return err; -} - - -/*============================================================================ - * Enable communications. - */ - -static int chdlc_comm_enable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - else - card->u.c.comm_enabled=1; - - return err; -} - -/*============================================================================ - * Disable communications and Drop the Modem lines (DCD and RTS). - */ -static int chdlc_comm_disable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - - return err; -} - -/*============================================================================ - * Read communication error statistics. - */ -static int chdlc_read_comm_err_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_COMMS_ERROR_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Read CHDLC operational statistics. - */ -static int chdlc_read_op_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_OPERATIONAL_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Update communications error and general packet statistics. - */ -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - COMMS_ERROR_STATS_STRUCT* err_stats; - CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; - - /* on the first timer interrupt, read the comms error statistics */ - if(chdlc_priv_area->update_comms_stats == 2) { - if(chdlc_read_comm_err_stats(card)) - return 1; - err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_over_errors = - err_stats->Rx_overrun_err_count; - card->wandev.stats.rx_crc_errors = - err_stats->CRC_err_count; - card->wandev.stats.rx_frame_errors = - err_stats->Rx_abort_count; - card->wandev.stats.rx_fifo_errors = - err_stats->Rx_dis_pri_bfrs_full_count; - card->wandev.stats.rx_missed_errors = - card->wandev.stats.rx_fifo_errors; - card->wandev.stats.tx_aborted_errors = - err_stats->sec_Tx_abort_count; - } - - /* on the second timer interrupt, read the operational statistics */ - else { - if(chdlc_read_op_stats(card)) - return 1; - op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_length_errors = - (op_stats->Rx_Data_discard_short_count + - op_stats->Rx_Data_discard_long_count); - } - - return 0; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int chdlc_send (sdla_t* card, void* data, unsigned len) -{ - CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; - - if (txbuf->opp_flag) - return 1; - - sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); - - txbuf->frame_length = len; - txbuf->opp_flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.c.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.c.txbuf_last) - card->u.c.txbuf = card->u.c.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * Cisco HDLC interrupt service routine. - */ -STATIC void wsppp_isr (sdla_t* card) -{ - struct net_device* dev; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i; - sdla_t *my_card; - - - /* Check for which port the interrupt has been generated - * Since Secondary Port is piggybacking on the Primary - * the check must be done here. - */ - - flags = card->u.c.flags; - if (!flags->interrupt_info_struct.interrupt_type){ - /* Check for a second port (piggybacking) */ - if((my_card = card->next)){ - flags = my_card->u.c.flags; - if (flags->interrupt_info_struct.interrupt_type){ - card = my_card; - card->isr(card); - return; - } - } - } - - dev = card->wandev.dev; - card->in_isr = 1; - flags = card->u.c.flags; - - /* If we get an interrupt with no network device, stop the interrupts - * and issue an error */ - if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != - COMMAND_COMPLETE_APP_INT_PEND){ - goto isr_done; - } - - - /* if critical due to peripheral operations - * ie. update() or getstats() then reset the interrupt and - * wait for the board to retrigger. - */ - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - flags->interrupt_info_struct. - interrupt_type = 0; - goto isr_done; - } - - - /* On a 508 Card, if critical due to if_send - * Major Error !!! - */ - if(card->hw.type != SDLA_S514) { - if(test_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %lx\n", - card->devname, card->wandev.critical); - goto isr_done; - } - } - - switch(flags->interrupt_info_struct.interrupt_type) { - - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - rx_intr(card); - break; - - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; - - netif_wake_queue(dev); - break; - - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - ++ Intr_test_counter; - break; - - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - process_chdlc_exception(card); - break; - - case GLOBAL_EXCEP_COND_APP_INT_PEND: - process_global_exception(card); - break; - - case TIMER_APP_INT_PEND: - timer_intr(card); - break; - - default: - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, - flags->interrupt_info_struct.interrupt_type); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - break; - } - -isr_done: - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr (sdla_t* card) -{ - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - unsigned addr = rxbuf->ptr_data_bfr; - void *buf; - int i,udp_type; - - if (rxbuf->opp_flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->opp_flag); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it measn that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - chdlc_set_intr_mode(card,0); - return; - } - - dev = card->wandev.dev; - - if (!dev){ - goto rx_exit; - } - - if (!netif_running(dev)){ - goto rx_exit; - } - - chdlc_priv_area = dev->priv; - - if (rxbuf->error_flag){ - goto rx_exit; - } - /* Take off two CRC bytes */ - - if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){ - goto rx_exit; - } - - len = rxbuf->frame_length - CRC_LENGTH; - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb == NULL) { - if (net_ratelimit()){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - ++card->wandev.stats.rx_dropped; - goto rx_exit; - } - - /* Copy data to the socket buffer */ - if((addr + len) > card->u.c.rx_top + 1) { - unsigned tmp = card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - skb->protocol = htons(ETH_P_WAN_PPP); - - card->wandev.stats.rx_packets ++; - card->wandev.stats.rx_bytes += skb->len; - udp_type = udp_pkt_type( skb, card ); - - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. - interrupt_permission |= - APP_INT_ON_TIMER; - } - }else{ - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - dev->last_rx = jiffies; - } - -rx_exit: - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->opp_flag = 0x00; - card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last){ - card->u.c.rxmb = card->u.c.rxbuf_base; - } -} - -/*============================================================================ - * Timer interrupt handler. - * The timer interrupt is used for two purposes: - * 1) Processing udp calls from 'cpipemon'. - * 2) Reading board-level statistics for updating the proc file system. - */ -void timer_intr(sdla_t *card) -{ - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area = NULL; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - - dev = card->wandev.dev; - chdlc_priv_area = dev->priv; - - if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { - if (!config_chdlc(card)){ - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - } - - /* process a udp call if pending */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { - process_udp_mgmt_pkt(card, dev, - chdlc_priv_area); - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - - /* read the communications statistics if required */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - update_comms_stats(card, chdlc_priv_area); - if(!(-- chdlc_priv_area->update_comms_stats)) { - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* only disable the timer interrupt if there are no udp or statistic */ - /* updates pending */ - if(!chdlc_priv_area->timer_int_enabled) { - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } -} - -/*------------------------------------------------------------------------------ - Miscellaneous Functions - - set_chdlc_config() used to set configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_chdlc_config(sdla_t* card) -{ - - CHDLC_CONFIGURATION_STRUCT cfg; - - memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking) - cfg.baud_rate = card->wandev.bps; - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - //API OPTIONS - cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; - cfg.modem_status_timer = 100; - cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; - cfg.percent_data_buffer_for_Tx = 50; - cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - cfg.max_CHDLC_data_field_length = card->wandev.mtu; - - cfg.transmit_keepalive_timer = 0; - cfg.receive_keepalive_timer = 0; - cfg.keepalive_error_tolerance = 0; - cfg.SLARP_request_timer = 0; - - cfg.IP_address = 0; - cfg.IP_netmask = 0; - - return chdlc_configure(card, &cfg); -} - -/*============================================================================ - * Process global exception condition - */ -static int process_global_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int err; - - mbox->buffer_length = 0; - mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; - err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; - - if(err != CMD_TIMEOUT ){ - - switch(mbox->return_code) { - - case EXCEP_MODEM_STATUS_CHANGE: - - printk(KERN_INFO "%s: Modem status change\n", - card->devname); - - switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { - case (DCD_HIGH): - printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); - break; - case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); - break; - case ((DCD_HIGH | CTS_HIGH)): - printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); - break; - default: - printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); - break; - } - - if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){ - //printk(KERN_INFO "Sending TERM Request Manually !\n"); - send_ppp_term_request(card->wandev.dev); - } - break; - - case EXCEP_TRC_DISABLED: - printk(KERN_INFO "%s: Line trace disabled\n", - card->devname); - break; - - case EXCEP_IRQ_TIMEOUT: - printk(KERN_INFO "%s: IRQ timeout occurred\n", - card->devname); - break; - - default: - printk(KERN_INFO "%s: Global exception %x\n", - card->devname, mbox->return_code); - break; - } - } - return 0; -} - - -/*============================================================================ - * Process chdlc exception condition - */ -static int process_chdlc_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_EXCEPTION_CONDITION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if(err != CMD_TIMEOUT) { - - switch (err) { - - case EXCEP_LINK_ACTIVE: - port_set_state(card, WAN_CONNECTED); - break; - - case EXCEP_LINK_INACTIVE_MODEM: - port_set_state(card, WAN_DISCONNECTED); - break; - - case EXCEP_LOOPBACK_CONDITION: - printk(KERN_INFO "%s: Loopback Condition Detected.\n", - card->devname); - break; - - case NO_CHDLC_EXCEP_COND_TO_REPORT: - printk(KERN_INFO "%s: No exceptions reported.\n", - card->devname); - break; - default: - printk(KERN_INFO "%s: Exception Condition %x!\n", - card->devname,err); - break; - } - - } - return 0; -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - int udp_pkt_stored = 0; - - if(!chdlc_priv_area->udp_pkt_lgth && - (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { - chdlc_priv_area->udp_pkt_lgth = skb->len; - chdlc_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK) - dev_kfree_skb_any(skb); - else - dev_kfree_skb_any(skb); - - return(udp_pkt_stored); -} - - -/*============================================================================= - * Process UDP management packet. - */ - -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short buffer_length, real_len; - unsigned long data_ptr; - unsigned data_length; - int udp_mgmt_req_valid = 1; - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - chdlc_udp_pkt_t *chdlc_udp_pkt; - struct timeval tv; - int err; - char ut_char; - - chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(chdlc_udp_pkt->cblock.command) { - case READ_GLOBAL_STATISTICS: - case READ_MODEM_STATUS: - case READ_CHDLC_LINK_STATUS: - case CPIPE_ROUTER_UP_TIME: - case READ_COMMS_ERROR_STATS: - case READ_CHDLC_OPERATIONAL_STATS: - - /* These two commands are executed for - * each request */ - case READ_CHDLC_CONFIGURATION: - case READ_CHDLC_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - chdlc_udp_pkt->cblock.buffer_length = 0; - - /* set return code */ - chdlc_udp_pkt->cblock.return_code = 0xCD; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,chdlc_udp_pkt->cblock.command); - } - - } else { - unsigned long trace_status_cfg_addr = 0; - TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; - TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; - - switch(chdlc_udp_pkt->cblock.command) { - - case CPIPE_ENABLE_TRACING: - if (!chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_ACTIVE; - /* Trace delay mode is not used because it slows - down transfer and results in a standoff situation - when there is a lot of data */ - - /* Configure the Trace based on user inputs */ - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= - chdlc_udp_pkt->data[0]; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_deactivation_timer = 4000; - - - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - card->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - /* Get the base address of the trace element list */ - mb->buffer_length = 0; - mb->command = READ_TRACE_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) - mb->data) -> ptr_trace_stat_el_cfg_struct; - - sdla_peek(&card->hw, trace_status_cfg_addr, - &trace_cfg_struct, sizeof(trace_cfg_struct)); - - chdlc_priv_area->start_trace_addr = trace_cfg_struct. - base_addr_trace_status_elements; - - chdlc_priv_area->number_trace_elements = - trace_cfg_struct.number_trace_status_elements; - - chdlc_priv_area->end_trace_addr = (unsigned long) - ((TRACE_STATUS_ELEMENT_STRUCT *) - chdlc_priv_area->start_trace_addr + - (chdlc_priv_area->number_trace_elements - 1)); - - chdlc_priv_area->base_addr_trace_buffer = - trace_cfg_struct.base_addr_trace_buffer; - - chdlc_priv_area->end_addr_trace_buffer = - trace_cfg_struct.end_addr_trace_buffer; - - chdlc_priv_area->curr_trace_addr = - trace_cfg_struct.next_trace_element_to_use; - - chdlc_priv_area->available_buffer_space = 2000 - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t) - - sizeof(trace_info_t); - } - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - chdlc_priv_area->TracingEnabled = 1; - break; - - - case CPIPE_DISABLE_TRACING: - if (chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_INACTIVE; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - break; - - - case CPIPE_GET_TRACE_INFO: - - if (!chdlc_priv_area->TracingEnabled) { - chdlc_udp_pkt->cblock.return_code = 1; - mb->buffer_length = 0; - break; - } - - chdlc_udp_pkt->trace_info.ismoredata = 0x00; - buffer_length = 0; /* offset of packet already occupied */ - - for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &chdlc_udp_pkt->data[buffer_length]; - - sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, - (unsigned char *)&trace_element_struct, - sizeof(TRACE_STATUS_ELEMENT_STRUCT)); - - if (trace_element_struct.opp_flag == 0x00) { - break; - } - - /* get pointer to real data */ - data_ptr = trace_element_struct.ptr_data_bfr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element_struct.trace_length; - }else{ - data_length = 0; - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - - if( (chdlc_priv_area->available_buffer_space - buffer_length) - < ( sizeof(trace_pkt_t) + data_length) ) { - - /* indicate there are more frames on board & exit */ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - break; - } - - trace_pkt->status = trace_element_struct.trace_type; - - trace_pkt->time_stamp = - trace_element_struct.trace_time_stamp; - - trace_pkt->real_length = - trace_element_struct.trace_length; - - /* see if we can fit the frame into the user buffer */ - real_len = trace_pkt->real_length; - - if (data_ptr == 0) { - trace_pkt->data_avail = 0x00; - } else { - unsigned tmp = 0; - - /* get the data from circular buffer - must check for end of buffer */ - trace_pkt->data_avail = 0x01; - - if ((data_ptr + real_len) > - chdlc_priv_area->end_addr_trace_buffer + 1){ - - tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; - sdla_peek(&card->hw, data_ptr, - trace_pkt->data,tmp); - data_ptr = chdlc_priv_area->base_addr_trace_buffer; - } - - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data[tmp], real_len - tmp); - } - - /* zero the opp flag to show we got the frame */ - ut_char = 0x00; - sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); - - /* now move onto the next frame */ - chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); - - /* check if we went over the last address */ - if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { - chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; - } - - if(trace_pkt->data_avail == 0x01) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += sizeof(trace_pkt_t); - - } /* For Loop */ - - if (frames == chdlc_priv_area->number_trace_elements){ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - chdlc_udp_pkt->trace_info.num_frames = frames; - - mb->buffer_length = buffer_length; - chdlc_udp_pkt->cblock.buffer_length = buffer_length; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - - break; - - - case CPIPE_FT1_READ_STATUS: - ((unsigned char *)chdlc_udp_pkt->data )[0] = - flags->FT1_info_struct.parallel_port_A_input; - - ((unsigned char *)chdlc_udp_pkt->data )[1] = - flags->FT1_info_struct.parallel_port_B_input; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 2; - break; - - case CPIPE_ROUTER_UP_TIME: - do_gettimeofday( &tv ); - chdlc_priv_area->router_up_time = tv.tv_sec - - chdlc_priv_area->router_start_time; - *(unsigned long *)&chdlc_udp_pkt->data = - chdlc_priv_area->router_up_time; - mb->buffer_length = sizeof(unsigned long); - break; - - case FT1_MONITOR_STATUS_CTRL: - /* Enable FT1 MONITOR STATUS */ - if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || - (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { - - if( rCount++ != 0 ) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( chdlc_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - default: - /* it's a board command */ - mb->command = chdlc_udp_pkt->cblock.command; - mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; - if (mb->buffer_length) { - memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> - data, mb->buffer_length); - } - /* run the command on the board */ - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - break; - } - - /* copy the result back to our buffer */ - memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); - - if (mb->buffer_length) { - memcpy(&chdlc_udp_pkt->data, &mb->data, - mb->buffer_length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - - len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - } - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf, chdlc_priv_area->udp_pkt_data, len); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - } - - chdlc_priv_area->udp_pkt_lgth = 0; - - return 0; -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ - -static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; - CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; - char err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - return; - } - - if(card->hw.type == SDLA_S514) { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct)); - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - tx_config->base_addr_Tx_status_elements); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *) - card->u.c.txbuf_base + - (tx_config->number_Tx_status_elements - 1); - - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - rx_config->base_addr_Rx_status_elements); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *) - card->u.c.rxbuf_base + - (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - tx_config->next_Tx_status_element_to_use); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - rx_config->next_Rx_status_element_to_use); - } - else { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base - + (tx_config->number_Tx_status_elements - 1); - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base - + (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); - } - - /* Setup Actual Buffer Start and end addresses */ - card->u.c.rx_base = rx_config->base_addr_Rx_buffer; - card->u.c.rx_top = rx_config->end_addr_Rx_buffer; - -} - -/*============================================================================= - * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err,i; - - Intr_test_counter = 0; - - /* The critical flag is unset because during initialization (if_open) - * we want the interrupts to be enabled so that when the wpc_isr is - * called it does not exit due to critical flag set. - */ - - err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); - - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - } - else { - return err; - } - - err = chdlc_set_intr_mode(card, 0); - - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. CPIPEAB ? - */ -static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) -{ - chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; - - if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && - (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - return UDP_CPIPE_TYPE; - } - else return UDP_INVALID_TYPE; -} - -/*============================================================================ - * Set PORT state. - */ -static void port_set_state (sdla_t *card, int state) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - - if (card->u.c.state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: HDLC link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: HDLC link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: HDLC link disconnected!\n", - card->devname); - break; - } - - card->wandev.state = card->u.c.state = state; - chdlc_priv_area->common.state = state; - } -} - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - if (card->next){ - /* It is ok to use spin_lock here, since we - * already turned off interrupts */ - spin_lock(&card->next->wandev.lock); - } -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - - - -/*=========================================================================== - * config_chdlc - * - * Configure the chdlc protocol and enable communications. - * - * The if_open() function binds this function to the poll routine. - * Therefore, this function will run every time the chdlc interface - * is brought up. We cannot run this function from the if_open - * because if_open does not have access to the remote IP address. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses have changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - * - */ - -static int config_chdlc (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - chdlc_comm_disable(card); - port_set_state(card, WAN_DISCONNECTED); - } - - if (set_chdlc_config(card)) { - printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", - card->devname); - return 0; - } - init_chdlc_tx_rx_buff(card, dev); - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return 0; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - - /* Initialize Rx/Tx buffer control fields */ - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -static void send_ppp_term_request(struct net_device *dev) -{ - struct sk_buff *new_skb; - unsigned char *buf; - - if ((new_skb = dev_alloc_skb(8)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, 8); - sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_WAN_PPP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } -} - - -MODULE_LICENSE("GPL"); - -/****** End ****************************************************************/ |