diff -ur --new-file old/atm/.kernel new/atm/.kernel --- old/atm/.kernel Sun Nov 1 19:39:09 1998 +++ new/atm/.kernel Tue Feb 9 16:36:57 1999 @@ -1,2 +1,2 @@ # this file is used to control automated generation of differences -2.1.126 +2.2.1 diff -ur --new-file old/atm/BUGS new/atm/BUGS --- old/atm/BUGS Sat Dec 5 01:40:57 1998 +++ new/atm/BUGS Tue Feb 9 16:46:46 1999 @@ -1,4 +1,4 @@ -Known bugs and restrictions in version 0.52 +Known bugs and restrictions in version 0.53 =========================================== - ENI driver: closing an AAL0 socket while data is arriving at a high rate diff -ur --new-file old/atm/CHANGES new/atm/CHANGES --- old/atm/CHANGES Sat Dec 5 01:44:40 1998 +++ new/atm/CHANGES Tue Feb 9 18:48:53 1999 @@ -1,3 +1,37 @@ +Version 0.52 to 0.53 (9-FEB-1999) +==================== + +Bug fixes +--------- + + - atmsigd: selecting the UNI version via compile-time options didn't yield + the desired result in some cases (reported by Vinay Kulkarni and others) + - ATM VCCs now use struct sock, as required by protocol-independent layer + starting with recent 2.1 kernels (by Mitchell Blank) + - led fixes: htons/htonl bugs in LANEv2 code, one duplicate close() removed + (by Heikki Vatiainen) + +New features +------------ + + - upgraded to the 2.2.1 kernel (by Mitchell Blank) + - LANE: added bridging support (by Heikki Vatiainen) + - complete rewrite of led (in led.new), which is now leaner and no longer + contains code (c) Digital (by Heikki Vatiainen) + - added macros for local AESA format and group addresses, and support in + atm2text (by Heikki Vatiainen) + +Other changes +------------- + + - ENI: buffer sizes are now limited to MID_MAX_BUF_SIZE even if max_sdu > + MID_MAX_BUF_SIZE/3 (reported by Andrew Lunn) + - plenty of NICStAR changes (Rui Prior and Mitchell Blank) + - LANE interface to upper layer looks more like Ethernet, so adding bridge and + 802.1Q support is easier, and tcpdump does not need any extra patches (by + Heikki Vatiainen) + + Version 0.51 to 0.52 (5-DEC-1998) ==================== diff -ur --new-file old/atm/COPYING new/atm/COPYING --- old/atm/COPYING Tue Aug 18 12:52:07 1998 +++ new/atm/COPYING Tue Feb 9 17:21:30 1999 @@ -1,6 +1,6 @@ Program code, documentation and auxiliary programs, except for the parts listen below, are -Copyright 1995-1998 EPFL-LRC/ICA +Copyright 1995-1999 EPFL-LRC/ICA All rights reserved. This package is free software; you can redistribute it and/or modify @@ -35,12 +35,12 @@ The LAN Emulation code is Copyright by Tampere University of Technology - Telecommunications Laboratory. In addition to that, portions of the -LAN Emulation client code are Copyright (C) 1995 by Digital Equipment -Corporation. -See lane/COPYRIGHT.TUT, led/COPYRIGHT.TUT, and led/COPYRIGHT.DEC for -copying terms. +LAN Emulation client code in led/ are Copyright (C) 1995 by Digital +Equipment Corporation. +See lane/COPYRIGHT.TUT, led.new/COPYRIGHT.TUT, led/COPYRIGHT.TUT, and +led/COPYRIGHT.DEC for copying terms. -The Multi-Protocol Over ATM (MOPA) code was developed at Tampere +The Multi-Protocol Over ATM (MPOA) code was developed at Tampere University of Technology - Telecommunications Laboratory and is Copyright by Heikki Vatiainen and Sampo Saaristo. It is released under the GNU General Public License. See the file COPYING.GPL for details. diff -ur --new-file old/atm/Makefile new/atm/Makefile --- old/atm/Makefile Sun Nov 1 16:04:04 1998 +++ new/atm/Makefile Tue Feb 9 17:19:03 1999 @@ -2,8 +2,8 @@ # "lib" must appear before anything else # "maint" must appear after "qgen" -DIRS=lib test debug qgen saal sigd maint arpd ilmid aqd man led lane mpoad \ - switch sigd.old # extra +DIRS=lib test debug qgen saal sigd maint arpd ilmid aqd man led led.new lane \ + mpoad switch sigd.old # extra all: for n in $(DIRS); do $(MAKE) -C $$n || exit; done diff -ur --new-file old/atm/README new/atm/README --- old/atm/README Sat Dec 5 01:27:05 1998 +++ new/atm/README Tue Feb 9 17:52:25 1999 @@ -1,4 +1,4 @@ -ATM on Linux, release 0.52 (alpha) by Werner Almesberger, EPFL ICA +ATM on Linux, release 0.53 (alpha) by Werner Almesberger, EPFL ICA ============================================== Werner.Almesberger@epfl.ch This is experimental software. There are known major bugs and certainly @@ -9,7 +9,7 @@ device drivers, source for demons, management and test tools, and some documentation. -The kernel patch is relative to the "standard" 2.1.126 kernel. +The kernel patch is relative to the "standard" 2.2.1 kernel. Please see http://lrcwww.epfl.ch/linux-atm/info.html for a list of features supported by ATM on Linux. diff -ur --new-file old/atm/USAGE new/atm/USAGE --- old/atm/USAGE Sat Dec 5 01:58:08 1998 +++ new/atm/USAGE Tue Feb 9 18:22:36 1999 @@ -1,4 +1,4 @@ -Usage instructions - ATM on Linux, release 0.52 +Usage instructions - ATM on Linux, release 0.53 ------------------------------------------------- For updates of ATM on Linux, please check the Web page at @@ -17,9 +17,9 @@ In order to install this package, you need - the package itself - ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.52.tar.gz - - the Linux kernel, version 2.1.126, e.g. from - ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.1.126.tar.gz + ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.53.tar.gz + - the Linux kernel, version 2.2.1, e.g. from + ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.2.1.tar.gz - Perl, version 4 or 5 - if you want memory debugging: MPR version 1.6, e.g. from ftp://sunsite.unc.edu/pub/Linux/devel/lang/c/mpr-1.6.tar.gz @@ -33,11 +33,11 @@ all the files listed above there. Then extract the ATM on Linux distribution: -tar xfz atm-0.52.tar.gz +tar xfz atm-0.53.tar.gz and the kernel source: -tar xfz linux-2.1.126.tar.gz +tar xfz linux-2.2.1.tar.gz Finally, you can extract the ATM-related patches: @@ -49,7 +49,7 @@ atm/ Documentation in ASCII format, kernel patch, top-level Makefile, and distribution scripts atm/sigd/ UNI 3.0, UNI 3.1, and UNI 4.0 signaling demon: atmsigd - atm/sigd.new/ Experimental version: atmsigd.new + atm/sigd.old/ Older version: atmsigd.old atm/saal/ Signaling AAL library (SSCOP, SSCF, and SAAL) atm/qgen/ Q.2931-style message handling atm/ilmid/ ILMI address registration demon: ilmid @@ -59,6 +59,7 @@ ttcp_atm, window atm/arpd/ ATMARP tools and demon: atmarp, atmarpd atm/led/ LAN Emulation demon: zeppelin + atm/led.new/ Experimental version: zeppelin.new atm/lane/ LAN Emulation servers: bus, lecs, les atm/mpoad/ Multi-Protocol Over ATM demon: mpcd atm/aqd/ Arequipa demon: aqpvc, arequipad diff -ur --new-file old/atm/VERSION new/atm/VERSION --- old/atm/VERSION Sat Dec 5 01:27:00 1998 +++ new/atm/VERSION Tue Feb 9 18:22:29 1999 @@ -1 +1 @@ -0.52 +0.53 diff -ur --new-file old/atm/atm.patch new/atm/atm.patch --- old/atm/atm.patch Sat Dec 5 01:58:02 1998 +++ new/atm/atm.patch Tue Feb 9 18:22:15 1999 @@ -1,6 +1,6 @@ ---- ref/Makefile Sat Oct 17 05:33:22 1998 -+++ work/Makefile Sun Nov 1 15:31:52 1998 -@@ -128,6 +128,10 @@ +--- ref/Makefile Tue Jan 26 02:46:35 1999 ++++ work/Makefile Tue Feb 9 15:49:57 1999 +@@ -122,6 +122,10 @@ DRIVERS := $(DRIVERS) drivers/net/net.a @@ -11,7 +11,7 @@ ifeq ($(CONFIG_SCSI),y) DRIVERS := $(DRIVERS) drivers/scsi/scsi.a endif -@@ -312,6 +316,7 @@ +@@ -321,6 +325,7 @@ if [ -f NET_MODULES ]; then inst_mod NET_MODULES net; fi; \ if [ -f IPV4_MODULES ]; then inst_mod IPV4_MODULES ipv4; fi; \ if [ -f IPV6_MODULES ]; then inst_mod IPV6_MODULES ipv6; fi; \ @@ -19,11 +19,11 @@ if [ -f SCSI_MODULES ]; then inst_mod SCSI_MODULES scsi; fi; \ if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \ if [ -f NLS_MODULES ]; then inst_mod NLS_MODULES fs; fi; \ ---- ref/Documentation/Configure.help Thu Oct 22 00:31:04 1998 -+++ work/Documentation/Configure.help Sun Nov 1 15:31:52 1998 -@@ -3235,6 +3235,164 @@ - remember to enable the driver for your HIPPI card below). Most - people will say N here. +--- ref/Documentation/Configure.help Wed Jan 20 20:05:32 1999 ++++ work/Documentation/Configure.help Tue Feb 9 15:49:57 1999 +@@ -3460,6 +3460,164 @@ + This is a backward compatibility option, choose Y for now. + This option will be removed soon. +Asynchronous Transfer Mode (ATM) +CONFIG_ATM @@ -187,15 +187,15 @@ CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/Documentation/atm.txt Sun Nov 1 15:31:52 1998 ++++ work/Documentation/atm.txt Tue Feb 9 15:49:57 1999 @@ -0,0 +1,4 @@ +In order to use anything but the most primitive functions of ATM, +several user-mode programs are required to assist the kernel. These +programs and related material can be found via the ATM on Linux Web +page at http://lrcwww.epfl.ch/linux-atm/ ---- ref/arch/i386/config.in Thu Oct 1 19:02:21 1998 -+++ work/arch/i386/config.in Sun Nov 1 15:31:52 1998 -@@ -101,6 +101,9 @@ +--- ref/arch/i386/config.in Wed Jan 20 19:18:53 1999 ++++ work/arch/i386/config.in Tue Feb 9 15:49:57 1999 +@@ -139,6 +139,9 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in @@ -205,8 +205,8 @@ fi endmenu fi ---- ref/arch/alpha/config.in Mon Oct 12 20:40:12 1998 -+++ work/arch/alpha/config.in Sun Nov 1 15:31:52 1998 +--- ref/arch/alpha/config.in Thu Jan 14 19:29:28 1999 ++++ work/arch/alpha/config.in Tue Feb 9 15:49:57 1999 @@ -227,6 +227,9 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then @@ -217,18 +217,18 @@ fi endmenu fi ---- ref/drivers/Makefile Sat Oct 3 03:12:55 1998 -+++ work/drivers/Makefile Sun Nov 1 15:31:52 1998 +--- ref/drivers/Makefile Fri Nov 20 17:59:01 1998 ++++ work/drivers/Makefile Tue Feb 9 15:49:57 1999 @@ -10,7 +10,7 @@ SUB_DIRS := block char net misc sound - MOD_SUB_DIRS := $(SUB_DIRS) sbus + MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \ - macintosh video dio zorro fc4 + macintosh video dio zorro fc4 atm ifdef CONFIG_DIO SUB_DIRS += dio -@@ -75,6 +75,11 @@ +@@ -76,6 +76,11 @@ ifeq ($(CONFIG_ISDN),m) MOD_SUB_DIRS += isdn endif @@ -241,7 +241,7 @@ ifeq ($(CONFIG_AP1000),y) --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/Config.in Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/Config.in Tue Feb 9 15:49:57 1999 @@ -0,0 +1,34 @@ +# +# ATM device configuration @@ -278,7 +278,7 @@ + tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR y +fi --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/Makefile Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/Makefile Tue Feb 9 15:49:57 1999 @@ -0,0 +1,57 @@ +# File: drivers/atm/Makefile +# @@ -338,7 +338,7 @@ + +include $(TOPDIR)/Rules.make --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/atmdev_init.c Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/atmdev_init.c Tue Feb 9 15:49:57 1999 @@ -0,0 +1,48 @@ +/* drivers/atm/atmdev_init.c - ATM device driver initialization */ + @@ -389,7 +389,7 @@ + return devs; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/atmtcp.c Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/atmtcp.c Tue Feb 9 15:49:57 1999 @@ -0,0 +1,339 @@ +/* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ + @@ -731,11 +731,11 @@ +#endif + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/eni.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,2250 @@ ++++ work/drivers/atm/eni.c Tue Feb 9 16:53:05 1999 +@@ -0,0 +1,2258 @@ +/* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ + -+/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ ++/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ + + +#include <linux/module.h> @@ -1289,11 +1289,11 @@ + else { + static unsigned long silence = 0; + -+ if (jiffies > silence) { ++ if (time_after(jiffies, silence) || silence == 0) { + printk(KERN_WARNING DEV_LABEL "(itf %d): " + "discarding PDU(s) with CRC error\n", + vcc->dev->number); -+ silence = jiffies+2*HZ; ++ silence = (jiffies+2*HZ)|1; + } + size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); + EVENT("CRC error (descr=0x%lx,size=%ld)\n",descr, @@ -1512,6 +1512,9 @@ + eni_vcc->rx = NULL; + if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; + size = vcc->qos.rxtp.max_sdu*3; /* @@@ improve this */ ++ if (size > MID_MAX_BUF_SIZE && vcc->qos.rxtp.max_sdu <= ++ MID_MAX_BUF_SIZE) ++ size = MID_MAX_BUF_SIZE; + eni_vcc->recv = (u32 *) eni_alloc_mem(eni_dev,&size); + DPRINTK("rx at 0x%p\n",eni_vcc->recv); + eni_vcc->words = size >> 2; @@ -1991,7 +1994,12 @@ + ubr = txtp->traffic_class == ATM_UBR; + unlimited = ubr && (!rate || rate <= -ATM_OC3_PCR || + rate >= ATM_OC3_PCR); -+ if (!unlimited) size = txtp->max_sdu*3; /* @@@ improve */ ++ if (!unlimited) { ++ size = txtp->max_sdu*3; /* @@@ improve */ ++ if (size > MID_MAX_BUF_SIZE && txtp->max_sdu <= ++ MID_MAX_BUF_SIZE) ++ size = MID_MAX_BUF_SIZE; ++ } + else { + if (eni_dev->ubr) { + eni_vcc->tx = eni_dev->ubr; @@ -2984,7 +2992,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/eni.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/eni.h Tue Feb 9 18:04:33 1999 @@ -0,0 +1,115 @@ +/* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ + @@ -3102,7 +3110,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/midway.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/midway.h Tue Feb 9 15:49:57 1999 @@ -0,0 +1,265 @@ +/* drivers/atm/midway.h - Efficient Networks Midway (SAR) description */ + @@ -3370,8 +3378,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/nicstar.h Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,753 @@ ++++ work/drivers/atm/nicstar.h Tue Feb 9 15:49:57 1999 +@@ -0,0 +1,746 @@ +/****************************************************************************** + * + * nicstar.h @@ -3401,9 +3409,9 @@ + +/* Options ********************************************************************/ + -+#define ESI_FROM_EPROM 1 /* Undef to use hardcoded ESI */ +#define NS_MAX_CARDS 1 /* Maximum number of NICStAR based cards -+ controlled by the device driver*/ ++ controlled by the device driver. Must ++ be <= 5 */ + +#undef RCQ_SUPPORT /* Do not define this for now */ + @@ -3466,13 +3474,6 @@ + +/* ESI stuff ******************************************************************/ + -+#define NS_ESI0 0x00 /* Hardcoded ESI, in case your card doesn't have */ -+#define NS_ESI1 0x00 /* it on the EPROM */ -+#define NS_ESI2 0x00 -+#define NS_ESI3 0x00 -+#define NS_ESI4 0x00 -+#define NS_ESI5 0x00 -+ +#define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C + + @@ -4126,13 +4127,13 @@ + +#endif /* _LINUX_NICSTAR_H_ */ --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/nicstar.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,2884 @@ ++++ work/drivers/atm/nicstar.c Tue Feb 9 15:49:57 1999 +@@ -0,0 +1,2945 @@ +/****************************************************************************** + * + * nicstar.c + * -+ * Device driver supporting CBR for NICStAR based cards. ++ * Device driver supporting CBR for IDT 77211 "NICStAR" based cards. + * + * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. + * It was taken from the frle-0.22 device driver. @@ -4143,6 +4144,13 @@ + * + * Author: Rui Prior + * ++ * URLs: ++ * NICStAR driver homepage ++ * http://jaguar.inescn.pt/~rprior/nicstar/nicstar.html ++ * ++ * IDT 77211 documentation ++ * http://www.idt.com/product_files/77211.html ++ * + * (C) INESC 1998 + * + ******************************************************************************/ @@ -4227,6 +4235,10 @@ + +#undef CEIL(d) + ++#ifndef ATM_SKB ++#define ATM_SKB(s) (&(s)->atm) ++#endif ++ + +/* Version definition *********************************************************/ +/* @@ -4269,6 +4281,8 @@ +static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); +static void which_list(ns_dev *card, struct sk_buff *skb); +static void ns_poll(unsigned long arg); ++static int ns_parse_mac(char *mac, unsigned char *esi); ++static short ns_h2i(char c); + + +/* Global variables ***********************************************************/ @@ -4294,6 +4308,24 @@ + ns_proc_read /* proc_read */ +}; +static struct timer_list ns_timer; ++static char *mac[NS_MAX_CARDS] = { NULL ++#if NS_MAX_CARDS > 1 ++ , NULL ++#endif /* NS_MAX_CARDS > 1 */ ++#if NS_MAX_CARDS > 2 ++ , NULL ++#endif /* NS_MAX_CARDS > 2 */ ++#if NS_MAX_CARDS > 3 ++ , NULL ++#endif /* NS_MAX_CARDS > 3 */ ++#if NS_MAX_CARDS > 4 ++ , NULL ++#endif /* NS_MAX_CARDS > 4 */ ++ }; ++ ++#ifdef MODULE ++MODULE_PARM(mac, "1-" __MODULE_STRING(NS_MAX_CARDS) "s"); ++#endif /* MODULE */ + + +/* Functions*******************************************************************/ @@ -4326,7 +4358,7 @@ + + error = ns_init_card(i, pcidev); + if (error) -+ i--; /* Try to find another card but don't increment index */ ++ cards[i--] = NULL; /* Try to find another card but don't increment index */ + } + + if (i == 0) @@ -4464,7 +4496,7 @@ + + error = ns_init_card(i, pcidev); + if (error) -+ i--; /* Try to find another card but don't increment index */ ++ cards[i--] = NULL; /* Try to find another card but don't increment index */ + } + + if (i == 0 && error) @@ -4591,7 +4623,7 @@ + if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0); + break; + } -+ if (j == 10) ++ if (j == 4) + { + printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY); + error = 7; @@ -4624,38 +4656,36 @@ + writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); + while (CMD_BUSY(card)); + data = readl(card->membase + DR0); -+ if (data == 0x00000009) -+ { -+ printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); -+ card->max_pcr = IDT_25_PCR; -+ while(CMD_BUSY(card)); -+ writel(0x00000008, card->membase + DR0); -+ writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); -+ /* Clear an eventual pending interrupt */ -+ writel(NS_STAT_SFBQF, card->membase + STAT); ++ switch(data) { ++ case 0x00000009: ++ printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); ++ card->max_pcr = IDT_25_PCR; ++ while(CMD_BUSY(card)); ++ writel(0x00000008, card->membase + DR0); ++ writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); ++ /* Clear an eventual pending interrupt */ ++ writel(NS_STAT_SFBQF, card->membase + STAT); +#ifdef PHY_LOOPBACK -+ while(CMD_BUSY(card)); -+ writel(0x00000022, card->membase + DR0); -+ writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); ++ while(CMD_BUSY(card)); ++ writel(0x00000022, card->membase + DR0); ++ writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); +#endif /* PHY_LOOPBACK */ -+ } -+ else if (data == 0x00000030) -+ { -+ printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); -+ card->max_pcr = ATM_OC3_PCR; ++ break; ++ case 0x00000030: ++ case 0x00000031: ++ printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); ++ card->max_pcr = ATM_OC3_PCR; +#ifdef PHY_LOOPBACK -+ while(CMD_BUSY(card)); -+ writel(0x00000002, card->membase + DR0); -+ writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); ++ while(CMD_BUSY(card)); ++ writel(0x00000002, card->membase + DR0); ++ writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); +#endif /* PHY_LOOPBACK */ -+ } -+ else -+ { -+ printk("nicstar%d: can't determine PHY type.\n", i); -+ error = 8; -+ ns_init_card_error(card, error); -+ return error; -+ } ++ break; ++ default: ++ printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data); ++ error = 8; ++ ns_init_card_error(card, error); ++ return error; } + writel(0x00000000, card->membase + GP); + + /* Determine SRAM size */ @@ -4691,10 +4721,9 @@ + else /* card->rct_size == 16384 */ + card->vcibits = 14 - NS_VPIBITS; + -+#ifdef ESI_FROM_EPROM + /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ -+ nicstar_init_eprom(card->membase); -+#endif /* ESI_FROM_EPROM */ ++ if (mac[i] == NULL) ++ nicstar_init_eprom(card->membase); + + if (request_irq(pcidev->irq, &ns_irq_handler, SA_INTERRUPT, "nicstar", card) != 0) + { @@ -4820,35 +4849,25 @@ + + card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ + -+ /* Allocate small buffers */ -+ skb_queue_head_init(&card->sbpool.queue); -+ card->sbpool.count = 0; /* Not used */ -+ for (j = 0; j < NUM_SB; j++) ++ /* Pre-allocate some huge buffers */ ++ skb_queue_head_init(&card->hbpool.queue); ++ card->hbpool.count = 0; ++ for (j = 0; j < NUM_HB; j++) + { -+ struct sk_buff *sb; -+ sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); -+ if (sb == NULL) ++ struct sk_buff *hb; ++ hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); ++ if (hb == NULL) + { -+ printk("nicstar%d: can't allocate %dth of %d small buffers.\n", -+ i, j, NUM_SB); ++ printk("nicstar%d: can't allocate %dth of %d huge buffers.\n", ++ i, j, NUM_HB); + error = 13; + ns_init_card_error(card, error); + return error; + } -+ skb_queue_tail(&card->sbpool.queue, sb); -+ skb_reserve(sb, NS_AAL0_HEADER); -+ push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); -+ } -+ /* Test for strange behaviour which leads to crashes */ -+ if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) -+ { -+ printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", -+ i, j, bcount); -+ error = 13; -+ ns_init_card_error(card, error); -+ return error; ++ skb_queue_tail(&card->hbpool.queue, hb); ++ card->hbpool.count++; + } -+ ++ + + /* Allocate large buffers */ + skb_queue_head_init(&card->lbpool.queue); @@ -4886,6 +4905,36 @@ + } + + ++ /* Allocate small buffers */ ++ skb_queue_head_init(&card->sbpool.queue); ++ card->sbpool.count = 0; /* Not used */ ++ for (j = 0; j < NUM_SB; j++) ++ { ++ struct sk_buff *sb; ++ sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); ++ if (sb == NULL) ++ { ++ printk("nicstar%d: can't allocate %dth of %d small buffers.\n", ++ i, j, NUM_SB); ++ error = 15; ++ ns_init_card_error(card, error); ++ return error; ++ } ++ skb_queue_tail(&card->sbpool.queue, sb); ++ skb_reserve(sb, NS_AAL0_HEADER); ++ push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); ++ } ++ /* Test for strange behaviour which leads to crashes */ ++ if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) ++ { ++ printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", ++ i, j, bcount); ++ error = 15; ++ ns_init_card_error(card, error); ++ return error; ++ } ++ ++ + /* Allocate iovec buffers */ + skb_queue_head_init(&card->iovpool.queue); + card->iovpool.count = 0; @@ -4897,7 +4946,7 @@ + { + printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n", + i, j, NUM_IOVB); -+ error = 15; ++ error = 16; + ns_init_card_error(card, error); + return error; + } @@ -4906,25 +4955,6 @@ + } + + -+ /* Pre-allocate some huge buffers */ -+ skb_queue_head_init(&card->hbpool.queue); -+ card->hbpool.count = 0; -+ for (j = 0; j < NUM_HB; j++) -+ { -+ struct sk_buff *hb; -+ hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); -+ if (hb == NULL) -+ { -+ printk("nicstar%d: can't allocate %dth of %d huge buffers.\n", -+ i, j, NUM_HB); -+ error = 16; -+ ns_init_card_error(card, error); -+ return error; -+ } -+ skb_queue_tail(&card->hbpool.queue, hb); -+ card->hbpool.count++; -+ } -+ + card->in_handler = 0; + card->in_poll = 0; + card->intcnt = 0; @@ -4961,20 +4991,13 @@ + return error; + } + -+#ifdef ESI_FROM_EPROM -+ nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, -+ card->atmdev->esi, 6); ++ if (ns_parse_mac(mac[i], card->atmdev->esi)) ++ nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, ++ card->atmdev->esi, 6); ++ + printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, + card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], + card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]); -+#else -+ card->atmdev->esi[0] = NS_ESI0; -+ card->atmdev->esi[1] = NS_ESI1; -+ card->atmdev->esi[2] = NS_ESI2; -+ card->atmdev->esi[3] = NS_ESI3; -+ card->atmdev->esi[4] = NS_ESI4; -+ card->atmdev->esi[5] = NS_ESI5; -+#endif /* ESI_FROM_EPROM */ + + card->atmdev->dev_data = card; + card->atmdev->ci_range.vpi_bits = card->vpibits; @@ -4995,16 +5018,17 @@ + } + if (error >= 16) + { -+ struct sk_buff *hb; -+ while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) -+ kfree_skb(hb); -+ } -+ if (error >= 15) -+ { + struct sk_buff *iovb; + while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) + kfree_skb(iovb); + } ++ if (error >= 15) ++ { ++ struct sk_buff *sb; ++ while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) ++ kfree_skb(sb); ++ free_scq(card->scq0, NULL); ++ } + if (error >= 14) + { + struct sk_buff *lb; @@ -5013,10 +5037,9 @@ + } + if (error >= 13) + { -+ struct sk_buff *sb; -+ while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) -+ kfree_skb(sb); -+ free_scq(card->scq0, NULL); ++ struct sk_buff *hb; ++ while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) ++ kfree_skb(hb); + } + if (error >= 12) + { @@ -5943,8 +5966,7 @@ + { + save_flags(flags); cli(); + scq->full = 1; -+ current->timeout = jiffies + SCQFULL_TIMEOUT; -+ interruptible_sleep_on(&scq->scqfull_waitq); ++ interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); + restore_flags(flags); + + if (scq->full) @@ -5978,8 +6000,7 @@ + { + save_flags(flags); cli(); + scq->full = 1; -+ current->timeout = jiffies + SCQFULL_TIMEOUT; -+ interruptible_sleep_on(&scq->scqfull_waitq); ++ interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); + restore_flags(flags); + } + @@ -6984,6 +7005,7 @@ + if (card->in_poll) + { + printk("nicstar: Re-entering ns_poll()???\n"); ++ restore_flags(flags); + continue; + } + card->in_poll = 1; @@ -6992,6 +7014,7 @@ + card->in_poll = 0; + printk("nicstar%d: ns_poll called while in interrupt handler!?\n", + card->index); ++ restore_flags(flags); + continue; + } + @@ -7012,8 +7035,47 @@ + mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); + PRINTK("nicstar: Leaving ns_poll().\n"); +} ++ ++ ++ ++static int ns_parse_mac(char *mac, unsigned char *esi) ++{ ++ int i, j; ++ short byte1, byte0; ++ ++ if (mac == NULL || esi == NULL) ++ return -1; ++ j = 0; ++ for (i = 0; i < 6; i++) ++ { ++ if ((byte1 = ns_h2i(mac[j++])) < 0) ++ return -1; ++ if ((byte0 = ns_h2i(mac[j++])) < 0) ++ return -1; ++ esi[i] = (unsigned char) (byte1 * 16 + byte0); ++ if (i < 5) ++ { ++ if (mac[j++] != ':') ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++ ++ ++static short ns_h2i(char c) ++{ ++ if (c >= '0' && c <= '9') ++ return (short) (c - '0'); ++ if (c >= 'A' && c <= 'A') ++ return (short) (c - 'A' + 10); ++ if (c >= 'a' && c <= 'f') ++ return (short) (c - 'a' + 10); ++ return -1; ++} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/nicstar.c.old_skb Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/nicstar.c.old_skb Tue Feb 9 15:49:57 1999 @@ -0,0 +1,2883 @@ +/****************************************************************************** + * @@ -9899,7 +9961,7 @@ + PRINTK("nicstar: Leaving ns_poll().\n"); +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/nicstarmac.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/nicstarmac.h Tue Feb 9 15:49:57 1999 @@ -0,0 +1,14 @@ +/****************************************************************************** + * @@ -9916,7 +9978,7 @@ +void nicstar_init_eprom( virt_addr_t base ); +void nicstar_read_eprom( virt_addr_t, u_int8_t, u_int8_t *, u_int32_t); --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/nicstarmac.c Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/nicstarmac.c Tue Feb 9 15:49:57 1999 @@ -0,0 +1,269 @@ +/* + * this file included by nicstar.c @@ -10188,7 +10250,7 @@ +*/ + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/nicstarmac.copyright Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/nicstarmac.copyright Tue Feb 9 15:49:57 1999 @@ -0,0 +1,61 @@ +/* nicstar.c v0.22 Jawaid Bazyar (bazyar@hypermall.com) + * nicstar.c, M. Welsh (matt.welsh@cl.cam.ac.uk) @@ -10252,7 +10314,7 @@ + * + */ --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/suni.c Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/suni.c Tue Feb 9 15:49:57 1999 @@ -0,0 +1,303 @@ +/* drivers/atm/suni.c - PMC SUNI (PHY) driver */ + @@ -10558,7 +10620,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/suni.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/suni.h Tue Feb 9 18:04:31 1999 @@ -0,0 +1,210 @@ +/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */ + @@ -10771,7 +10833,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/tonga.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/tonga.h Tue Feb 9 15:49:57 1999 @@ -0,0 +1,20 @@ +/* drivers/atm/tonga.h - Efficient Networks Tonga (PCI bridge) declarations */ + @@ -10794,7 +10856,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/uPD98401.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/uPD98401.h Tue Feb 9 15:49:57 1999 @@ -0,0 +1,292 @@ +/* drivers/atm/uPD98401.h - NEC uPD98401 (SAR) declarations */ + @@ -11089,8 +11151,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/uPD98402.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,224 @@ ++++ work/drivers/atm/uPD98402.c Tue Feb 9 15:49:57 1999 +@@ -0,0 +1,225 @@ +/* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -11254,10 +11316,11 @@ + (void) GET(PCOCR); /* clear interrupt cause */ + PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT); + } -+ if ((reason & uPD98402_INT_RFO) && jiffies > silence) { ++ if ((reason & uPD98402_INT_RFO) && ++ (time_after(jiffies, silence) || silence == 0)) { + printk(KERN_WARNING "%s(itf %d): uPD98402 receive " + "FIFO overflow\n",dev->type,dev->number); -+ silence = jiffies+HZ/2; ++ silence = (jiffies+HZ/2)|1; + } + } +} @@ -11316,7 +11379,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/uPD98402.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/uPD98402.h Tue Feb 9 15:49:57 1999 @@ -0,0 +1,106 @@ +/* drivers/atm/uPD98402.h - NEC uPD98402 (PHY) declarations */ + @@ -11425,8 +11488,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/zatm.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,1875 @@ ++++ work/drivers/atm/zatm.c Tue Feb 9 15:49:57 1999 +@@ -0,0 +1,1876 @@ +/* drivers/atm/zatm.c - ZeitNet ZN122x device driver */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -12041,12 +12104,13 @@ + static unsigned long silence = 0; + static int last_error = 0; + -+ if (error != last_error || jiffies > silence) { ++ if (error != last_error || ++ time_after(jiffies, silence) || silence == 0){ + printk(KERN_WARNING DEV_LABEL "(itf %d): " + "chan %d error %s\n",dev->number,chan, + err_txt[error]); + last_error = error; -+ silence = jiffies+2*HZ; ++ silence = (jiffies+2*HZ)|1; + } + size = 0; + } @@ -13303,7 +13367,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/zatm.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/zatm.h Tue Feb 9 18:04:37 1999 @@ -0,0 +1,137 @@ +/* drivers/atm/zatm.h - ZeitNet ZN122x device driver declarations */ + @@ -13443,7 +13507,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/drivers/atm/zeprom.h Sun Nov 1 15:31:53 1998 ++++ work/drivers/atm/zeprom.h Tue Feb 9 15:49:57 1999 @@ -0,0 +1,34 @@ +/* drivers/atm/zeprom.h - ZeitNet ZN122x EEPROM (NM93C46) declarations */ + @@ -13479,17 +13543,17 @@ +/* No other commands are needed. */ + +#endif ---- ref/drivers/block/genhd.c Tue Oct 20 22:52:01 1998 -+++ work/drivers/block/genhd.c Sun Nov 1 15:31:53 1998 +--- ref/drivers/block/genhd.c Sat Jan 9 07:54:17 1999 ++++ work/drivers/block/genhd.c Tue Feb 9 15:49:57 1999 @@ -60,6 +60,7 @@ extern int blk_dev_init(void); extern int scsi_dev_init(void); extern int net_dev_init(void); +extern int atmdev_init(void); - /* - * disk_name() is used by genhd.c and md.c. -@@ -1207,6 +1208,9 @@ + #ifdef CONFIG_PPC + extern void note_bootable_part(kdev_t dev, int part); +@@ -1310,6 +1311,9 @@ #endif #ifdef CONFIG_INET net_dev_init(); @@ -13500,7 +13564,7 @@ #ifdef CONFIG_VT console_map_init(); --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/arequipa.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/arequipa.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,63 @@ +/* arequipa.h - Arequipa interface definitions */ + @@ -13566,8 +13630,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm.h Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,239 @@ ++++ work/include/linux/atm.h Tue Feb 9 17:40:13 1999 +@@ -0,0 +1,245 @@ +/* atm.h - general ATM declarations */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -13750,6 +13814,12 @@ +#define ATM_AFI_DCC 0x39 /* DCC ATM Format */ +#define ATM_AFI_ICD 0x47 /* ICD ATM Format */ +#define ATM_AFI_E164 0x45 /* E.164 ATM Format */ ++#define ATM_AFI_LOCAL 0x49 /* Local ATM Format */ ++ ++#define ATM_AFI_DCC_GROUP 0xBD /* DCC ATM Group Format */ ++#define ATM_AFI_ICD_GROUP 0xC5 /* ICD ATM Group Format */ ++#define ATM_AFI_E164_GROUP 0xC3 /* E.164 ATM Group Format */ ++#define ATM_AFI_LOCAL_GROUP 0xC7 /* Local ATM Group Format */ + +#define ATM_LIJ_NONE 0 /* no leaf-initiated join */ +#define ATM_LIJ 1 /* request joining */ @@ -13808,7 +13878,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm_eni.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atm_eni.h Tue Feb 9 18:04:33 1999 @@ -0,0 +1,15 @@ +/* atm_eni.h - Driver-specific declarations of the ENI driver (for use by + driver-specific utilities) */ @@ -13826,7 +13896,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm_nicstar.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atm_nicstar.h Tue Feb 9 15:49:57 1999 @@ -0,0 +1,52 @@ +/****************************************************************************** + * @@ -13881,7 +13951,7 @@ + +#endif /* LINUX_ATM_NICSTAR_H */ --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm_suni.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atm_suni.h Tue Feb 9 18:04:31 1999 @@ -0,0 +1,19 @@ +/* atm_suni.h - Driver-specific declarations of the SUNI driver (for use by + driver-specific utilities) */ @@ -13903,7 +13973,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm_tcp.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atm_tcp.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,46 @@ +/* atm_tcp.h - Driver-specific declarations of the ATMTCP driver (for use by + driver-specific utilities) */ @@ -13952,7 +14022,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atm_zatm.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atm_zatm.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,54 @@ +/* atm_zatm.h - Driver-specific declarations of the ZATM driver (for use by + driver-specific utilities) */ @@ -14009,7 +14079,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmarp.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atmarp.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,42 @@ +/* atmarp.h - ATM ARP protocol and kernel-demon interface definitions */ + @@ -14054,7 +14124,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmclip.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atmclip.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,25 @@ +/* atmclip.h - Classical IP over ATM */ + @@ -14082,7 +14152,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmdev.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atmdev.h Tue Feb 9 18:04:31 1999 @@ -0,0 +1,324 @@ +/* atmdev.h - ATM device driver declarations */ + @@ -14105,7 +14175,7 @@ + bits per cell: /8/53 + max cell rate: 353207.547 cells/sec */ + -+#define ATM_SD(s) ((struct atm_vcc *) ((s)->sk)) ++#define ATM_SD(s) ((s)->sk->protinfo.af_atm) + + +struct atm_aal_stats { @@ -14409,7 +14479,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmioc.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atmioc.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,39 @@ +/* atmioc.h - ranges for ATM-related ioctl numbers */ + @@ -14451,8 +14521,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmlec.h Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,70 @@ ++++ work/include/linux/atmlec.h Tue Feb 9 18:09:24 1999 +@@ -0,0 +1,78 @@ +/* + * + * ATM Lan Emulation Daemon vs. driver interface @@ -14473,7 +14543,7 @@ +#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2) + +/* Maximum number of LEC interfaces (tweakable) */ -+#define MAX_LEC_ITF 4 ++#define MAX_LEC_ITF 16 + +typedef enum { + l_set_mac_addr, l_del_mac_addr, @@ -14483,10 +14553,11 @@ + l_narp_req, /* LANE2 mandates the use of this */ + l_config, l_flush_tran_id, + l_set_lecid, l_arp_xmt, -+ l_associate_req ++ l_associate_req, ++ l_should_bridge /* should we bridge this MAC? */ +} atmlec_msg_type; + -+#define ATMLEC_MSG_TYPE_MAX l_associate_req ++#define ATMLEC_MSG_TYPE_MAX l_should_bridge + +struct atmlec_config_msg { + unsigned int maximum_unknown_frame_count; @@ -14498,6 +14569,7 @@ + unsigned long flush_timeout; + unsigned long path_switching_delay; + unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */ ++ int is_proxy; /* bridging support */ +}; + +struct atmlec_msg { @@ -14514,7 +14586,13 @@ + unsigned int no_source_le_narp; /* LANE2 */ + } normal; + struct atmlec_config_msg config; -+ } content; ++ struct { ++ uint16_t lec_id; /* requestor lec_id */ ++ uint32_t tran_id; /* transaction id */ ++ unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */ ++ unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */ ++ } proxy; /* For mapping LE_ARP requests to responses. Filled by */ ++ } content; /* zeppelin, returned by kernel. Used only when proxying */ +}; + +struct atmlec_ioc { @@ -14524,7 +14602,7 @@ +}; +#endif /* _ATMLEC_H_ */ --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmmpc.h Sat Dec 5 01:45:34 1998 ++++ work/include/linux/atmmpc.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,124 @@ +#ifndef _ATMMPC_H_ +#define _ATMMPC_H_ @@ -14651,7 +14729,7 @@ +#endif /* _ATMMPC_H_ */ + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmsap.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atmsap.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,161 @@ +/* atmsap.h - ATM Service Access Point addressing definitions */ + @@ -14815,7 +14893,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/atmsvc.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/atmsvc.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,52 @@ +/* atmsvc.h - ATM signaling kernel-demon interface definitions */ + @@ -14869,8 +14947,8 @@ + (tp).max_pcr : (tp).min_pcr ? (tp).min_pcr : ATM_MAX_PCR) + +#endif ---- ref/include/linux/capability.h Fri Oct 23 19:14:47 1998 -+++ work/include/linux/capability.h Sun Nov 1 15:34:05 1998 +--- ref/include/linux/capability.h Thu Jan 28 21:43:10 1999 ++++ work/include/linux/capability.h Tue Feb 9 18:02:00 1999 @@ -131,6 +131,7 @@ #define CAP_LINUX_IMMUTABLE 9 @@ -14887,8 +14965,8 @@ #define CAP_NET_ADMIN 12 ---- ref/include/linux/if_arp.h Fri Oct 23 19:16:30 1998 -+++ work/include/linux/if_arp.h Sun Nov 1 15:31:53 1998 +--- ref/include/linux/if_arp.h Thu Jan 28 21:43:16 1999 ++++ work/include/linux/if_arp.h Tue Feb 9 18:03:14 1999 @@ -35,6 +35,7 @@ #define ARPHRD_ARCNET 7 /* ARCnet */ #define ARPHRD_APPLETLK 8 /* APPLEtalk */ @@ -14897,7 +14975,7 @@ #define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ /* Dummy types for non ARP hardware */ -@@ -71,6 +72,9 @@ +@@ -72,6 +73,9 @@ #define ARPOP_REPLY 2 /* ARP reply */ #define ARPOP_RREQUEST 3 /* RARP request */ #define ARPOP_RREPLY 4 /* RARP reply */ @@ -14908,7 +14986,7 @@ /* ARP ioctl request. */ --- ref/include/linux/pkt_sched.h Tue Apr 28 20:10:10 1998 -+++ work/include/linux/pkt_sched.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/pkt_sched.h Tue Feb 9 15:49:58 1999 @@ -274,4 +274,17 @@ #define TCA_CBQ_MAX TCA_CBQ_POLICE @@ -14927,8 +15005,8 @@ +#define TCA_ATM_MAX TCA_ATM_ADDR + #endif ---- ref/include/linux/skbuff.h Fri Oct 23 19:15:48 1998 -+++ work/include/linux/skbuff.h Sun Nov 1 15:34:09 1998 +--- ref/include/linux/skbuff.h Thu Jan 28 21:43:15 1999 ++++ work/include/linux/skbuff.h Tue Feb 9 18:02:02 1999 @@ -112,6 +112,25 @@ __u32 ifield; } private; @@ -14956,7 +15034,7 @@ /* These are just the default values. This is run time configurable. --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/linux/sonet.h Sun Nov 1 15:31:53 1998 ++++ work/include/linux/sonet.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,52 @@ +/* sonet.h - SONET/SHD physical layer control */ + @@ -15011,7 +15089,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/include/net/atmclip.h Sun Nov 1 15:31:53 1998 ++++ work/include/net/atmclip.h Tue Feb 9 18:08:04 1999 @@ -0,0 +1,62 @@ +/* net/atm/atmarp.h - RFC1577 ATM ARP */ + @@ -15075,8 +15153,31 @@ +int clip_encap(struct atm_vcc *vcc,int mode); + +#endif ---- ref/net/Config.in Sun Sep 13 19:22:17 1998 -+++ work/net/Config.in Sun Nov 1 15:31:53 1998 +--- ref/include/net/sock.h Thu Jan 28 21:43:16 1999 ++++ work/include/net/sock.h Tue Feb 9 18:03:17 1999 +@@ -81,6 +81,10 @@ + #include <net/dn.h> + #endif + ++#if defined(CONFIG_ATM) || defined(CONFIG_ATM_MODULE) ++struct atm_vcc; ++#endif ++ + #ifdef CONFIG_FILTER + #include <linux/filter.h> + #endif +@@ -492,6 +496,9 @@ + #endif + #if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE) + struct econet_opt *af_econet; ++#endif ++#if defined(CONFIG_ATM) || defined(CONFIG_ATM_MODULE) ++ struct atm_vcc *af_atm; + #endif + } protinfo; + +--- ref/net/Config.in Tue Dec 29 20:21:49 1998 ++++ work/net/Config.in Tue Feb 9 15:49:58 1999 @@ -25,6 +25,27 @@ fi fi @@ -15105,18 +15206,18 @@ comment ' ' tristate 'The IPX protocol' CONFIG_IPX ---- ref/net/Makefile Mon Jul 27 08:35:57 1998 -+++ work/net/Makefile Sun Nov 1 15:31:53 1998 +--- ref/net/Makefile Thu Dec 17 18:03:57 1998 ++++ work/net/Makefile Tue Feb 9 15:49:58 1999 @@ -10,7 +10,7 @@ MOD_SUB_DIRS := ipv4 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ netrom rose lapb x25 wanrouter netlink sched packet sunrpc \ -- econet #decnet -+ econet atm #decnet +- econet irda #decnet ++ econet irda atm #decnet SUB_DIRS := core ethernet sched MOD_LIST_NAME := NET_MISC_MODULES -@@ -131,6 +131,17 @@ +@@ -139,6 +139,17 @@ ifeq ($(CONFIG_SUNRPC),m) MOD_SUB_DIRS += sunrpc endif @@ -15134,9 +15235,20 @@ endif ifeq ($(CONFIG_DECNET),y) ---- ref/net/protocols.c Fri Jul 10 22:51:41 1998 -+++ work/net/protocols.c Sun Nov 1 15:31:53 1998 -@@ -79,6 +79,10 @@ +--- ref/net/netsyms.c Thu Jan 7 18:26:42 1999 ++++ work/net/netsyms.c Tue Feb 9 17:15:25 1999 +@@ -214,6 +214,8 @@ + + #ifdef CONFIG_BRIDGE + EXPORT_SYMBOL(br_ioctl); ++EXPORT_SYMBOL(port_info); ++EXPORT_SYMBOL(br_avl_find_addr); + #endif + + #ifdef CONFIG_INET +--- ref/net/protocols.c Thu Dec 17 18:03:57 1998 ++++ work/net/protocols.c Tue Feb 9 15:49:58 1999 +@@ -87,6 +87,10 @@ extern void rif_init(struct net_proto *); #endif @@ -15147,7 +15259,7 @@ #ifdef NEED_LLC #define NEED_802 #include <net/llccall.h> -@@ -113,6 +117,11 @@ +@@ -121,6 +125,11 @@ #ifdef CONFIG_TR { "RIF", rif_init }, /* RIF for Token ring */ #endif @@ -15159,8 +15271,8 @@ #ifdef NEED_LLC { "802.2LLC", llc_init }, /* 802.2 LLC */ ---- ref/net/ipv4/arp.c Wed Oct 7 20:13:49 1998 -+++ work/net/ipv4/arp.c Sun Nov 1 15:31:53 1998 +--- ref/net/ipv4/arp.c Wed Nov 18 18:06:05 1998 ++++ work/net/ipv4/arp.c Tue Feb 9 15:49:58 1999 @@ -115,6 +115,9 @@ #include <net/netrom.h> #endif @@ -15171,7 +15283,7 @@ #include <asm/system.h> #include <asm/uaccess.h> -@@ -405,7 +408,11 @@ +@@ -402,7 +405,11 @@ if (dev == NULL) return 0; if (dst->neighbour == NULL) @@ -15185,7 +15297,7 @@ } --- ref/net/sched/Config.in Thu May 14 19:26:23 1998 -+++ work/net/sched/Config.in Sun Nov 1 15:31:53 1998 ++++ work/net/sched/Config.in Tue Feb 9 15:49:58 1999 @@ -7,6 +7,9 @@ tristate 'CSZ packet scheduler' CONFIG_NET_SCH_CSZ #tristate 'H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ @@ -15197,7 +15309,7 @@ tristate 'RED queue' CONFIG_NET_SCH_RED tristate 'SFQ queue' CONFIG_NET_SCH_SFQ --- ref/net/sched/Makefile Tue Apr 28 20:10:11 1998 -+++ work/net/sched/Makefile Sun Nov 1 15:31:53 1998 ++++ work/net/sched/Makefile Tue Feb 9 15:49:58 1999 @@ -7,6 +7,8 @@ # # Note 2! The CFLAGS definition is now in the main makefile... @@ -15218,8 +15330,8 @@ endif ifeq ($(CONFIG_NET_CLS_U32), y) ---- ref/net/sched/sch_api.c Fri Aug 28 04:33:09 1998 -+++ work/net/sched/sch_api.c Sun Nov 1 15:31:53 1998 +--- ref/net/sched/sch_api.c Thu Jan 7 18:26:42 1999 ++++ work/net/sched/sch_api.c Tue Feb 9 15:49:58 1999 @@ -987,6 +987,9 @@ #ifdef CONFIG_NET_SCH_PRIO INIT_QDISC(prio); @@ -15231,7 +15343,7 @@ tc_filter_init(); #endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/sched/sch_atm.c Sun Nov 1 15:31:53 1998 ++++ work/net/sched/sch_atm.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,611 @@ +/* net/sched/sch_atm.c - ATM VC selection "queueing discipline" */ + @@ -15845,7 +15957,7 @@ +} +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/Makefile Sun Nov 1 15:31:53 1998 ++++ work/net/atm/Makefile Tue Feb 9 15:49:58 1999 @@ -0,0 +1,64 @@ +# +# Makefile for the ATM Protocol Families. @@ -15912,7 +16024,7 @@ +mpoa.o: mpc.o mpoa_caches.o mpoa_proc.o + ld -r -o mpoa.o mpc.o mpoa_caches.o mpoa_proc.o --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/addr.c Sun Nov 1 15:31:53 1998 ++++ work/net/atm/addr.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,159 @@ +/* net/atm/addr.c - Local ATM address registry */ + @@ -16074,7 +16186,7 @@ + return total; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/addr.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/addr.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,18 @@ +/* net/atm/addr.h - Local ATM address registry */ + @@ -16095,8 +16207,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/clip.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,652 @@ ++++ work/net/atm/clip.c Tue Feb 9 15:49:58 1999 +@@ -0,0 +1,654 @@ +/* net/atm/clip.c - RFC1577 Classical IP over ATM */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -16227,15 +16339,16 @@ + for (clip_vcc = entry->vccs; clip_vcc; + clip_vcc = clip_vcc->next) + if (clip_vcc->idle_timeout && -+ clip_vcc->last_use+clip_vcc->idle_timeout < -+ jiffies) { ++ time_after(jiffies, clip_vcc->last_use+ ++ clip_vcc->idle_timeout)) { + DPRINTK("releasing vcc %p->%p of " + "entry %p\n",clip_vcc,clip_vcc->vcc, + entry); + atm_async_release_vcc(clip_vcc->vcc, + -ETIMEDOUT); + } -+ if (entry->vccs || entry->expires > jiffies) { ++ if (entry->vccs || ++ time_before(jiffies, entry->expires)) { + np = &n->next; + continue; + } @@ -16451,7 +16564,8 @@ + } + entry = NEIGH2ENTRY(skb->dst->neighbour); + if (!entry->vccs) { -+ if (entry->expires < jiffies) {/* should be resolved */ ++ if (time_after(jiffies, entry->expires)) { ++ /* should be resolved */ + entry->expires = jiffies+ATMARP_RETRY_DELAY*HZ; + to_atmarpd(act_need,PRIV(dev)->number,entry->ip); + } @@ -16750,8 +16864,8 @@ + return 0; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/common.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,926 @@ ++++ work/net/atm/common.c Tue Feb 9 15:49:58 1999 +@@ -0,0 +1,928 @@ +/* net/atm/common.c - ATM sockets (common part for PVC and SVC) */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -16773,6 +16887,7 @@ +#include <linux/sched.h> +#include <linux/time.h> /* struct timeval */ +#include <linux/skbuff.h> ++#include <net/sock.h> /* struct sock */ + +#include <asm/uaccess.h> +#include <asm/poll.h> @@ -16851,13 +16966,15 @@ +} + + -+int atm_create(struct socket *sock,int protocol) ++int atm_create(struct socket *sock,int protocol,int family) +{ ++ struct sock *sk; + struct atm_vcc *vcc; + -+ ATM_SD(sock) = NULL; ++ sock->sk = NULL; + if (sock->type == SOCK_STREAM) return -EINVAL; -+ if (!(vcc = alloc_atm_vcc())) return -ENOMEM; ++ if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM; ++ vcc = sk->protinfo.af_atm; +#ifdef CONFIG_AREQUIPA + vcc->upper = NULL; + vcc->sock = sock; @@ -16882,15 +16999,17 @@ + vcc->sleep = vcc->wsleep = NULL; + skb_queue_head_init(&vcc->recvq); + skb_queue_head_init(&vcc->listenq); -+ ATM_SD(sock) = vcc; ++ sock->sk = sk; + return 0; +} + + -+int atm_release_vcc(struct atm_vcc *vcc,int free_vcc) ++void atm_release_vcc_sk(struct sock *sk,int free_sk) +{ ++ struct atm_vcc *vcc; + struct sk_buff *skb; + ++ vcc = sk->protinfo.af_atm; + vcc->flags &= ~ATM_VF_READY; + if (vcc->dev) { + if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); @@ -16907,18 +17026,15 @@ + atomic_read(&vcc->rx_inuse)); + bind_vcc(vcc,NULL); + } -+ if (free_vcc) free_atm_vcc(vcc); -+ return 0; ++ if (free_sk) free_atm_vcc_sk(sk); +} + + +int atm_release(struct socket *sock,struct socket *peer) +{ -+ struct atm_vcc *vcc; -+ -+ vcc = ATM_SD(sock); -+ if (!vcc) return 0; -+ return atm_release_vcc(vcc,1); ++ if (sock->sk) ++ atm_release_vcc_sk(sock->sk,1); ++ return 0; +} + + @@ -17679,7 +17795,7 @@ + return atm_do_getsockopt(sock,level,optname,optval,len); +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/common.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/common.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,46 @@ +/* net/atm/common.h - ATM sockets (common part for PVC and SVC) */ + @@ -17693,7 +17809,7 @@ +#include <linux/poll.h> /* for poll_table */ + + -+int atm_create(struct socket *sock,int protocol); ++int atm_create(struct socket *sock,int protocol,int family); +int atm_release(struct socket *sock,struct socket *peer); +int atm_connect(struct socket *sock,int itf,short vpi,int vci); +int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, @@ -17708,7 +17824,7 @@ + int *optlen); + +int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci); -+int atm_release_vcc(struct atm_vcc *vcc,int free_vcc); ++void atm_release_vcc_sk(struct sock *sk,int free_sk); +int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); +/* -- now in atmdev.h: +void atm_async_release_vcc(struct atm_vcc *vcc,int reply); @@ -17728,7 +17844,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/ipcommon.c Sun Nov 1 15:31:53 1998 ++++ work/net/atm/ipcommon.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,52 @@ +/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */ + @@ -17783,7 +17899,7 @@ + skb_queue_head_init(from); +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/ipcommon.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/ipcommon.h Tue Feb 9 18:09:30 1999 @@ -0,0 +1,21 @@ +/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ + @@ -17807,7 +17923,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/misc.c Sun Nov 1 15:31:53 1998 ++++ work/net/atm/misc.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,184 @@ +/* net/atm/misc.c - Various functions for use by ATM drivers */ + @@ -17994,8 +18110,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/lec.c Sat Dec 5 01:49:36 1998 -@@ -0,0 +1,2054 @@ ++++ work/net/atm/lec.c Tue Feb 9 17:15:25 1999 +@@ -0,0 +1,2076 @@ +/* + * lec.c: Lan Emulation driver + * Marko Kiiskila carnil@cs.tut.fi @@ -18021,6 +18137,11 @@ +#include <linux/atmdev.h> +#include <linux/atmlec.h> + ++/* Bridge */ ++#ifdef CONFIG_BRIDGE ++#include <net/br.h> ++#endif ++ +/* Modular too */ +#include <linux/config.h> +#include <linux/module.h> @@ -18078,6 +18199,43 @@ + return &dev_lec[0]; +} + ++#ifdef CONFIG_BRIDGE ++static void handle_bridge(struct sk_buff *skb, struct device *dev) ++{ ++ struct ethhdr *eth; ++ char *buff; ++ struct lec_priv *priv; ++ unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; ++ ++ /* Check if this is a BPDU. If so, ask zeppelin to send ++ * LE_TOPOLOGY_REQUEST with the value of Topology Change bit ++ * in the Config BPDU*/ ++ eth = (struct ethhdr *)skb->data; ++ buff = skb->data + skb->dev->hard_header_len; ++ if ((memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) && ++ *buff++ == BRIDGE_LLC1_DSAP && ++ *buff++ == BRIDGE_LLC1_SSAP && ++ *buff++ == BRIDGE_LLC1_CTRL) { ++ struct sk_buff *skb2; ++ struct atmlec_msg *mesg; ++ ++ skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); ++ if (skb2 == NULL) return; ++ skb2->len = sizeof(struct atmlec_msg); ++ mesg = (struct atmlec_msg *)skb2->data; ++ mesg->type = l_topology_change; ++ mesg->content.normal.flag = *(skb->nh.raw + BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) & TOPOLOGY_CHANGE; ++ ++ priv = (struct lec_priv *)dev->priv; ++ if (atm_charge(priv->lecd, skb2->truesize) == 0) return; ++ skb_queue_tail(&priv->lecd->recvq, skb2); ++ wake_up(&priv->lecd->sleep); ++ } ++ ++ return; ++} ++#endif /* CONFIG_BRIDGE */ ++ +/* + * Open/initialize the netdevice. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. @@ -18107,7 +18265,7 @@ + struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lecdatahdr_8023 *lec_h; + struct atm_vcc *send_vcc; -+ struct lec_arp_table *entry = NULL; ++ struct lec_arp_table *entry; + unsigned char *nb; +#if DUMP_PACKETS > 0 + char buf[300]; @@ -18126,17 +18284,8 @@ + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ -+#if 0 /* 24.8.1998 hessu@cs.tut.fi */ -+ priv->stats.tx_dropped++; -+ printk("%s: lec_send_packet: transmit timed out, dropping packet...\n", dev->name); -+ dev_kfree_skb(skb); -+ dev->tbusy=0; -+ return 0; -+#endif -+#if 1 /* 24.8.1998 hessu@cs.tut.fi */ + printk("%s: transmit timed out\n", dev->name); + dev->tbusy = 0; -+#endif + } + + /* @@ -18151,12 +18300,26 @@ + DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n", + (long)skb->head, (long)skb->data, (long)skb->tail, + (long)skb->end); -+ ++#ifdef CONFIG_BRIDGE ++ if (skb->pkt_bridged == IS_BRIDGED) ++ handle_bridge(skb, dev); ++#endif /* CONFIG_BRIDGE */ ++ ++ /* Make sure we have room for lec_id */ ++ if (skb_headroom(skb) < 2) { ++ ++ DPRINTK("lec_send_packet: reallocating skb\n"); ++ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); ++ kfree_skb(skb); ++ if (skb2 == NULL) return 0; ++ skb = skb2; ++ } ++ skb_push(skb, 2); ++ + /* Put le header to place */ + lec_h = (struct lecdatahdr_8023*)skb->data; -+ /* + lec_h->le_header = htons(priv->lecid); -+ */ ++ +#if DUMP_PACKETS > 0 + printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name, + skb->len, priv->lecid); @@ -18174,48 +18337,7 @@ + else + printk("%s...\n",buf); +#endif /* DUMP_PACKETS > 0 */ -+ /* Send to right vcc */ -+ send_vcc = lec_arp_resolve(priv, lec_h->h_dest, &entry); -+ DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name, -+ send_vcc, send_vcc?send_vcc->flags:0, entry); -+ if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) { -+#if 0 /* 24.8.1998 hessu@cs.tut.fi */ -+ priv->stats.tx_dropped++; -+ printk("%s:lec_send_packet: bad vcc, dropping packet...\n", -+ dev->name); -+ dev_kfree_skb(skb); -+ dev->tbusy=0; -+ return 0; -+#endif -+#if 0 /* 26.8.1998 hessu@cs.tut.fi */ -+ priv->stats.tx_errors++; -+ printk("%s:lec_send_packet: handing back ", dev->name); -+ printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", -+ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], -+ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); -+ dev->tbusy = 1; -+ return 1; -+#endif -+#if 1 /* 30.10.1998 s156953@cs.tut.fi hessu@cs.tut.fi */ -+ if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { -+ printk("%s:lec_send_packet: queuing packet, ", dev->name); -+ printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", -+ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], -+ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); -+ skb_queue_tail(&entry->tx_wait, skb); -+ } else { -+ printk("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name); -+ printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", -+ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], -+ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); -+ priv->stats.tx_dropped++; -+ dev_kfree_skb(skb); -+ dev->tbusy = 0; -+ return 0; -+ } -+#endif -+ -+ } ++ + /* Minimum ethernet-frame size */ + if (skb->len <62) { + if (skb->truesize < 62) { @@ -18234,7 +18356,27 @@ + skb->len = 62; + } + } -+ if(!send_vcc){ ++ ++ /* Send to right vcc */ ++ entry = NULL; ++ send_vcc = lec_arp_resolve(priv, lec_h->h_dest, &entry); ++ DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name, ++ send_vcc, send_vcc?send_vcc->flags:0, entry); ++ if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) { ++ if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { ++ DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name); ++ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", ++ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], ++ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); ++ skb_queue_tail(&entry->tx_wait, skb); ++ } else { ++ DPRINTK("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name); ++ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", ++ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], ++ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); ++ priv->stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ } + dev->tbusy=0; + return 0; + } @@ -18245,14 +18387,16 @@ +#endif /* DUMP_PACKETS > 0 */ + + while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { -+ printk("lec.c: emptying tx queue, "); -+ printk("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", ++ DPRINTK("lec.c: emptying tx queue, "); ++ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], + lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + ATM_SKB(skb2)->vcc = send_vcc; + atomic_add(skb2->truesize, &send_vcc->tx_inuse); + ATM_SKB(skb2)->iovcnt = 0; + ATM_SKB(skb2)->atm_options = send_vcc->atm_options; ++ DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name, ++ send_vcc->vpi, send_vcc->vci); + send_vcc->dev->ops->send(send_vcc, skb2); + priv->stats.tx_packets++; + } @@ -18291,83 +18435,6 @@ + return (struct enet_statistics *)&priv->stats; +} + -+int -+lec_hard_header(struct sk_buff *skb, struct device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned len) -+{ -+ struct lec_priv *priv = (struct lec_priv *)dev->priv; -+ struct lecdatahdr_8023 *hdr = -+ (struct lecdatahdr_8023 *)skb_push(skb, LEC_HEADER_LEN); -+ -+ /* Set lecid header */ -+ if (priv) -+ hdr->le_header = htons(priv->lecid); -+ else -+ hdr->le_header = 0; -+ -+ /* Set the protocol type. */ -+ if(type!=ETH_P_802_3) -+ hdr->h_type = htons(type); -+ else -+ hdr->h_type = htons(len); -+ -+ /* Source hw address */ -+ if (saddr) -+ memcpy(hdr->h_source, saddr, dev->addr_len); -+ else -+ memcpy(hdr->h_source, dev->dev_addr, dev->addr_len); -+ -+ /* Destination addr */ -+ if (daddr) { -+ memcpy(hdr->h_dest, daddr, dev->addr_len); -+ return dev->hard_header_len; -+ } -+ return -dev->hard_header_len; -+} -+ -+int -+lec_rebuild_header(struct sk_buff *skb) -+{ -+ struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023*)skb->data; -+ struct device *dev = skb->dev; -+ -+ switch (hdr->h_type) -+ { -+#ifdef CONFIG_INET -+ case __constant_htons(ETH_P_IP): -+ return arp_find(hdr->h_dest, skb); -+#endif -+ default: -+ printk(KERN_DEBUG -+ "%s: unable to resolve type %X addresses.\n", -+ dev->name, (int)hdr->h_type); -+ -+ memcpy(hdr->h_source, dev->dev_addr, dev->addr_len); -+ return 0; -+ break; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Called by Address Resolution module to notify changes in address. -+ */ -+void -+lec_header_cache_update(struct hh_cache *hh, struct device *dev, -+ unsigned char *haddr) -+{ -+ u16 *u16ptr = (u16 *)hh->hh_data; -+ -+ if (hh->hh_type != ETH_P_IP) { -+ printk("lec_header_cache_update: %04x cache is not implemented\n", -+ hh->hh_type); -+ return; -+ } -+ memcpy(u16ptr+1, haddr, ETH_ALEN); -+} -+ +static int +lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ @@ -18418,7 +18485,7 @@ + mesg->content.normal.targetless_le_arp); + DPRINTK("lec: in l_arp_update\n"); + if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */ -+ DPRINTK("lec: LANE2 3.1.5, got tlvs\n"); ++ DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n", mesg->sizeoftlvs); + lane2_associate_ind(dev, + mesg->content.normal.mac_addr, + tmp, mesg->sizeoftlvs); @@ -18443,6 +18510,7 @@ + priv->lane2_ops = NULL; + if (priv->lane_version > 1) + priv->lane2_ops = &lane2_ops; ++ priv->is_proxy = mesg->content.config.is_proxy; + break; + case l_flush_tran_id: + lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr, @@ -18451,6 +18519,35 @@ + case l_set_lecid: + priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag); + break; ++ case l_should_bridge: { ++#ifdef CONFIG_BRIDGE ++ struct fdb *f; ++ extern Port_data port_info[]; ++ ++ DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n", ++ dev->name, ++ mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1], ++ mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3], ++ mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]); ++ f = br_avl_find_addr(mesg->content.proxy.mac_addr); /* bridge/br.c */ ++ if (f != NULL && ++ port_info[f->port].dev != dev && ++ port_info[f->port].state == Forwarding) { ++ /* hit from bridge table, send LE_ARP_RESPONSE */ ++ struct sk_buff *skb2; ++ ++ DPRINTK("%s: entry found, responding to zeppelin\n", dev->name); ++ skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); ++ if (skb2 == NULL) break; ++ skb2->len = sizeof(struct atmlec_msg); ++ memcpy(skb2->data, mesg, sizeof(struct atmlec_msg)); ++ if (atm_charge(priv->lecd, skb2->truesize) == 0) break; ++ skb_queue_tail(&priv->lecd->recvq, skb2); ++ wake_up(&priv->lecd->sleep); ++ } ++#endif /* CONFIG_BRIDGE */ ++ } ++ break; + default: + printk("%s: Unknown message type %d\n", dev->name, mesg->type); + dev_kfree_skb(skb); @@ -18587,14 +18684,9 @@ + + ether_setup(dev); + dev->change_mtu = lec_change_mtu; -+ dev->hard_header = lec_hard_header; -+ dev->rebuild_header = lec_rebuild_header; -+ dev->hard_header_cache = NULL; -+ dev->header_cache_update = lec_header_cache_update; + dev->open = lec_open; + dev->stop = lec_close; + dev->hard_start_xmit = lec_send_packet; -+ dev->hard_header_len = LEC_HEADER_LEN; + + dev->get_stats = lec_get_stats; + dev->set_multicast_list = NULL; @@ -18615,7 +18707,7 @@ + struct device *dev = (struct device *)vcc->proto_data; + struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lecdatahdr_8023 *hdr; -+ unsigned char *rawp; ++ +#if DUMP_PACKETS >0 + int i=0; + char buf[300]; @@ -18664,25 +18756,8 @@ + lec_arp_check_empties(priv, vcc, skb); + } + skb->dev = dev; -+ skb->mac.raw = (unsigned char *)skb->data; -+ if (*hdr->h_dest&1) { -+ if (memcmp(hdr->h_dest,dev->broadcast, ETH_ALEN)==0) -+ skb->pkt_type=PACKET_BROADCAST; -+ else -+ skb->pkt_type=PACKET_MULTICAST; -+ } else if (dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) { -+ if (memcmp(hdr->h_dest,dev->dev_addr, ETH_ALEN)) -+ skb->pkt_type=PACKET_OTHERHOST; -+ } -+ if (ntohs(hdr->h_type)>=1536) -+ skb->protocol = hdr->h_type; -+ else -+ skb->protocol = htons(ETH_P_802_2); -+ skb->h.raw = skb_pull(skb, LEC_HEADER_LEN); -+ rawp = skb->data; -+ /* Magic hack for IPX ... */ -+ if (*(unsigned short*)rawp == 0xFFFF) -+ skb->protocol = htons(ETH_P_802_3); ++ skb->data += 2; /* skip lec_id */ ++ skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + priv->stats.rx_packets++; + } @@ -18919,6 +18994,8 @@ +{ + int i = 0; + struct lec_priv *priv = (struct lec_priv *)dev->priv; ++#if 0 /* Why have the TLVs in LE_ARP entries since we do not use them? When you ++ uncomment this code, make sure the TLVs get freed when entry is killed */ + struct lec_arp_table *entry = lec_arp_find(priv, mac_addr); + + if (entry == NULL) @@ -18932,7 +19009,7 @@ + + entry->sizeoftlvs = sizeoftlvs; + memcpy(entry->tlvs, tlvs, sizeoftlvs); -+ ++#endif +#if 0 + printk("lec.c: lane2_associate_ind()\n"); + printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs); @@ -19027,8 +19104,9 @@ +#if 0 /* August 6, 1998 */ + entry->vcc->flags |= ATM_VF_RELEASED; + entry->vcc->flags &= ~ATM_VF_READY; -+#endif + atm_async_release_vcc(entry->vcc, -EPIPE); ++#endif ++ entry->vcc->push(entry->vcc, NULL); + entry->vcc = NULL; + } + if (entry->recv_vcc) { @@ -19036,8 +19114,9 @@ +#if 0 + entry->recv_vcc->flags |= ATM_VF_RELEASED; + entry->recv_vcc->flags &= ~ATM_VF_READY; -+#endif + atm_async_release_vcc(entry->recv_vcc, -EPIPE); ++#endif ++ entry->recv_vcc->push(entry->recv_vcc, NULL); + entry->recv_vcc = NULL; + } +} @@ -19172,6 +19251,8 @@ + (struct lec_arp_table *)priv->lec_arp_empty_ones; + struct lec_arp_table *lec_no_forward = + (struct lec_arp_table *)priv->lec_no_forward; ++ struct lec_arp_table *mcast_fwds = priv->mcast_fwds; ++ + + printk("Dump %p:\n",priv); + for (i=0;i<LEC_ARP_TABLE_SIZE;i++) { @@ -19271,6 +19352,38 @@ + printk("%s",buf); + } + ++ rulla = mcast_fwds; ++ if (rulla) ++ printk("Multicast Forward VCCs\n"); ++ while(rulla) { ++ offset=0; ++ offset += sprintf(buf+offset,"Mac:"); ++ for(j=0;j<ETH_ALEN;j++) { ++ offset+=sprintf(buf+offset,"%2.2x ", ++ rulla->mac_addr[j]&0xff); ++ } ++ offset +=sprintf(buf+offset,"Atm:"); ++ for(j=0;j<ATM_ESA_LEN;j++) { ++ offset+=sprintf(buf+offset,"%2.2x ", ++ rulla->atm_addr[j]&0xff); ++ } ++ offset+=sprintf(buf+offset, ++ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", ++ rulla->vcc?rulla->vcc->vpi:0, ++ rulla->vcc?rulla->vcc->vci:0, ++ rulla->recv_vcc?rulla->recv_vcc->vpi:0, ++ rulla->recv_vcc?rulla->recv_vcc->vci:0, ++ rulla->last_used, ++ rulla->timestamp, rulla->no_tries); ++ offset+=sprintf(buf+offset, ++ "Flags:%x, Packets_flooded:%x, Status: %s ", ++ rulla->flags, rulla->packets_flooded, ++ get_status_string(rulla->status)); ++ offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next); ++ rulla = rulla->next; ++ printk("%s",buf); ++ } ++ +#endif +} + @@ -19304,7 +19417,6 @@ + next = entry->next; + del_timer(&entry->timer); + lec_arp_clear_vccs(entry); -+ skb_queue_purge(&entry->tx_wait); + kfree(entry); + entry = next; + } @@ -19314,11 +19426,19 @@ + next = entry->next; + del_timer(&entry->timer); + lec_arp_clear_vccs(entry); -+ skb_queue_purge(&entry->tx_wait); + kfree(entry); + entry = next; + } + priv->lec_no_forward = NULL; ++ entry = priv->mcast_fwds; ++ while(entry) { ++ next = entry->next; ++ del_timer(&entry->timer); ++ lec_arp_clear_vccs(entry); ++ kfree(entry); ++ entry = next; ++ } ++ priv->mcast_fwds = NULL; + priv->mcast_vcc = NULL; + memset(priv->lec_arp_tables, 0, + sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE); @@ -19490,7 +19610,8 @@ + + DPRINTK("About to expire: %lx - %lx > %lx\n", + now,entry->last_used, time_to_check); -+ if( (now-entry->last_used > time_to_check) && ++ if( time_after(now, entry->last_used+ ++ time_to_check) && + !(entry->flags & LEC_PERMANENT_FLAG) && + !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */ + /* Remove entry */ @@ -19503,16 +19624,18 @@ + /* Something else */ + if ((entry->status == ESI_VC_PENDING || + entry->status == ESI_ARP_PENDING) -+ && -+ now-entry->timestamp >= -+ priv->max_unknown_frame_time) { ++ && time_after_eq(now, ++ entry->timestamp + ++ priv->max_unknown_frame_time)) { + entry->timestamp = jiffies; + entry->packets_flooded = 0; ++ if (entry->status == ESI_VC_PENDING) ++ send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL); + } + if (entry->status == ESI_FLUSH_PENDING -+ && -+ now-entry->timestamp >= -+ priv->path_switching_delay) { ++ && ++ time_after_eq(now, entry->timestamp+ ++ priv->path_switching_delay)) { + entry->last_used = jiffies; + entry->status = + ESI_FORWARD_DIRECT; @@ -19543,7 +19666,7 @@ + return priv->mcast_vcc; + break; + case 2: /* LANE2 wants arp for multicast addresses */ -+ if ( memcmp(mac_to_find, &bus_mac, ETH_ALEN) == 0) ++ if ( memcmp(mac_to_find, bus_mac, ETH_ALEN) == 0) + return priv->mcast_vcc; + break; + default: @@ -19560,10 +19683,6 @@ + *ret_entry = entry; + return entry->vcc; + } -+ if (entry->status == ESI_UNKNOWN) { -+ del_timer(&entry->timer); -+ goto make_arp_entry; -+ } + /* Data direct VC not yet set up, check to see if the unknown + frame count is greater than the limit. If the limit has + not been reached, allow the caller to send packet to @@ -19574,7 +19693,12 @@ + DPRINTK("LEC_ARP: Flooding..\n"); + return priv->mcast_vcc; + } ++ /* We got here because entry->status == ESI_FLUSH_PENDING ++ * or BUS flood limit was reached for an entry which is ++ * in ESI_ARP_PENDING or ESI_VC_PENDING state. ++ */ + *ret_entry = entry; ++ DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc); + return NULL; + } else { + /* No matching entry was found */ @@ -19584,7 +19708,6 @@ + return priv->mcast_vcc; + } + lec_arp_put(priv->lec_arp_tables, entry); -+ make_arp_entry: + /* We want arp-request(s) to be sent */ + entry->packets_flooded =1; + entry->status = ESI_ARP_PENDING; @@ -19594,7 +19717,6 @@ + entry->timer.expires = jiffies + (1*HZ); + entry->timer.function = lec_arp_expire_arp; + add_timer(&entry->timer); -+ *ret_entry = entry; + return priv->mcast_vcc; + } +} @@ -19634,7 +19756,6 @@ + unsigned int targetless_le_arp) +{ + struct lec_arp_table *entry, *tmp; -+ struct sk_buff *skb; + int i; + + DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " "); @@ -19674,8 +19795,7 @@ + tmp->vcc = entry->vcc; + tmp->old_push = entry->old_push; + tmp->last_used = jiffies; -+ while((skb = skb_dequeue(&entry->tx_wait)) != NULL) -+ skb_queue_tail(&tmp->tx_wait, skb); ++ del_timer(&entry->timer); + kfree(entry); + entry=tmp; + } else { @@ -19729,7 +19849,7 @@ + if (entry->status == ESI_ARP_PENDING || + entry->status == ESI_UNKNOWN) { + entry->status = ESI_VC_PENDING; -+ send_to_lecd(priv, l_svc_setup, NULL, atm_addr, NULL); ++ send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL); + } + DPRINTK("After update2\n"); + dump_arp_table(priv); @@ -19750,8 +19870,10 @@ + + lec_arp_lock(priv); + if (ioc_data->receive == 2) { -+ /* Vcc for BUS distribute */ -+ DPRINTK("LEC_ARP: Attaching mcast distribute\n"); ++ /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */ ++ ++ DPRINTK("LEC_ARP: Attaching mcast forward\n"); ++#if 0 + entry = lec_arp_find(priv, bus_mac); + if (!entry) { + printk("LEC_ARP: Multicast entry not found!\n"); @@ -19761,6 +19883,13 @@ + memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); + entry->recv_vcc = vcc; + entry->old_recv_push = old_push; ++#endif ++ entry = make_entry(priv, bus_mac); ++ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); ++ entry->recv_vcc = vcc; ++ entry->old_recv_push = old_push; ++ entry->next = priv->mcast_fwds; ++ priv->mcast_fwds = entry; + lec_arp_unlock(priv); + return; + } else if (ioc_data->receive == 1) { @@ -19793,15 +19922,15 @@ + return; + } + DPRINTK("LEC_ARP:Attaching data direct, default:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", -+ ioc_data->atm_addr[0],ioc_data->atm_addr[1], -+ ioc_data->atm_addr[2],ioc_data->atm_addr[3], -+ ioc_data->atm_addr[4],ioc_data->atm_addr[5], -+ ioc_data->atm_addr[6],ioc_data->atm_addr[7], -+ ioc_data->atm_addr[8],ioc_data->atm_addr[9], -+ ioc_data->atm_addr[10],ioc_data->atm_addr[11], -+ ioc_data->atm_addr[12],ioc_data->atm_addr[13], -+ ioc_data->atm_addr[14],ioc_data->atm_addr[15], -+ ioc_data->atm_addr[16],ioc_data->atm_addr[17], ++ ioc_data->atm_addr[0],ioc_data->atm_addr[1], ++ ioc_data->atm_addr[2],ioc_data->atm_addr[3], ++ ioc_data->atm_addr[4],ioc_data->atm_addr[5], ++ ioc_data->atm_addr[6],ioc_data->atm_addr[7], ++ ioc_data->atm_addr[8],ioc_data->atm_addr[9], ++ ioc_data->atm_addr[10],ioc_data->atm_addr[11], ++ ioc_data->atm_addr[12],ioc_data->atm_addr[13], ++ ioc_data->atm_addr[14],ioc_data->atm_addr[15], ++ ioc_data->atm_addr[16],ioc_data->atm_addr[17], + ioc_data->atm_addr[18],ioc_data->atm_addr[19]); + for (i=0;i<LEC_ARP_TABLE_SIZE;i++) { + for (entry = priv->lec_arp_tables[i];entry;entry=entry->next) { @@ -19813,7 +19942,7 @@ + entry->recv_vcc?entry->recv_vcc->vci:0); + found_entry=1; + del_timer(&entry->timer); -+ if (vcc) { ++ if (entry->vcc) { + lec_arp_clear_vccs(entry); + } + entry->vcc = vcc; @@ -19918,6 +20047,7 @@ + to_add = make_entry(priv, mac_addr); + if (!to_add) + return -ENOMEM; ++ memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN); + to_add->status = ESI_FORWARD_DIRECT; + to_add->flags |= LEC_PERMANENT_FLAG; + to_add->vcc = vcc; @@ -19947,14 +20077,6 @@ + if (priv->mcast_vcc == vcc) { + priv->mcast_vcc = NULL; + } -+ } else if (vcc == entry->recv_vcc) { -+ /* Bus distribution closed */ -+ priv->mcast_vcc = NULL; -+ lec_arp_remove(priv->lec_arp_tables,entry); -+ kfree(entry); -+ lec_arp_unlock(priv); -+ vcc->push(vcc, NULL); -+ return; + } + } + } @@ -19991,6 +20113,22 @@ + entry = next; + } + ++ entry = priv->mcast_fwds; ++ priv->mcast_fwds = NULL; ++ while (entry != NULL) { ++ next = entry->next; ++ if (entry->recv_vcc == vcc) { ++ lec_arp_clear_vccs(entry); ++ /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ ++ kfree(entry); ++ } ++ else { ++ entry->next = priv->mcast_fwds; ++ priv->mcast_fwds = entry; ++ } ++ entry = next; ++ } ++ + lec_arp_unlock(priv); + dump_arp_table(priv); +} @@ -20051,8 +20189,8 @@ +} + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/lec.h Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,143 @@ ++++ work/net/atm/lec.h Tue Feb 9 18:09:24 1999 +@@ -0,0 +1,149 @@ +/* + * + * Lan Emulation client header file @@ -20140,8 +20278,13 @@ + age out by not using them to forward packets. + This is because to some LE clients there will be 2 VCCs. Only + one of them gets used. */ ++ struct lec_arp_table *mcast_fwds; ++ /* With LANEv2 it is possible that BUS (or a special multicast server) ++ establishes multiple Multicast Forward VCCs to us. This list ++ collects all those VCCs. LANEv1 client has only one item in this ++ list. These entries are not aged out. */ + atomic_t lec_arp_lock_var; -+ struct atm_vcc *mcast_vcc; ++ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ + struct atm_vcc *lecd; + struct timer_list lec_arp_timer; + /* C10 */ @@ -20180,6 +20323,7 @@ + int lane_version; /* LANE2 */ + int itfnum; /* e.g. 2 for lec2, 5 for lec5 */ + struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */ ++ int is_proxy; /* bridge between ATM and Ethernet */ +}; + +int lecd_attach(struct atm_vcc *vcc, int arg); @@ -20197,7 +20341,7 @@ +#endif _LEC_H_ + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/lec_arpc.h Tue Nov 3 18:41:56 1998 ++++ work/net/atm/lec_arpc.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,114 @@ +/* + * Lec arp cache @@ -20314,8 +20458,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/mpc.c Sat Dec 5 01:50:04 1998 -@@ -0,0 +1,1519 @@ ++++ work/net/atm/mpc.c Tue Feb 9 17:15:25 1999 +@@ -0,0 +1,1515 @@ +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/timer.h> @@ -20692,12 +20836,20 @@ + dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name); + dprintk("total length of all TLVs %d\n", sizeoftlvs); + mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */ ++ if (mpc == NULL) { ++ printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev->name); ++ return; ++ } + end_of_tlvs = tlvs + sizeoftlvs; + while (end_of_tlvs - tlvs >= 5) { + type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3]; + length = tlvs[4]; + tlvs += 5; + dprintk(" type 0x%x length %02x\n", type, length); ++ if (tlvs + length > end_of_tlvs) { ++ printk("TLV value extends past its buffer, aborting parse\n"); ++ return; ++ } + + if (type == 0) { + printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name); @@ -20747,8 +20899,9 @@ +} + +/* -+ * store either advertizing router's MAC address -+ * or the MAC address(es) in this TLV ++ * Store at least advertizing router's MAC address ++ * plus the possible MAC address(es) to mpc->mps_macs. ++ * For a freshly allocated MPOA client mpc->mps_macs == 0. + */ +static uint8_t *copy_macs(struct mpoa_client *mpc, uint8_t *router_mac, + uint8_t *tlvs, uint8_t mps_macs, uint8_t device_type) @@ -20756,27 +20909,21 @@ + int num_macs; + num_macs = (mps_macs > 1) ? mps_macs : 1; + -+ if (mpc->number_of_mps_macs != num_macs) { -+ kfree(mpc->mps_macs); -+ mpc->number_of_mps_macs = num_macs; ++ if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */ ++ if (mpc->number_of_mps_macs != 0) kfree(mpc->mps_macs); ++ mpc->number_of_mps_macs = 0; + mpc->mps_macs = kmalloc(num_macs*ETH_ALEN, GFP_KERNEL); + if (mpc->mps_macs == NULL) { + printk("mpoa: (%s) copy_macs: out of mem\n", mpc->dev->name); + return NULL; + } + } -+ -+ /* copy the advertizing routers MAC address */ + memcpy(mpc->mps_macs, router_mac, ETH_ALEN); -+ + tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20; -+ /* -+ * collect the MPS MAC addresses. -+ * however, it is possible that TLV includes no MACs -+ */ + if (mps_macs > 0) + memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN); + tlvs += mps_macs*ETH_ALEN; ++ mpc->number_of_mps_macs = num_macs; + + return tlvs; +} @@ -20803,7 +20950,6 @@ + + ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr); + -+ + entry = mpc->in_ops->search(ipaddr, mpc); + if (entry == NULL) { + mpc->in_ops->new_entry(ipaddr, mpc); @@ -20827,11 +20973,11 @@ + if (entry->ctrl_info.tag != 0) { + ddprintk("mpoa: (%s) send_via_shortcut() adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag); + tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; -+ skb_pull(skb, LEC_HEADER_LEN); /* get rid of LANE+Eth header */ -+ skb_push(skb, sizeof(tagged_llc_snap_hdr)); /* add LLC/SNAP header */ ++ skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ ++ skb_push(skb, sizeof(tagged_llc_snap_hdr)); /* add LLC/SNAP header */ + memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr)); + } else { -+ skb_pull(skb, LEC_HEADER_LEN); /* get rid of LANE+Eth header */ ++ skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ + skb_push(skb, sizeof(struct llc_snap_hdr)); /* add LLC/SNAP header + tag */ + memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)); + } @@ -20852,6 +20998,7 @@ +{ + int retval; + struct mpoa_client *mpc; ++ struct ethhdr *eth; + int i = 0; + + mpc = find_mpc_by_lec(dev); /* this should NEVER fail */ @@ -20860,11 +21007,12 @@ + goto non_ip; + } + -+ if ( ((struct ethhdr *)(skb->data + 2))->h_proto != htons(ETH_P_IP) ) ++ eth = (struct ethhdr *)skb->data; ++ if (eth->h_proto != htons(ETH_P_IP)) + goto non_ip; /* Multi-Protocol Over ATM :-) */ + + while (i < mpc->number_of_mps_macs) { -+ if (memcmp(skb->data + 2, (mpc->mps_macs + i*ETH_ALEN), ETH_ALEN) == 0) ++ if (memcmp(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN), ETH_ALEN) == 0) + if ( send_via_shortcut(skb, mpc) == 0 ) /* try shortcut */ + return 0; /* success! */ + i++; @@ -21025,21 +21173,13 @@ + skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */ + new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */ + kfree_skb(skb); -+ skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */ ++ if (new_skb == NULL) return; ++ skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */ + memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length); -+ new_skb->mac.raw = new_skb->data; -+ skb_pull(new_skb, ETH_HLEN); -+ -+ tmp = eg->ctrl_info.DLL_header + 2*ETH_ALEN; -+ memcpy(&new_skb->protocol, tmp, sizeof(uint16_t)); -+ if ( ntohs(new_skb->protocol) < 1536 ) { -+ printk("mpoa: (%s) mpc_push() received non-DIX Ethernet frame, purging\n", -+ dev->name); -+ kfree_skb(new_skb); -+ return; -+ } ++ new_skb->protocol = eth_type_trans(new_skb, dev); ++ new_skb->nh.raw = new_skb->data; + -+ eg->latest_ip_addr = ((struct iphdr *)new_skb->data)->saddr; ++ eg->latest_ip_addr = new_skb->nh.iph->saddr; + eg->packets_rcvd++; + + netif_rx(new_skb); @@ -21836,7 +21976,7 @@ +} +#endif /* MODULE */ --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/mpc.h Sat Dec 5 01:50:17 1998 ++++ work/net/atm/mpc.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,65 @@ +#ifndef _MPC_H_ +#define _MPC_H_ @@ -21904,7 +22044,7 @@ + +#endif /* _MPC_H_ */ --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/mpoa_caches.c Sat Dec 5 01:50:28 1998 ++++ work/net/atm/mpoa_caches.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,557 @@ +#include <linux/types.h> +#include <linux/atmmpc.h> @@ -22464,7 +22604,7 @@ + return; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/mpoa_caches.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/mpoa_caches.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,90 @@ +#ifndef MPOA_CACHES_H +#define MPOA_CACHES_H @@ -22557,8 +22697,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/mpoa_proc.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,388 @@ ++++ work/net/atm/mpoa_proc.c Tue Feb 9 17:15:25 1999 +@@ -0,0 +1,395 @@ +#include <linux/config.h> + +#ifdef CONFIG_PROC_FS @@ -22883,26 +23023,34 @@ + /* next receive values */ + tmp = strstr(buff, "rx="); + if(tmp == NULL) return 0; -+ tmp += 3; -+ prev = tmp; -+ for( i = 0; i < 2; i++){ -+ tmp = strchr(prev, ','); -+ if (tmp == NULL) return 0; -+ memset(temp, '\0', 256); -+ memcpy(temp, prev, tmp-prev); -+ value[i] = (int)simple_strtoul(temp, NULL, 0); -+ tmp ++; -+ prev = tmp; -+ } -+ tmp = strchr(prev, '\0'); -+ if (tmp == NULL) return 0; -+ memset(temp, '\0', 256); -+ memcpy(temp, prev, tmp-prev); -+ value[i] = (int)simple_strtoul(temp, NULL, 0); -+ qos.rxtp.traffic_class = ATM_CBR; -+ qos.rxtp.max_pcr = value[0]; -+ qos.rxtp.max_cdv = value[1]; -+ qos.rxtp.max_sdu = value[2]; ++ if (strstr(buff, "rx=tx")) { /* rx == tx */ ++ qos.rxtp.traffic_class = qos.txtp.traffic_class; ++ qos.rxtp.max_pcr = qos.txtp.max_pcr; ++ qos.rxtp.max_cdv = qos.txtp.max_cdv; ++ qos.rxtp.max_sdu = qos.txtp.max_sdu; ++ } else { ++ tmp += 3; ++ prev = tmp; ++ for( i = 0; i < 2; i++){ ++ tmp = strchr(prev, ','); ++ if (tmp == NULL) return 0; ++ memset(temp, '\0', 256); ++ memcpy(temp, prev, tmp-prev); ++ value[i] = (int)simple_strtoul(temp, NULL, 0); ++ tmp ++; ++ prev = tmp; ++ } ++ tmp = strchr(prev, '\0'); ++ if (tmp == NULL) return 0; ++ memset(temp, '\0', 256); ++ memcpy(temp, prev, tmp-prev); ++ value[i] = (int)simple_strtoul(temp, NULL, 0); ++ qos.rxtp.traffic_class = ATM_CBR; ++ qos.rxtp.max_pcr = value[0]; ++ qos.rxtp.max_cdv = value[1]; ++ qos.rxtp.max_sdu = value[2]; ++ } ++ qos.aal = ATM_AAL5; + dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d,%d rx=%d,%d,%d\n", + qos.txtp.max_pcr, + qos.txtp.max_cdv, @@ -22912,7 +23060,6 @@ + qos.rxtp.max_sdu + ); + -+ qos.aal = ATM_AAL5; + atm_mpoa_add_qos(ipaddr, &qos); + return 1; +} @@ -22948,7 +23095,7 @@ + + --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/lane_mpoa_init.c Sun Nov 1 15:31:53 1998 ++++ work/net/atm/lane_mpoa_init.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,48 @@ +#include <linux/config.h> +#include <linux/module.h> @@ -22999,8 +23146,8 @@ +} +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/proc.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,610 @@ ++++ work/net/atm/proc.c Tue Feb 9 17:15:25 1999 +@@ -0,0 +1,618 @@ +/* net/atm/proc.c - ATM /proc interface */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -23227,7 +23374,8 @@ + off += ip_len; + while (ip_len++ < 16) buf[off++] = ' '; + if (!clip_vcc) -+ if (entry->expires > jiffies) strcpy(buf+off,"(resolving)\n"); ++ if (time_before(jiffies, entry->expires)) ++ strcpy(buf+off,"(resolving)\n"); + else sprintf(buf+off,"(expired, ref %d)\n", + atomic_read(&entry->neigh->refcnt)); + else if (!svc) @@ -23513,6 +23661,13 @@ + lec_info(entry, buf+e); + return strlen(buf); + } ++ for(entry=priv->mcast_fwds; entry; ++ entry=entry->next) { ++ if (--count) continue; ++ e=sprintf(buf,"%s ",dev_lec[d]->name); ++ lec_info(entry, buf+e); ++ return strlen(buf); ++ } + } + return 0; + } @@ -23612,7 +23767,7 @@ + return error; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/protocols.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/protocols.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,16 @@ +/* net/atm/protocols.h - ATM protocol handler entry points */ + @@ -23631,7 +23786,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/pvc.c Sun Nov 1 15:31:53 1998 ++++ work/net/atm/pvc.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,158 @@ +/* net/atm/pvc.c - ATM PVC sockets */ + @@ -23756,7 +23911,7 @@ +static int pvc_create(struct socket *sock,int protocol) +{ + sock->ops = &pvc_proto_ops; -+ return atm_create(sock,protocol); ++ return atm_create(sock,protocol,PF_ATMPVC); +} + + @@ -23792,7 +23947,7 @@ +#endif +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/raw.c Sun Nov 1 15:31:53 1998 ++++ work/net/atm/raw.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,80 @@ +/* net/atm/raw.c - Raw AAL0 and AAL5 transports */ + @@ -23875,11 +24030,11 @@ + return 0; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/resources.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,186 @@ ++++ work/net/atm/resources.c Tue Feb 9 16:45:37 1999 +@@ -0,0 +1,201 @@ +/* net/atm/resources.c - Staticly allocated resources */ + -+/* Written 1995-1998 by Werner Almesberger, EPFL LRC */ ++/* Written 1995-1999 by Werner Almesberger, EPFL LRC */ + + +#include <linux/config.h> @@ -23888,6 +24043,7 @@ +#include <linux/atmdev.h> +#include <linux/kernel.h> /* for barrier */ +#include <linux/module.h> ++#include <net/sock.h> /* for struct sock */ +#include <asm/segment.h> /* for get_fs_long and put_fs_long */ + +#include "common.h" @@ -24003,18 +24159,32 @@ +} + + -+struct atm_vcc *alloc_atm_vcc(void) ++/* Handler for sk->destruct, invoked by sk_free() */ ++static void atm_free_sock(struct sock *sk) ++{ ++ kfree(sk->protinfo.af_atm); ++} ++ ++ ++struct sock *alloc_atm_vcc_sk(int family) +{ ++ struct sock *sk; + struct atm_vcc *vcc; + -+ vcc = kmalloc(sizeof(*vcc),GFP_KERNEL); -+ if (!vcc) return NULL; ++ sk = sk_alloc(family, GFP_KERNEL, 1); ++ if (!sk) return NULL; ++ vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL); ++ if (!vcc) { ++ sk_free(sk); ++ return NULL; ++ } ++ sk->destruct = atm_free_sock; + memset(vcc,0,sizeof(*vcc)); + if (nodev_vccs) nodev_vccs->prev = vcc; + vcc->prev = NULL; + vcc->next = nodev_vccs; + nodev_vccs = vcc; -+ return vcc; ++ return sk; +} + + @@ -24031,10 +24201,10 @@ +} + + -+void free_atm_vcc(struct atm_vcc *vcc) ++void free_atm_vcc_sk(struct sock *sk) +{ -+ unlink_vcc(vcc,NULL); -+ kfree(vcc); ++ unlink_vcc(sk->protinfo.af_atm,NULL); ++ sk_free(sk); +} + + @@ -24064,7 +24234,7 @@ +EXPORT_SYMBOL(shutdown_atm_dev); +EXPORT_SYMBOL(bind_vcc); --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/resources.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/resources.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,32 @@ +/* net/atm/resources.h - ATM-related resources */ + @@ -24082,8 +24252,8 @@ +extern struct atm_vcc *nodev_vccs; /* VCCs not linked to any device */ + + -+struct atm_vcc *alloc_atm_vcc(void); -+void free_atm_vcc(struct atm_vcc *vcc); ++struct sock *alloc_atm_vcc_sk(int family); ++void free_atm_vcc_sk(struct sock *sk); + + +#ifdef CONFIG_PROC_FS @@ -24099,7 +24269,7 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/signaling.c Sun Nov 1 15:31:53 1998 ++++ work/net/atm/signaling.c Tue Feb 9 15:49:58 1999 @@ -0,0 +1,252 @@ +/* net/atm/signaling.c - ATM signaling */ + @@ -24145,10 +24315,10 @@ + + while (!sigd) { +#ifdef WAIT_FOR_DEMON -+ if (silence < jiffies) { ++ if (time_after(jiffies, silence) || silence == 0) { + printk(KERN_INFO "atmsvc: waiting for signaling demon " + "...\n"); -+ silence = jiffies+30*HZ; ++ silence = (jiffies+30*HZ)|1; + } + sleep_on(&sigd_sleep); +#else @@ -24354,7 +24524,7 @@ + return 0; +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/signaling.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/signaling.h Tue Feb 9 18:09:24 1999 @@ -0,0 +1,25 @@ +/* net/atm/signaling.h - ATM signaling */ + @@ -24382,8 +24552,8 @@ + +#endif --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/svc.c Sun Nov 1 15:31:53 1998 -@@ -0,0 +1,387 @@ ++++ work/net/atm/svc.c Tue Feb 9 15:49:58 1999 +@@ -0,0 +1,388 @@ +/* net/atm/svc.c - ATM SVC sockets */ + +/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ @@ -24471,17 +24641,18 @@ + +static int svc_release(struct socket *sock,struct socket *peer) +{ -+ struct atm_vcc *vcc = ATM_SD(sock); ++ struct atm_vcc *vcc; + ++ if (!sock->sk) return 0; ++ vcc = ATM_SD(sock); + DPRINTK("svc_release %p\n",vcc); -+ if (!vcc) return 0; + vcc->flags &= ~ATM_VF_READY; -+ atm_release_vcc(vcc,0); ++ atm_release_vcc_sk(sock->sk,0); + svc_disconnect(vcc); + /* VCC pointer is used as a reference, so we must not free it + (thereby subjecting it to re-use) before all pending connections + are closed */ -+ free_atm_vcc(vcc); ++ free_atm_vcc_sk(sock->sk); + return 0; +} + @@ -24742,7 +24913,7 @@ + int error; + + sock->ops = &svc_proto_ops; -+ error = atm_create(sock,protocol); ++ error = atm_create(sock,protocol,AF_ATMSVC); + if (error) return error; + ATM_SD(sock)->callback = svc_callback; + ATM_SD(sock)->local.sas_family = AF_ATMSVC; @@ -24772,7 +24943,7 @@ + } +} --- /dev/null Tue Jan 1 05:00:00 1980 -+++ work/net/atm/tunable.h Sun Nov 1 15:31:53 1998 ++++ work/net/atm/tunable.h Tue Feb 9 15:49:58 1999 @@ -0,0 +1,26 @@ +/* net/atm/tunable.h - Tunable parameters of ATM support */ + @@ -24801,7 +24972,7 @@ + +#endif --- ref/net/core/skbuff.c Tue Sep 15 07:52:10 1998 -+++ work/net/core/skbuff.c Sun Nov 1 15:31:53 1998 ++++ work/net/core/skbuff.c Tue Feb 9 15:49:58 1999 @@ -61,6 +61,10 @@ #include <asm/uaccess.h> #include <asm/system.h> diff -ur --new-file old/atm/doc/usage.tex new/atm/doc/usage.tex --- old/atm/doc/usage.tex Sat Dec 5 01:27:24 1998 +++ new/atm/doc/usage.tex Tue Feb 9 17:54:34 1999 @@ -1,7 +1,7 @@ %%def%:= %:\begin{verbatim} -%:Usage instructions - ATM on Linux, release 0.52 +%:Usage instructions - ATM on Linux, release 0.53 %:------------------------------------------------- %: %:\end{verbatim} @@ -38,7 +38,7 @@ \title{ATM on Linux \\ User's guide \\ - Release 0.52 (alpha)} + Release 0.53 (alpha)} \author{Werner Almesberger \\ {\tt Werner.Almesberger@epfl.ch} \\ \\ @@ -82,9 +82,9 @@ In order to install this package, you need \begin{itemize} \item the package itself - \url{ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.52.tar.gz} - \item the Linux kernel, version 2.1.126, e.g. from - \url{ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.1.126.tar.gz} + \url{ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.53.tar.gz} + \item the Linux kernel, version 2.2.1, e.g. from + \url{ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.2.1.tar.gz} \item Perl, version 4 or 5 \item if you want memory debugging: MPR version 1.6, e.g. from \url{ftp://sunsite.unc.edu/pub/Linux/devel/lang/c/mpr-1.6.tar.gz} @@ -99,13 +99,13 @@ distribution: \begin{verbatim} -tar xfz atm-0.52.tar.gz +tar xfz atm-0.53.tar.gz \end{verbatim} and the kernel source: \begin{verbatim} -tar xfz linux-2.1.126.tar.gz +tar xfz linux-2.2.1.tar.gz \end{verbatim} Finally, you can extract the ATM-related patches: @@ -120,9 +120,9 @@ \begin{description} \item[\path{atm/}] Documentation in ASCII format, kernel patch, top-level \name{Makefile}, and distribution scripts - \item[\path{atm/sigd/}] UNI 3.0, UNI 3.1, and UNI 4.0 signaling demon: + \item[\path{atm/sigd/}] UNI 3.0, UNI 3.1, and UNI 4.0 signaling demon: \name{atmsigd} - \item[\path{atm/sigd.new/}] Experimental version: \name{atmsigd.new} + \item[\path{atm/sigd.old/}] Older version: \name{atmsigd.old} \item[\path{atm/saal/}] Signaling AAL library (SSCOP, SSCF, and SAAL) \item[\path{atm/qgen/}] Q.2931-style message handling \item[\path{atm/ilmid/}] ILMI address registration demon: \name{ilmid} @@ -134,6 +134,7 @@ \name{ttcp\_atm}, \name{window} \item[\path{atm/arpd/}] ATMARP tools and demon: \name{atmarp}, \name{atmarpd} \item[\path{atm/led/}] LAN Emulation demon: \name{zeppelin} + \item[\path{atm/led.new/}] Experimental version: \name{zeppelin.new} \item[\path{atm/lane/}] LAN Emulation servers: \name{bus}, \name{lecs}, \name{les} \item[\path{atm/mpoad/}] Multi-Protocol Over ATM demon: \name{mpcd} diff -ur --new-file old/atm/doc/usage.txt new/atm/doc/usage.txt --- old/atm/doc/usage.txt Sat Dec 5 01:58:08 1998 +++ new/atm/doc/usage.txt Tue Feb 9 18:22:36 1999 @@ -1,4 +1,4 @@ -Usage instructions - ATM on Linux, release 0.52 +Usage instructions - ATM on Linux, release 0.53 ------------------------------------------------- For updates of ATM on Linux, please check the Web page at @@ -17,9 +17,9 @@ In order to install this package, you need - the package itself - ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.52.tar.gz - - the Linux kernel, version 2.1.126, e.g. from - ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.1.126.tar.gz + ftp://lrcftp.epfl.ch/pub/linux/atm/dist/atm-0.53.tar.gz + - the Linux kernel, version 2.2.1, e.g. from + ftp://ftp.kernel.org/pub/linux/kernel/v2.1/linux-2.2.1.tar.gz - Perl, version 4 or 5 - if you want memory debugging: MPR version 1.6, e.g. from ftp://sunsite.unc.edu/pub/Linux/devel/lang/c/mpr-1.6.tar.gz @@ -33,11 +33,11 @@ all the files listed above there. Then extract the ATM on Linux distribution: -tar xfz atm-0.52.tar.gz +tar xfz atm-0.53.tar.gz and the kernel source: -tar xfz linux-2.1.126.tar.gz +tar xfz linux-2.2.1.tar.gz Finally, you can extract the ATM-related patches: @@ -49,7 +49,7 @@ atm/ Documentation in ASCII format, kernel patch, top-level Makefile, and distribution scripts atm/sigd/ UNI 3.0, UNI 3.1, and UNI 4.0 signaling demon: atmsigd - atm/sigd.new/ Experimental version: atmsigd.new + atm/sigd.old/ Older version: atmsigd.old atm/saal/ Signaling AAL library (SSCOP, SSCF, and SAAL) atm/qgen/ Q.2931-style message handling atm/ilmid/ ILMI address registration demon: ilmid @@ -59,6 +59,7 @@ ttcp_atm, window atm/arpd/ ATMARP tools and demon: atmarp, atmarpd atm/led/ LAN Emulation demon: zeppelin + atm/led.new/ Experimental version: zeppelin.new atm/lane/ LAN Emulation servers: bus, lecs, les atm/mpoad/ Multi-Protocol Over ATM demon: mpcd atm/aqd/ Arequipa demon: aqpvc, arequipad diff -ur --new-file old/atm/led/conn.c new/atm/led/conn.c --- old/atm/led/conn.c Sat Dec 5 01:35:52 1998 +++ new/atm/led/conn.c Tue Feb 9 17:12:00 1999 @@ -234,7 +234,6 @@ } for(conn=connlist;conn;conn=next) { next=conn->next; - close(conn->fd); if (conn->conn_info) mem_free(EINST, conn->conn_info); close(conn->fd); diff -ur --new-file old/atm/led/kernel_itf.c new/atm/led/kernel_itf.c --- old/atm/led/kernel_itf.c Tue Aug 11 16:53:57 1998 +++ new/atm/led/kernel_itf.c Tue Feb 9 17:12:01 1999 @@ -109,7 +109,15 @@ memset(mesg, 0, sizeof(struct atmlec_msg) + datalen); mesg->type = type; - if (type != l_config) { + + if (type == l_config) + memcpy(&mesg->content.config, config, sizeof(struct atmlec_config_msg)); + else if (type == l_should_bridge) { + memcpy(mesg->content.proxy.mac_addr, mac_addr, ETH_ALEN); + mesg->content.proxy.tran_id = flag; + mesg->content.proxy.lec_id = no_source_le_narp; /* cheat with arguments */ + } + else { if (mac_addr) memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN); if (atm_addr) @@ -117,8 +125,7 @@ mesg->content.normal.flag = flag; mesg->content.normal.targetless_le_arp = targetless_le_arp; /* LANE2 */ mesg->content.normal.no_source_le_narp = no_source_le_narp; - } else - memcpy(&mesg->content.config, config, sizeof(struct atmlec_config_msg)); + } mesg->sizeoftlvs = datalen; if (datalen > 0) @@ -167,6 +174,8 @@ return "CONFIG"; case l_associate_req: return "LANE2_ASSOCIATE_REQ"; + case l_should_bridge: + return "SHOULD_BRIDGE"; default: return "UNKNOWN MSG TYPE"; } diff -ur --new-file old/atm/led/lec_arp.c new/atm/led/lec_arp.c --- old/atm/led/lec_arp.c Tue Aug 11 16:53:57 1998 +++ new/atm/led/lec_arp.c Tue Feb 9 17:12:01 1999 @@ -77,6 +77,10 @@ SVC_SETUP_CALLBACK svc_setup_callback; void (*associate_req_callback) (HANDLE lc_elan_handle, int sizeoftlvs); /* LANE2 */ + void (*proxy_arp_rsp_callback) (HANDLE lc_elan_handle, + UINT8 *mac_addr, UINT32 tran_id, + UINT16 lec_id, UINT8 *atm_addr); + void (*topo_req_xmt_callback)(HANDLE lc_elan_handle, UINT32 flag); LA_ELAN_LIST elan_list; } LA_CONTEXT; @@ -141,11 +145,39 @@ } } +static void +kernel_proxy_arp_rsp_callback(struct atmlec_msg *mesg) +{ + LA_ELAN_CONTEXT *p_elan; + + utl_list_traverse(lec_arp_context.elan_list, p_elan) { + lec_arp_context.proxy_arp_rsp_callback(p_elan->lc_elan_handle, + mesg->content.proxy.mac_addr, + mesg->content.proxy.tran_id, + mesg->content.proxy.lec_id, + mesg->content.proxy.atm_addr); + } +} + +static void +kernel_topo_req_xmt_callback(struct atmlec_msg *mesg) +{ + LA_ELAN_CONTEXT *p_elan; + + utl_list_traverse(lec_arp_context.elan_list, p_elan) { + lec_arp_context.topo_req_xmt_callback(p_elan->lc_elan_handle, + mesg->content.normal.flag); + } +} + STATUS la_create (HANDLE lc_handle, ARP_XMT_CALLBACK arp_xmt_callback, FLUSH_XMT_CALLBACK flush_xmt_callback, SVC_SETUP_CALLBACK svc_setup_callback, void (*associate_req_callback)(HANDLE lc_elan_handle, int sizeoftlvs), /* LANE2 */ + void (*proxy_arp_rsp_callback)(HANDLE lc_elan_handle, UINT8 *mac_addr, + UINT32 tran_id, UINT16 lec_id, UINT8 *atm_addr), + void (*topo_req_xmt_callback)(HANDLE lc_elan_handle, UINT32 flag), HANDLE *p_la_handle) { lec_arp_context.lc_handle = lc_handle; @@ -153,12 +185,16 @@ lec_arp_context.flush_xmt_callback = flush_xmt_callback; lec_arp_context.svc_setup_callback = svc_setup_callback; lec_arp_context.associate_req_callback = associate_req_callback; /* LANE2 */ + lec_arp_context.proxy_arp_rsp_callback = proxy_arp_rsp_callback; + lec_arp_context.topo_req_xmt_callback = topo_req_xmt_callback; utl_list_init(lec_arp_context.elan_list); kernel_register_callback(l_arp_xmt, kernel_arp_xmt_callback); kernel_register_callback(l_svc_setup, kernel_svc_setup_xmt_callback); kernel_register_callback(l_associate_req, kernel_associate_req_callback); + kernel_register_callback(l_should_bridge, kernel_proxy_arp_rsp_callback); + kernel_register_callback(l_topology_change, kernel_topo_req_xmt_callback); *p_la_handle = (HANDLE)&lec_arp_context; @@ -249,6 +285,7 @@ conf_mesg.flush_timeout = flush_timeout; conf_mesg.path_switching_delay = path_switching_delay; conf_mesg.lane_version = lane_version_number; /* LANE2 */ + conf_mesg.is_proxy = (proxy_flag == TRUE) ? 1 : 0; kernel_sendmsg(l_config, NULL, NULL, &conf_mesg, 0, NULL, 0, 0, 0); } diff -ur --new-file old/atm/led/lec_arp.h new/atm/led/lec_arp.h --- old/atm/led/lec_arp.h Tue Aug 11 16:53:57 1998 +++ new/atm/led/lec_arp.h Tue Feb 9 17:12:01 1999 @@ -313,6 +313,13 @@ SVC_SETUP_CALLBACK svc_setup_callback, void (*associate_req_callback)(HANDLE lc_elan_handle, int sizeoftlvs), /* LANE2 */ + void (*proxy_arp_rsp_callback)(HANDLE lc_elan_handle, + UINT8 *mac_addr, + UINT32 tran_id, + UINT16 lec_id, + UINT8 *atm_addr), + void (*topo_req_xmt_callback)(HANDLE lc_elan_handle, + UINT32 flag), HANDLE *p_la_handle); /*++ diff -ur --new-file old/atm/led/lec_ctrl.c new/atm/led/lec_ctrl.c --- old/atm/led/lec_ctrl.c Sat Dec 5 01:36:13 1998 +++ new/atm/led/lec_ctrl.c Tue Feb 9 17:12:04 1999 @@ -1478,7 +1478,7 @@ *tlvdata++ = 0x00; *tlvdata++ = 0xa0; *tlvdata++ = 0x3e; *tlvdata++ = 0x2c; #endif - *(UINT32 *)tlvdata = TLV_X5_ADJUSTEMENT; + *(UINT32 *)tlvdata = hton32(TLV_X5_ADJUSTEMENT); tlvdata += sizeof(TLV_X5_ADJUSTEMENT); /* should be 4 */ *tlvdata++ = 0x00; /* length 0 */ frame_size += 5; @@ -1494,7 +1494,7 @@ *tlvdata++ = 0x00; *tlvdata++ = 0xa0; *tlvdata++ = 0x3e; *tlvdata++ = 0x11; #endif - *(UINT32 *)tlvdata = TLV_L3_ADDRESS; + *(UINT32 *)tlvdata = hton32(TLV_L3_ADDRESS); tlvdata += sizeof(TLV_L3_ADDRESS); *tlvdata++ = l3_address_size; memcpy(tlvdata, &l3_addr, l3_address_size); @@ -1632,7 +1632,7 @@ *tlvdata++ = 0x00; *tlvdata++ = 0xa0; *tlvdata++ = 0x3e; *tlvdata++ = 0x2c; #endif - *(UINT32 *)tlvdata = TLV_X5_ADJUSTEMENT; + *(UINT32 *)tlvdata = hton32(TLV_X5_ADJUSTEMENT); tlvdata += sizeof(TLV_X5_ADJUSTEMENT); /* should be 4 */ *tlvdata++ = 0x00; /* length 0 */ frame_size += 5; @@ -1648,7 +1648,7 @@ *tlvdata++ = 0x00; *tlvdata++ = 0xa0; *tlvdata++ = 0x3e; *tlvdata++ = 0x11; #endif - *(UINT32 *)tlvdata = TLV_L3_ADDRESS; + *(UINT32 *)tlvdata = hton32(TLV_L3_ADDRESS); tlvdata += sizeof(TLV_L3_ADDRESS); *tlvdata++ = l3_address_size; memcpy(tlvdata, &l3_addr, l3_address_size); @@ -2087,6 +2087,75 @@ } +/*++ +* l_should_bridge msg from kernel causes this function to be called. +* We are acting as a bridge and know mac_addr is behind us. +* +* ================= +* = proxy_arp_rsp = +* ================= +--*/ +static void proxy_arp_rsp(HANDLE lc_elan_handle, UINT8 *mac_addr, + UINT32 tran_id, UINT16 lec_id, UINT8 *atm_addr) +{ + LE_ARP_FRAME *frame; + size_t framelength; + LC_ELAN_CONTEXT *p_elan = (LC_ELAN_CONTEXT *) lc_elan_handle; + + framelength = sizeof(LE_ARP_FRAME) + p_elan->lec_state.sizeoftlvs; + frame = (LE_ARP_FRAME *)os_mem_alloc(framelength); + memset(frame, 0 , framelength); + + /* construct frame with the parameters supplied by requestor */ + lc_ctrl_hdr_make(lc_elan_handle, &frame->hdr, LE_ARP_RSP); + frame->hdr.tran_id = tran_id; + frame->hdr.req_lec_id = lec_id; + frame->hdr.flags = hton16(LE_FLAG_REMOTE_ADDR); + frame->target_lan_dst.tag = hton16(TAG_MAC_ADDR); + ESI_COPY(mac_addr, frame->target_lan_dst.mac_addr); + ATM_COPY (p_elan->lec_state.c1n_my_atm_addr, frame->target_atm_addr); + memcpy(&frame->src_atm_addr, atm_addr, ATM_ESA_LEN); + + /* add TLVs, if any */ + if (p_elan->lec_state.sizeoftlvs != 0) { + memcpy(frame + 1, p_elan->lec_state.tlvs, p_elan->lec_state.sizeoftlvs); + frame->tlv_count++; + } + + cm_sap_xmt_vc(p_elan->ctrl_direct_conn_handle, + frame, framelength, + USER_DATA_INTERNAL, NULL); + + os_mem_dealloc(frame); + return; +} + + +/*++ +* Kernel sent a Configuration Bridge PDU to BUS and asks us to send a +* respective LE_TOPOLOGY_REQUEST to LES +* +* ==================== +* = lc_topo_req_xmt = +* ==================== +--*/ +static void lc_topo_req_xmt (HANDLE lc_elan_handle, + UINT32 flag) +{ + LE_TOPOLOGY_FRAME frame; + LC_ELAN_CONTEXT *p_elan = (LC_ELAN_CONTEXT *) lc_elan_handle; + + memset(&frame, 0, sizeof(LE_TOPOLOGY_FRAME)); + lc_ctrl_hdr_make(lc_elan_handle, &frame.hdr, LE_TOPOLOGY_REQ); + + if (flag) + frame.hdr.flags = hton16(LE_FLAG_TOPOLOGY_CHANGE); + + cm_sap_xmt_vc(p_elan->ctrl_direct_conn_handle, &frame, + sizeof(LE_TOPOLOGY_FRAME), USER_DATA_INTERNAL, NULL); + + return; +} /*++ * ==================== @@ -2162,6 +2231,8 @@ lc_flush_xmt, lc_svc_setup, associate_req, /* LANE2 */ + proxy_arp_rsp, + lc_topo_req_xmt, &p_context->la_handle); if (status != STATUS_K_SUCCESS) { @@ -2413,7 +2484,7 @@ p_elan->lec_state.c20_le_arp_response_time, p_elan->lec_state.c21_flush_timeout, p_elan->lec_state.c22_path_switching_delay, - (v2_capable)? 2:1); + (v2_capable)? 2 : 1); /* Register as a client to the Address Registration module. */ @@ -3245,12 +3316,12 @@ /* LANE2: If LES is not v2 capable we can't be either */ - if (frame->hdr.flags & LE_FLAG_V2_REQUIRED && + if (frame->hdr.flags & hton16(LE_FLAG_V2_REQUIRED) && p_elan->lec_state.c29_v2_capable == FALSE) { EVENT (EM_NERR, ("LES requires LANEv2 but I'm not v2 capable\n")); return; } - if (!frame->hdr.flags & LE_FLAG_V2_REQUIRED) { /* LES not v2 */ + if (!frame->hdr.flags & hton16(LE_FLAG_V2_REQUIRED)) { /* LES not v2 */ p_elan->lec_state.c29_v2_capable = FALSE; p_elan->lec_state.c32_selective_mcast = FALSE; } @@ -3487,6 +3558,12 @@ user_data, NULL); break; + } else { /* check if our bridging tables knows this MAC */ + if (p_elan->lec_state.c4_proxy_flag == TRUE) + kernel_sendmsg(l_should_bridge, frame->target_lan_dst.mac_addr, + NULL, NULL, frame->hdr.tran_id, + NULL, 0, 0, frame->hdr.req_lec_id); + break; } break; diff -ur --new-file old/atm/led/main.c new/atm/led/main.c --- old/atm/led/main.c Sat Dec 5 01:36:26 1998 +++ new/atm/led/main.c Tue Feb 9 17:12:04 1999 @@ -271,7 +271,7 @@ printf("Usage: %s [-c LECS_address]|[-s LES_address] [-e esi] [-n VLAN_name]" " [-m mesg_mask] [-l listen_address] [-i interface_number]" " [-q qos_spec] [-1] [-2] [-f Fore specific name]" - " [-t 1516|1580|4544|9234|18190]\n", progname); + " [-t 1516|1580|4544|9234|18190] [-p]\n", progname); } static int @@ -372,7 +372,7 @@ memset(foreId, '\0', FORE_ID_LEN); memset(&preferred_les, 0, sizeof(ADDR_ATM)); while(poll_ret != -1) { - poll_ret = getopt(argc, argv, "c:e:n:s:m:l:i:q:12f:t:"); + poll_ret = getopt(argc, argv, "c:e:n:s:m:l:i:q:12pf:t:"); switch(poll_ret) { case 'c': if (atm_set) { @@ -454,6 +454,9 @@ case '2': spec_version = 2; v2_capable = TRUE; + break; + case 'p': + proxy_flag = TRUE; break; case 'f': memcpy (foreId, optarg, FORE_ID_LEN); diff -ur --new-file old/atm/led/zeppelin.8 new/atm/led/zeppelin.8 --- old/atm/led/zeppelin.8 Sat Dec 5 01:36:31 1998 +++ new/atm/led/zeppelin.8 Tue Feb 9 17:12:05 1999 @@ -1,15 +1,20 @@ -.TH zeppelin 8 "Dec 2, 1998" "Linux" "Maintenance Commands" +.TH zeppelin 8 "Feb 6, 1998" "Linux" "Maintenance Commands" .SH NAME zeppelin \- ATM LAN Emulation client demon (LED) Zeppelin .SH SYNOPSIS .B zeppelin -.RB [ \-c\ \fILECS_address\fP ] | -.RB [ \-s\ \fILES_address\fP ] +.RB [ \-c\ \fILECS_address\fP\ |\ \-s\ \fILES_address\fP ] .RB [ \-e\ \fIesi\fP ] .RB [ \-n\ \fIVLAN_name\fP ] .RB [ \-m\ \fImesg_mask\fP ] +.RB [ \-l\ \fIlisten_address\fP ] .RB [ \-i\ \fIinterface_number\fP ] .RB [ \-q\ \fIqos_spec\fP ] +.RB [ \-1\ ] +.RB [ \-2\ ] +.RB [ \-t\ \fI1516|1580|4544|9234|18190\fP ] +.RB [ \-p\ ] +.RB [ \-f\ \fIFore_specific_name\fP ] .SH DESCRIPTION A LAN Emulation Client is an entity in an ATM endstation that performs data forwarding, address resolution and other control functions. It @@ -51,9 +56,9 @@ signalling. Use this if you are running more than one client or a set of LE servers. .IP \fB\-i\ \fIinterface_number\fP -Linux LEC supports up to 4 network interfaces. This number tells +Linux LEC supports up to 16 network interfaces. This number tells zeppelin to which of these to attach. Network interfaces are -numbered from "lec0" to "lec3". +numbered from "lec0" to "lec15". .IP \fB\-t\ \fIMTU\fP The MTU of ELAN to join. You need to also use \fBifconfig(8)\fP to set the MTU of the LANE interface. @@ -61,12 +66,17 @@ Run as LANEv1 client. This is the default. .IP \fB\-2\fP Run as LANEv2 client. This is required by MPOA. +.IP \fB\-p\fP +Enable proxy. When started with this option, it is possible to bridge +packets between ATM and Ethernet. That is, you can use LANE interfaces +with normal bridging. See the Bridging mini-Howto for more info. .IP \fB\-f\ \fIFore\ specific\ name\fP The LANE servers on Fore ATM switches can display a special name if a client can supply one. This name shows with command \'conf lane les show advanced\'. .SH BUGS -Supports only IEEE 802.3 / Ethernet type of ELANs. +Supports only IEEE 802.3 / Ethernet type of ELANs. Please report any +new bugs to Heikki Vatiainen <hessu@cs.tut.fi> .PP John Bonham died 1980 and Led Zeppelin broke. .SH AUTHOR diff -ur --new-file old/atm/led.new/COPYRIGHT.TUT new/atm/led.new/COPYRIGHT.TUT --- old/atm/led.new/COPYRIGHT.TUT Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/COPYRIGHT.TUT Sat Feb 6 14:49:41 1999 @@ -0,0 +1,21 @@ +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Tampere University of Technology - Telecommunications Laboratory + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ diff -ur --new-file old/atm/led.new/Makefile new/atm/led.new/Makefile --- old/atm/led.new/Makefile Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/Makefile Tue Feb 9 17:19:11 1999 @@ -0,0 +1,10 @@ +LIBS=-latm -latmd +OBJS=join.o conn.o main.o address.o frames.o display.o kernel.c +BOOTPGMS=zeppelin.new +MAN8=zeppelin.new.8 +CFLAGS_PRIVATE= + +include ../Rules.make + +zeppelin.new:$(OBJS) + $(CC) $(LDFLAGS) -o $(BOOTPGMS) $(OBJS) $(LIBD) $(LDLIBS) $(LIBS) diff -ur --new-file old/atm/led.new/address.c new/atm/led.new/address.c --- old/atm/led.new/address.c Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/address.c Sat Feb 6 15:11:34 1999 @@ -0,0 +1,92 @@ +/* address.c - functions to query ESI and local ATM address from kernel */ + +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Copyright (c) 1996 + * Tampere University of Technology - Telecommunications Laboratory + * All rights reserved. + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#include <sys/ioctl.h> +#include <unistd.h> +#include <errno.h> + +#include <atm.h> +#include <linux/atmdev.h> +#include <atmd.h> + +#include "address.h" + +#define COMPONENT "address.c" + +/* Gets End System Identifier (MAC address) from kernel + * Returns < 0 for error + */ +int addr_getesi(unsigned char *mac_addr) +{ + int fd, retval; + struct atmif_sioc req; + + fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); + if (fd < 0) { + diag(COMPONENT, DIAG_ERROR, "addr_getesi: socket: %s\n", + strerror(errno)); + return -1; + } + req.number = 0; + req.arg = mac_addr; + req.length = ESI_LEN; + retval = ioctl(fd, ATM_GETESI, &req); + if (retval < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_GETESI: %s\n", + strerror(errno)); + close(fd); + + return retval; +} + +/* Gets our ATM address from kernel. Useful for binding listen sockets. + * Returns < 0 for error + */ +int get_listenaddr(unsigned char *atm_addr) +{ + int fd, retval; + struct atmif_sioc req; + struct sockaddr_atmsvc listen_addr; + + fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); + if (fd < 0) { + diag(COMPONENT, DIAG_ERROR, "get_listenaddr: socket: %s\n", + strerror(errno)); + return -1; + } + req.number = 0; + req.arg = &listen_addr; + req.length = sizeof(struct sockaddr_atmsvc); + retval = ioctl(fd, ATM_GETADDR, &req); + if (retval < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_GETADDR: %s\n", + strerror(errno)); + close(fd); + + memcpy(atm_addr, listen_addr.sas_addr.prv, ATM_ESA_LEN); + + return retval; +} diff -ur --new-file old/atm/led.new/address.h new/atm/led.new/address.h --- old/atm/led.new/address.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/address.h Sat Feb 6 15:06:08 1999 @@ -0,0 +1,31 @@ +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Tampere University of Technology - Telecommunications Laboratory + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef ADDRESS_H +#define ADDRESS_H + +int addr_getesi(unsigned char *mac_addr); +int get_listenaddr(unsigned char *atm_addr); + +#endif /* ADDRESS_H */ diff -ur --new-file old/atm/led.new/conn.c new/atm/led.new/conn.c --- old/atm/led.new/conn.c Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/conn.c Sat Feb 6 21:21:58 1999 @@ -0,0 +1,899 @@ +/* conn.c - functions for handling SVCs, create, accept, send, etc. */ + +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Copyright (c) 1996 + * Tampere University of Technology - Telecommunications Laboratory + * All rights reserved. + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> + +#include <atm.h> +#include <atmsap.h> +#include <linux/atmlec.h> + +#include <atmd.h> + +#include "conn.h" +#include "display.h" +#include "lec.h" +#include "frames.h" +#include "kernel.h" + +#define COMPONENT "conn.c" + +/* status */ +#define CONNECTED 42 /* Operational socket */ +#define CONNECTING 43 /* Non-blocking socket, not yet connected */ + +/* type */ +#define WEMADE 7 +#define THEYMADE 8 +#define LISTENING 9 +#define KERNEL_SOCK 10 + +static Conn_t *connlist = NULL; + +/* Local protos */ +static void list_remove_conn(Conn_t *conn); +static Conn_t *list_add_conn(unsigned char *dest_atm_addr); +static Conn_t *conn_already_exists(unsigned char *atm_addr, Conn_t *current); +static const char *get_type_string(int type); +static int maxmtu2maxsdu(uint8_t mtu); + +static void delete_addr(unsigned char *atm_addr) +{ + struct atmlec_msg msg; + + msg.type = l_addr_delete; + memcpy(msg.content.normal.atm_addr, atm_addr, ATM_ESA_LEN); + msg_to_kernel(&msg, sizeof(struct atmlec_msg)); + + return; +} + +/* Checks if connection to atm_addr already exists. Does not + * check against current though. + * Returns NULL for no connection, or Conn_t of existing connection. + */ +static Conn_t *conn_already_exists(unsigned char *atm_addr, Conn_t *current) +{ + Conn_t *conn; + + conn = connlist; + while (conn) { + if (conn != current && + conn->type != LISTENING && + conn->type != KERNEL_SOCK) { + if (memcmp(conn->atm_address, atm_addr, ATM_ESA_LEN) == 0) + return conn; + } + conn = conn->next; + } + + return NULL; +} + +/* Initializes and fills in *sap and *qos according to Blli + * code point value specified in conn_type. + */ +void init_conn_params(struct atm_sap *sap, struct atm_qos *qos, + uint16_t conn_type) +{ + + unsigned int bllicode; + int i, sdu; + char qos_text[MAX_ATM_QOS_LEN + 1]; + + diag(COMPONENT, DIAG_DEBUG, "init_conn_params, conn_type %x\n", conn_type); + + memset(qos, 0, sizeof(struct atm_qos)); + memset(sap, 0, sizeof(struct atm_sap)); + qos->aal = ATM_AAL5; + + /* Set the forward and backward Max CPCS-SDU Size */ + switch(conn_type) { + case CONTROL_CONN: + qos->rxtp.max_sdu = 1516; + qos->txtp.max_sdu = 1516; + break; + case DATA_DIRECT_CONN: + case MCAST_CONN: + sdu = maxmtu2maxsdu(lec_params.c3_max_frame_size); + qos->rxtp.max_sdu = sdu; + qos->txtp.max_sdu = sdu; + break; + default: + diag(COMPONENT, DIAG_ERROR, "unknown conn_type %x\n", conn_type); + break; + } + + /* ATM User Cell Rate/ATM Traffic Descriptor. */ + qos->txtp.traffic_class = ATM_UBR; + qos->rxtp.traffic_class = ATM_UBR; + + if (get_verbosity(COMPONENT) >= DIAG_DEBUG) { + if (qos2text(qos_text, sizeof(qos_text), qos, 0) < 0) + sprintf(qos_text, "<bad qos>"); + diag(COMPONENT, DIAG_DEBUG, "init_conn_params, QoS '%s'\n", qos_text); + } + + /* No Broadband High Layer Information in LANE. */ + sap->bhli.hl_type = ATM_HL_NONE; + + /* Broadband Lower Layer Information. */ + sap->blli[0].l3_proto = ATM_L3_TR9577; + sap->blli[0].l3.tr9577.ipi = NLPID_IEEE802_1_SNAP; + sap->blli[0].l3.tr9577.snap[0] = 0x00; + sap->blli[0].l3.tr9577.snap[1] = 0xa0; + sap->blli[0].l3.tr9577.snap[2] = 0x3e; + bllicode = htons(conn_type); + sap->blli[0].l3.tr9577.snap[3] = (unsigned char)(0xff&bllicode); + sap->blli[0].l3.tr9577.snap[4] = (unsigned char)(0xff&(bllicode>>8)); + + if (get_verbosity(COMPONENT) == DIAG_DEBUG) { + for(i=0; i < 5; i++) { + diag(COMPONENT, DIAG_DEBUG, "snap[%d] = 0x%2.2x", + i, sap->blli[0].l3.tr9577.snap[i]); + } + } + + return; +} + +/* Returns != 0 if blli indicates Data Direct + * connection + */ +static int is_data_direct(struct atm_blli *blli) +{ + return (blli->l3.tr9577.snap[4] == DATA_DIRECT_CONN); +} + +/* Creates a socket with the specified parameters. + * If listen_addr is non NULL binds to it. + * Returns < 0 for error or new socket descriptor. + */ +static int get_socket(struct sockaddr_atmsvc *listen_addr, + struct atm_sap *sap, struct atm_qos *qos) +{ + int s, ret; + + s = socket(PF_ATMSVC, SOCK_DGRAM, 0); + if (s < 0) { + diag(COMPONENT, DIAG_ERROR, "socket creation failure: %s\n", + strerror(errno)); + return -1; + } + diag(COMPONENT, DIAG_DEBUG, "get_socket: got fd %d\n", s); + + if (setsockopt(s, SOL_ATM, SO_ATMQOS, qos, sizeof(struct atm_qos)) < 0) { + diag(COMPONENT, DIAG_ERROR, "get_socket: setsockopt SO_ATMQOS: %s\n", strerror(errno)); + close(s); + return -1; + } + if (setsockopt(s, SOL_ATM, SO_ATMSAP, sap, sizeof(struct atm_sap)) < 0) { + diag(COMPONENT, DIAG_ERROR, "setup_svc setsockop(SO_ATMSAP)\n"); + close(s); + return -1; + } + + /* Bind the socket to our local address */ + if (listen_addr == NULL) + return s; + ret = bind(s, (struct sockaddr *)listen_addr, sizeof(struct sockaddr_atmsvc)); + if (ret < 0) { + diag(COMPONENT, DIAG_ERROR, "bind error: %s\n", strerror(errno)); + close(s); + return -1; + } + + return s; +} + + +/* + * You need to check this if setup_svc() returns NULL + */ +#if 0 + if (is_data_direct(&sap->blli[0])) { + /* Try to remove possible entry in kernel */ + delete_addr(conn->atm_address); + } +#endif +/* Does an active open to dst_addr using pre-filled + * parameters in sap and qos. + * If listen_addr is non NULL, binds to it. + * Data direct SVCs are non-blocking, others block + * Returns NULL for error or new connections. + */ +Conn_t *setup_svc(struct sockaddr_atmsvc *dst_addr, + struct sockaddr_atmsvc *listen_addr, + struct atm_sap *sap, struct atm_qos *qos) +{ + Conn_t *conn; + int s, ret; + char buff[MAX_ATM_ADDR_LEN+1]; + + diag(COMPONENT, DIAG_DEBUG, "Outgoing call setup\n"); + + /* The code below is commented out due to the following scenario: + We have made a connection to another LEC and our address was + numerically lower than theirs (LANEv2 8.1.13). + The other end has also connected us, but we must not use that + VCC. + However, if the connection we made gets closed, we can not open + it again since a connection to the destination LEC already exists. + */ +#if 0 + /* We don't create connection to an entity where we already have + a connection. */ + if (conn_already_exists(dst_addr->sas_addr.prv, NULL) && + is_data_direct(&sap->blli[0])) + return NULL; +#endif + + dst_addr->sas_family = AF_ATMSVC; + listen_addr->sas_family = AF_ATMSVC; + + switch(sap->blli[0].l3.tr9577.snap[4]) { /* Kludge. Eh? */ + case CONTROL_CONN: + diag(COMPONENT, DIAG_DEBUG, "LE Control SVC setup\n"); + break; + case DATA_DIRECT_CONN: + diag(COMPONENT, DIAG_DEBUG, "Data direct 802.3\n"); + break; + case MCAST_CONN: + diag(COMPONENT, DIAG_DEBUG, "Multicast 802.3\n"); + break; + default: + diag(COMPONENT, DIAG_ERROR, "Unknown codepoint in svc setup\n"); + } + + s = get_socket(listen_addr, sap, qos); + if (s < 0) return NULL; + if (atm2text(buff, sizeof(buff), (struct sockaddr *)dst_addr, A2T_PRETTY | A2T_NAME | A2T_LOCAL) < 0) + sprintf(buff, "<Unknown ATM address>"); + diag(COMPONENT, DIAG_DEBUG, "Call to %s", buff); + + /* Make data direct SVCs non-blocking */ + if (is_data_direct(&sap->blli[0])) { + ret = fcntl(s, F_GETFL); + if (ret < 0) { + diag(COMPONENT, DIAG_ERROR, "fcntl(s, F_GETFL)\n"); + close(s); + } else if (fcntl(s, F_SETFL, ret|O_NONBLOCK) < 0) { + diag(COMPONENT, DIAG_ERROR, "fcntl(s, F_SETFL, x|O_NONBLOCK)\n"); + close(s); + return NULL; + } + } + + ret = connect(s, (struct sockaddr *)dst_addr, sizeof(struct sockaddr_atmsvc)); + if (ret < 0 && errno != EINPROGRESS) { + diag(COMPONENT, DIAG_ERROR, "connect error: %s\n", strerror(errno)); + close(s); + return NULL; + } + + conn = list_add_conn(dst_addr->sas_addr.prv); + diag(COMPONENT, DIAG_DEBUG, "Conn:%p\n", conn); + if (conn == NULL) { + close(s); + return NULL; + } + conn->fd = s; + conn->type = WEMADE; + conn->codepoint = sap->blli[0].l3.tr9577.snap[4]; + + if (is_data_direct(&sap->blli[0])) + conn->status = CONNECTING; + else + conn->status = CONNECTED; + + return conn; +} + +/* Creates listen socket for incoming data direct connections. + * Only for data direct, not for Control or Multicast listen sockets. + * Returns < 0 for error + */ +int create_data_listen(void) +{ + struct atm_sap sap; + struct atm_qos qos; + struct sockaddr_atmsvc addr; + + memset(&addr, 0, sizeof(struct sockaddr_atmsvc)); + memcpy(addr.sas_addr.prv, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + addr.sas_family = AF_ATMSVC; + init_conn_params(&sap, &qos, DATA_DIRECT_CONN); + + lec_params.data_listen = create_listensocket(&addr, &sap, &qos); + if (lec_params.data_listen == NULL) { + diag(COMPONENT, DIAG_FATAL, "Could not create listen socket for incoming Data Direct VCCs\n"); + return -1; + } + + return 0; +} + +/* Opens a non-blocking Data Direct VCC to atm_addr. + * Not for Control or Multicast connections. + * Returns < 0 for error + */ +int create_data_svc(unsigned char *atm_addr, int codepoint) +{ + struct atm_sap sap; + struct atm_qos qos; + struct sockaddr_atmsvc my_addr, dst_addr; + Conn_t *conn; + + memset(&my_addr, 0, sizeof(struct sockaddr_atmsvc)); + memcpy(my_addr.sas_addr.prv, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + memset(&dst_addr, 0, sizeof(struct sockaddr_atmsvc)); + memcpy(dst_addr.sas_addr.prv, atm_addr, ATM_ESA_LEN); + my_addr.sas_family = dst_addr.sas_family = AF_ATMSVC; + init_conn_params(&sap, &qos, codepoint); + + conn = setup_svc(&dst_addr, &my_addr, &sap, &qos); + if (conn == NULL) { + diag(COMPONENT, DIAG_ERROR, "Could not create Data Direct VCC\n"); + delete_addr(dst_addr.sas_addr.prv); + return -1; + } + + return 0; +} + +/* Creates a listen socket with parameters specified with + * arguments. + * Returns NULL for error or Conn_t for new listen socket. + */ +Conn_t *create_listensocket(struct sockaddr_atmsvc *listen_addr, + struct atm_sap *sap, struct atm_qos *qos) +{ + int fd, ret; + Conn_t *conn; + + diag(COMPONENT, DIAG_DEBUG, "conn_create_listensocket\n"); + + fd = get_socket(listen_addr, sap, qos); + if (fd < 0) return NULL; + + ret = listen(fd, 5); + if (ret != 0) { + diag(COMPONENT, DIAG_DEBUG, "Listen failed: %s\n", strerror(errno)); + close(fd); + return NULL; + } + + conn = list_add_conn(NULL); + if (conn == NULL) { + diag(COMPONENT, DIAG_ERROR, "List_add_conn failed\n"); + close(fd); + return NULL; + } + + conn->type = LISTENING; + conn->fd = fd; + diag(COMPONENT, DIAG_DEBUG, "Listen socket created blli:%2.2x %2.2x fd: %d\n", + sap->blli[0].l3.tr9577.snap[3], + sap->blli[0].l3.tr9577.snap[4], + conn->fd); + + return conn; +} + +/* Accepts a new connection from listen socket in conn. + * Returns NULL for error + */ +Conn_t *accept_conn(Conn_t *conn) +{ + Conn_t *new; + struct sockaddr_atmsvc addr; + size_t len; + int fd; + char buff[MAX_ATM_ADDR_LEN+1]; + + diag(COMPONENT, DIAG_DEBUG, "Accepting connection on fd %d\n", conn->fd); + len = sizeof(addr); + fd = accept(conn->fd, (struct sockaddr *)&addr, &len); + diag(COMPONENT, DIAG_DEBUG, "accept returned %d\n", fd); + if (fd < 0) { + diag(COMPONENT, DIAG_ERROR, "accept: %s\n", strerror(errno)); + return NULL; + } + if (atm2text(buff, sizeof(buff), (struct sockaddr *)&addr, A2T_PRETTY | A2T_NAME | A2T_LOCAL) < 0) + sprintf(buff, "<Unknown ATM address>"); + diag(COMPONENT, DIAG_DEBUG, "Call from %s", buff); + + new = list_add_conn(addr.sas_addr.prv); + if (new == NULL) return NULL; + new->fd = fd; + new->status = CONNECTED; + new->type = THEYMADE; + if (conn == lec_params.ctrl_listen) new->codepoint = CONTROL_CONN; + if (conn == lec_params.mcast_listen) new->codepoint = MCAST_CONN; + if (conn == lec_params.data_listen) new->codepoint = DATA_DIRECT_CONN; + + return new; +} + +/* Close all connections, important or not. + */ +void close_connections(void) +{ + Conn_t *conn, *next; + + for(conn = connlist; conn; conn = next) { + diag(COMPONENT, DIAG_DEBUG, "Destroying:%p fd:%d type:%d\n", + conn, conn->fd, conn->type); + next = conn->next; + close(conn->fd); + list_remove_conn(conn); + free(conn); + } + + return; +} + +/* Closes a connection and checks its importance. + * Important connections are kernel socket, LES connections, + * BUS Default Multicast Send VCC, last Multicast Forward VCC from Bus + * and any of the listen sockets. + * Returns < 0 for important connection. + */ +int close_connection(Conn_t *conn) +{ + int bad = 0; + Conn_t *mcast; + + diag(COMPONENT, DIAG_DEBUG, "close_connection %p\n", conn); + + if (conn == lec_params.kernel || + conn == lec_params.ctrl_direct || + conn == lec_params.ctrl_dist || + conn == lec_params.mcast_send || + conn == lec_params.mcast_listen || + conn == lec_params.data_listen) + bad = -1; + else { + bad = -1; + for (mcast = connlist; mcast; mcast = mcast->next) + if (mcast != conn && + mcast->type == THEYMADE && + mcast->codepoint == MCAST_CONN) + bad = 0; + } + + close(conn->fd); + list_remove_conn(conn); + free(conn); + + return bad; +} + +/* Accepts a new incoming Data Direct or Multicast Forward connection. + * Control connections (LECS/LES) are accepted during configuration/join. + * Returns < 0 for serious error such as broken listen socket. + */ +static int handle_accept(Conn_t *conn) +{ + Conn_t *new; + struct atmlec_ioc ioc; + + new = accept_conn(conn); + if (new == NULL) return -1; + + if (conn == lec_params.mcast_listen) { + diag(COMPONENT, DIAG_DEBUG, "Multicast Forward VCC accepted\n"); + ioc.receive = 2; + } else { + diag(COMPONENT, DIAG_DEBUG, "Data Direct VCC accepted\n"); + ioc.receive = 0; + if (conn_already_exists(new->atm_address, new) && + memcmp(lec_params.c1n_my_atm_addr, new->atm_address, ATM_ESA_LEN) < 0) { + diag(COMPONENT, DIAG_DEBUG, "Using it only to receive, spec 8.1.1\n"); + ioc.receive = 1; + } + } + memcpy(ioc.atm_addr, new->atm_address, ATM_ESA_LEN); + ioc.dev_num = lec_params.itf_num; + diag(COMPONENT, DIAG_DEBUG, "Attaching a new VCC, fd %d\n", new->fd); + if (ioctl(new->fd, ATMLEC_DATA, &ioc) < 0) { + diag(COMPONENT, DIAG_ERROR, "VCC attach failed: ioctl: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +/* Reads a LE control frame from conn, usually Data Direct or + * Multicast Forward connection. Calls the incoming packet + * handler function. + * Returns < 0 for serious error such as broken LES connection + */ +static int handle_data(Conn_t *conn) +{ + char buff[MAX_CTRL_FRAME]; + int retval; + + retval = recv_frame(conn, buff, sizeof(buff)); + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "handle_data: read: %s\n", strerror(errno)); + return (close_connection(conn)); + } + if (retval == 0) { + diag(COMPONENT, DIAG_DEBUG, "fd %d, Data or Multicast VCC closed\n", conn->fd); + return (close_connection(conn)); + } + + return handle_frame(conn, buff, retval); +} + +/* Checks connections in *fds. The only allowed sockets + * in *fds are listen sockets, data direct and control + * sockets. + * Returns < 0 for serious error such as broken LES connection + */ +int check_connections(fd_set *fds) +{ + Conn_t *conn, *next; + + conn = connlist; + while (conn != NULL) { + next = conn->next; + if (!FD_ISSET(conn->fd, fds)) { + conn = next; + continue; + } + + switch (conn->type) { + case LISTENING: + if (handle_accept(conn) < 0) + return -1; + break; + case WEMADE: + case THEYMADE: + if (handle_data(conn) < 0) + return -1; + break; + default: + diag(COMPONENT, DIAG_ERROR, "check_connections: bad_type '%s'\n", + get_type_string(conn->type)); + break; + } + + conn = next; + } + + return 0; +} + +/* Completes a non-blocking connect. + * Returns < 0 for serious error + */ +static int handle_connect(Conn_t *conn) +{ + int retval; + struct sockaddr_atmsvc dummy; + struct atmlec_msg msg; + struct atmlec_ioc ioc; + + diag(COMPONENT, DIAG_DEBUG, "handle_connect: completing fd %d\n", conn->fd); + /* this seems to be common method in Linux-ATM + * making sure that nonblocking connect was + * completed successfully + */ + conn->status = CONNECTED; + retval = connect(conn->fd, (struct sockaddr *)&dummy, sizeof(struct sockaddr_atmsvc)); + if (retval < 0) { + diag(COMPONENT, DIAG_DEBUG, "handle_connect: connect: %s\n", strerror(errno)); + delete_addr(conn->atm_address); + close_connection(conn); + return 0; + } + + send_ready_ind(conn); + + memset(&msg, 0, sizeof(struct atmlec_msg)); + msg.type = l_flush_tran_id; + memcpy(msg.content.normal.atm_addr, conn->atm_address, ATM_ESA_LEN); + msg.content.normal.flag = send_flush_req(conn); + + msg_to_kernel(&msg, sizeof(struct atmlec_msg)); + + memcpy(ioc.atm_addr, conn->atm_address, ATM_ESA_LEN); + ioc.dev_num = lec_params.itf_num; + ioc.receive = 0; + diag(COMPONENT, DIAG_DEBUG, "Attaching a new active VCC, fd %d\n", conn->fd); + if (ioctl(conn->fd, ATMLEC_DATA, &ioc) < 0) { + diag(COMPONENT, DIAG_ERROR, "VCC attach failed: ioctl: %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +/* Complete non-blocking connections in *fds. + * Returns < 0 for serious error (problems with kernel). + */ +int complete_connections(fd_set *fds) +{ + Conn_t *conn, *next; + int retval; + + conn = connlist; + while (conn) { + next = conn->next; + if (FD_ISSET(conn->fd, fds)) { + retval = handle_connect(conn); + if (retval < 0) return -1; + } + conn = next; + } + + return 0; +} + +/* Send a LE control frame using *conn. + * Returns < 0 for serious error + */ +int send_frame(Conn_t *conn, void *frame, int length) +{ + struct frame_hdr *hdr; + int ret; + + diag(COMPONENT, DIAG_DEBUG, "send_frame: fd:%d len:%ld\n", conn->fd, length); + hdr = (struct frame_hdr *)frame; + if (hdr->opcode == htons(READY_QUERY) || + hdr->opcode == htons(READY_IND)) + diag(COMPONENT, DIAG_DEBUG, "%s\n", opcode2text(hdr->opcode)); + else + display_frame(frame); + + ret = write(conn->fd, frame, length); + if (ret < 0) { + diag(COMPONENT, DIAG_ERROR, "send_frame: write: %s\n", strerror(errno)); + return -1; + } + + return ret; +} + +/* Receive a LE control frame from *conn. + * Returns < 0 for serious error. + */ +int recv_frame(Conn_t *conn, void *buff, int length) +{ + int ret; + + diag(COMPONENT, DIAG_DEBUG, "recv_frame: fd:%d\n", conn->fd); + ret = read(conn->fd, buff, length); + if (ret < 0) { + diag(COMPONENT, DIAG_ERROR, "Read failed: %s\n", strerror(errno)); + return -1; + } + +#if 0 + diag(COMPONENT, DIAG_DEBUG, "recv_frame: read %d bytes\n", ret); + if (get_verbosity(COMPONENT) >= DIAG_DEBUG) { + int i; + for (i = 0; i < 11; i++) + diag(COMPONENT, DIAG_DEBUG, "0x%2x", ((unsigned char *)buff)[i]); + } +#endif + + return ret; +} + + +/* + * LANE2: 5.2.1.4 and others, sleep random time before trying to reconnect + */ +void random_delay(void) +{ + struct timeval tv; + int millis, interval; + + srand(time(NULL)); + interval = lec_params.c38_max_reconfig_delay - lec_params.c37_min_reconfig_delay; + millis = (rand() % interval) + lec_params.c37_min_reconfig_delay; + tv.tv_sec = (millis - (millis % 1000)) / 1000; + tv.tv_usec = (millis % 1000) * 1000; + + diag(COMPONENT, DIAG_DEBUG, "random_delay: sleeping %d.%d seconds\n", tv.tv_sec, tv.tv_usec); + (void)select(0, NULL, NULL, NULL, &tv); + + return; +} + +/* Collect already connected sockets in *fds + */ +void conn_get_fds(fd_set *fds) +{ + Conn_t *conn; + + diag(COMPONENT, DIAG_DEBUG, "collecting ready fds "); + conn = connlist; + while (conn) { + if (conn->status != CONNECTING) { + FD_SET(conn->fd, fds); + diag(COMPONENT, DIAG_DEBUG, "%d type %s", conn->fd, get_type_string(conn->type)); + } + conn = conn->next; + } + + return; +} + +/* Collect non-blocking connecting sockets in *fds + */ +void conn_get_connecting_fds(fd_set *fds) +{ + Conn_t *conn; + + diag(COMPONENT, DIAG_DEBUG, "collecting connecting fds "); + conn = connlist; + while (conn) { + if (conn->status == CONNECTING) { + FD_SET(conn->fd, fds); + diag(COMPONENT, DIAG_DEBUG, "%d", conn->fd); + } + conn = conn->next; + } + +} + +/* Creates Conn_t for fd and marks it as kernel socket + * Returns < 0 for error + */ +int conn_set_kernel_socket(int fd) +{ + Conn_t *conn; + + conn = list_add_conn(NULL); + if (conn == NULL) { + diag(COMPONENT, DIAG_ERROR, "conn_set_kernel_socket: list_add_conn failed\n"); + return -1; + } + conn->type = KERNEL_SOCK; + conn->status = CONNECTED; + conn->fd = fd; + lec_params.kernel = conn; + + return fd; +} + +/* Creates new Conn_t object and allocates memory for it. + * atm_addr should be the ATM address of the other end + * or NULL if not applicable + */ +static Conn_t *list_add_conn(unsigned char *atm_addr) +{ + Conn_t *conn; + + conn = (Conn_t *)malloc(sizeof(Conn_t)); + if (!conn) + return NULL; + + memset(conn, 0, sizeof(Conn_t)); + if (atm_addr) + memcpy(conn->atm_address, atm_addr, ATM_ESA_LEN); + + conn->next = connlist; + conn->previous = NULL; + if (connlist) + connlist->previous = conn; + connlist = conn; + diag(COMPONENT, DIAG_DEBUG, "Added conn:%p\n", conn); + + return conn; +} + +/* Helper for close_connection and close_connections + */ +static void list_remove_conn(Conn_t *conn) +{ + + if (conn->next == NULL && conn->previous == NULL + && connlist != conn) return; + diag(COMPONENT, DIAG_DEBUG, "Removing conn:%p fd:%d previous:%p next:%p ", + conn, conn->fd, conn->previous, conn->next); + + if (conn->previous) + diag(COMPONENT, DIAG_DEBUG, "Previous:%p, fd:%d, next:%p, previous:%p ", + conn->previous, conn->previous->fd, + conn->previous->next, conn->previous->previous); + if (conn->next) + diag(COMPONENT, DIAG_DEBUG, "Next:%p, fd:%d next:%p, previous:%p ", + conn->next, conn->next->fd, + conn->next->next, conn->next->previous); + if (conn->previous) { + conn->previous->next = conn->next; + } else /* First in line */ + connlist = conn->next; + if (conn->next) + conn->next->previous = conn->previous; + diag(COMPONENT, DIAG_DEBUG, "Connlist: %p\n", connlist); + conn->next=conn->previous= NULL; + + return; +} + +static const char *get_type_string(int type) +{ + switch(type) { + case WEMADE: + return "WEMADE"; + break; + case THEYMADE: + return "THEYMADE"; + break; + case LISTENING: + return "LISTENING"; + break; + case KERNEL_SOCK: + return "KERNEL_SOCK"; + break; + default: + break; + } + + return "UNKNOWN"; +} + +static int maxmtu2maxsdu(uint8_t mtu) +{ + + int sdu; + + switch (mtu) { + case MTU_1516: + sdu = 1516; + break; + case MTU_1580: /* LANE2: MTU can be 1580 too (IEEE 802.1p/Q) */ + sdu = 1580; + break; + case MTU_4544: + sdu = 4544; + break; + case MTU_9234: + sdu = 9234; + break; + case MTU_18190: + sdu = 18190; + break; + default: + sdu = 1516; + break; + } + + return sdu; +} diff -ur --new-file old/atm/led.new/conn.h new/atm/led.new/conn.h --- old/atm/led.new/conn.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/conn.h Sat Feb 6 21:29:32 1999 @@ -0,0 +1,82 @@ +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Copyright (c) 1996 + * Tampere University of Technology - Telecommunications Laboratory + * All rights reserved. + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef CONN_H +#define CONN_H + +typedef struct _conn_t_ { + int fd; /* Socket connected to this connection */ + int status; /* Connection status */ + int type; /* We made, they made, listen socket */ + int codepoint; /* One of the below, MCAST_CONN etc. */ + unsigned char atm_address[ATM_ESA_LEN]; + /* Destination address, not in listen or + kernel sockets */ + struct _conn_t_ *next; + struct _conn_t_ *previous; +} Conn_t; + +void close_connections(void); +void init_conn_params(struct atm_sap *sap, struct atm_qos *qos, + uint16_t blli_codepoint); +int create_data_svc(unsigned char *atm_addr, int codepoint); +Conn_t *setup_svc(struct sockaddr_atmsvc *dst_addr, + struct sockaddr_atmsvc *listen_addr, + struct atm_sap *sap, struct atm_qos *qos); +int create_data_listen(void); +Conn_t *create_listensocket(struct sockaddr_atmsvc *listen_addr, + struct atm_sap *sap, struct atm_qos *qos); +Conn_t *accept_conn(Conn_t *conn); +int close_connection(Conn_t *conn); +int check_connections(fd_set *fds); +int complete_connections(fd_set *fds); + +int send_frame(Conn_t *conn, void *frame, int length); +int recv_frame(Conn_t *conn, void *buff, int length); + +void conn_get_fds(fd_set *fds); +void conn_get_connecting_fds(fd_set *fds); + +void random_delay(void); + +/* + * Connection types for BLLI codepoints. + */ +#define CONTROL_CONN 1 +#define DATA_DIRECT_CONN 2 +#define MCAST_CONN 4 + +/* + * MTU sizes + */ +#define MTU_UNSPEC 0 +#define MTU_1516 1 +#define MTU_1580 5 /* LANEv2 */ +#define MTU_4544 2 +#define MTU_9234 3 +#define MTU_18190 4 + +#endif /* CONN_H */ diff -ur --new-file old/atm/led.new/display.c new/atm/led.new/display.c --- old/atm/led.new/display.c Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/display.c Sat Feb 6 21:54:37 1999 @@ -0,0 +1,307 @@ +/* display.c - display frames, addresses, opcodes, etc. */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#include <atm.h> +#include <atmd.h> + +#include "display.h" +#include "frame_defs.h" + +#define COMPONENT "display.c" + +#define MAX_TEXT 1024 /* Buffer size for displaying LE control frames */ + +static int my_atm2text(unsigned char *atm_addr, char *dest); +static const char *lan_dst2text(struct lan_dst *dst); +static void display_ready(void *buff); + +/* Prints out more or less human readable summary of + * LE Control Frame pointed by frame. + */ +void display_frame(void *frame) +{ + struct frame_hdr *hdr; + struct ctrl_frame *f; + char text[MAX_TEXT]; + char *p; + + hdr = (struct frame_hdr *)frame; + if (hdr->opcode == htons(READY_QUERY) || + hdr->opcode == htons(READY_IND)) + display_ready(frame); + + p = text; + p += sprintf(p, "\n"); + p += sprintf(p, "Marker 0x%x\n", ntohs(hdr->marker)); + p += sprintf(p, "Protocol 0x%x\n", hdr->protocol); + p += sprintf(p, "Version 0x%x\n", hdr->version); + p += sprintf(p, "Op-Code 0x%x (%s)\n", ntohs(hdr->opcode), opcode2text(hdr->opcode)); + p += sprintf(p, "Status %d (%s)\n", hdr->status, status2text(hdr->status)); + p += sprintf(p, "Trans-ID %d\n", ntohl(hdr->tran_id)); + p += sprintf(p, "Req Lec-ID %d\n", ntohs(hdr->lec_id)); + p += sprintf(p, "Flags 0x%x", ntohs(hdr->flags)); + if (hdr->flags & htons(REMOTE_ADDRESS)) p+= sprintf(p, " 'Remote Address'"); + if (hdr->flags & htons(V2_CAPABLE)) p+= sprintf(p, " 'V2 Capable'"); + if (hdr->flags & htons(V2_REQUIRED)) p+= sprintf(p, " 'V2 Required'"); + if (hdr->flags & htons(PROXY_FLAG)) p+= sprintf(p, " 'Proxy Flag'"); + if (hdr->flags & htons(TOPO_CHANGE)) p+= sprintf(p, " 'Topology Change'"); + p += sprintf(p, "\n"); + + f = (struct ctrl_frame *)frame; + p += sprintf(p, "Source Lan 0x%x (%s)\n", ntohs(f->src_lan_dst.tag), lan_dst2text(&f->src_lan_dst)); + p += sprintf(p, "Target Lan 0x%x (%s)\n", ntohs(f->target_lan_dst.tag), lan_dst2text(&f->target_lan_dst)); + p += sprintf(p, "Source ATM "); p += my_atm2text(f->src_atm_addr, p); p += sprintf(p, "\n"); + p += sprintf(p, "Lan type 0x%x\n", f->lan_type); + p += sprintf(p, "Lan MTU 0x%x\n", f->max_frame_size); + p += sprintf(p, "# of TLVs 0x%x\n", f->num_tlvs); + p += sprintf(p, "Elan Name size 0x%x\n", f->elan_name_size); + p += sprintf(p, "Target ATM "); p += my_atm2text(f->target_atm_addr, p); p += sprintf(p, "\n"); + p += sprintf(p, "Elan Name ("); + memcpy(p, f->elan_name, f->elan_name_size); p += f->elan_name_size; + p += sprintf(p, ")\n"); + + + *p = '\0'; + diag(COMPONENT, DIAG_DEBUG, "%s\n", text); + + return; +} + +static void display_ready(void *ready_frame) +{ + diag(COMPONENT, DIAG_DEBUG, "ready frame\n"); + + return; +} + +/* Poor man's atm2text */ +static int my_atm2text(unsigned char *atm_addr, char *dest) +{ + int i, len; + + len = 0; + for (i = 0; i < ATM_ESA_LEN; i++) + len += sprintf(dest + len, "%2.2x ", *(atm_addr + i)); + + return len; +} + +static const char *lan_dst2text(struct lan_dst *dst) +{ + static char text[42]; /* big enough for text + MAC */ + char *p = text; + + switch(ntohs(dst->tag)) { + case LAN_DST_NOT_PRESENT: + sprintf(text, "Not present"); + break; + case LAN_DST_MAC_ADDR: + p += sprintf(p, "MAC address"); + p += sprintf(p, " "); + mac2text(p, dst->mac); + break; + case LAN_DST_ROUTE_DESC: + p += sprintf(p, "Route Descriptor"); + p += sprintf(p, " "); + mac2text(p, dst->mac); + break; + default: + sprintf(text, "<Unknown Lan destination>"); + break; + } + + return text; +} + +void mac2text(char *buff, unsigned char *mac_addr) +{ + sprintf(buff, "%02x-%02x-%02x-%02x-%02x-%02x", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + return; +} + +const char *opcode2text(uint16_t opcode) { + switch (ntohs(opcode)) { + case LE_CONFIG_REQ: + return "LE_CONFIG_REQUEST"; + break; + case LE_CONFIG_RSP: + return "LE_CONFIG_RESPONSE"; + break; + case LE_JOIN_REQ: + return "LE_JOIN_REQUEST"; + break; + case LE_JOIN_RSP: + return "LE_JOIN_RESPONSE"; + break; + case LE_REG_REQ: + return "LE_REGISTER_REQUEST"; + break; + case LE_REG_RSP: + return "LE_REGISTER_RESPONSE"; + break; + case LE_ARP_REQ: + return "LE_ARP_REQUEST"; + break; + case LE_ARP_RSP: + return "LE_ARP_RESPONSE"; + break; + case LE_FLUSH_REQ: + return "LE_FLUSH_REQUEST"; + break; + case LE_FLUSH_RSP: + return "LE_FLUSH_RESPONSE"; + break; + case READY_QUERY: + return "READY_QUERY"; + break; + case READY_IND: + return "READY_INDICATION"; + break; + case LE_TOPO_REQ: + return "LE_TOPOLOGY_REQUEST"; + break; + case LE_NARP_REQ: + return "LE_NARP_REQUEST"; + break; + default: + break; + } + + return "<Unknown OP-CODE>"; +} + +const char *tlv2text(uint32_t type) +{ + switch (type) { + case MAX_CUM_CTRL_TIMEOUT: + return "Max-Cumulative-Control-Time-out"; + break; + case MAX_UNKNOWN_FRAME_CNT: + return "Max-Unknown-Frame-Count"; + break; + case MAX_UNKNOWN_FRAME_TIME: + return "Max-Unknown-Frame-Time"; + break; + case VCC_TIMEOUT_PERIOD: + return "VCC-Timeout-Period"; + break; + case MAX_RETRY_COUNT: + return "Max-Retry-Count"; + break; + case AGING_TIME: + return "Aging-Time"; + break; + case FORWARD_DELAY_TIME: + return "Forward-Delay-Time"; + break; + case EXPECTED_LE_ARP_TIME: + return "Expected-LE_ARP-Response-Time"; + break; + case FLUSH_TIMEOUT: + return "Flush-Time-out"; + break; + case PATH_SWITCHING_DELAY: + return "Path-Switching-Delay"; + break; + case LOCAL_SEGMENT_ID: + return "Local-Segment-ID"; + break; + case DEF_MCAST_SND_VCC_TYPE: + return "Default-Mcast-Send-VCC-Type"; + break; + case DEF_MCAST_SND_VCC_AVG: + return "Default-Mcast-Send-VCC-AvgRate"; + break; + case DEF_MCAST_SEND_PEAK_RT: + return "Default-Mcast-Send-VCC-PeakRate"; + break; + case CONN_COMPLETION_TIMER: + return "Connection-Completion-Timer"; + break; + case CONFIG_FRAG_INFO: + return "Config-Frag-Info"; + break; + case LAYER3_ADDRESS: + return "Layer-3-Address"; + break; + case ELAN_ID: + return "ELAN-ID"; + break; + case SERVICE_CATEGORY: + return "Service-Category"; + break; + case LLC_MUXED_ATM_ADDR: + return "LLC-Muxed-ATM-Address"; + break; + case X5_ADJUSTMENT: + return "X5-Adjustment"; + break; + case PREFERRED_LES: + return "Preferred-LES"; + break; + case FORE_NAME: + return "Fore's LANE client name"; + break; + default: + break; + } + + return "<Unknown TLV type>"; +} + +const char *status2text(uint16_t status) +{ + + switch (ntohs(status)) { + case 0: + return "Success"; + break; + case 1: + return "Version Not Supported"; + break; + case 2: + return "Invalid request parameters"; + break; + case 4: + return "Duplicate LAN Destination registration"; + break; + case 5: + return "Dupliate ATM address"; + break; + case 6: + return "Insufficient resources to grant request"; + break; + case 7: + return "Access denied"; + break; + case 8: + return "Invalid REQUESTOR-ID"; + break; + case 9: + return "Invalid LAN Destination"; + break; + case 10: + return "Invalid ATM Address"; + break; + case 20: + return "No Configuration"; + break; + case 21: + return "LE_CONFIGURE Error"; + break; + case 22: + return "Insufficient Information"; + break; + case 24: + return "TLV Not Found"; + break; + default: + break; + } + + return "<Something not supported in LANEv2>"; +} diff -ur --new-file old/atm/led.new/display.h new/atm/led.new/display.h --- old/atm/led.new/display.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/display.h Sat Feb 6 14:44:23 1999 @@ -0,0 +1,13 @@ +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef DISPLAY_H +#define DISPLAY_H + +void display_frame(void *frame); + +void mac2text(char *buff, unsigned char *mac_addr); +const char *opcode2text(uint16_t opcode); +const char *tlv2text(uint32_t type); +const char *status2text(uint16_t status); + +#endif /* DISPLAY_H */ diff -ur --new-file old/atm/led.new/frame_defs.h new/atm/led.new/frame_defs.h --- old/atm/led.new/frame_defs.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/frame_defs.h Sun Feb 7 12:05:21 1999 @@ -0,0 +1,125 @@ +/* frame_defs.h - definitions for LANE control frames, TLVs etc. */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef FRAMES_DEFS_H +#define FRAMES_DEFS_H + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +/* Try to squeeze out all the padding from the structs so that we + * can use them as templates for filling in and examining frames. + * From the gcc documentation: + * This attribute, attached to an `enum', `struct', or `union' type + * definition, specified that the minimum required memory be used to + * represent the type. + */ +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif + +/* READY_QUERY and READY_IND frame format + */ +struct ready_frame { + uint16_t marker; + uint8_t protocol; + uint8_t version; + uint16_t opcode; +}; + +/* Fields common to all control frames, + * not including READY_* + */ +struct frame_hdr { + uint16_t marker; + uint8_t protocol; + uint8_t version; + uint16_t opcode; + uint16_t status; + uint32_t tran_id; + uint16_t lec_id; + uint16_t flags; +} PACKED; + +/* values for lan_dst.tag + */ +#define LAN_DST_NOT_PRESENT 0x0000 +#define LAN_DST_MAC_ADDR 0x0001 +#define LAN_DST_ROUTE_DESC 0x0002 + +struct lan_dst { /* Token Ring route descriptors omitted */ + uint16_t tag; + uint8_t mac[ETH_ALEN]; +} PACKED; + +/* All frames except STATUS_INQ and STATUS_REPLY look like this + */ +struct ctrl_frame { + struct frame_hdr header; + struct lan_dst src_lan_dst; + struct lan_dst target_lan_dst; + uint8_t src_atm_addr[ATM_ESA_LEN]; + uint8_t lan_type; + uint8_t max_frame_size; + uint8_t num_tlvs; + uint8_t elan_name_size; + uint8_t target_atm_addr[ATM_ESA_LEN]; + uint8_t elan_name[32]; + /* TLVs if any follow elan_name */ +} PACKED; + +/* Frame types + */ +#define LE_CONFIG_REQ 0x0001 +#define LE_CONFIG_RSP 0x0101 +#define LE_JOIN_REQ 0x0002 +#define LE_JOIN_RSP 0x0102 +#define LE_REG_REQ 0x0004 +#define LE_REG_RSP 0x0104 +#define LE_ARP_REQ 0x0006 +#define LE_ARP_RSP 0x0106 +#define LE_FLUSH_REQ 0x0007 +#define LE_FLUSH_RSP 0x0107 +#define LE_NARP_REQ 0x0008 +#define LE_TOPO_REQ 0x0009 +#define READY_QUERY 0x0003 /* READY_* are not in ctrl_frame format */ +#define READY_IND 0x0103 + +/* Flags for LE Control Frames + */ +#define REMOTE_ADDRESS 0x0001 +#define V2_CAPABLE 0x0002 +#define V2_REQUIRED 0x0008 +#define PROXY_FLAG 0x0080 +#define TOPO_CHANGE 0x0100 + +/* TLV types defined in LANEv1 and v2 + one Fore specific TLV + */ +#define MAX_CUM_CTRL_TIMEOUT 0x00A03E01 +#define MAX_UNKNOWN_FRAME_CNT 0x00A03E02 +#define MAX_UNKNOWN_FRAME_TIME 0x00A03E03 +#define VCC_TIMEOUT_PERIOD 0x00A03E04 +#define MAX_RETRY_COUNT 0x00A03E05 +#define AGING_TIME 0x00A03E06 +#define FORWARD_DELAY_TIME 0x00A03E07 +#define EXPECTED_LE_ARP_TIME 0x00A03E08 +#define FLUSH_TIMEOUT 0x00A03E09 +#define PATH_SWITCHING_DELAY 0x00A03E0A +#define LOCAL_SEGMENT_ID 0x00A03E0B +#define DEF_MCAST_SND_VCC_TYPE 0x00A03E0C +#define DEF_MCAST_SND_VCC_AVG 0x00A03E0D +#define DEF_MCAST_SEND_PEAK_RT 0x00A03E0E +#define CONN_COMPLETION_TIMER 0x00A03E0F +#define CONFIG_FRAG_INFO 0x00A03E10 /* This and the rest are LANEv2 only */ +#define LAYER3_ADDRESS 0x00A03E11 +#define ELAN_ID 0x00A03E12 +#define SERVICE_CATEGORY 0x00A03E13 +#define LLC_MUXED_ATM_ADDR 0x00A03E2B +#define X5_ADJUSTMENT 0x00A03E2C /* length 0 */ +#define PREFERRED_LES 0x00A03E2D + +#define FORE_NAME 0x00204808 /* check zeppelin(8), -f option */ + +#endif /* FRAMES_DEFS_H */ diff -ur --new-file old/atm/led.new/frames.c new/atm/led.new/frames.c --- old/atm/led.new/frames.c Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/frames.c Sat Feb 6 21:45:03 1999 @@ -0,0 +1,582 @@ +/* frames.c - handle incoming frames, prefill outgoing frames, parse TLVs etc. */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +/* Functions for handling LANE control frames used when joining an + * ELAN are in lec.c + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <atm.h> +#include <linux/atmlec.h> +#include <atmd.h> + +#include "conn.h" +#include "lec.h" +#include "frames.h" +#include "display.h" +#include "kernel.h" + +#define COMPONENT "frames.c" + +static uint32_t transaction_id = 0; +static void extract_tlv_value(uint16_t opcode, uint32_t type, unsigned char *tlvp, int len); +static void handle_x5(uint16_t opcode); + +/* Initializes LANE Control frame of type 'type' + */ +void prefill_frame(void *buff, uint16_t type) +{ + struct frame_hdr *header; + + memset(buff, 0, sizeof(struct ctrl_frame)); + header = (struct frame_hdr *)buff; + header->marker = htons(0xff00); + header->protocol = 0x01; + header->version = 0x01; + header->opcode = htons(type); + header->status = htons(0x0000); + header->tran_id = htonl(transaction_id); + header->lec_id = htons(lec_params.c14_lec_id); + header->flags = htons(0x0000); + + transaction_id++; + + return; +} + +/* Validates incoming Control frames except READY_IND and + * READY_QUERY which do not start with the common header. + * Also calls display_frame() to print out conforming frames. + * Returns < 0 for error + */ +int validate_frame(unsigned char *buff, int size) +{ + struct ready_frame *hdr; /* Ready is the shortest possible */ + + if (size < sizeof(struct ready_frame)) { + diag(COMPONENT, DIAG_DEBUG, "short frame, size %d\n", size); + return -1; + } + + hdr = (struct ready_frame *)buff; + if (hdr->marker != htons(0xff00) || + hdr->protocol != 0x01 || + hdr->version != 0x01) + return -1; + + /* READY_* frames are shorter than others */ + if (hdr->opcode == htons(READY_QUERY) || + hdr->opcode == htons(READY_IND)) { + diag(COMPONENT, DIAG_DEBUG, "Received a %s\n", opcode2text(hdr->opcode)); + return 0; + } + + if (size < sizeof(struct ctrl_frame)) { + diag(COMPONENT, DIAG_DEBUG, "short frame, size %d\n", size); + return -1; + } + + display_frame(buff); + + return 0; +} + +/* Handle incoming LE_FLUSH_REQUEST frames. + */ +static void handle_flush_req(struct ctrl_frame *f) +{ + if (memcmp(lec_params.c1n_my_atm_addr, f->target_atm_addr, ATM_ESA_LEN) != 0) + return; + f->header.opcode = htons(LE_FLUSH_RSP); + if (send_frame(lec_params.ctrl_direct, f, sizeof(struct ctrl_frame)) < 0) + diag(COMPONENT, DIAG_DEBUG, "could not send LE_FLUSH_RESPONSE\n"); + + return; +} + +/* Handle incoming LE_FLUSH_RESPONSE frames. + */ +static void handle_flush_rsp(struct ctrl_frame *f) +{ + struct atmlec_msg msg; + + if (f->header.lec_id != htons(lec_params.c14_lec_id)) { + diag(COMPONENT, DIAG_DEBUG, "Wrong lec_id, ignoring\n"); + return; + } + + memset(&msg, 0, sizeof(struct atmlec_msg)); + msg.type = l_flush_complete; + msg.content.normal.flag = ntohl(f->header.tran_id); + msg_to_kernel(&msg, sizeof(struct atmlec_msg)); + + return; +} + +/* Handle incoming READY_QUERY frames. + */ +static void handle_ready_query(Conn_t *conn, struct ready_frame *f) +{ + f->opcode = htons(READY_IND); + send_frame(conn, f, sizeof(struct ready_frame)); + + return; +} + +/* Helper for handle_le_arp_req. + * If the target_lan_dst was not our MAC address, try to + * see if the bridging table in the kernel knows about it. + * Returns < 0 for serious error + */ +static int check_bridge(struct ctrl_frame *frame, int size) +{ + struct atmlec_msg msg; + + if (lec_params.c4_proxy_flag == 0) + return 0; + + memset(&msg, 0, sizeof(struct atmlec_msg)); + msg.type = l_should_bridge; + memcpy(msg.content.proxy.mac_addr, frame->target_lan_dst.mac, ETH_ALEN); + memcpy(msg.content.proxy.atm_addr, frame->src_atm_addr, ATM_ESA_LEN); + msg.content.proxy.tran_id = frame->header.tran_id; + msg.content.proxy.lec_id = frame->header.lec_id; + + return msg_to_kernel(&msg, sizeof(struct atmlec_msg)); +} + +/* Handles incoming LE_ARP_REQ and targetless LE_ARP_REQ. + * See LANEv2, 7.1.5 and 7.1.30 + * Returns < 0 for serious error + */ +static int handle_le_arp_req(struct ctrl_frame *frame, int size) +{ + int sizeoftlvs, sizeofrsp, retval; + struct ctrl_frame *rsp; + struct atmlec_msg *msg; + + if (frame->header.lec_id == htons(lec_params.c14_lec_id)) { + diag(COMPONENT, DIAG_DEBUG, "Ignoring own LE_ARP_REQUEST\n"); + return 0; + } + + retval = 0; + if (frame->target_lan_dst.tag == htons(LAN_DST_MAC_ADDR)) { + if (memcmp(frame->target_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN) != 0) + return (check_bridge(frame, size)); /* target was not us */ + sizeofrsp = sizeof(struct ctrl_frame) + lec_params.sizeoftlvs; + rsp = (struct ctrl_frame *)malloc(sizeofrsp); + if (rsp == NULL) return 0; + memcpy(rsp, frame, sizeof(struct ctrl_frame)); + rsp->header.opcode = htons(LE_ARP_RSP); + memcpy(rsp->target_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + rsp->num_tlvs = lec_params.num_tlvs; + if (lec_params.num_tlvs > 0) + memcpy(rsp + 1, lec_params.tlvs, lec_params.sizeoftlvs); + + retval = send_frame(lec_params.ctrl_direct, rsp, sizeofrsp); + free(rsp); + } else if (frame->target_lan_dst.tag == htons(LAN_DST_NOT_PRESENT) && + lec_params.c29_v2_capable) { + sizeoftlvs = size - sizeof(struct ctrl_frame); + msg = (struct atmlec_msg *)malloc(sizeof(struct atmlec_msg) + sizeoftlvs); + if (msg == NULL) return -1; + memset(msg, 0, sizeof(struct atmlec_msg)); + msg->type = l_arp_update; + memcpy(msg->content.normal.mac_addr, frame->src_lan_dst.mac, ETH_ALEN); + memcpy(msg->content.normal.atm_addr, frame->src_atm_addr, ATM_ESA_LEN); + msg->content.normal.flag = (frame->header.flags & REMOTE_ADDRESS) ? 1 : 0; + msg->content.normal.targetless_le_arp = 1; + msg->sizeoftlvs = sizeoftlvs; + if (sizeoftlvs > 0) memcpy(msg + 1, frame + 1, sizeoftlvs); + + retval = msg_to_kernel(msg, sizeof(struct atmlec_msg) + sizeoftlvs); + free(msg); + } + + return retval; +} + +/* Handles incoming LE_NARP_REQUESTS frames. + * Mandatory only in LANEv2. If we are LANEv1, we'll just ignore these. + * See LANEv2, 7.1.31-35 LE_NARP_REQUEST/RESPONSE. + * For no-source, i.e. no source ATM address, we remove the LE_ARP cache entry. + * If the source is non-zero, we first remove the entry + * and then add the new entry in the LE_ARP cache. + * Returns < 0 for serious error. + */ +static int handle_narp_req(struct ctrl_frame *frame, int size) +{ + int sizeoftlvs, no_source = 0, retval; + struct atmlec_msg *msg; + unsigned char empty[ATM_ESA_LEN]; + + if (frame->header.lec_id == htons(lec_params.c14_lec_id) || + lec_params.c29_v2_capable == 0) { + diag(COMPONENT, DIAG_DEBUG, "Ignoring LE_NARP_REQUEST\n"); + return 0; + } + + memset(empty, 0, ATM_ESA_LEN); + if (memcmp(empty, frame->src_atm_addr, ATM_ESA_LEN) == 0) + no_source = 1; + + sizeoftlvs = size - sizeof(struct ctrl_frame); + msg = (struct atmlec_msg *)malloc(sizeof(struct atmlec_msg) + sizeoftlvs); + if (msg == NULL) return -1; + memset(msg, 0, sizeof(struct atmlec_msg)); + msg->type = l_narp_req; + memcpy(msg->content.normal.mac_addr, frame->src_lan_dst.mac, ETH_ALEN); + memcpy(msg->content.normal.atm_addr, frame->src_atm_addr, ATM_ESA_LEN); + msg->content.normal.flag = (frame->header.flags & REMOTE_ADDRESS) ? 1 : 0; + msg->content.normal.no_source_le_narp = no_source; + msg->sizeoftlvs = sizeoftlvs; + if (sizeoftlvs > 0) memcpy(msg + 1, frame + 1, sizeoftlvs); + retval = msg_to_kernel(msg, sizeof(struct atmlec_msg) + sizeoftlvs); + + free(msg); + + return retval; +} + +/* Handles incoming LE_ARP_RESPONSE frames. + * Returns < 0 for serious error + */ +static int handle_arp_rsp(struct ctrl_frame *frame, int size) +{ + int sizeoftlvs, msglen, retval; + char buff[MAX_CTRL_FRAME]; + struct atmlec_msg *msg; + + if (frame->header.lec_id != htons(lec_params.c14_lec_id)) { + diag(COMPONENT, DIAG_DEBUG, "Wrong lec_id, ignoring\n"); + return 0; + } + + sizeoftlvs = size - sizeof(struct ctrl_frame); + msglen = sizeof(struct atmlec_msg) + sizeoftlvs; + msg = (struct atmlec_msg *)buff; + memset(msg, 0, msglen); + + msg->type = l_arp_update; + memcpy(msg->content.normal.mac_addr, frame->target_lan_dst.mac, ETH_ALEN); + memcpy(msg->content.normal.atm_addr, frame->target_atm_addr, ATM_ESA_LEN); + msg->content.normal.flag = (frame->header.flags & REMOTE_ADDRESS) ? 1 : 0; + msg->sizeoftlvs = sizeoftlvs; + if (sizeoftlvs > 0) memcpy(msg + 1, frame + 1, sizeoftlvs); + + retval = msg_to_kernel(msg, msglen); + + return retval; +} + +/* Handles incoming LE_TOPOLOGY_REQUEST frames. + * Returns < 0 for serious error + */ +static int handle_topo_req(struct ctrl_frame *frame) +{ + struct atmlec_msg msg; + + memset(&msg, 0, sizeof(struct atmlec_msg)); + msg.type = l_topology_change; + if (frame->header.flags & htons(TOPO_CHANGE)) + msg.content.normal.flag = 1; + + return(msg_to_kernel(&msg, sizeof(struct atmlec_msg))); +} + +/* Processes and validates incoming frames. Calls frame + * dependant handler functions. + * Returns < 0 for serious error + */ +int handle_frame(Conn_t *conn, char *buff, int size) +{ + struct ctrl_frame *frame; + + if (validate_frame(buff, size) < 0) + return 0; + + frame = (struct ctrl_frame *)buff; + + switch (ntohs(frame->header.opcode)) { + case LE_FLUSH_REQ: + handle_flush_req(frame); + break; + case LE_FLUSH_RSP: + handle_flush_rsp(frame); + break; + case READY_QUERY: + handle_ready_query(conn, (struct ready_frame *)frame); + break; + case READY_IND: + /* We can ignore these */ + break; + case LE_ARP_REQ: + if (handle_le_arp_req(frame, size) < 0) + return -1; + break; + case LE_ARP_RSP: + if (handle_arp_rsp(frame, size) < 0) + return -1; + break; + case LE_TOPO_REQ: + if (handle_topo_req(frame) < 0) + return -1; + break; + case LE_REG_RSP: + /* FIXME: Should we do something? */ + break; + case LE_NARP_REQ: + if (handle_narp_req(frame, size) < 0) + return -1; + break; + default: + diag(COMPONENT, DIAG_ERROR, + "Unknown frame, opcode 0x%x %s\n", ntohs(frame->header.opcode), + opcode2text(frame->header.opcode)); + break; + } + + return 0; +} + +/* Sends a READY_INDICATION when a non-blocking connect completes. + */ +void send_ready_ind(Conn_t *conn) +{ + struct ready_frame frame; + int retval; + + frame.marker = htons(0xff00); + frame.protocol = 0x01; + frame.version = 0x01; + frame.opcode = htons(READY_IND); + + retval = send_frame(conn, &frame, sizeof(struct ready_frame)); + if (retval < 0) + diag(COMPONENT, DIAG_DEBUG, "Could not send READY_IND, fd %d\n", conn->fd); + + return; +} + +/* Sends a LE_FLUSH_REQUEST + * Returns the transaction used with this flush REQ/RSP pair. + */ +uint32_t send_flush_req(Conn_t *conn) +{ + struct ctrl_frame frame; + + prefill_frame(&frame, LE_FLUSH_REQ); + memcpy(frame.src_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + memcpy(frame.target_atm_addr, conn->atm_address, ATM_ESA_LEN); + + send_frame(lec_params.mcast_send, &frame, sizeof(struct ctrl_frame)); + + return ntohl(frame.header.tran_id); +} + +/* Registers our MAC address and associated TLVs with LES. + * See LANEv2, 6. Registaration Protocol + */ +void send_register_req(void) +{ + char buff[MAX_CTRL_FRAME]; + struct ctrl_frame *frame; + + frame = (struct ctrl_frame *)buff; + prefill_frame(frame, LE_REG_REQ); + frame->src_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + memcpy(frame->src_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN); + memcpy(frame->src_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + frame->num_tlvs = lec_params.num_tlvs; + if (lec_params.sizeoftlvs > 0) + memcpy((frame + 1), lec_params.tlvs, lec_params.sizeoftlvs); + + send_frame(lec_params.ctrl_direct, frame, sizeof(struct ctrl_frame) + lec_params.sizeoftlvs); + + return; +} + +/* Goes through the TLVs trailing a frame while passing them + * one by one to the TLV handler. + */ +void parse_tlvs(uint16_t opcode, unsigned char *tlvp, int numtlvs, int sizeoftlvs) +{ + uint32_t type; + uint8_t len; + unsigned char *end_of_tlvs; + + end_of_tlvs = tlvp + sizeoftlvs; + while (numtlvs-- > 0 && end_of_tlvs - tlvp >= 5) { + type = *(uint32_t *)tlvp; + type = ntohl(type); + len = tlvp[4]; + tlvp += 5; + diag(COMPONENT, DIAG_DEBUG, "parse_tlvs: type %s len %d\n", + tlv2text(type), len); + if (tlvp + len > end_of_tlvs) + return; /* value too long */ + + extract_tlv_value(opcode, type, tlvp, len); + tlvp += len; + } + + return; +} + +/* Does something depending on the frame type this TLV arrived with, + * TLV type, and contents of TLV. + */ +static void extract_tlv_value(uint16_t opcode, uint32_t type, unsigned char *tlvp, int len) +{ + + uint16_t value16; + uint32_t value32; + + /* LE_JOIN_RESPONSE does not support all the TLVs */ + if (opcode == htons(LE_JOIN_RSP) && type != htonl(ELAN_ID)) + return; + + switch(len) { + case 0: + switch (type) { + case X5_ADJUSTMENT: + handle_x5(opcode); + break; + default: + goto whine; + break; + } + break; + case 2: + value16 = *(uint16_t *)tlvp; + value16 = ntohs(value16); + diag(COMPONENT, DIAG_DEBUG, "value of TLV %d\n", value16); + switch (type) { + case MAX_CUM_CTRL_TIMEOUT: + lec_params.c7_ctrl_timeout = value16; + break; + case MAX_UNKNOWN_FRAME_CNT: + lec_params.c10_max_unknown_frames = value16; + break; + case MAX_UNKNOWN_FRAME_TIME: + lec_params.c11_max_unknown_frame_time = value16; + break; + case MAX_RETRY_COUNT: + lec_params.c13_max_retry_count = value16; + break; + case FORWARD_DELAY_TIME: + lec_params.c18_forward_delay_time = value16; + break; + case EXPECTED_LE_ARP_TIME: + lec_params.c20_le_arp_response_time = value16; + break; + case FLUSH_TIMEOUT: + lec_params.c21_flush_timeout = value16; + break; + case PATH_SWITCHING_DELAY: + lec_params.c22_path_switching_delay = value16; + break; + case LOCAL_SEGMENT_ID: + case DEF_MCAST_SND_VCC_TYPE: + case CONN_COMPLETION_TIMER: + case SERVICE_CATEGORY: + /* do nothing */ + break; + default: + goto whine; + break; + } + break; + case 4: + value32 = *(uint32_t *)tlvp; + value32 = ntohl(value32); + diag(COMPONENT, DIAG_DEBUG, "value of TLV %d\n", value32); + switch (type) { + case VCC_TIMEOUT_PERIOD: + lec_params.c12_vcc_timeout = value32; + break; + case AGING_TIME: + lec_params.c17_aging_time = value32; + break; + case ELAN_ID: + lec_params.c31_elan_id = value32; + break; + case DEF_MCAST_SND_VCC_AVG: + case DEF_MCAST_SEND_PEAK_RT: + /* do nothing */ + break; + default: + goto whine; + break; + } + break; + case 20: + switch(type) { + case PREFERRED_LES: + memcpy(lec_params.c35_preferred_les, tlvp, ATM_ESA_LEN); + lec_params.c35_contains_address = 1; + break; + case LLC_MUXED_ATM_ADDR: + /* do nothing */ + break; + default: + goto whine; + break; + } + break; + default: + /* handle variable length TLVs */ + switch(type) { + case CONFIG_FRAG_INFO: + diag(COMPONENT, DIAG_INFO, "Got Config-Frag-Info TLV\n"); + break; + case LAYER3_ADDRESS: + /* do nothing */ + break; + default: + goto whine; + break; + } + break; + } + + return; + + whine: + diag(COMPONENT, DIAG_DEBUG, "Unknown TLV, type 0x%x, len %d\n", type, len); + + return; +} + +/* Figures out what to do when we get a X5-Adjustment TLV + */ +static void handle_x5(uint16_t opcode) +{ + if (!lec_params.c29_v2_capable) + return; + if (opcode != ntohs(LE_CONFIG_RSP)) { + diag(COMPONENT, DIAG_WARN, "X5-Adjustment TLV received but not with LE_CONFIG_RSP\n"); + return; + } + + switch(lec_params.c3_max_frame_size) { + case 1: + lec_params.c3_max_frame_size = 5; /* 1580 */ + return; + break; + case 2: + lec_params.c3_max_frame_size = 5; /* 1580 */ + return; + break; + default: + /* rest of the values are not affected by X5 */ + break; + } + + return; +} diff -ur --new-file old/atm/led.new/frames.h new/atm/led.new/frames.h --- old/atm/led.new/frames.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/frames.h Sat Feb 6 21:54:23 1999 @@ -0,0 +1,21 @@ +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef FRAMES_H +#define FRAMES_H + +#include "frame_defs.h" + +#define MAX_CTRL_FRAME 512 + +void prefill_frame(void *ctrl_frame, uint16_t type); +int validate_frame(unsigned char *buff, int size); + +void send_ready_ind(Conn_t *conn); +void send_register_req(void); + +int handle_frame(Conn_t *conn, char *buff, int size); +uint32_t send_flush_req(Conn_t *conn); + +void parse_tlvs(uint16_t opcode, unsigned char *tlvp, int numtlvs, int sizeoftlvs); + +#endif /* FRAMES_H */ diff -ur --new-file old/atm/led.new/join.c new/atm/led.new/join.c --- old/atm/led.new/join.c Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/join.c Sat Feb 6 21:58:04 1999 @@ -0,0 +1,766 @@ +/* join.c - functions which are only needed when joining an ELAN */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> /* for rand() */ +#include <sys/ioctl.h> +#include <atm.h> + +#include <linux/atmlec.h> + +#include <atmd.h> + +#include "conn.h" +#include "lec.h" +#include "join.h" +#include "frames.h" +#include "display.h" + +#define COMPONENT "lec.c" + +struct lec_params lec_params; + +static unsigned char bus_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static unsigned char well_known_lecs[ATM_ESA_LEN] = {0x47,0x00,0x79,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xA0, + 0x3E,0x00,0x00,0x01,0x00}; +static int do_lec_configure(Conn_t *conn); +static int send_config_req(Conn_t *conn); +static int read_config_rsp(Conn_t *conn, char *buff, int buffsize); +static int parse_config_rsp(unsigned char *buff, int size); + +static int send_join_req(Conn_t *conn); +static int read_join_rsp(char *buff, int buffsize); +static int parse_join_rsp(unsigned char *buff, int size); + +static int get_bus_addr(struct sockaddr_atmsvc *addr); +static int read_bus_arp(Conn_t *conn, struct sockaddr_atmsvc *addr, char *buff, int buffsize); + +/* + * 5.1, Initial state + */ +void init_lec_params(unsigned char *mac_addr, char *elan_name, + unsigned char *listen_addr, int itf, char *foreId, + int max_frame_size, int proxy_flag, int lane_version) +{ + memcpy(lec_params.c6_mac_addr, mac_addr, ETH_ALEN); + strcpy(lec_params.c5_elan_name, elan_name); + memcpy(lec_params.c1n_my_atm_addr, listen_addr, ATM_ESA_LEN); + lec_params.itf_num = itf; + strcpy(lec_params.foreId, foreId); + lec_params.c3_max_frame_size = max_frame_size; + lec_params.c4_proxy_flag = proxy_flag; + + if (lane_version > 1 ) lec_params.c29_v2_capable = 1; + else lec_params.c29_v2_capable = 0; + + /* then come the defaults */ + lec_params.c2_lan_type = 0x01; /* Ethernet/IEEE 802.3 */ + if (lec_params.c29_v2_capable) { + lec_params.c7_ctrl_timeout = 30; + lec_params.c10_max_unknown_frames = 10; + } + else { + lec_params.c7_ctrl_timeout = 10; + lec_params.c10_max_unknown_frames = 1; + } + lec_params.c7i_initial_ctrl_timeout = 5; + lec_params.c7x_timeout_multiplier = 2; + lec_params.c7c_current_timeout = lec_params.c7i_initial_ctrl_timeout; + lec_params.c11_max_unknown_frame_time = 1; + lec_params.c12_vcc_timeout = 1200; + lec_params.c13_max_retry_count = 2; + lec_params.c14_lec_id = 0; + lec_params.c17_aging_time = 300; + lec_params.c18_forward_delay_time = 15; + lec_params.c19_topology_change = 0; + lec_params.c20_le_arp_response_time = 1; + lec_params.c21_flush_timeout = 4; + lec_params.c22_path_switching_delay = 6; + /* LANE2 added the following, only the ones used are listed */ + memset(lec_params.c35_preferred_les, 0, ATM_ESA_LEN); + lec_params.c35_contains_address = 0; + lec_params.c37_min_reconfig_delay = 1; /* milliseconds */ + lec_params.c38_max_reconfig_delay = 5000; /* milliseconds */ + + if (lec_params.tlvs != NULL) free (lec_params.tlvs); + lec_params.tlvs = NULL; + lec_params.sizeoftlvs = 0; + lec_params.num_tlvs = 0; + + return; +} + +/* ------------- Configure phase specific stuff starts ------------- */ + +/* + * 5.2 LECS connect phase + * Returns < 0 for error + */ +int lec_configure(int lecs_method, struct sockaddr_atmsvc *manual_atm_addr, + struct sockaddr_atmsvc *listen_addr) +{ + int retval; + struct sockaddr_atmsvc addr_c5, addr_47; + struct atm_sap sap; + struct atm_qos qos; + Conn_t *conn; + + diag(COMPONENT, DIAG_DEBUG, "entering lec_configure\n"); + + /* initialize well known LECS addresses */ + memset(&addr_c5, 0, sizeof(struct sockaddr_atmsvc)); + memset(&addr_47, 0, sizeof(struct sockaddr_atmsvc)); + addr_c5.sas_family = addr_47.sas_family = AF_ATMSVC; + memcpy(addr_c5.sas_addr.prv, well_known_lecs, ATM_ESA_LEN); + memcpy(addr_47.sas_addr.prv, well_known_lecs, ATM_ESA_LEN); + addr_c5.sas_addr.prv[0] = 0xC5; + + /* see if the user wants to skip LECS */ + if (lecs_method == LECS_NONE) + return 0; + + init_conn_params(&sap, &qos, CONTROL_CONN); + + while(1) { + if (lecs_method == LECS_MANUAL) { + diag(COMPONENT, DIAG_DEBUG, "trying manual LECS address\n"); + conn = setup_svc(manual_atm_addr, listen_addr, &sap, &qos); + if (conn) { + retval = do_lec_configure(conn); + close_connection(conn); + return retval; + } + else random_delay(); + } + diag(COMPONENT, DIAG_DEBUG, "trying well-known anycast LECS address\n"); + conn = setup_svc(&addr_c5, listen_addr, &sap, &qos); + if (conn) { + retval = do_lec_configure(conn); + close_connection(conn); + return retval; + } + else random_delay(); + diag(COMPONENT, DIAG_DEBUG, "trying well-known LECS address\n"); + conn = setup_svc(&addr_47, listen_addr, &sap, &qos); + if (conn) { + retval = do_lec_configure(conn); + close_connection(conn); + return retval; + } + else random_delay(); + } + + return -1; /* not reached */ +} + +/* + * 5.3 Configuration phase, get configuration from LECS + * Returns < 0 for error + */ +static int do_lec_configure(Conn_t *conn) +{ + int frame_size = 0; + char buff[MAX_CTRL_FRAME]; + + lec_params.c7c_current_timeout = lec_params.c7i_initial_ctrl_timeout; /* reset it */ + while (lec_params.c7c_current_timeout <= lec_params.c7_ctrl_timeout) { + if (send_config_req(conn) < 0) return -1; + frame_size = read_config_rsp(conn, buff, sizeof(buff)); + if (frame_size < 0) return -1; + if (frame_size == 0) /* timeout */ + lec_params.c7c_current_timeout *= lec_params.c7x_timeout_multiplier; + else + break; /* frame in */ + } + lec_params.c7c_current_timeout = lec_params.c7i_initial_ctrl_timeout; /* reset it */ + if (frame_size == 0) { + diag(COMPONENT, DIAG_INFO, "Timed out while waiting for LE_CONFIGURE_RESPONSE\n"); + return -1; /* timeout */ + } + + if (parse_config_rsp(buff, frame_size) < 0) { + diag(COMPONENT, DIAG_ERROR, "Parsing LE_CONFIG_RESPONSE indicates failure\n"); + return -1; + } + + return 0; +} + +/* + * Compose a LE Config request frame and send it to LECS + * Returns < 0 for error + */ +static int send_config_req(Conn_t *conn) +{ + int frame_size; + struct ctrl_frame *config_req; + char buff[MAX_CTRL_FRAME]; + + diag(COMPONENT, DIAG_DEBUG, "Sending LE_CONFIGURE_REQUEST\n"); + + /* TLVs make config frame variable length */ + frame_size = sizeof(struct ctrl_frame); + if (lec_params.c3_max_frame_size == MTU_1580) frame_size += 5; + config_req = (struct ctrl_frame *)buff; + memset(config_req, 0, frame_size); + + prefill_frame(config_req, LE_CONFIG_REQ); + if (lec_params.c29_v2_capable) + config_req->header.flags = htons(V2_CAPABLE); + config_req->src_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + memcpy(config_req->src_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN); + memcpy(config_req->src_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + config_req->lan_type = lec_params.c2_lan_type; + config_req->max_frame_size = lec_params.c3_max_frame_size; + config_req->elan_name_size = strlen(lec_params.c5_elan_name); + if (strlen(lec_params.c5_elan_name) > 0) + strcpy(config_req->elan_name, lec_params.c5_elan_name); + if (lec_params.c3_max_frame_size == MTU_1580) { + lec_params.c3_max_frame_size = MTU_1516; + *(uint32_t *)(config_req + 1) = htonl(X5_ADJUSTMENT); + config_req->num_tlvs++; + } + + if (send_frame(conn, buff, frame_size) != frame_size) + return -1; + + return 0; +} + +/* + * Reads in Config frame or timeouts + * Returns Config frame length, < 0 for error, 0 for timeout + */ +static int read_config_rsp(Conn_t *conn, char *buff, int buffsize) +{ + int frame_size, retval; + struct timeval tv; + fd_set rfds; + + tv.tv_sec = lec_params.c7c_current_timeout; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(conn->fd, &rfds); + + retval = select(conn->fd + 1, &rfds, NULL, NULL, &tv); + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "read_ctrl_rsp: select: %s\n", + strerror(errno)); + return retval; + } + if (retval == 0) return 0; /* timeout */ + + frame_size = recv_frame(conn, buff, buffsize); + if (frame_size < 0) { + diag(COMPONENT, DIAG_ERROR, "read_ctrl_rsp: recv_frame: %s\n", + strerror(errno)); + return frame_size; + } + if (frame_size == 0) { + diag(COMPONENT, DIAG_ERROR, "read_ctrl_rsp: conn closed: %s\n", + strerror(errno)); + return -1; + } + + return frame_size; +} + +/* Validates and parses a LE_CONFIGURE_RESPONSE. + * See LANEv2, 5.3.x + * Returns < 0 for error + */ +static int parse_config_rsp(unsigned char *buff, int size) +{ + struct ctrl_frame *frame; + + diag(COMPONENT, DIAG_DEBUG, "Parsing LE_CONFIG_RESPONSE\n"); + if (validate_frame(buff, size) < 0) { + diag(COMPONENT, DIAG_ERROR, "parse_config_rsp: bad frame\n"); + return -1; + } + + frame = (struct ctrl_frame *)buff; + if (frame->header.opcode != htons(LE_CONFIG_RSP)) { + diag(COMPONENT, DIAG_ERROR, "parse_config_rsp: not a LE_CONFIG_RESPONSE\n"); + return -1; + } + + if (frame->header.status != 0) { + diag(COMPONENT, DIAG_ERROR, "LECS said: %s\n", + status2text(frame->header.status)); + return -1; + } + if (frame->elan_name_size > 32) return -1; + + /* looks good, now extract the information */ + lec_params.c2_lan_type = frame->lan_type; + lec_params.c3_max_frame_size = frame->max_frame_size; + if (frame->elan_name_size != 0) + strncpy(lec_params.c5_elan_name, frame->elan_name, frame->elan_name_size); + lec_params.c5_elan_name[frame->elan_name_size] = '\0'; + memcpy(lec_params.c9_les_atm_addr, frame->target_atm_addr, ATM_ESA_LEN); + + parse_tlvs(frame->header.opcode, buff + sizeof(struct ctrl_frame), + frame->num_tlvs, size - sizeof(struct ctrl_frame)); + + return 0; +} + +/* ------------- Configure phase specific stuff ends ------------- */ + + +/* -------------- Join phase specific stuff starts --------------- */ + +/* + * 5.4 Join phase + * Create control direct VCC and accept possible control distribute VCC + * Returns < 0 for error + */ +int les_connect(int lecs_method, struct sockaddr_atmsvc *manual_atm_addr, + struct sockaddr_atmsvc *listen_addr) +{ + struct sockaddr_atmsvc les_addr; + struct atm_sap sap; + struct atm_qos qos; + char buff[MAX_CTRL_FRAME]; + int frame_size = 0; /* shut up, GCC */ + + diag(COMPONENT, DIAG_DEBUG, "Entering Join phase\n"); + + if (lecs_method == LECS_NONE) { + diag(COMPONENT, DIAG_DEBUG, "Skipping LECS, connecting straight to LES\n"); + memcpy(les_addr.sas_addr.prv, manual_atm_addr->sas_addr.prv, ATM_ESA_LEN); + } else memcpy(les_addr.sas_addr.prv, lec_params.c9_les_atm_addr, ATM_ESA_LEN); + + init_conn_params(&sap, &qos, CONTROL_CONN); + lec_params.ctrl_direct = setup_svc(&les_addr, listen_addr, &sap, &qos); + if (lec_params.ctrl_direct == NULL) { + diag(COMPONENT, DIAG_ERROR, "Control direct SVC failed\n"); + random_delay(); + return -1; + } + lec_params.ctrl_listen = create_listensocket(listen_addr, &sap, &qos); + if (lec_params.ctrl_listen == NULL) { + diag(COMPONENT, DIAG_ERROR, "Control distribute listen socket failed\n"); + random_delay(); + return -1; + } + + lec_params.c7c_current_timeout = lec_params.c7i_initial_ctrl_timeout; /* reset it */ + while (lec_params.c7c_current_timeout <= lec_params.c7_ctrl_timeout) { + if (send_join_req(lec_params.ctrl_direct) < 0) { + diag(COMPONENT, DIAG_ERROR, "Sending LE_JOIN_REQUEST failed\n"); + random_delay(); + return -1; + } + frame_size = read_join_rsp(buff, sizeof(buff)); + if (frame_size < 0) { + diag(COMPONENT, DIAG_ERROR, "Receiving LE_JOIN_RESPONSE failed\n"); + random_delay(); + return -1; + } else if (frame_size == 0) /* timeout */ + lec_params.c7c_current_timeout *= lec_params.c7x_timeout_multiplier; + else + break; /* frame in */ + } + lec_params.c7c_current_timeout = lec_params.c7i_initial_ctrl_timeout; /* reset it */ + if (frame_size == 0) { + diag(COMPONENT, DIAG_ERROR, "LE_JOIN_RESPONSE timed out\n"); + return -1; + } + + if (parse_join_rsp(buff, frame_size) < 0) { + diag(COMPONENT, DIAG_ERROR, "Parsing LE_JOIN_RESPONSE failed\n"); + return -1; + } + + return 0; +} + +/* 5.4.1.2 Transmitting LE_JOIN_REQUEST + * Note that the TLVs should be the same as in LE_CONFIG_REQUEST + * excluding X5-Adjustment and Preferred-LES + */ +static int send_join_req(Conn_t *conn) +{ + char buff[MAX_CTRL_FRAME], *tlvp; + struct ctrl_frame *frame; + int frame_size; + + frame_size = sizeof(struct ctrl_frame); + if (lec_params.c3_max_frame_size == 5) frame_size += 5; + if (lec_params.c35_contains_address) frame_size += (5 + ATM_ESA_LEN); + if (strlen(lec_params.foreId) > 0) frame_size += (5 + strlen(lec_params.foreId)); + + frame = (struct ctrl_frame *)buff; + tlvp = (char *)(frame + 1); + prefill_frame(frame, LE_JOIN_REQ); + frame->lan_type = lec_params.c2_lan_type; + if (lec_params.c4_proxy_flag) frame->header.flags |= htons(PROXY_FLAG); + frame->src_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + strcpy(frame->elan_name, lec_params.c5_elan_name); + frame->elan_name_size = strlen(lec_params.c5_elan_name); + if (lec_params.c29_v2_capable) frame->header.flags |= htons(V2_CAPABLE); + memcpy(frame->src_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + memcpy(frame->src_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN); + frame->max_frame_size = lec_params.c3_max_frame_size; + if (lec_params.c3_max_frame_size == 5) { + frame->max_frame_size = 1; + *(uint32_t *)tlvp = htonl(X5_ADJUSTMENT); + tlvp += 4; *tlvp = 0; tlvp++; + frame->num_tlvs++; + } + if (lec_params.c35_contains_address) { + *(uint32_t *)tlvp = htonl(PREFERRED_LES); + tlvp +=4; *tlvp = (uint8_t)ATM_ESA_LEN; tlvp++; + memcpy(tlvp, lec_params.c35_preferred_les, ATM_ESA_LEN); + tlvp += 20; + frame->num_tlvs++; + } + if (strlen(lec_params.foreId) > 0) { + *(uint32_t *)tlvp = htonl(FORE_NAME); + tlvp +=4; *tlvp = (uint8_t)strlen(lec_params.foreId); tlvp++; + memcpy(tlvp, lec_params.foreId, strlen(lec_params.foreId)); + tlvp += strlen(lec_params.foreId); + frame->num_tlvs++; + } + + if (send_frame(conn, frame, frame_size) != frame_size) + return -1; + + return 0; +} + +/* LE_JOIN_RESPONSE can either come over ctrl_direct or ctrl_dist. + * However, if LES uses Control Direct VCC, we can ignore connections + * to ctrl_listen and if it connects to ctrl_listen we can wait + * the reponse to arrive that route. Simple :) + * + * Returns < 0 for error, 0 for timeout, > 0 for frame size + */ +static int read_join_rsp(char *buff, int buffsize) +{ + Conn_t *dist; + int n, retval, frame_size = 0; + struct timeval tv; + fd_set rfds; + + /* Idea here is always to listen for two sockets. One of the + sockets is always Control Direct and the other is either + listen socket for Control Distribute or the Control + Distribute itself. We can do it like this, since listen + socket gets closed as soon as it creates a new connection + */ + + dist = (lec_params.ctrl_listen != NULL) ? lec_params.ctrl_listen : lec_params.ctrl_dist; + n = (lec_params.ctrl_direct->fd > dist->fd) ? lec_params.ctrl_direct->fd : dist->fd; + n++; + + tv.tv_sec = lec_params.c7c_current_timeout; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(lec_params.ctrl_direct->fd, &rfds); + FD_SET(dist->fd, &rfds); + + retval = select(n, &rfds, NULL, NULL, &tv); + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "get_join_rsp: select: %s\n", + strerror(errno)); + return -1; + } + if (retval == 0) return 0; /* timeout */ + + /* Be careful here. The both sockets might be readable + * and the response can come from either one + */ + if (FD_ISSET(lec_params.ctrl_direct->fd, &rfds)) { + /* Control Direct was changed */ + frame_size = recv_frame(lec_params.ctrl_direct, buff, buffsize); + if (frame_size < 0) { + diag(COMPONENT, DIAG_ERROR, "get_join_rsp: recv_frame: %s\n", + strerror(errno)); + return -1; + } + if (frame_size == 0) { + diag(COMPONENT, DIAG_ERROR, "get_join_rsp: Control direct VCC closed\n"); + return -1; + } + diag(COMPONENT, DIAG_DEBUG, "LE_JOIN_RESPONSE over Control direct VCC\n"); + } + if (FD_ISSET(dist->fd, &rfds)) { + /* Event in listen socket or Control Distribute */ + if (dist == lec_params.ctrl_listen) { + /* Connection to control listen */ + lec_params.ctrl_dist = accept_conn(lec_params.ctrl_listen); + if (lec_params.ctrl_dist == NULL) { + diag(COMPONENT, DIAG_ERROR, "accept of Ctrl distribute failed\n"); + return -1; + } + diag(COMPONENT, DIAG_DEBUG, "Closing listen socket for Ctrl distribute VCC\n"); + close_connection(lec_params.ctrl_listen); + lec_params.ctrl_listen = NULL; + + /* let's see if this new socket has something for us */ + return (read_join_rsp(buff, buffsize)); + } + /* Event in Control distribute */ + frame_size = recv_frame(lec_params.ctrl_dist, buff, buffsize); + if (frame_size < 0) { + diag(COMPONENT, DIAG_ERROR, "get_join_rsp: recv_frame: %s\n", + strerror(errno)); + return -1; + } + if (frame_size == 0) { + diag(COMPONENT, DIAG_ERROR, "Control distribute VCC closed\n"); + return -1; + } + diag(COMPONENT, DIAG_DEBUG, "LE_JOIN_RESPONSE over Control distribute VCC\n"); + } + + return frame_size; +} + +/* Validates and parses a LE_JOIN_RESPONSE. + * See LANEv2 5.4.x + * Returns < 0 for error + */ +static int parse_join_rsp(unsigned char *buff, int size) +{ + struct ctrl_frame *frame; + + diag(COMPONENT, DIAG_DEBUG, "Parsing LE_JOIN_RESPONSE\n"); + if (validate_frame(buff, size) < 0) + return -1; + + frame = (struct ctrl_frame *)buff; + if (frame->header.opcode != htons(LE_JOIN_RSP)) + return -1; + + if (frame->header.status != 0) { + diag(COMPONENT, DIAG_ERROR, "LES said: %s\n", + status2text(frame->header.status)); + return -1; + } + if (frame->elan_name_size > 32) return -1; + + /* looks good, now extract the information */ + lec_params.c2_lan_type = frame->lan_type; + lec_params.c3_max_frame_size = frame->max_frame_size; + if (frame->elan_name_size != 0) + strncpy(lec_params.c5_elan_name, frame->elan_name, frame->elan_name_size); + lec_params.c5_elan_name[frame->elan_name_size] = '\0'; + lec_params.c14_lec_id = ntohs(frame->header.lec_id); + + if (!(frame->header.flags & htons(V2_REQUIRED)) && lec_params.c29_v2_capable) { + diag(COMPONENT, DIAG_INFO, "LES did not return V2 Required Flag, acting as V1 client\n"); + lec_params.c29_v2_capable = 0; + } + if (!(frame->header.flags & htons(V2_REQUIRED)) && + (lec_params.c3_max_frame_size == MTU_1580)) { + /* Against spec, but we'll accept the MTU and clear the flag */ + diag(COMPONENT, DIAG_ERROR, "LES not LANEv2 but uses MTU of 1580 bytes\n"); + lec_params.c29_v2_capable = 0; + } + parse_tlvs(frame->header.opcode, buff + sizeof(struct ctrl_frame), + frame->num_tlvs, size - sizeof(struct ctrl_frame)); + + return 0; +} + +/* --------------- Join phase specific stuff ends ---------------- */ + + +/* -------------- Bus connect specific stuff starts --------------- */ + +int bus_connect(void) +{ + struct ctrl_frame *frame; + char buff[MAX_CTRL_FRAME]; + struct sockaddr_atmsvc bus_addr, listen_addr; + int retval, tries, n; + struct atm_sap sap; + struct atm_qos qos; + struct timeval tv; + fd_set rfds; + Conn_t *mcast_fwd; + struct atmlec_ioc ioc_data; + + frame = (struct ctrl_frame *)buff; + memset(&bus_addr, 0, sizeof(struct sockaddr_atmsvc)); + memset(&listen_addr, 0, sizeof(struct sockaddr_atmsvc)); + + /* try to arp BUS two times */ + tries = 2; + while (tries > 0) { + prefill_frame(frame, LE_ARP_REQ); + frame->header.lec_id = htons(lec_params.c14_lec_id); + frame->src_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + memcpy(frame->src_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN); + memcpy(frame->src_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + frame->target_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + memcpy(frame->target_lan_dst.mac, bus_mac, ETH_ALEN); + retval = send_frame(lec_params.ctrl_direct, frame, sizeof(struct ctrl_frame)); + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "LE_ARP_REQUEST for BUS failed\n"); + return -1; + } + retval = get_bus_addr(&bus_addr); + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "LE_ARP_RESPONSE for BUS failed\n"); + return -1; + } else if (retval > 0) + break; /* got it */ + tries--; + } + if (tries == 0) { + diag(COMPONENT, DIAG_ERROR, "LE_ARP_RESPONSE for BUS timed out\n"); + return -1; + } + + /* We got address for BUS. Make the listen socket for Multicast + * Forward first and then contact BUS. + */ + memcpy(listen_addr.sas_addr.prv, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + listen_addr.sas_family = bus_addr.sas_family = AF_ATMSVC; + init_conn_params(&sap, &qos, MCAST_CONN); + lec_params.mcast_listen = create_listensocket(&listen_addr, &sap, &qos); + if (lec_params.mcast_listen == NULL) { + diag(COMPONENT, DIAG_ERROR, "Listen socket for BUS failed\n"); + return -1; + } + + lec_params.mcast_send = setup_svc(&bus_addr, &listen_addr, &sap, &qos); + if (lec_params.mcast_send == NULL) { + diag(COMPONENT, DIAG_ERROR, "Connect to BUS failed\n"); + return -1; + } + /* Default Multicast send VCC to BUS ready, notify kernel */ + if (ioctl(lec_params.mcast_send->fd, ATMLEC_MCAST, lec_params.itf_num) < 0) { + diag(COMPONENT, DIAG_FATAL, "Can't change socket into LE mcast socket: %s\n", strerror(errno)); + return -1; + } + + diag(COMPONENT, DIAG_DEBUG, "About to wait for BUS to connect\n"); + tv.tv_sec = lec_params.c7_ctrl_timeout; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(lec_params.mcast_listen->fd, &rfds); + n = lec_params.mcast_listen->fd + 1; + retval = select(n, &rfds, NULL, NULL, &tv); + if (retval == 0) { + diag(COMPONENT, DIAG_ERROR, "BUS connect to Multicast Forward listen socket timed out\n"); + return -1; + } + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "while waiting for Multicast Forward VCC: select: %s\n", + strerror(errno)); + return -1; + } + mcast_fwd = accept_conn(lec_params.mcast_listen); + if (mcast_fwd == NULL) { + diag(COMPONENT, DIAG_ERROR, "BUS connect to Multicast Forward listen socket failed\n"); + return -1; + } + + memcpy(ioc_data.atm_addr, mcast_fwd->atm_address, ATM_ESA_LEN); + ioc_data.dev_num = lec_params.itf_num; + ioc_data.receive = 2; /* Multicast distribute */ + diag(COMPONENT, DIAG_DEBUG, "About to notify kernel about Multicast Forward VCC\n"); + if (ioctl(mcast_fwd->fd, ATMLEC_DATA, &ioc_data) < 0) { + diag(COMPONENT, DIAG_DEBUG, "Could not notify kernel: %s\n", strerror(errno)); + return -1; + } + + /* All done. We're in! */ + return 0; +} + +/* + * Waits for LE_ARP_RESPONSE for BUS' ATM address to arrive. + * Returns < 0 for error, 0 for timeout > 0 for success + * BUS ATM address will be stored in *addr */ +static int get_bus_addr(struct sockaddr_atmsvc *addr) +{ + + fd_set rfds; + struct timeval tv; + int n = 0, retval, timeout; + char buff[MAX_CTRL_FRAME]; + + timeout = 4; /* wait response for 4 seconds */ + lec_params.c7c_current_timeout = 1; + while (lec_params.c7c_current_timeout <= timeout) { + tv.tv_sec = lec_params.c7c_current_timeout; /* actually not specified exactly */ + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(lec_params.ctrl_direct->fd, &rfds); + if (lec_params.ctrl_dist != NULL) { + FD_SET(lec_params.ctrl_dist->fd, &rfds); + n = lec_params.ctrl_dist->fd; + } + n = (lec_params.ctrl_direct->fd > n) ? lec_params.ctrl_direct->fd : n; + n++; + + retval = select(n, &rfds, NULL, NULL, &tv); + if (retval == 0) { + lec_params.c7c_current_timeout++; + continue; /* back to waiting */ + } + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "get_bus_addr: select: %s\n", strerror(errno)); + return -1; + } + if (FD_ISSET(lec_params.ctrl_direct->fd, &rfds)) { + diag(COMPONENT, DIAG_DEBUG, "get_bus_addr: ctrl.direct changed:\n"); + retval = read_bus_arp(lec_params.ctrl_direct, addr, buff, sizeof(buff)); + if (retval < 0) return -1; + if (retval > 0) return retval; + } + if (lec_params.ctrl_dist != NULL && FD_ISSET(lec_params.ctrl_dist->fd, &rfds)) { + diag(COMPONENT, DIAG_DEBUG, "get_bus_addr: ctrl.dist changed:\n"); + retval = read_bus_arp(lec_params.ctrl_dist, addr, buff, sizeof(buff)); + if (retval < 0) return -1; + if (retval > 0) return retval; + } + diag(COMPONENT, DIAG_DEBUG, "get_bus_addr: consumed a packet\n"); + } + + diag(COMPONENT, DIAG_ERROR, "Timeout while waiting for BUS LE_ARP response\n"); + return 0; +} +/* + * Tries to read BUS ATM address in *addr + * returns < 0 for error, 0 for not found > 0 for success + */ +static int read_bus_arp(Conn_t *conn, struct sockaddr_atmsvc *addr, char *buff, int buffsize) +{ + int frame_size; + struct ctrl_frame *frame; + + frame_size = recv_frame(conn, buff, buffsize); + if (frame_size == 0) { + diag(COMPONENT, DIAG_ERROR, "LES Control connection closed\n"); + return -1; + } + if (frame_size < 0) { + diag(COMPONENT, DIAG_ERROR, "get_bus_arp: recv_frame: %s\n", strerror(errno)); + return -1; + } + frame = (struct ctrl_frame *)buff; + if (validate_frame(buff, frame_size) >= 0 && + frame->header.opcode == htons(LE_ARP_RSP) && + memcmp(frame->src_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN) == 0) { + memcpy(addr->sas_addr.prv, frame->target_atm_addr, ATM_ESA_LEN); + return frame_size; + } + + return 0; /* not found */ +} + +/* --------------- Bus connect specific stuff ends --------------- */ diff -ur --new-file old/atm/led.new/join.h new/atm/led.new/join.h --- old/atm/led.new/join.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/join.h Sat Feb 6 21:20:44 1999 @@ -0,0 +1,20 @@ +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef JOIN_H +#define JOIN_H + +void init_lec_params(unsigned char *mac_addr, char *elan_name, + unsigned char *listen_addr, int itf, char *foreId, + int max_frame_size, int proxy_flag, int lane_version); +int lec_configure(int lecs_method, struct sockaddr_atmsvc *manual_atm_addr, + struct sockaddr_atmsvc *listen_addr); +int les_connect(int lecs_method, struct sockaddr_atmsvc *manual_atm_addr, + struct sockaddr_atmsvc *listen_addr); +int bus_connect(void); + +/* Different ways to contact LECS */ +#define LECS_NONE 0 +#define LECS_WELLKNOWN 1 +#define LECS_MANUAL 2 + +#endif /* JOIN_H */ diff -ur --new-file old/atm/led.new/kernel.c new/atm/led.new/kernel.c --- old/atm/led.new/kernel.c Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/kernel.c Sun Feb 7 12:11:57 1999 @@ -0,0 +1,327 @@ +/* kernel.c - send and receive messages from kernel and act accordingly */ + +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Copyright (c) 1996 + * Tampere University of Technology - Telecommunications Laboratory + * All rights reserved. + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +/* System includes */ +#include <errno.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <string.h> +#include <stdlib.h> + +/* Atm includes */ +#include <atm.h> +#include <linux/atmdev.h> +#include <linux/atmlec.h> + +#include <atmd.h> + +/* Local includes */ +#include "kernel.h" +#include "lec.h" +#include "frames.h" + +#define COMPONENT "kernel.c" + +/* Local vars */ +static int lec_socket; + +static const char* get_mesg_type_str(atmlec_msg_type type); +static void send_le_arp_req(unsigned char *mac_addr, int sizeoftlvs); +static void send_proxy_arp_rsp(unsigned char *target_mac, uint32_t tran_id, + uint16_t lec_id, unsigned char *src_atm_addr); +static void send_topology_req(int flag); +static void associate_tlvs(int sizeoftlvs); + +/* Notify kernel that zeppelin is present and tell + * kernel what MAC address this LEC uses + */ +int kernel_init(unsigned char *mac_addr, int itf) +{ + int rvalue; + struct atmlec_msg msg; + + lec_socket = socket(PF_ATMSVC, SOCK_DGRAM, 0); + if (lec_socket < 0) { + diag(COMPONENT, DIAG_FATAL, "Kernel socket creation failed: %s\n", + strerror(errno)); + return -1; + } + itf = ioctl(lec_socket, ATMLEC_CTRL, itf); + if (itf < 0) { + diag(COMPONENT, DIAG_FATAL, "Socket ioctl to lecd_ctrl failed:%s\n", + strerror(errno)); + close(lec_socket); + return -1; + } + msg.type = l_set_mac_addr; + memcpy(msg.content.normal.mac_addr, mac_addr, ETH_ALEN); + + rvalue = write(lec_socket, &msg, sizeof(msg)); + if (rvalue < 0) { + diag(COMPONENT, DIAG_FATAL, "Can't write mac address to LEC:%s\n", + strerror(errno)); + close(lec_socket); + return -1; + } + diag(COMPONENT, DIAG_DEBUG, "Kernel interface initialized\n"); + + if (conn_set_kernel_socket(lec_socket) < 0) { + close(lec_socket); + return -1; + } + + return itf; +} + +/* Send a message to kernel + * Returns < 0 for error + */ +int msg_to_kernel(struct atmlec_msg *msg, int msg_size) +{ + int retval; + + diag(COMPONENT, DIAG_DEBUG, "msg_to_kernel, type %s\n", get_mesg_type_str(msg->type)); + retval = write(lec_params.kernel->fd, msg, msg_size); + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "msg_to_kernel: write: %s\n", strerror(errno)); + return -1; + } + if (retval != msg_size) { + diag(COMPONENT, DIAG_ERROR, "msg_to_kernel: partial write\n"); + return -1; + } + + return retval; +} + +/* Read and process message from kernel + * Returns < 0 for error + */ +int msg_from_kernel(void) +{ + int retval; + struct atmlec_msg msg; + int codepoint; + + retval = read(lec_params.kernel->fd, &msg, sizeof(struct atmlec_msg)); + if (retval < 0) { + diag(COMPONENT, DIAG_FATAL, "msg_from_kernel: read: %s\n", strerror(errno)); + return -1; + } + if (retval != sizeof(struct atmlec_msg)) { + diag(COMPONENT, DIAG_ERROR, "msg_from_kernel: msg size != sizeof(atmlec_msg)\n"); + return 0; + } + + diag(COMPONENT, DIAG_DEBUG, "msg_from_kernel: type %s\n", get_mesg_type_str(msg.type)); + switch (msg.type) { + case l_arp_xmt: + if (msg.content.normal.targetless_le_arp) + send_le_arp_req(NULL, msg.sizeoftlvs); + else + send_le_arp_req(msg.content.normal.mac_addr, msg.sizeoftlvs); + break; + case l_svc_setup: + codepoint = (msg.content.normal.mac_addr[0] & 0x01) ? MCAST_CONN : DATA_DIRECT_CONN; + if (create_data_svc(msg.content.normal.atm_addr, codepoint) < 0) + diag(COMPONENT, DIAG_ERROR, "Data direct VCC failed\n"); + break; + case l_associate_req: + associate_tlvs(msg.sizeoftlvs); + break; + case l_should_bridge: + send_proxy_arp_rsp(msg.content.proxy.mac_addr, msg.content.proxy.tran_id, + msg.content.proxy.lec_id, msg.content.proxy.atm_addr); + break; + case l_topology_change: + send_topology_req(msg.content.normal.flag); + break; + default: + diag(COMPONENT, DIAG_ERROR, "no handler for kernel msg %s\n", get_mesg_type_str(msg.type)); + break; + } + + return 0; +} + +/* Send LE_ARP_REQUEST. If mac_addr is NULL, sends a targetless LE_ARP. + * If sizeoftlvs != 0, reads TLVs waiting in the kernel socket and + * adds them to the frame. If sizeoftlvs == 0 then the TLVs (if any) + * associated with this LEC are used. + * FIXME: add TLV count in kernel messages + */ +static void send_le_arp_req(unsigned char *mac_addr, int sizeoftlvs) +{ + struct ctrl_frame *frame; + int frame_size; + char buff[MAX_CTRL_FRAME]; + + diag(COMPONENT, DIAG_DEBUG, "Sending LE_ARP_REQUEST\n"); + + if (sizeoftlvs == 0) frame_size = sizeof(struct ctrl_frame) + lec_params.sizeoftlvs; + else frame_size = sizeof(struct ctrl_frame) + sizeoftlvs; + frame = (struct ctrl_frame *)buff; + memset(frame, 0, frame_size); + + prefill_frame(frame, LE_ARP_REQ); + frame->header.lec_id = htons(lec_params.c14_lec_id); + frame->src_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + memcpy(frame->src_lan_dst.mac, lec_params.c6_mac_addr, ETH_ALEN); + memcpy(frame->src_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + if (mac_addr != NULL) { + frame->target_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + memcpy(frame->target_lan_dst.mac, mac_addr, ETH_ALEN); + } else diag(COMPONENT, DIAG_DEBUG, "Sending targetless LE_ARP\n"); + + if (sizeoftlvs != 0) { + if (read(lec_params.kernel->fd, (frame + 1), sizeoftlvs) < 0) { + diag(COMPONENT, DIAG_ERROR, "reading TLVs from kernel failed: %s\n", strerror(errno)); + return; + } + frame->num_tlvs++; + } else if (lec_params.sizeoftlvs != 0) { + memcpy((frame + 1), lec_params.tlvs, lec_params.sizeoftlvs); + frame->num_tlvs += lec_params.num_tlvs; + } + + send_frame(lec_params.ctrl_direct, frame, frame_size); + + return; +} + +/* Associate the set of TLVs available in kernel socket + * with this LEC. The old TLVs, if any, are removed. + * Also, send a LE_REGISTER_REQUEST to register the TLVs + * we just got. + */ +static void associate_tlvs(int sizeoftlvs) +{ + + if (lec_params.tlvs != NULL) free (lec_params.tlvs); + lec_params.sizeoftlvs = 0; + lec_params.num_tlvs = 0; + lec_params.tlvs = malloc(sizeoftlvs); + if (lec_params.tlvs == NULL) { + diag(COMPONENT, DIAG_ERROR, "Could not associate TLVs, out of memory\n"); + lec_params.sizeoftlvs = 0; + lec_params.num_tlvs = 0; + return; + } + if (read(lec_params.kernel->fd, lec_params.tlvs, sizeoftlvs) < 0) { + diag(COMPONENT, DIAG_ERROR, "reading TLVs from kernel failed: %s\n", strerror(errno)); + return; + } + + lec_params.sizeoftlvs = sizeoftlvs; + lec_params.num_tlvs = 1; /* FIXME, add TLV count in messages */ + + send_register_req(); + + return; +} + +/* Send a LE_ARP_RESPONSE for a LAN destination (MAC address) when + * the LAN destination is present in kernel bridging table and we + * are acting as a proxy lane client + */ +static void send_proxy_arp_rsp(unsigned char *target_mac, uint32_t tran_id, + uint16_t lec_id, unsigned char *src_atm_addr) +{ + struct ctrl_frame *frame; + int frame_size; + + frame_size = sizeof(struct ctrl_frame) + lec_params.sizeoftlvs; + frame = malloc(frame_size); + if (frame == NULL) return; + memset(frame, 0, frame_size); + prefill_frame(frame, LE_ARP_RSP); + frame->header.tran_id = tran_id; + frame->header.lec_id = lec_id; + frame->header.flags = htons(REMOTE_ADDRESS); + memcpy(frame->target_atm_addr, lec_params.c1n_my_atm_addr, ATM_ESA_LEN); + frame->target_lan_dst.tag = htons(LAN_DST_MAC_ADDR); + memcpy(frame->target_lan_dst.mac, target_mac, ETH_ALEN); + memcpy(frame->src_atm_addr, src_atm_addr, ATM_ESA_LEN); + frame->num_tlvs = lec_params.num_tlvs; + if (lec_params.num_tlvs > 0) + memcpy(frame + 1, lec_params.tlvs, lec_params.sizeoftlvs); + + if (send_frame(lec_params.ctrl_direct, frame, frame_size) < 0) + diag(COMPONENT, DIAG_ERROR, "send_proxy_arp_rsp: send_frame() failed"); + + return; +} + +/* 7.1.25 Send a LE_TOPOLOGY_REQUEST */ +static void send_topology_req(int flag) +{ + struct ctrl_frame frame; + + prefill_frame(&frame, LE_TOPO_REQ); + if (flag) frame.header.flags = htons(TOPO_CHANGE); + + send_frame(lec_params.ctrl_direct, &frame, sizeof(struct ctrl_frame)); + + return; +} + +static const char *get_mesg_type_str(atmlec_msg_type type) +{ + switch(type) { + case l_set_mac_addr: + return "SET_MAC_ADDR"; + case l_del_mac_addr: + return "DEL_MAC_ADDR"; + case l_svc_setup: + return "SVC_SETUP"; + case l_arp_xmt: + return "ARP_XMT"; + case l_addr_delete: + return "ADDR_DELETE"; + case l_topology_change: + return "TOPOLOGY_CHANGE"; + case l_flush_tran_id: + return "FLUSH_TRANSACTION_ID"; + case l_flush_complete: + return "FLUSH_COMPLETE"; + case l_arp_update: + return "ARP_UPDATE"; + case l_config: + return "CONFIG"; + case l_associate_req: + return "LANE2_ASSOCIATE_REQ"; + case l_set_lecid: + return "SET_LEC_ID"; + case l_narp_req: + return "LE_NARP_REQUEST"; + case l_should_bridge: + return "SHOULD_BRIDGE"; + default: + return "<Unknown message type>"; + } +} diff -ur --new-file old/atm/led.new/kernel.h new/atm/led.new/kernel.h --- old/atm/led.new/kernel.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/kernel.h Sat Feb 6 14:45:20 1999 @@ -0,0 +1,36 @@ +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Copyright (c) 1996 + * Tampere University of Technology - Telecommunications Laboratory + * All rights reserved. + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef KERNEL_H +#define KERNEL_H +#include <linux/atmlec.h> + +int kernel_init(unsigned char *mac_addr, int itf); +int msg_to_kernel(struct atmlec_msg *msg, int msg_size); +int msg_from_kernel(void); +int read_from_kernel (char *buff, int size); + +#endif /* KERNEL_H */ diff -ur --new-file old/atm/led.new/lec.h new/atm/led.new/lec.h --- old/atm/led.new/lec.h Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/lec.h Sat Feb 6 21:49:04 1999 @@ -0,0 +1,64 @@ +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +#ifndef LEC_H +#define LEC_H + +#include "conn.h" + +/* + * LANE client configuration and operation values. + * These are in host byte order since there are + * some values coming from network and some values + * which are used by the host only + */ +struct lec_params { + unsigned char c1n_my_atm_addr[ATM_ESA_LEN]; + uint8_t c2_lan_type; + uint8_t c3_max_frame_size; + int c4_proxy_flag; + char c5_elan_name[32 + 1]; + char c6_mac_addr[ETH_ALEN]; + int c7_ctrl_timeout; + int c7i_initial_ctrl_timeout; + int c7x_timeout_multiplier; + int c7c_current_timeout; /* sum of c7i and c7x, LANEv2 5.3.1.7 */ + unsigned char c9_les_atm_addr[ATM_ESA_LEN]; + int c10_max_unknown_frames; + int c11_max_unknown_frame_time; + int c12_vcc_timeout; + int c13_max_retry_count; + uint16_t c14_lec_id; + int c17_aging_time; + int c18_forward_delay_time; + int c19_topology_change; + int c20_le_arp_response_time; + int c21_flush_timeout; + int c22_path_switching_delay; + /* LANE2 variables follow */ + int c29_v2_capable; + uint32_t c31_elan_id; + unsigned char c35_preferred_les[ATM_ESA_LEN]; + int c35_contains_address; + int c37_min_reconfig_delay; /* milliseconds */ + int c38_max_reconfig_delay; /* milliseconds */ + + /* other stuff */ + int itf_num; /* 1 for lec1 and so forth */ + int sizeoftlvs; /* total size of TLVs associated with this LEC */ + int num_tlvs; /* number of the TLVs */ + unsigned char *tlvs; /* the TLVs */ + char foreId[255]; + + /* connections to and from LES/BUS plus listen sockets */ + Conn_t *kernel; + Conn_t *ctrl_direct; + Conn_t *ctrl_listen; /* Closed when join phase is over */ + Conn_t *ctrl_dist; + Conn_t *mcast_send; /* LANEv2 calls this Default Mcast Send VCC */ + Conn_t *mcast_listen; + Conn_t *data_listen; +}; + +extern struct lec_params lec_params; + +#endif /* LEC_H */ diff -ur --new-file old/atm/led.new/main.c new/atm/led.new/main.c --- old/atm/led.new/main.c Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/main.c Sun Feb 7 12:07:52 1999 @@ -0,0 +1,451 @@ +/* main.c - Do what ever a LANE client does */ + +/* + * Marko Kiiskila carnil@cs.tut.fi + * + * Copyright (c) 1996 + * Tampere University of Technology - Telecommunications Laboratory + * All rights reserved. + * + * Permission to use, copy, modify and distribute this + * software and its documentation is hereby granted, + * provided that both the copyright notice and this + * permission notice appear in all copies of the software, + * derivative works or modified versions, and any portions + * thereof, that both notices appear in supporting + * documentation, and that the use of this software is + * acknowledged in any publications resulting from using + * the software. + * + * TUT ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + * + */ + +/* Copyright (C) 1999 Heikki Vatiainen hessu@cs.tut.fi */ + +/* Global includes */ +#include <stdlib.h> +#include <stdio.h> +#include <sys/time.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> + +#include <atm.h> +#include <atmd.h> + +#include <linux/atmlec.h> + +/* Local incs */ +#include "join.h" +#include "lec.h" +#include "address.h" +#include "display.h" +#include "kernel.h" + +#define COMPONENT "main.c" + +static void main_loop(void); +static int reset = 0; + +void sig_reset(int a) +{ + reset = 1; + + return; +} + +static void usage(const char *progname) +{ + printf("Usage: %s [-c LECS_address | -s LES_address] [-e esi] [-n VLAN_name]" + " [-m mesg_mask] [-l listen_address] [-i interface_number]" + " [-t 1516|1580|4544|9234|18190] [-1] [-2] [-p] [-F logfile]" + " [-f Fore specific name]\n", progname); +} + +/* + * My First C function (TM), hessu@cs.tut.fi + */ +static int esi_convert(char *parsestring, unsigned char *mac_addr) +{ + const char *hexchars = "abcdefABCDEF0123456789"; + char hexnum [17+1], curr; + int i = 0, j = -1, hexindex = 0, tmp; + char *k, *string; + + if (strchr(parsestring,'.') || /* do we have separators like */ + strchr(parsestring,':')) { /* 00:20:22:23:04:05 */ + k = parsestring; + for (i = 0; i < strlen(parsestring); i++) { + curr = *k; + if (curr == ':' || curr == '.') { /* separator ? */ + if (i - j == 3) { /* there were 2 hex characters */ + ; + } + else if (i - j == 2) { /* there was only 1 hex char */ + hexnum [hexindex] = hexnum [hexindex-1]; + hexnum [hexindex-1] = '0'; + hexindex +=1; + } + else /* too many hexchars in a byte */ + return -1; + j = i; /* j is the location of the last separator */ + } + else if (strchr(hexchars, curr) == NULL) /* not a hexchar ? */ + return -1; + else { /* we have a hex character */ + hexnum [hexindex] = curr; + hexindex +=1; + } + k++; + } + hexnum [hexindex] = '\0'; + string = hexnum; + } else { /* no separators */ + k = parsestring; + while (*k != '\0') { + if (strchr(hexchars, *k) == NULL) + return -1; + k++; + } + + string = parsestring; + } + + /* the esi now looks like 002022230405 */ + i = strlen(string); + if (i != 12) + return -1; + for(i=0; i<6; i++) { + sscanf(&string[i*2], "%2x", &tmp); + mac_addr[i] = (unsigned char)tmp; + } + return 0; +} + +/* Tells kernel what our LEC_ID is. + * Returns < 0 for serisous error + */ +static int set_lec_id(uint16_t lec_id) +{ + struct atmlec_msg msg; + + memset(&msg, 0, sizeof(struct atmlec_msg)); + msg.type = l_set_lecid; + msg.content.normal.flag = lec_id; + if (msg_to_kernel(&msg, sizeof(struct atmlec_msg)) < 0) { + diag(COMPONENT, DIAG_ERROR, "Could not tell kernel LEC_ID\n"); + return -1; + } + + return 0; +} + +/* Tell kernel the parameters this ELAN has. + * Returns < 0 for serious error + */ +static int config_kernel(void) +{ + struct atmlec_msg msg; + + memset(&msg, 0, sizeof(struct atmlec_msg)); + msg.type = l_config; + msg.content.config.maximum_unknown_frame_count = lec_params.c10_max_unknown_frames; + msg.content.config.max_unknown_frame_time = lec_params.c11_max_unknown_frame_time; + msg.content.config.max_retry_count = lec_params.c13_max_retry_count; + msg.content.config.aging_time = lec_params.c17_aging_time; + msg.content.config.forward_delay_time = lec_params.c18_forward_delay_time; + msg.content.config.arp_response_time = lec_params.c20_le_arp_response_time; + msg.content.config.flush_timeout = lec_params.c21_flush_timeout; + msg.content.config.path_switching_delay = lec_params.c22_path_switching_delay; + msg.content.config.lane_version = (lec_params.c29_v2_capable) ? 2 : 1; + + if (msg_to_kernel(&msg, sizeof(struct atmlec_msg)) < 0) { + diag(COMPONENT, DIAG_ERROR, "Could not tell kernel ELAN parameters\n"); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + char mac_addr[ETH_ALEN]; + char elan_name[32 + 1]; + char preferred_les[ATM_ESA_LEN]; /* LANE2 */ + char foreId[255]; /* Max size for a TLV */ + char atm2textbuff[100]; + char esibuff[20]; + int esi_set = 0; + int atm_set=0; + int proxy_flag = 0; + int lane_version = 0; /* LANE2 */ + int max_frame_size = MTU_UNSPEC; + int lecs_method = LECS_WELLKNOWN; + int poll_ret = 0, itf = 0; + struct sockaddr_atmsvc manual_atm_addr; + struct sockaddr_atmsvc listen_addr; + + memset(elan_name, '\0', sizeof(elan_name)); + memset(foreId, '\0', sizeof(foreId)); + memset(preferred_les, 0, ATM_ESA_LEN); + memset(&manual_atm_addr, 0, sizeof(struct sockaddr_atmsvc)); + memset(&listen_addr, 0, sizeof(struct sockaddr_atmsvc)); + + set_application("zeppelin"); /* for debug msgs */ + + if (get_listenaddr(listen_addr.sas_addr.prv) < 0) { + diag(COMPONENT, DIAG_FATAL, "Could not figure out my ATM address\n"); + exit(-1); + } + + while(poll_ret != -1) { + poll_ret = getopt(argc, argv, "c:e:n:s:m:l:i:q:12pf:t:F:"); + switch(poll_ret) { + case 'c': + if (atm_set) { + usage(argv[0]); + exit(-1); + } + if (text2atm(optarg, (struct sockaddr *)&manual_atm_addr, + sizeof(struct sockaddr_atmsvc), T2A_NAME) < 0) { + diag(COMPONENT, DIAG_ERROR, "Invalid LECS address\n"); + usage(argv[0]); + exit(-1); + } + atm2text(atm2textbuff, sizeof(atm2textbuff), + (struct sockaddr *)&manual_atm_addr, 0); + diag(COMPONENT, DIAG_INFO, "LECS address: %s\n", atm2textbuff); + lecs_method = LECS_MANUAL; + atm_set=1; + break; + case 'e': + if(esi_convert(optarg, mac_addr)<0) { + diag(COMPONENT, DIAG_ERROR, "Invalid ESI format\n"); + usage(argv[0]); + exit(-1); + } + mac2text(esibuff, mac_addr); + diag(COMPONENT, DIAG_DEBUG, "LEC ESI:%s\n", esibuff); + esi_set=1; + break; + case 'n': + if (strlen(optarg) > 32) { + diag(COMPONENT, DIAG_ERROR, "ELAN name too long\n"); + exit(-1); + } + strcpy(elan_name, optarg); + diag(COMPONENT, DIAG_INFO, "Vlan name :'%s'\n", elan_name); + break; + case 's': + if (atm_set) { + usage(argv[0]); + exit(-1); + } + if (text2atm(optarg, (struct sockaddr *)&manual_atm_addr, + sizeof(struct sockaddr_atmsvc), T2A_NAME) < 0) { + diag(COMPONENT, DIAG_ERROR, "Invalid LES address\n"); + usage(argv[0]); + exit(-1); + } + atm2text(atm2textbuff, sizeof(atm2textbuff), + (struct sockaddr *)&manual_atm_addr, 0); + diag(COMPONENT, DIAG_INFO, "LES address: %s\n", atm2textbuff); + lecs_method = LECS_NONE; + atm_set=1; + break; + case 'm': + set_verbosity(NULL, DIAG_DEBUG); + break; + case 'l': + if (text2atm(optarg, (struct sockaddr *)&listen_addr, + sizeof(struct sockaddr_atmsvc), T2A_NAME) < 0) { + diag(COMPONENT, DIAG_ERROR, "Invalid ATM listen address\n"); + usage(argv[0]); + exit(-1); + } + atm2text(atm2textbuff, sizeof(atm2textbuff), + (struct sockaddr *)&listen_addr, 0); + diag(COMPONENT, DIAG_INFO, "Our ATM address: %s\n", atm2textbuff); + break; + case 'i': + if (sscanf(optarg, "%d", &itf) < 0 || itf >= MAX_LEC_ITF) { + diag(COMPONENT, DIAG_ERROR, "Invalid interface number\n"); + usage(argv[0]); + exit(-1); + } + diag(COMPONENT, DIAG_INFO, "Interface number set to %d\n", itf); + break; + case 'q': +#if 0 + if (text2qos(optarg,NULL,0) < 0) { + diag(COMPONENT, DIAG_ERROR, "Invalid QOS specification\n"); + usage(argv[0]); + exit(-1); + } + qos_spec = optarg; +#endif + diag(COMPONENT, DIAG_INFO, "-q is deprecated, ignoring it\n"); + break; + case '1': + lane_version = 1; + break; + case '2': + lane_version = 2; + break; + case 'p': + proxy_flag = 1; + break; + case 'f': + if (strlen(optarg) > 255) { + diag(COMPONENT, DIAG_ERROR, "foreId too long\n"); + exit(-1); + } + memcpy (foreId, optarg, strlen(optarg)); + foreId[strlen(optarg)] = '\0'; + diag(COMPONENT, DIAG_INFO, "foreId :'%s'\n", foreId); + break; + case 't': /* ERIC */ + if( !strncmp( optarg, "1516", 4 )) max_frame_size = MTU_1516; + else if( !strncmp( optarg, "1580", 4 )) max_frame_size = MTU_1580; + else if( !strncmp( optarg, "4544", 4 )) max_frame_size = MTU_4544; + else if( !strncmp( optarg, "9234", 4 )) max_frame_size = MTU_9234; + else if( !strncmp( optarg, "18190", 5 )) max_frame_size = MTU_18190; + break; + case 'F': + set_logfile(optarg); + diag(COMPONENT, DIAG_DEBUG, "logfile set to %s\n", optarg); + break; + case -1: + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (argc != optind) { + usage(argv[0]); + exit(1); + } + if (lane_version == 1 && max_frame_size == MTU_1580) { + diag(COMPONENT, DIAG_ERROR, "MTU 1580 not defined with LANEv1\n"); + exit(-1); + } + + /* Reserve signals */ + signal(SIGHUP, sig_reset); + + if (!esi_set) { + if(addr_getesi(mac_addr) < 0) { + diag(COMPONENT, DIAG_ERROR, "Can't get ESI from kernel!\n"); + return -1; + } + mac2text(esibuff, mac_addr); + diag(COMPONENT, DIAG_DEBUG, "LEC ESI:%s\n", esibuff); + } + + /* Loop here until the Sun gets cold */ + while (1) { + if ((itf = kernel_init(mac_addr, itf)) < 0 ) { + diag(COMPONENT, DIAG_FATAL, "Kernel interface creation failed, exiting...\n"); + return -1; + } + + diag(COMPONENT, DIAG_DEBUG, "initializing lec parameters\n"); + init_lec_params(mac_addr, elan_name, listen_addr.sas_addr.prv, + itf, foreId, max_frame_size, proxy_flag, lane_version); + + diag(COMPONENT, DIAG_DEBUG, "About to connect LECS\n"); + if (lec_configure(lecs_method, &manual_atm_addr, &listen_addr) < 0) { + close_connections(); + random_delay(); + continue; + } + diag(COMPONENT, DIAG_DEBUG, "About to connect LES\n"); + if (les_connect(lecs_method, &manual_atm_addr, &listen_addr) < 0) { + close_connections(); + random_delay(); + continue; + } + diag(COMPONENT, DIAG_DEBUG, "About to connect BUS\n"); + if (bus_connect() < 0) { + close_connections(); + random_delay(); + continue; + } + diag(COMPONENT, DIAG_DEBUG, "About to create data direct listen socket\n"); + if (create_data_listen() < 0) { + close_connections(); + random_delay(); + continue; + } + diag(COMPONENT, DIAG_DEBUG, "About to tell kernel our LEC_ID %d\n", lec_params.c14_lec_id); + if (set_lec_id(lec_params.c14_lec_id) < 0) { + close_connections(); + continue; + } + diag(COMPONENT, DIAG_DEBUG, "About to tell kernel LEC parameters\n"); + if (config_kernel() < 0) { + close_connections(); + continue; + } + + diag(COMPONENT, DIAG_DEBUG, "Joined ELAN '%s' successfully\n", lec_params.c5_elan_name); + + main_loop(); + diag(COMPONENT, DIAG_INFO, "Resetting...\n"); + close_connections(); + random_delay(); + + reset = 0; + } + + return 0; /* not reached */ +} + +/* zeppelin loops here when it is in operational state. The check + * against reset variable is probably not needed since select() will + * return < 0 when a signal interrupts it. + */ +static void main_loop(void) +{ + fd_set rfds, cfds; + int retval, ret1, ret2, ret3; + + while(!reset) { + retval = ret1 = ret2 = ret3 = 0; + FD_ZERO(&rfds); + conn_get_fds(&rfds); + FD_ZERO(&cfds); + conn_get_connecting_fds(&cfds); + + retval = select(FD_SETSIZE, &rfds, &cfds, NULL, NULL); + diag(COMPONENT, DIAG_DEBUG, "main_loop: select returned %d\n", retval); + if (retval < 0) { + diag(COMPONENT, DIAG_ERROR, "main_loop: select: %s\n", strerror(errno)); + break; /* leave main_loop */ + } + if (retval == 0) { + /* Timeout, funny, since we have no timers */ + continue; + } + if (FD_ISSET(lec_params.kernel->fd, &rfds)) { + ret1 = msg_from_kernel(); + FD_CLR(lec_params.kernel->fd, &rfds); + } + ret2 = complete_connections(&cfds); + ret3 = check_connections(&rfds); + + if (ret1 < 0 || ret2 < 0 || ret3 < 0) + break; /* leave main_loop */ + } + + diag(COMPONENT, DIAG_DEBUG, "exiting main_loop\n"); + + return; +} diff -ur --new-file old/atm/led.new/zeppelin.new.8 new/atm/led.new/zeppelin.new.8 --- old/atm/led.new/zeppelin.new.8 Thu Jan 1 01:00:00 1970 +++ new/atm/led.new/zeppelin.new.8 Sat Feb 6 23:48:20 1999 @@ -0,0 +1,91 @@ +.TH zeppelin 8 "Feb 6, 1999" "Linux" "Maintenance Commands" +.SH NAME +zeppelin \- ATM LAN Emulation client demon (LED) Zeppelin +.SH SYNOPSIS +.B zeppelin +.RB [ \-c\ \fILECS_address\fP\ |\ \-s\ \fILES_address\fP ] +.RB [ \-e\ \fIesi\fP ] +.RB [ \-n\ \fIVLAN_name\fP ] +.RB [ \-m\ \fImesg_mask\fP ] +.RB [ \-l\ \fIlisten_address\fP ] +.RB [ \-i\ \fIinterface_number\fP ] +.RB [ \-t\ \fI1516|1580|4544|9234|18190\fP ] +.RB [ \-1\ ] +.RB [ \-2\ ] +.RB [ \-p\ ] +.RB [ \-F\ \fIlogfile\fP ] +.RB [ \-f\ \fIFore_specific_name\fP ] +.SH DESCRIPTION +A LAN Emulation Client is an entity in an ATM endstation that performs +data forwarding, address resolution and other control functions. It +uses the LUNI interface when communicating with other components in +emulated LANs. It provides upper protocol layers a MAC like +interface similar to IEEE 802.3/Ethernet or IEEE 802.5/Token Ring LAN. +.PP +LAN Emulation client code is divided into two parts: user space +application LAN Emulation Demon called (LED) \fBzeppelin(8)\fP, and the +kernel component. \fBZeppelin\fP is responsible for control operations needed +in LAN Emulation clienthood. It forms the necessary VCCs and receives +all the LE control frames and acts accordingly. It also controls the +operation of the LEC kernel component. +.PP +Linux LEC supports only Ethernet type of emulated LAN. +.PP +\fBSIGHUP\fP causes restart of the LEC. All resources are +released and \fBzeppelin\fP is started. +.SH OPTIONS +.IP \fB\-c\ \fILECS_address\fP +ATM address of \fBlecs(8)\fP (Lan Emulation Configuration Server), if not +set, Well-Known server address is used. +.IP \fB\-s\ \fILES_address\fP +ATM address of \fBles(8)\fP (Lan Emulation Server), can be used in +bypassing configuration phase in joining emulated Lan i.e \fBlecs\fP address +is not used. +.IP \fB\-e\ \fIesi\fP +Mac address to use when communicating in Emulated LAN. E.g. 00:20:22:23:04:05 . +.IP \fB\-n\ \fIVLAN_name\fP +Name of the virtual LAN to which joining is requested. +This is used in LE_CONFIGURE_REQUEST to LECS or +LE_JOIN_RESPONSE to LES, if configuration phase is bypassed. +.IP \fB\-m\ \fImesg_mask\fP +Sometimes one wants to know more what is happening in LE +daemon e.g. when nothing works. This is a hexadecimal long value +setting global message mask. 0 = No messages, ffff = All messages. +.IP \fB\-l\ \fIlisten_address\fP +Local ATM address that zeppelin uses as local binding point in +signalling. Use this if you are running more than one client or +a set of LE servers. +.IP \fB\-i\ \fIinterface_number\fP +Linux LEC supports up to 16 network interfaces. This number tells +zeppelin to which of these to attach. Network interfaces are +numbered from "lec0" to "lec15". +.IP \fB\-t\ \fIMTU\fP +The MTU of ELAN to join. You need to also use \fBifconfig(8)\fP to +set the MTU of the LANE interface. +.IP \fB\-1\fP +Run as LANEv1 client. This is the default. +.IP \fB\-2\fP +Run as LANEv2 client. This is required by MPOA. +.IP \fB\-p\fP +Enable proxy. When started with this option, it is possible to bridge +packets between ATM and Ethernet. That is, you can use LANE interfaces +with normal bridging. See the Bridging mini-Howto for more info. +.IP \fB\-F\ \fIlogfile\fP +Instead of writing debug messages to \fBstderr\fP, write the messages +to the file \fBlogfile\fP. Use \fBsyslog\fP as the file name to use +the \fBsyslog(3)\fP facility. +.IP \fB\-f\ \fIFore\ specific\ name\fP +The LANE servers on Fore ATM switches can display a special +name if a client can supply one. This name shows with command +\'conf lane les show advanced\'. +.SH BUGS +Supports only IEEE 802.3 / Ethernet type of ELANs. Please report any +new bugs to Heikki Vatiainen <hessu@cs.tut.fi> +.PP +John Bonham died 1980 and Led Zeppelin broke. +.SH AUTHORS +Marko Kiiskila, TUT <carnil@cs.tut.fi> and Heikki Vatiainen, TUT +<hessu@cs.tut.fi> +.SH "SEE ALSO" +lecs(8), mpcd(8), atmsigd(8), les(8), qos(7) +.\"{{{}}} diff -ur --new-file old/atm/lib/ans.c new/atm/lib/ans.c --- old/atm/lib/ans.c Sat Jun 6 01:52:45 1998 +++ new/atm/lib/ans.c Tue Feb 9 17:31:56 1999 @@ -137,9 +137,14 @@ switch (*addr) { case ATM_AFI_DCC: case ATM_AFI_ICD: + case ATM_AFI_LOCAL: + case ATM_AFI_DCC_GROUP: + case ATM_AFI_ICD_GROUP: + case ATM_AFI_LOCAL_GROUP: fmt = fmt_dcc; break; case ATM_AFI_E164: + case ATM_AFI_E164_GROUP: fmt = fmt_e164; break; default: diff -ur --new-file old/atm/lib/atm2text.c new/atm/lib/atm2text.c --- old/atm/lib/atm2text.c Wed Sep 9 21:04:49 1998 +++ new/atm/lib/atm2text.c Tue Feb 9 17:31:56 1999 @@ -65,6 +65,7 @@ { static int pure[] = { 20 }; static int bin[] = { 1,2,10,6,1 }; + static int local[] = { 1,12,6,1 }; static int e164[] = { 4,6,1 }; int orig_len,len,i,left,value; @@ -94,9 +95,16 @@ switch (*addr->sas_addr.prv) { case ATM_AFI_DCC: case ATM_AFI_ICD: + case ATM_AFI_DCC_GROUP: + case ATM_AFI_ICD_GROUP: fmt = bin; break; + case ATM_AFI_LOCAL: + case ATM_AFI_LOCAL_GROUP: + fmt = local; + break; case ATM_AFI_E164: + case ATM_AFI_E164_GROUP: for (i = 2; i < 17; i++) if (addr->sas_addr.prv[i >> 1] & (0xf0 >> 4*(i & 1))) break; diff -ur --new-file old/atm/mkdist new/atm/mkdist --- old/atm/mkdist Sat Dec 5 01:43:59 1998 +++ new/atm/mkdist Tue Feb 9 17:18:50 1999 @@ -101,6 +101,13 @@ atm/led/address.c atm/led/conn.c atm/led/main.c atm/led/kernel_itf.c \ atm/led/lane2.h \ atm/led/Makefile atm/led/zeppelin.8 \ + atm/led.new/COPYRIGHT.TUT atm/led.new/Makefile \ + atm/led.new/address.c atm/led.new/address.h atm/led.new/conn.c \ + atm/led.new/conn.h atm/led.new/display.c atm/led.new/display.h \ + atm/led.new/frame_defs.h atm/led.new/frames.c atm/led.new/frames.h \ + atm/led.new/join.c atm/led.new/join.h atm/led.new/kernel.c \ + atm/led.new/kernel.h atm/led.new/lec.h atm/led.new/main.c \ + atm/led.new/zeppelin.new.8 \ atm/lane/COPYRIGHT.TUT atm/lane/Makefile atm/lane/USAGE \ atm/lane/bus.8 atm/lane/lecs.8 atm/lane/les.8 \ atm/lane/atm.c \ diff -ur --new-file old/atm/sigd/atmsigd.c new/atm/sigd/atmsigd.c --- old/atm/sigd/atmsigd.c Tue Nov 3 17:23:38 1998 +++ new/atm/sigd/atmsigd.c Tue Jan 5 16:35:04 1999 @@ -1,6 +1,6 @@ /* atmsigd.c - ATM signaling demon */ -/* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ +/* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #include <stdlib.h> @@ -339,7 +339,22 @@ diag(COMPONENT,DIAG_FATAL,"Error in config file. - Aborting."); if (!atmpvc_addr_in_use(_entity.signaling_pvc)) _entity.signaling_pvc.sap_addr.vci = 5; - if (!_entity.uni) _entity.uni = S_UNI30; + if (!_entity.uni) + _entity.uni = +#ifdef UNI31 + S_UNI31 +#ifdef ALLOW_UNI30 + | S_UNI30 +#endif +#elif defined(UNI40) + S_UNI40 +#ifdef Q2963_1 + | S_Q2963_1 +#endif +#else + S_UNI30 +#endif + ; /* process all other options but -c */ optind = 0; while ((c = getopt(argc,argv,"Abc:dD:l:m:nNP:q:t:")) != EOF) diff -ur --new-file old/atm/sigd/uni.c new/atm/sigd/uni.c --- old/atm/sigd/uni.c Wed Dec 2 18:45:17 1998 +++ new/atm/sigd/uni.c Tue Jan 5 20:01:23 1999 @@ -1,6 +1,6 @@ /* uni.c - Processing of incoming UNI signaling messages */ -/* Written 1995-1998 by Werner Almesberger, EPFL-LRC/ICA */ +/* Written 1995-1999 by Werner Almesberger, EPFL-LRC/ICA */ #include <stdarg.h> @@ -754,7 +754,7 @@ } if (curr && q_present(&in_dsc,QF_ep_ref) && mid != ATM_MSG_ADD_PARTY && mid != ATM_MSG_DROP_PARTY_ACK) - if (curr->ep_ref != q_fetch(&in_dsc,QF_ep_ref) ^ 0x8000) { + if (curr->ep_ref != (q_fetch(&in_dsc,QF_ep_ref) ^ 0x8000)) { send_drop_party_ack(sig,call_ref, q_fetch(&in_dsc,QF_ep_ref) ^ 0x8000,ATM_CV_INV_EPR); return;