diff -ur --new-file old/atm/.kernel new/atm/.kernel --- old/atm/.kernel Sat Nov 16 00:24:00 1996 +++ new/atm/.kernel Wed May 14 23:13:09 1997 @@ -1,2 +1,2 @@ # this file is used to control automated generation of differences -2.0.25 +2.1.37 diff -ur --new-file old/atm/CHANGES new/atm/CHANGES --- old/atm/CHANGES Tue Apr 22 23:36:23 1997 +++ new/atm/CHANGES Thu Jul 10 19:14:34 1997 @@ -1,3 +1,45 @@ +Version 0.31 to 0.32 (10-JUL-1997) +==================== + +Bug fixes +--------- + + - manipulation of local ATM addresses didn't check for permission + +New features +------------ + + - ilmid now supports the system group and a couple of ILMI MIB objects (by + Scott Shumate) + - device and VCC allocation is now dynamic + - E.164 addressing support and corrections to address coding in uni3x/uni40 + (by S. A. Wright, T. C. Jepsen, and Z. Zhang) + - support for device de-allocation via per-device operation dev_close + +Other changes +------------- + + - upgrade to kernel version 2.1.37 + - ENI driver cleanup (uses readl/writel, skb_put, etc.) + - socket option handling has changed: optval is now void * (to improve + compile-time type checking) and optlen is int (not int *) in getsockopt + - socket option "names" now encode the level and the size (based on an idea of + Elwyn Davies) + - cleaned up some of the #includes in net/atm/proc.c + - total rewrite of ATMTCP (now the data forwarding is done in user space, + which makes things slower but a lot more flexible) + - separated PDU parsing and printing from SSCOP state machine + - new per-device operation dev_close to shut down devices + - changed a few DIAG_WARNs to DIAG_INFO in ilmid + +Removed features +---------------- + + - polled ATM devices are no longer supported + - CLIP is gone (use ATMARP instead) + - Arequipa and LANE don't work yet (will come back later) + + Version 0.30 to 0.31 (22-APR-1997) ==================== diff -ur --new-file old/atm/VERSION new/atm/VERSION --- old/atm/VERSION Tue Apr 22 23:31:03 1997 +++ new/atm/VERSION Wed May 14 23:12:56 1997 @@ -1 +1 @@ -0.31 +0.32 diff -ur --new-file old/atm/arpd/io.c new/atm/arpd/io.c --- old/atm/arpd/io.c Thu Apr 10 11:48:29 1997 +++ new/atm/arpd/io.c Wed Jul 9 18:35:29 1997 @@ -381,7 +381,17 @@ FD_SET(entry->vccs->fd,&rset); if (entry->vccs->fd >= fds) fds = entry->vccs->fd+1; } - ret = select(fds,&rset,&cset,&cset,next_timer()); + ret = select(fds,&rset,&cset,NULL,next_timer()); +fprintf(stderr,"select = %d\n",ret); +#if 0 +{ + int i; + for (i = 0; i < sizeof(rset); i++) + fprintf(stderr,"%02x:%02x ",((unsigned char *) &rset)[i], + ((unsigned char *) &cset)[i]); + fprintf(stderr,"\n"); +} +#endif if (ret < 0) { if (errno != EINTR) perror("select"); } @@ -407,7 +417,7 @@ if (FD_ISSET(entry->vccs->fd,&rset)) recv_vcc(entry->vccs); } expire_timers(); - /* expire timers after handling messges to make sure we don't + /* expire timers after handling messages to make sure we don't time out unnecessarily because of scheduling delays */ } dump_all(); diff -ur --new-file old/atm/atm-0.31-1.spec new/atm/atm-0.31-1.spec --- old/atm/atm-0.31-1.spec Tue Apr 22 23:37:40 1997 +++ new/atm/atm-0.31-1.spec Thu Jan 1 01:00:00 1970 @@ -1,138 +0,0 @@ -Summary: ATM (Asynchronous Transfer Mode) -Name: atm -Version: 0.31 -Release: 1 -Source: atm-0.31.tar.gz -Source: lrcftp.epfl.ch:/pub/linux/atm/dist/atm-0.31.tar.gz -Copyright: distributable -Group: Networking/ATM -ExclusiveArch: i386 -ExclusiveOS: Linux - -%description -Programs, libraries, and configuration files required for using ATM -on Linux. Note that you still need to patch your kernel. - -%package ans -Summary: ANS (ATM Name Server) -Group: Networking/ATM - -%description ans -ANS is a version of BIND with extensions for ATM. This package contains -the complete BIND distribution, including tools like nslookup and dig. - -%prep - -%setup -n atm - -%build -make -cd extra -make tcpdump -make ans - -%install -INSTPREFIX=/usr make -e -cd config/redhat-4.0 -make install -cd ../../extra -INSTPREFIX=/usr make -e install - -%files ans -/usr/lib/libresolv.a -/usr/include/arpa/inet.h -/usr/include/arpa/nameser.h -/usr/include/netdb.h -/usr/include/resolv.h -/usr/include/sys/bitypes.h -/usr/lib/lib44bsd.a -/usr/sbin/named -/usr/sbin/named-xfer -/usr/sbin/named.restart -/usr/sbin/named.reload -/usr/sbin/ndc -/usr/bin/nslookup -/usr/lib/nslookup.help -/usr/bin/host -/usr/bin/dig -/usr/bin/dnsquery -/usr/bin/addr -/usr/man/man1/dig.1 -/usr/man/man1/host.1 -/usr/man/man1/dnsquery.1 -/usr/man/man8/named.8 -/usr/man/man8/named.reload.8 -/usr/man/man8/named.restart.8 -/usr/man/man8/ndc.8 -/usr/man/man8/named-xfer.8 -/usr/man/man8/nslookup.8 -/usr/man/man3/gethostbyname.3 -/usr/man/man3/resolver.3 -/usr/man/man3/getnetent.3 -/usr/man/man5/resolver.5 -/usr/man/man7/hostname.7 -/usr/man/man7/mailaddr.7 - -%files -%doc README -%doc USAGE -%config /etc/sysconfig/atm -%config /etc/atmsigd.conf -%config /etc/sysconfig/network-scripts/ifcfg-atm0 -%config /etc/sysconfig/network-scripts/ifup-atm -%config /etc/hosts.atm -/usr/sbin/tcpdump -/usr/lib/libatm.a -/usr/lib/libatmd.a -/usr/lib/libarequipa.a -/usr/include/atm.h -/usr/include/atmd.h -/usr/include/atmsap.h -/usr/include/arequipa.h -/usr/sbin/atmaddr -/usr/sbin/atmtcp -/usr/sbin/zntune -/usr/bin/atmdiag -/usr/bin/atmdump -/usr/bin/sonetdiag -/usr/man/man8/atmaddr.8 -/usr/man/man8/atmdiag.8 -/usr/man/man8/atmdump.8 -/usr/man/man8/atmtcp.8 -/usr/sbin/clip -/usr/sbin/atmarp -/usr/man/man8/clip.8 -/usr/man/man8/atmarp.8 -/usr/bin/aping -/usr/bin/aread -/usr/bin/awrite -/usr/bin/br -/usr/bin/bw -/usr/bin/ttcp_atm -/usr/bin/window -/usr/sbin/delay -/usr/sbin/aqtest -/usr/sbin/ed -/usr/sbin/encopy -/usr/sbin/endump -/usr/sbin/zndump -/usr/sbin/znth -/usr/sbin/atmsigd -/usr/man/man4/atmsigd.conf.4 -/usr/man/man8/atmsigd.8 -/usr/sbin/atmarpd -/usr/man/man8/atmarpd.8 -/usr/sbin/ilmid -/usr/sbin/zeppelin -/usr/man/man8/zeppelin.8 -/usr/sbin/les -/usr/sbin/bus -/usr/sbin/lecs -/usr/man/man8/les.8 -/usr/man/man8/lecs.8 -/usr/man/man8/bus.8 -/usr/sbin/arequipad -/usr/sbin/aqpvc -/usr/man/man8/arequipad.8 -/usr/man/man8/aqpvc.8 -/usr/man/man7/qos.7 diff -ur --new-file old/atm/atm-0.32-1.spec new/atm/atm-0.32-1.spec --- old/atm/atm-0.32-1.spec Thu Jan 1 01:00:00 1970 +++ new/atm/atm-0.32-1.spec Thu Jul 10 18:46:07 1997 @@ -0,0 +1,136 @@ +Summary: ATM (Asynchronous Transfer Mode) +Name: atm +Version: 0.32 +Release: 1 +Source: atm-0.32.tar.gz +Source: lrcftp.epfl.ch:/pub/linux/atm/dist/atm-0.32.tar.gz +Copyright: distributable +Group: Networking/ATM +ExclusiveArch: i386 +ExclusiveOS: Linux + +%description +Programs, libraries, and configuration files required for using ATM +on Linux. Note that you still need to patch your kernel. + +%package ans +Summary: ANS (ATM Name Server) +Group: Networking/ATM + +%description ans +ANS is a version of BIND with extensions for ATM. This package contains +the complete BIND distribution, including tools like nslookup and dig. + +%prep + +%setup -n atm + +%build +make +cd extra +make tcpdump +make ans + +%install +INSTPREFIX=/usr make -e +cd config/redhat-4.0 +make install +cd ../../extra +INSTPREFIX=/usr make -e install + +%files ans +/usr/lib/libresolv.a +/usr/include/arpa/inet.h +/usr/include/arpa/nameser.h +/usr/include/netdb.h +/usr/include/resolv.h +/usr/include/sys/bitypes.h +/usr/lib/lib44bsd.a +/usr/sbin/named +/usr/sbin/named-xfer +/usr/sbin/named.restart +/usr/sbin/named.reload +/usr/sbin/ndc +/usr/bin/nslookup +/usr/lib/nslookup.help +/usr/bin/host +/usr/bin/dig +/usr/bin/dnsquery +/usr/bin/addr +/usr/man/man1/dig.1 +/usr/man/man1/host.1 +/usr/man/man1/dnsquery.1 +/usr/man/man8/named.8 +/usr/man/man8/named.reload.8 +/usr/man/man8/named.restart.8 +/usr/man/man8/ndc.8 +/usr/man/man8/named-xfer.8 +/usr/man/man8/nslookup.8 +/usr/man/man3/gethostbyname.3 +/usr/man/man3/resolver.3 +/usr/man/man3/getnetent.3 +/usr/man/man5/resolver.5 +/usr/man/man7/hostname.7 +/usr/man/man7/mailaddr.7 + +%files +%doc README +%doc USAGE +%config /etc/sysconfig/atm +%config /etc/atmsigd.conf +%config /etc/sysconfig/network-scripts/ifcfg-atm0 +%config /etc/sysconfig/network-scripts/ifup-atm +%config /etc/hosts.atm +/usr/sbin/tcpdump +/usr/lib/libatm.a +/usr/lib/libatmd.a +/usr/lib/libarequipa.a +/usr/include/atm.h +/usr/include/atmd.h +/usr/include/atmsap.h +/usr/include/arequipa.h +/usr/sbin/atmaddr +/usr/sbin/atmtcp +/usr/sbin/zntune +/usr/bin/atmdiag +/usr/bin/atmdump +/usr/bin/sonetdiag +/usr/man/man8/atmaddr.8 +/usr/man/man8/atmdiag.8 +/usr/man/man8/atmdump.8 +/usr/man/man8/atmtcp.8 +/usr/sbin/atmarp +/usr/man/man8/atmarp.8 +/usr/bin/aping +/usr/bin/aread +/usr/bin/awrite +/usr/bin/br +/usr/bin/bw +/usr/bin/ttcp_atm +/usr/bin/window +/usr/sbin/delay +/usr/sbin/aqtest +/usr/sbin/ed +/usr/sbin/encopy +/usr/sbin/endump +/usr/sbin/zndump +/usr/sbin/znth +/usr/sbin/atmsigd +/usr/man/man4/atmsigd.conf.4 +/usr/man/man8/atmsigd.8 +/usr/sbin/atmarpd +/usr/man/man8/atmarpd.8 +/usr/sbin/ilmid +/usr/sbin/zeppelin +/usr/man/man8/zeppelin.8 +/usr/sbin/les +/usr/sbin/bus +/usr/sbin/lecs +/usr/man/man8/les.8 +/usr/man/man8/lecs.8 +/usr/man/man8/bus.8 +/usr/sbin/arequipad +/usr/sbin/aqpvc +/usr/man/man8/arequipad.8 +/usr/man/man8/aqpvc.8 +/usr/man/man7/qos.7 diff -ur --new-file old/atm/atm.patch new/atm/atm.patch --- old/atm/atm.patch Tue Apr 22 23:38:51 1997 +++ new/atm/atm.patch Thu Jul 10 19:16:01 1997 @@ -1,6 +1,6 @@ ---- ref/Makefile Wed Oct 30 11:46:07 1996 -+++ work/Makefile Fri Nov 15 19:06:16 1996 -@@ -126,6 +126,10 @@ +--- ref/Makefile Thu Jul 10 14:21:56 1997 ++++ work/Makefile Wed May 14 16:14:44 1997 +@@ -129,6 +129,10 @@ DRIVERS := $(DRIVERS) drivers/net/net.a @@ -8,224 +8,31 @@ +DRIVERS := $(DRIVERS) drivers/atm/atm.a +endif + - ifdef CONFIG_CD_NO_IDESCSI - DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a + ifeq ($(CONFIG_SCSI),y) + DRIVERS := $(DRIVERS) drivers/scsi/scsi.a endif -@@ -288,6 +292,7 @@ +@@ -300,6 +304,7 @@ if [ -f SCSI_MODULES ]; then inst_mod SCSI_MODULES scsi; fi; \ if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \ if [ -f CDROM_MODULES ]; then inst_mod CDROM_MODULES cdrom; fi; \ -+ if [ -f ATM_MODULES ]; then inst_mod ATM_MODULES atm; fi; \ ++ if [ -f ATM_MODULES ]; then inst_mod ATM_MODULES atm; fi; \ \ ls *.o > .allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \ ---- ref/Documentation/Configure.help Sat Oct 5 10:13:56 1996 -+++ work/Documentation/Configure.help Fri Apr 4 20:19:34 1997 -@@ -674,6 +674,14 @@ - say "386" or "486" here even if running on a Pentium or PPro - machine. If you don't know what to do, say "386". +--- ref/arch/i386/config.in Thu Jul 10 14:05:31 1997 ++++ work/arch/i386/config.in Thu May 15 22:20:00 1997 +@@ -46,6 +46,7 @@ + bool 'Video mode selection support' CONFIG_VIDEO_SELECT -+Support for big physical area reservation -+CONFIG_BIGPHYS_AREA -+ Enables kernel support for reserving large areas of physical memory -+ at boot-time for use by certain device drivers (such as video -+ framegrabbers, etc.) which require it. To use this feature, boot -+ the kernel with the boot-time option 'bigphysarea=nnn' where -+ 'nnn' is the number of pages (a page is usually 4K) to reserve. -+ - Compile the kernel into the ELF object format - CONFIG_ELF_KERNEL - ELF (Executable and Linkable Format) is a format for libraries and -@@ -1194,6 +1202,116 @@ - with major number 36 and minor number 0 using mknod ("man mknod"), - you can read some network related routing information from that - file. Everything you write to that file will be discarded. -+ -+Asynchronous Transfer Mode (ATM) -+CONFIG_ATM -+ You are likely to want to enable this. -+ -+Enable single-copy -+CONFIG_MMU_HACKS -+ Single-copy avoids intermediate buffering of AAL5 PDUs when using the -+ native ATM API. Enabling single-copy may lead to significant throughput -+ improvements. Note that single-copy probably still has bugs, so -+ enabling it may de-stabilize the system. -+ -+Extended debugging for single-copy -+CONFIG_MMU_HACKS_DEBUG -+ Extended debugging records various events and displays that list when -+ an inconsistency is detected. This mechanism is faster than generally -+ using printks, but still has some impact on performance. Enable this -+ if you suspect problems with single-copy. -+ -+Classical IP over ATM with ATMARP -+CONFIG_ATM_ATMARP -+ Classical IP over ATM for PVCs and SVCs, supporting InARP and ATMARP. -+ This interface is younger than the old "CLIP" interface (next item) -+ and it may therefore still have some bugs. In the future, it will -+ replace the old interface entirely. -+ -+Classical IP over ATM for PVCs (obsolete) -+CONFIG_ATM_CLIP -+ Classical IP over ATM for PVCs only and without InARP. This interface -+ is obsolete and will be removed in later versions of ATM on Linux, as -+ soon as ATMARP is fully mature. -+ -+Application REQUested IP over ATM -+CONFIG_AREQUIPA -+ Arequipa is an experimental mechanism to create short-cut ATM SVCs for -+ IP traffic. See -+ ftp://lrcftp.epfl.ch/pub/arequipa/draft-almesberger-arequipa-01.txt -+ for details. -+ -+LANE support -+CONFIG_ATM_LANE -+ Lan Emulation emulates services of existing LANs across an ATM network. -+ Client in Linux currently supports only one virtual LAN, and it has -+ not been tested in environment which uses other than DIX Ethernet- -+ data frames, i.e. Appletalk, IPX support has not been tested. -+ Specification for LANE can be found from ATM Forum's specification -+ LAN Emulation Over ATM - Version 1.0. -+ -+ATM over TCP -+CONFIG_ATM_TCP -+ ATM over TCP driver. Useful for doing some simple experiments with the -+ native ATM socket API, but not for many other things. You don't need -+ this is you have a "real" ATM card. -+ -+Efficient Networks ENI155P -+CONFIG_ATM_ENI -+ Driver for the Efficient Networks ENI155p series and SMC ATM Power155 -+ 155 Mbps ATM adapters. Both, the versions with 512kB and 2MB ob-board -+ RAM (Efficient calls them "C" and "S", respectively), and the FPGA and -+ the ASIC Tonga versions of the board are supported. The driver works -+ with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) adapters. -+ -+Enable extended debugging -+CONFIG_ATM_ENI_DEBUG -+ Extended debugging records various events and displays that list when -+ an inconsistency is detected. This mechanism is faster than generally -+ using printks, but still has some impact on performance. Note that -+ extended debugging may create certain race conditions itself. Enable -+ this ONLY if you suspect problems with the driver. -+ -+ZeitNet ZN1221/ZN1225 -+CONFIG_ATM_ZATM -+ Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM -+ adapters. -+ -+Enable extended debugging -+CONFIG_ATM_ZATM_DEBUG -+ Extended debugging records various events and displays that list when -+ an inconsistency is detected. This mechanism is faster than generally -+ using printks, but still has some impact on performance. Note that -+ extended debugging may create certain race conditions itself. Enable -+ this ONLY if you suspect problems with the driver. -+ -+Enable usec resolution timestamps -+CONFIG_ATM_ZATM_EXACT_TS -+ The uPD98401 SAR chip supports a high-resolution timer (approx. 30 MHz) -+ that is used for very accurate reception timestamps. Because that timer -+ overflows after 140 seconds, and also to avoid timer drift, time -+ measurements need to be periodically synchronized with the normal -+ system time. Enabling this feature will add some general overhead for -+ timer synchronization and also per-packet overhead for time conversion. -+ -+Rolfs TI TNETA1570 -+CONFIG_ATM_TNETA1570 -+ Driver for the TNETA1570 (or UniNET 1570) 155 Mbps ATM adapter, both -+ (driver and adapter) developed by Rolf Fiedler at TU Chemnitz, see also -+ ftp://ftp.infotech.tu-chemnitz.de/pub/linux-atm -+ -+Enable extended debugging -+CONFIG_ATM_TNETA1570_DEBUG -+ Extended debugging records various events and displays that list when -+ an inconsistency is detected. This mechanism is faster than generally -+ using printks, but still has some impact on performance. Note that -+ extended debugging may create certain race conditions itself. Enable -+ this ONLY if you suspect problems with the driver. -+ -+IDT 77201 (NICStAR) -+CONFIG_ATM_NICSTAR -+ Driver for the IDT 77901/77903 ("NICStAR", 77201/77211 SAR) ATM adapters. -+ Written by Matt Welsh and Stuart Daniel . - - SCSI support? - CONFIG_SCSI ---- ref/kernel/ksyms.c Wed Oct 30 02:42:42 1996 -+++ work/kernel/ksyms.c Fri Nov 15 19:06:20 1996 -@@ -63,6 +63,12 @@ - #ifdef __SMP__ - #include - #endif -+#ifdef CONFIG_ATM -+#include -+#endif -+#ifdef CONFIG_BIGPHYS_AREA -+#include -+#endif - - extern char *get_options(char *str, int *ints); - extern void set_device_ro(kdev_t dev,int flag); -@@ -77,6 +83,10 @@ - - extern void hard_reset_now(void); - -+#ifdef CONFIG_ATM_TCP_MODULE -+extern int (*atmtcp_attach_hook)(struct socket *sock); -+#endif -+ - struct symbol_table symbol_table = { - #include - #ifdef MODVERSIONS -@@ -136,6 +146,13 @@ - X(high_memory), - X(update_vm_cache), - -+#ifdef CONFIG_BIGPHYS_AREA -+ /* Large physical area memory management */ -+ X(bigphysarea_alloc), -+ X(bigphysarea_free), -+ X(bigphysarea), -+#endif -+ - /* filesystem internal functions */ - X(getname), - X(putname), -@@ -350,7 +367,16 @@ - #ifdef CONFIG_BLK_DEV_MD - X(disk_name), /* for md.c */ - #endif -- -+ -+#ifdef CONFIG_ATM -+ X(atm_dev_register), -+ X(atm_dev_deregister), -+ X(atm_find_ci), -+#endif -+#ifdef CONFIG_ATM_TCP_MODULE -+ X(atmtcp_attach_hook), -+#endif -+ - /* binfmt_aout */ - X(get_write_access), - X(put_write_access), ---- ref/arch/i386/config.in Mon May 13 06:17:23 1996 -+++ work/arch/i386/config.in Fri Nov 15 19:06:21 1996 -@@ -43,6 +43,8 @@ - 486 CONFIG_M486 \ - Pentium CONFIG_M586 \ - PPro CONFIG_M686" Pentium -+# Added by M. Welsh + tristate 'Parallel port support' CONFIG_PNP_PARPORT +bool 'Support for big physical area reservation' CONFIG_BIGPHYS_AREA + endmenu - source drivers/block/Config.in -@@ -70,6 +72,10 @@ - source drivers/net/Config.in - fi - endmenu +@@ -55,6 +56,10 @@ + + if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +if [ "$CONFIG_ATM" = "y" ]; then @@ -233,36 +40,21 @@ fi mainmenu_option next_comment ---- ref/arch/sparc/config.in Thu Apr 25 12:22:05 1996 -+++ work/arch/sparc/config.in Fri Nov 15 19:06:21 1996 -@@ -100,6 +100,12 @@ - endmenu - fi - -+if [ "$CONFIG_ATM" = "y" ]; then -+ if [ "$CONFIG_INET" = "y" ]; then -+ tristate 'ATM over TCP' CONFIG_ATM_TCP n -+ fi -+fi -+ - source fs/Config.in - - mainmenu_option next_comment ---- ref/drivers/Makefile Mon Apr 22 09:59:39 1996 -+++ work/drivers/Makefile Fri Nov 15 19:06:21 1996 +--- ref/drivers/Makefile Thu Jul 10 14:13:48 1997 ++++ work/drivers/Makefile Wed May 14 16:16:23 1997 @@ -9,7 +9,7 @@ - SUB_DIRS := block char net #streams - MOD_SUB_DIRS := $(SUB_DIRS) --ALL_SUB_DIRS := $(SUB_DIRS) pci sbus scsi sound cdrom isdn -+ALL_SUB_DIRS := $(SUB_DIRS) atm pci sbus scsi sound cdrom isdn + SUB_DIRS := block char net pnp #streams + MOD_SUB_DIRS := $(SUB_DIRS) sbus +-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp ++ALL_SUB_DIRS := $(SUB_DIRS) atm pci scsi sbus sound cdrom isdn pnp ifdef CONFIG_PCI SUB_DIRS += pci -@@ -50,6 +50,11 @@ - ifeq ($(CONFIG_ISDN),m) - MOD_SUB_DIRS += isdn - endif +@@ -17,6 +17,11 @@ + + ifdef CONFIG_SBUS + SUB_DIRS += sbus +endif + +ifdef CONFIG_ATM @@ -270,16 +62,17 @@ +MOD_SUB_DIRS += atm endif - ifeq ($(CONFIG_AP1000),y) + # If CONFIG_SCSI is set, the core of scsi support will be added to the kernel, --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/Config.in Fri Nov 15 20:40:08 1996 -@@ -0,0 +1,23 @@ ++++ work/drivers/atm/Config.in Mon Jun 30 17:51:47 1997 +@@ -0,0 +1,25 @@ +# +# ATM device configuration +# ++mainmenu_option next_comment +comment 'ATM drivers' +if [ "$CONFIG_INET" = "y" ]; then -+ tristate 'ATM over TCP' CONFIG_ATM_TCP n ++ tristate 'ATM over TCP' CONFIG_ATM_TCP y +fi +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI y @@ -297,28 +90,9 @@ + fi + tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR y +fi ---- ref/net/Config.in Mon Jul 8 09:21:46 1996 -+++ work/net/Config.in Fri Nov 15 19:06:22 1996 -@@ -27,4 +27,17 @@ - if [ "$CONFIG_NETLINK" = "y" ]; then - bool 'Routing messages' CONFIG_RTNETLINK - fi -+bool 'Asynchronous Transfer Mode (ATM)' CONFIG_ATM y -+if [ "$CONFIG_ATM" = "y" ]; then -+ bool ' Enable single-copy' CONFIG_MMU_HACKS n -+ if [ "$CONFIG_MMU_HACKS" = "y" ]; then -+ bool ' Extended debugging for single-copy' CONFIG_MMU_HACKS_DEBUG y -+ fi -+ if [ "$CONFIG_INET" = "y" ]; then -+ bool ' Classical IP over ATM with ATMARP' CONFIG_ATM_ATMARP y -+ bool ' Classical IP over ATM for PVCs (obsolete)' CONFIG_ATM_CLIP n -+ bool ' Application REQUested IP over ATM' CONFIG_AREQUIPA y -+ fi -+ bool ' LANE support' CONFIG_ATM_LANE y -+fi - endmenu ++endmenu --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/Makefile Fri Nov 15 20:39:35 1996 ++++ work/drivers/atm/Makefile Wed May 14 15:34:10 1997 @@ -0,0 +1,55 @@ +# File: drivers/atm/Makefile +# @@ -376,11 +150,11 @@ + +include $(TOPDIR)/Rules.make --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/atmdev_init.c Fri Nov 15 20:39:03 1996 -@@ -0,0 +1,53 @@ ++++ work/drivers/atm/atmdev_init.c Tue Jul 1 08:43:50 1997 +@@ -0,0 +1,47 @@ +/* drivers/atm/atmdev_init.c - ATM device driver initialization */ + -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + +#include @@ -401,9 +175,6 @@ +#ifdef CONFIG_ATM_NICSTAR +extern int nicstar_detect(void); +#endif -+#ifdef CONFIG_ATM_TCP -+extern int atmtcp_init(void); -+#endif + + +int atmdev_init(void) @@ -426,66 +197,37 @@ +#ifdef CONFIG_ATM_NICSTAR + devs += nicstar_detect(); +#endif -+#ifdef CONFIG_ATM_TCP -+ devs += atmtcp_init(); -+#endif + return devs; +} --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/atmtcp.c Mon Apr 7 14:11:46 1997 -@@ -0,0 +1,316 @@ ++++ work/drivers/atm/atmtcp.c Tue Jul 1 14:18:39 1997 +@@ -0,0 +1,208 @@ +/* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+/* Various enhancements 1996 by Ronald A. McCormick */ -+ -+ -+#include -+#include /* printk */ -+#include /* verify_area */ -+#include -+#include -+#include -+#include -+#include -+#include /* xtime */ -+#include /* set_fs, get_fs, ... */ -+#include /* ntohs, htons */ -+ -+ -+#define DEV_LABEL "atmtcp" -+ -+ -+#define MAX_VPI_BITS 8 -+#define MAX_VCI_BITS 16 -+ + -+#define PRIV(c) ((struct private *) ((c)->dev_data)) ++/* Written 1997 by Werner Almesberger, EPFL LRC */ + + -+extern int (*atmtcp_attach_hook)(struct socket *sock); -+ ++#include ++#include ++#include ++#include "../../net/atm/tunable.h" /* fix this */ ++#include "../../net/atm/protocols.h" /* fix this */ ++#include "../../net/atm/resources.h" /* fix this */ + -+/* BIG BUG: we can never get rid of an ATMTCP interface @@@ */ + ++#define DEV_LABEL "atmtcp" + -+/* -+ * correct compilation of this is implementation-dependent ! -+ */ ++#define MAX_VPI_BITS 8 /* simplifies life */ ++#define MAX_VCI_BITS 16 + -+struct atmtcp_hdr { -+ unsigned short vpi; -+ unsigned short vci; -+ unsigned short length; /* ... of data part */ -+}; + -+struct private { -+ struct atm_dev *dev; /* device back pointer */ -+ struct socket *sock; /* file descriptor */ -+}; ++static void atmtcp_v_dev_close(struct atm_dev *dev) ++{ ++ /* do nothing */ ++} + + -+static int atmtcp_open(struct atm_vcc *vcc,short vpi,int vci) ++static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci) +{ + int error; + @@ -493,203 +235,120 @@ + if (error) return error; + vcc->vpi = vpi; + vcc->vci = vci; -+ if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0; -+#ifdef DEBUG -+ printk(KERN_DEBUG DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number, -+ vcc->vpi,vcc->vci); -+#endif ++ if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0; + vcc->flags |= ATM_VF_ADDR | ATM_VF_READY; + return 0; +} + + -+int atmtcp_ioctl(struct atm_dev *dev,unsigned int cmd,unsigned long arg) ++static void atmtcp_v_close(struct atm_vcc *vcc) +{ -+ if (cmd == ATM_SETCIRANGE) { -+ struct atm_cirange ci; -+ struct atm_vcc *walk; -+ -+ memcpy_fromfs(&ci,(void *) arg,sizeof(struct atm_cirange)); -+ if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS; -+ if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; -+ if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 || -+ ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) -+ return -EINVAL; -+/* -+ * should all this checking be done in net/atm ? -+ */ -+ for (walk = dev->vccs; walk; walk = walk->next) -+ if ((walk->vpi >> ci.vpi_bits) || -+ (walk->vci >> ci.vci_bits)) return -EBUSY; -+ dev->ci_range = ci; -+ return 0; -+ } -+ return -EINVAL; ++ vcc->flags &= ~(ATM_VF_READY | ATM_VF_ADDR); +} + + -+ -+static int do_recv(struct socket *sock,unsigned char *ubuf,int size, -+ int nonblock) ++static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ -+ struct iovec iov; -+ struct msghdr msg; -+ -+ iov.iov_base = ubuf; -+ iov.iov_len = size; -+ -+ msg.msg_name = NULL; -+ msg.msg_namelen = 0; -+ msg.msg_control = NULL; -+ msg.msg_iov = &iov; -+ msg.msg_iovlen = 1; ++ struct atm_cirange ci; ++ struct atm_vcc *vcc; ++ int error; + -+ return sock->ops->recvmsg(sock,&msg,size,nonblock,0,NULL); ++ if (cmd != ATM_SETCIRANGE) return -EINVAL; ++ error = copy_from_user(&ci,(void *) arg,sizeof(ci)); ++ if (error) return error; ++ if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS; ++ if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; ++ if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 || ++ ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL; ++ for (vcc = dev->vccs; vcc; vcc = vcc->next) ++ if ((vcc->vpi >> ci.vpi_bits) || ++ (vcc->vci >> ci.vci_bits)) return -EBUSY; ++ dev->ci_range = ci; ++ return 0; +} + + -+static int do_send(struct socket *sock,const void *buff,int len,int nonblock) -+{ -+ struct iovec iov; -+ struct msghdr msg; -+ -+ iov.iov_base = (void *)buff; -+ iov.iov_len = len; -+ -+ msg.msg_name = NULL; -+ msg.msg_namelen = 0; -+ msg.msg_control = NULL; -+ msg.msg_iov = &iov; -+ msg.msg_iovlen = 1; -+ -+ return sock->ops->sendmsg(sock,&msg,len,nonblock,0); ++static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) ++{ ++ struct atm_vcc *out_vcc; ++ struct sk_buff *new_skb; ++ struct atmtcp_hdr *hdr; ++ ++ atomic_sub(skb->len+ATM_PDU_OVHD,&vcc->tx_inuse); ++ out_vcc = vcc->dev->dev_data; ++ new_skb = out_vcc->peek(out_vcc,skb->len+sizeof(struct atmtcp_hdr), ++ NULL); ++ if (!new_skb) { ++ kfree_skb(skb,FREE_WRITE); ++ vcc->stats->tx_err++; ++ return -ENOBUFS; ++ } ++ hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr)); ++ hdr->vpi = htons(vcc->vpi); ++ hdr->vci = htons(vcc->vci); ++ hdr->length = htonl(skb->len); ++ memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); ++ kfree_skb(skb,FREE_WRITE); ++ out_vcc->push(out_vcc,new_skb); ++ return 0; +} + + -+static int atmtcp_setsockopt(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int optlen) ++static void atmtcp_c_close(struct atm_vcc *vcc) +{ -+ return -EINVAL; ++ shutdown_atm_dev(vcc->dev_data); ++ vcc->dev_data = NULL; +} + + -+static int atmtcp_send(struct atm_vcc *vcc,struct sk_buff *skb) ++static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) +{ -+ struct atmtcp_hdr hdr; -+ unsigned long old_fs; -+ int len,size; -+ void *pos; -+ -+ if (!PRIV(vcc->dev)->sock) { -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } -+ hdr.vpi = htons(vcc->vpi); -+ hdr.vci = htons(vcc->vci); -+ old_fs = get_fs(); -+ set_fs(get_ds()); -+ hdr.length = htons(skb->len); -+ size = do_send(PRIV(vcc->dev)->sock,(char *) &hdr,sizeof(hdr),0); -+ if (size <= 0) { -+ printk(KERN_WARNING "atmtcp_send: PDU lost; errno = %d\n", -+ -size); -+ dev_kfree_skb(skb,FREE_WRITE); -+ set_fs(old_fs); ++ struct atm_dev *dev; ++ struct atmtcp_hdr *hdr; ++ struct atm_vcc *out_vcc; ++ struct sk_buff *new_skb; ++ ++ if (!skb->len) return 0; ++ atomic_sub(skb->len+ATM_PDU_OVHD,&vcc->tx_inuse); ++ dev = vcc->dev_data; ++ hdr = (void *) skb->data; ++ for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next) ++ if (out_vcc->vpi == ntohs(hdr->vpi) && ++ out_vcc->vci == ntohs(hdr->vci) && ++ out_vcc->qos.rxtp.traffic_class != ATM_NONE) ++ break; ++ if (!out_vcc) { ++ kfree_skb(skb,FREE_WRITE); + vcc->stats->tx_err++; -+ return size; ++ return -ENOTCONN; + } -+ pos = skb->data; -+ len = skb->len; -+ while (len) { -+ size = do_send(PRIV(vcc->dev)->sock,pos,len,0); -+ if (size < 0 && size != -EAGAIN) { -+ printk(KERN_ERR "atmtcp_send: link failure; errno = " -+ "%d\n",-size); -+ dev_kfree_skb(skb,FREE_WRITE); -+ set_fs(old_fs); -+ vcc->stats->tx_err++; -+ return size; -+ } -+ if (size > 0) { -+ len -= size; -+ pos += size; -+ } ++ skb_pull(skb,sizeof(struct atmtcp_hdr)); ++ new_skb = out_vcc->peek(out_vcc,skb->len,NULL); ++ if (!new_skb) { ++ kfree_skb(skb,FREE_WRITE); ++ return -ENOBUFS; + } -+ dev_kfree_skb(skb,FREE_WRITE); -+ set_fs(old_fs); -+ vcc->stats->tx++; ++ memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); ++ kfree_skb(skb,FREE_WRITE); ++ out_vcc->push(out_vcc,new_skb); + return 0; +} + + -+static void atmtcp_poll(struct atm_vcc *vcc,int nonblock) -+{ -+ struct atm_dev *dev; -+ struct atm_vcc *walk; -+ struct sk_buff *skb; -+ struct atmtcp_hdr hdr; -+ unsigned long old_fs; -+ int size,left; -+ void *pos; -+ -+ if (!(dev = vcc->dev) || !PRIV(dev)->sock) return; -+ if (skb_peek(&vcc->recvq)) nonblock = 1; -+ old_fs = get_fs(); -+ set_fs(get_ds()); -+ while ((size = do_recv(PRIV(dev)->sock,(char*) &hdr,sizeof(hdr), -+ nonblock) == sizeof(hdr))) { -+ if (!(skb = vcc->peek(vcc,ntohs(hdr.length),NULL))) { -+ printk(KERN_WARNING "atmtcp_poll: peek reject (%d)\n", -+ ntohs(hdr.length)); -+ break; -+ } -+ skb->atm.timestamp = xtime; -+ skb->len = ntohs(hdr.length); -+ skb->free = 1; -+ pos = skb->data; -+ for (left = ntohs(hdr.length); left; left -= size) { -+ size = do_recv(PRIV(dev)->sock,pos,left,0); -+ if (size == -EAGAIN) size = 0; -+ if (size < 0) { -+ printk(KERN_ERR "atmtcp_poll: bad read: %d\n", -+ size); -+ vcc->stats->rx_err++; -+ break; -+ } -+ pos += size; -+ } -+ for (walk = dev->vccs; walk; walk = walk->next) -+ if (walk->vpi == ntohs(hdr.vpi) && walk->vci == -+ ntohs(hdr.vci)) break; -+ if (walk) { -+ vcc->push(vcc,skb); -+ nonblock = 1; -+ vcc->stats->rx++; -+ } -+ else { -+ printk(KERN_ERR "atmtcp_poll: bad label %d.%d at itf " -+ "%d\n",ntohs(hdr.vpi),ntohs(hdr.vci),dev->number); -+ kfree_skb(skb,FREE_READ); -+ vcc->stats->rx_err++; -+ } -+ } -+ set_fs(old_fs); -+ if (size > 0 && size != sizeof(hdr)) { -+ printk(KERN_ERR "atmtcp_poll: bad header (%d)\n",size); -+ vcc->stats->rx_err++; -+ } -+} ++/* ++ * Device operations for the virtual ATM devices created by ATMTCP. ++ */ + + -+static struct atmdev_ops ops = { -+ atmtcp_open, -+ NULL, /* no close */ -+ atmtcp_ioctl, ++static struct atmdev_ops atmtcp_v_dev_ops = { ++ atmtcp_v_dev_close, ++ atmtcp_v_open, ++ atmtcp_v_close, ++ atmtcp_v_ioctl, + NULL, /* no getsockopt */ -+ atmtcp_setsockopt, -+ atmtcp_send, ++ NULL, /* no setsockopt */ ++ atmtcp_v_send, + NULL, /* no direct writes */ -+ atmtcp_poll, + NULL, /* no send_oam */ + NULL, /* no phy_put */ + NULL, /* no phy_get */ @@ -699,60 +358,61 @@ +}; + + -+int atmtcp_attach(struct socket *sock) -+{ -+ struct private *dsc; ++/* ++ * Device operations for the ATMTCP control device. ++ */ + -+ if (!suser()) return -EPERM; -+ dsc = kmalloc(sizeof(struct private),GFP_KERNEL); -+ if (!dsc) return -ENOMEM; -+ dsc->dev = atm_dev_register(DEV_LABEL,&ops,0); -+ if (!dsc->dev) { -+ kfree(dsc); -+ return -EBUSY; -+ } -+ dsc->dev->dev_data = dsc; -+ dsc->dev->ci_range.vpi_bits = MAX_VPI_BITS; -+ dsc->dev->ci_range.vci_bits = MAX_VCI_BITS; -+ sock->inode->i_count++; -+ dsc->sock = sock; -+ printk(KERN_NOTICE DEV_LABEL "(itf %d): ready\n",dsc->dev->number); -+ MOD_INC_USE_COUNT; -+ return dsc->dev->number; -+} + ++static struct atmdev_ops atmtcp_c_dev_ops = { ++ NULL, /* no dev_close */ ++ NULL, /* no open */ ++ atmtcp_c_close, ++ NULL, /* no ioctl */ ++ NULL, /* no getsockopt */ ++ NULL, /* no setsockopt */ ++ atmtcp_c_send, ++ NULL, /* no sg_send */ ++ NULL, /* no send_oam */ ++ NULL, /* no phy_put */ ++ NULL, /* no phy_get */ ++ NULL, /* no feedback */ ++ NULL, /* no change_qos */ ++ NULL /* no free_rx_skb */ ++}; + -+int atmtcp_init(void) -+{ -+ printk(KERN_NOTICE DEV_LABEL ": ready (dynamic device creation)\n"); -+ atmtcp_attach_hook = atmtcp_attach; -+ return 1; -+} + ++static struct atm_dev atmtcp_dev = { ++ &atmtcp_c_dev_ops, ++ NULL, /* no PHY */ ++ "atmtcp", /* type */ ++ 999, /* dummy device number */ ++ NULL,NULL, /* pretend not to have any VCCs */ ++ NULL,NULL, /* no data */ ++ 0, /* no flags */ ++ NULL, /* no local address */ ++ { 0 } /* no ESI, no statistics */ ++}; + -+#ifdef MODULE + -+int init_module(void) ++int atmtcp_attach(struct atm_vcc *vcc) +{ -+ (void) atmtcp_init(); -+ return 0; -+} -+ ++ struct atm_dev *dev; + -+void cleanup_module(void) -+{ -+ /* -+ * We currently have no means to detach ATM devices. That'll follow -+ * a bit later. (Needs careful usage tracking and open/close -+ * interlocking.) -+ */ -+ atmtcp_attach_hook = NULL; ++ dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,0); ++ if (!dev) return -ENOMEM; ++ dev->ci_range.vpi_bits = MAX_VPI_BITS; ++ dev->ci_range.vci_bits = MAX_VCI_BITS; ++ dev->dev_data = vcc; ++ vcc->dev = &atmtcp_dev; ++ vcc->flags |= ATM_VF_READY | ATM_VF_META; ++ vcc->dev_data = dev; ++ (void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */ ++ vcc->stats = &atmtcp_dev.stats.aal5; ++ return dev->number; +} -+ -+#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/eni.c Thu Apr 17 18:09:14 1997 -@@ -0,0 +1,1958 @@ ++++ work/drivers/atm/eni.c Thu May 29 21:56:48 1997 +@@ -0,0 +1,1955 @@ +/* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ + +/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ @@ -774,6 +434,8 @@ +#include +#include +#include ++#include ++#include +#include +#include + @@ -1054,8 +716,8 @@ + +static __u32 fetch(struct atm_vcc *vcc,int i) +{ -+ return ntohl(ENI_VCC(vcc)->recv[(ENI_VCC(vcc)->descr+i+1) & -+ (ENI_VCC(vcc)->words-1)]); /* ^ skip descr */ ++ return ntohl(readl(ENI_VCC(vcc)->recv+((ENI_VCC(vcc)->descr+i+1) & ++ (ENI_VCC(vcc)->words-1)))); /* skip descr ^ */ +} + + @@ -1066,8 +728,8 @@ + + dev = vcc->dev; + /* immediately halt adapter */ -+ ENI_DEV(dev)->reg[MID_MC_S] &= ~(MID_DMA_ENABLE | MID_TX_ENABLE | -+ MID_RX_ENABLE); ++ writel(readl(ENI_DEV(dev)->reg+MID_MC_S) & ~(MID_DMA_ENABLE | ++ MID_TX_ENABLE | MID_RX_ENABLE),ENI_DEV(dev)->reg+MID_MC_S); + /* dump useful information */ + eni_vcc = ENI_VCC(vcc); + printk(KERN_ALERT DEV_LABEL "(itf %d): driver error - RX ident " @@ -1075,8 +737,8 @@ + printk(KERN_ALERT " VCI %d, rxing %d, words %ld\n",vcc->vci, + eni_vcc->rxing,eni_vcc->words); + printk(KERN_ALERT " host descr 0x%08lx, rx pos 0x%08lx, descr value " -+ "0x%08lx\n",eni_vcc->descr,eni_vcc->rx_pos, -+ eni_vcc->recv[eni_vcc->descr]); ++ "0x%08x\n",eni_vcc->descr,eni_vcc->rx_pos, ++ readl(eni_vcc->recv+eni_vcc->descr)); + printk(KERN_ALERT " last 0x%p, servicing %d\n",eni_vcc->last, + eni_vcc->servicing); + EVENT("---dump ends here---\n",0,0); @@ -1136,7 +798,7 @@ + if (init > words) init = words; + dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | + (vcc->vci << MID_DMA_VCI_SHIFT); -+ dma[j++] = paddr; ++ dma[j++] = virt_to_bus((void *) paddr); + paddr += init << 2; + words -= init; + } @@ -1145,14 +807,14 @@ + dma[j++] = MID_DT_8W | ((words >> 3) << + MID_DMA_COUNT_SHIFT) | (vcc->vci << + MID_DMA_VCI_SHIFT); -+ dma[j++] = paddr; ++ dma[j++] = virt_to_bus(paddr); + paddr += (words & ~7) << 2; + words &= 7; +#else + dma[j++] = MID_DT_4W | ((words >> 2) << + MID_DMA_COUNT_SHIFT) | (vcc->vci << + MID_DMA_VCI_SHIFT); -+ dma[j++] = paddr; ++ dma[j++] = virt_to_bus((void *) paddr); + paddr += (words & ~3) << 2; + words &= 3; +#endif @@ -1160,7 +822,7 @@ + if (words) { + dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) + | (vcc->vci << MID_DMA_VCI_SHIFT); -+ dma[j++] = paddr; ++ dma[j++] = virt_to_bus((void *) paddr); + } + } + if (size != eff) { @@ -1175,8 +837,8 @@ + } + dma[j-2] |= MID_DMA_END; + j = j >> 1; -+ dma_wr = eni_dev->reg[MID_DMA_WR_RX]; -+ dma_rd = eni_dev->reg[MID_DMA_RD_RX]; ++ dma_wr = readl(eni_dev->reg+MID_DMA_WR_RX); ++ dma_rd = readl(eni_dev->reg+MID_DMA_RD_RX); + /* + * Can I move the dma_wr pointer by 2j+1 positions without overwriting + * data that hasn't been read (position of dma_rd) yet ? @@ -1188,8 +850,8 @@ + return -1; + } + for (i = 0; i < j; i++) { -+ eni_dev->rx_dma[dma_wr*2] = dma[i*2]; -+ eni_dev->rx_dma[dma_wr*2+1] = dma[i*2+1]; ++ writel(dma[i*2],eni_dev->rx_dma+dma_wr*2); ++ writel(dma[i*2+1],eni_dev->rx_dma+dma_wr*2+1); + dma_wr = (dma_wr+1) & (NR_DMA_RX-1); + } + if (skb) { @@ -1199,7 +861,7 @@ +rx_enqueued++; + } + eni_vcc->descr = here; -+ eni_dev->reg[MID_DMA_WR_RX] = dma_wr; ++ writel(dma_wr,eni_dev->reg+MID_DMA_WR_RX); + return 0; +} + @@ -1231,7 +893,7 @@ + + DPRINTK(">rx_aal0\n"); + eni_vcc = ENI_VCC(vcc); -+ descr = eni_vcc->recv[eni_vcc->descr]; ++ descr = readl(eni_vcc->recv+eni_vcc->descr); + if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) { + rx_ident_err(vcc); + return 1; @@ -1251,9 +913,8 @@ + discard(vcc,length >> 2); + return 0; + } -+ skb->free = 1; /* not very useful ... */ -+ skb->len = length; -+ skb->atm.timestamp = eni_vcc->timestamp; ++ skb_put(skb,length); ++ skb->stamp = eni_vcc->timestamp; + DPRINTK("got len %ld\n",length); + if (do_rx_dma(vcc,skb,1,length >> 2,length >> 2)) return 1; + eni_vcc->rxing++; @@ -1271,7 +932,7 @@ + EVENT("rx_aal5\n",0,0); + DPRINTK(">rx_aal5\n"); + eni_vcc = ENI_VCC(vcc); -+ descr = eni_vcc->recv[eni_vcc->descr]; ++ descr = readl(eni_vcc->recv+eni_vcc->descr); + if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) { + rx_ident_err(vcc); + return 1; @@ -1302,8 +963,8 @@ + else { + size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); + DPRINTK("size=%ld\n",size); -+ length = eni_vcc->recv[(eni_vcc->descr+size-1) & -+ (eni_vcc->words-1)] & 0xffff; /* -trailer(2)+header(1) */ ++ length = readl(eni_vcc->recv+((eni_vcc->descr+size-1) & ++ (eni_vcc->words-1))) & 0xffff; /* -trailer(2)+header(1) */ + if (length && length <= (size << 2)-8 && length <= + ATM_MAX_AAL5_PDU) eff = (length+3) >> 2; + else { /* ^ trailer length (8) */ @@ -1329,8 +990,7 @@ + discard(vcc,size); + return 0; + } -+ skb->free = 1; /* not very useful ... */ -+ skb->len = length; ++ skb_put(skb,length); + DPRINTK("got len %ld\n",length); + if (do_rx_dma(vcc,skb,1,size,eff)) return 1; + eni_vcc->rxing++; @@ -1340,35 +1000,37 @@ + +static inline int rx_vcc(struct atm_vcc *vcc) +{ -+ volatile unsigned long *vci_dsc; ++ unsigned long *vci_dsc; + struct eni_vcc *eni_vcc; + unsigned long tmp; + + eni_vcc = ENI_VCC(vcc); + vci_dsc = ENI_DEV(vcc->dev)->vci+vcc->vci*4; + EVENT("rx_vcc(1)\n",0,0); -+ while (eni_vcc->descr != (tmp = (vci_dsc[1] & MID_VCI_DESCR) >> ++ while (eni_vcc->descr != (tmp = (readl(vci_dsc+1) & MID_VCI_DESCR) >> + MID_VCI_DESCR_SHIFT)) { + EVENT("rx_vcc(2: host dsc=0x%lx, nic dsc=0x%lx)\n", + eni_vcc->descr,tmp); -+ DPRINTK("CB_DESCR %ld REG_DESCR %ld\n",ENI_VCC(vcc)->descr, -+ ((vci_dsc[1] & MID_VCI_DESCR) >> MID_VCI_DESCR_SHIFT)); ++ DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr, ++ ((readl(vci_dsc+1) & MID_VCI_DESCR) >> ++ MID_VCI_DESCR_SHIFT)); + if (ENI_VCC(vcc)->rx(vcc)) return 1; + } + /* clear IN_SERVICE flag */ -+ vci_dsc[0] &= ~MID_VCI_IN_SERVICE; ++ writel(readl(vci_dsc) & ~MID_VCI_IN_SERVICE,vci_dsc); + /* + * If new data has arrived between evaluating the while condition and + * clearing IN_SERVICE, we wouldn't be notified until additional data + * follows. So we have to loop again to be sure. + */ + EVENT("rx_vcc(3)\n",0,0); -+ while (ENI_VCC(vcc)->descr != (tmp = (vci_dsc[1] & MID_VCI_DESCR) >> -+ MID_VCI_DESCR_SHIFT)) { ++ while (ENI_VCC(vcc)->descr != (tmp = (readl(vci_dsc+1) & MID_VCI_DESCR) ++ >> MID_VCI_DESCR_SHIFT)) { + EVENT("rx_vcc(4: host dsc=0x%lx, nic dsc=0x%lx)\n", + eni_vcc->descr,tmp); -+ DPRINTK("CB_DESCR %ld REG_DESCR %ld\n",ENI_VCC(vcc)->descr, -+ ((vci_dsc[1] & MID_VCI_DESCR) >> MID_VCI_DESCR_SHIFT)); ++ DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr, ++ ((readl(vci_dsc+1) & MID_VCI_DESCR) >> ++ MID_VCI_DESCR_SHIFT)); + if (ENI_VCC(vcc)->rx(vcc)) return 1; + } + return 0; @@ -1406,8 +1068,8 @@ + + DPRINTK(">get_service\n"); + eni_dev = ENI_DEV(dev); -+ while (eni_dev->reg[MID_SERV_WRITE] != eni_dev->serv_read) { -+ vci = eni_dev->service[eni_dev->serv_read]; ++ while (readl(eni_dev->reg+MID_SERV_WRITE) != eni_dev->serv_read) { ++ vci = readl(eni_dev->service+eni_dev->serv_read); + eni_dev->serv_read = (eni_dev->serv_read+1) & (NR_SERVICE-1); + vcc = eni_dev->rx_map[vci & 1023]; + if (!vcc) { @@ -1448,7 +1110,7 @@ + struct eni_vcc *eni_vcc; + struct atm_vcc *vcc; + struct sk_buff *skb; -+ volatile unsigned long *vci_dsc; ++ unsigned long *vci_dsc; + int first; + + eni_dev = ENI_DEV(dev); @@ -1465,13 +1127,12 @@ + } + EVENT("dequeued (size=%d,pos=0x%lx)\n",skb->atm.size, + skb->atm.pos); -+/*printk("DMA@0x%X\n",eni_dev->reg[MID_DMA_ADDR]);*/ +rx_dequeued++; + vcc = skb->atm.vcc; + eni_vcc = ENI_VCC(vcc); + first = 0; + vci_dsc = eni_dev->vci+(vcc->vci << 2); -+ if (!EEPMOK(eni_vcc->rx_pos,skb->atm.size,(vci_dsc[1] & ++ if (!EEPMOK(eni_vcc->rx_pos,skb->atm.size,(readl(vci_dsc+1) & + MID_VCI_READ) >> MID_VCI_READ_SHIFT,eni_vcc->words)) { + EVENT("requeuing\n",0,0); + skb_queue_head(&eni_dev->rx_queue,skb); @@ -1482,7 +1143,7 @@ + if (!skb->len) kfree_skb(skb,FREE_READ); + else { + EVENT("pushing (len=%d)\n",skb->len,0); -+ if (vcc->aal == ATM_AAL0) ++ if (vcc->qos.aal == ATM_AAL0) + *(unsigned long *) skb->data = + ntohl(*(unsigned long *) skb->data); + vcc->push(vcc,skb); @@ -1506,11 +1167,11 @@ + eni_vcc->rx = NULL; + if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; + size = vcc->qos.rxtp.max_sdu*3; /* @@@ improve this */ -+ eni_vcc->recv = (volatile unsigned long *) eni_alloc_mem(eni_dev,&size); ++ eni_vcc->recv = (unsigned long *) eni_alloc_mem(eni_dev,&size); + DPRINTK("rx at 0x%p\n",eni_vcc->recv); + eni_vcc->words = size >> 2; + if (!eni_vcc->recv) return -ENOBUFS; -+ eni_vcc->rx = vcc->aal == ATM_AAL5 ? rx_aal5 : rx_aal0; ++ eni_vcc->rx = vcc->qos.aal == ATM_AAL5 ? rx_aal5 : rx_aal0; + eni_vcc->descr = 0; + eni_vcc->rx_pos = 0; + eni_vcc->rxing = 0; @@ -1522,7 +1183,7 @@ + +static int open_rx_second(struct atm_vcc *vcc) +{ -+ volatile unsigned long *here; ++ unsigned long *here; + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + unsigned long size; @@ -1537,23 +1198,23 @@ + DPRINTK("loc 0x%x\n",eni_vcc->recv-eni_dev->ram); + size = eni_vcc->words >> 8; + for (order = -1; size; order++) size >>= 1; -+ here[1] = 0; /* descr, read = 0 */ -+ here[2] = 0; /* write, state, count = 0 */ ++ writel(0,here+1); /* descr, read = 0 */ ++ writel(0,here+2); /* write, state, count = 0 */ + if (eni_dev->rx_map[vcc->vci]) + printk(KERN_CRIT DEV_LABEL "(itf %d): BUG - VCI %d already " + "in use\n",vcc->dev->number,vcc->vci); + eni_dev->rx_map[vcc->vci] = vcc; /* now it counts */ -+ here[0] = ((vcc->aal != ATM_AAL5 ? MID_MODE_RAW : MID_MODE_AAL5) << ++ writel(((vcc->qos.aal != ATM_AAL5 ? MID_MODE_RAW : MID_MODE_AAL5) << + MID_VCI_MODE_SHIFT) | MID_VCI_PTI_MODE | + (((eni_vcc->recv-eni_dev->ram) >> MID_LOC_SKIP) << -+ MID_VCI_LOCATION_SHIFT) | (order << MID_VCI_SIZE_SHIFT); ++ MID_VCI_LOCATION_SHIFT) | (order << MID_VCI_SIZE_SHIFT),here); + return 0; +} + + +static void close_rx(struct atm_vcc *vcc) +{ -+ volatile unsigned long *here; ++ unsigned long *here; + struct eni_dev *eni_dev; + struct eni_vcc *eni_vcc; + unsigned long flags,tmp; @@ -1564,12 +1225,12 @@ + if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) { + here = eni_dev->vci+(vcc->vci << 2); + /* block receiver */ -+ *here = (*here & ~MID_VCI_MODE) | (MID_MODE_TRASH << -+ MID_VCI_MODE_SHIFT); ++ writel((readl(here) & ~MID_VCI_MODE) | (MID_MODE_TRASH << ++ MID_VCI_MODE_SHIFT),here); + /* wait for receiver to become idle */ + udelay(27); + /* discard pending cell */ -+ *here &= ~MID_VCI_IN_SERVICE; ++ writel(readl(here) & ~MID_VCI_IN_SERVICE,here); + /* don't accept any new ones */ + eni_dev->rx_map[vcc->vci] = NULL; + /* wait for RX queue to drain */ @@ -1617,8 +1278,8 @@ + eni_dev->slow = eni_dev->last_slow = NULL; + eni_dev->rx_wait = NULL; + skb_queue_head_init(&eni_dev->rx_queue); -+ eni_dev->serv_read = eni_dev->reg[MID_SERV_WRITE]; -+ eni_dev->reg[MID_DMA_WR_RX] = 0; ++ eni_dev->serv_read = readl(eni_dev->reg+MID_SERV_WRITE); ++ writel(0,eni_dev->reg+MID_DMA_WR_RX); + return 0; +} + @@ -1649,21 +1310,21 @@ + if (init > size) init = size; + dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | + (chan << MID_DMA_CHAN_SHIFT); -+ dma[(*j)++] = paddr; ++ dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += init << 2; + size -= init; + } + if (size & ~7) { + dma[(*j)++] = MID_DT_8W | ((size >> 3) << MID_DMA_COUNT_SHIFT) + | (chan << MID_DMA_CHAN_SHIFT); -+ dma[(*j)++] = paddr; ++ dma[(*j)++] = virt_to_bus((void *) paddr); + paddr += (size & ~7) << 2; + size &= 7; + } + if (size) { + dma[(*j)++] = MID_DT_WORD | (size << MID_DMA_COUNT_SHIFT) | + (chan << MID_DMA_CHAN_SHIFT); -+ dma[(*j)++] = paddr; ++ dma[(*j)++] = virt_to_bus((void *) paddr); + } +} + @@ -1698,7 +1359,7 @@ + */ + + /* check space in buffer */ -+ if (!(aal5 = vcc->aal == ATM_AAL5)) ++ if (!(aal5 = vcc->qos.aal == ATM_AAL5)) + size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE; + /* cell without HEC plus segmentation header (includes + four-byte cell header) */ @@ -1714,14 +1375,14 @@ + * the manual calls "too close". + */ + if (!NEPMOK(tx->tx_pos,size+TX_GAP, -+ eni_dev->reg[MID_TX_RDPTR(tx->index)],tx->words)) { ++ readl(eni_dev->reg+MID_TX_RDPTR(tx->index)),tx->words)) { + DPRINTK(DEV_LABEL "(itf %d): TX full (size %ld)\n", + vcc->dev->number,size); + return enq_next; + } + /* check DMA */ -+ dma_wr = eni_dev->reg[MID_DMA_WR_TX]; -+ dma_rd = eni_dev->reg[MID_DMA_RD_TX]; ++ dma_wr = readl(eni_dev->reg+MID_DMA_WR_TX); ++ dma_rd = readl(eni_dev->reg+MID_DMA_RD_TX); + dma_size = 2; /* JK for descriptor and final fill */ +DPRINTK("iovcnt = %d\n",skb->atm.iovcnt); + if (!skb->atm.iovcnt) dma_size += 3; @@ -1770,14 +1431,14 @@ +/*printk("dsc = 0x%08lx\n",tx->send[tx->tx_pos]);*/ + tx->send[(tx->tx_pos+1) & (tx->words-1)] = (vcc->vci << + MID_SEG_VCI_SHIFT) | (aal5 ? 0 : (skb->data[3] & 0xf)); -+ DPRINTK("size: %ld, len:%ld\n",size,skb->len); ++ DPRINTK("size: %ld, len:%d\n",size,skb->len); + if (aal5) + tx->send[(tx->tx_pos+size-AAL5_TRAILER) & (tx->words-1)] = + skb->len; + j = j >> 1; + for (i = 0; i < j; i++) { -+ eni_dev->tx_dma[dma_wr*2] = eni_dev->dma[i*2]; -+ eni_dev->tx_dma[dma_wr*2+1] = eni_dev->dma[i*2+1]; ++ writel(eni_dev->dma[i*2],eni_dev->tx_dma+dma_wr*2); ++ writel(eni_dev->dma[i*2+1],eni_dev->tx_dma+dma_wr*2+1); + dma_wr = (dma_wr+1) & (NR_DMA_TX-1); + } + skb->atm.pos = tx->tx_pos; @@ -1785,7 +1446,7 @@ + ENI_VCC(vcc)->txing += size; + tx->tx_pos = (tx->tx_pos+size) & (tx->words-1); + DPRINTK("dma_wr set to %ld, tx_pos is now %ld\n",dma_wr,tx->tx_pos); -+ eni_dev->reg[MID_DMA_WR_TX] = dma_wr; ++ writel(dma_wr,eni_dev->reg+MID_DMA_WR_TX); + skb_queue_tail(&eni_dev->tx_queue,skb); +queued++; + return enq_ok; @@ -1832,10 +1493,10 @@ + NULLCHECK(vcc); + tx = ENI_VCC(vcc)->tx; + NULLCHECK(ENI_VCC(vcc)->tx); -+ DPRINTK("dequeue_tx: next 0x%lx curr 0x%lx\n",skb->atm.pos, -+ eni_dev->reg[MID_TX_DESCRSTART(tx->index)]); ++ DPRINTK("dequeue_tx: next 0x%lx curr 0x%x\n",skb->atm.pos, ++ readl(eni_dev->reg+MID_TX_DESCRSTART(tx->index))); + if (ENI_VCC(vcc)->txing < tx->words && skb->atm.pos == -+ eni_dev->reg[MID_TX_DESCRSTART(tx->index)]) { ++ readl(eni_dev->reg+MID_TX_DESCRSTART(tx->index))) { + skb_queue_head(&eni_dev->tx_queue,skb); + break; + } @@ -1932,15 +1593,16 @@ + else eni_dev->tx_bw -= pcr; + if (pcr > ATM_OC3_PCR) pcr = ATM_OC3_PCR; + vcc->qos.txtp.min_pcr = vcc->qos.txtp.max_pcr = pcr; -+ eni_dev->tx[tx_ind].send = (volatile unsigned long *) mem; ++ eni_dev->tx[tx_ind].send = (unsigned long *) mem; + eni_dev->tx[tx_ind].words = size >> 2; + skb_queue_head_init(&eni_dev->tx[tx_ind].backlog); + size >>= 10; + for (order = -1; size; order++) size >>= 1; -+ eni_dev->reg[MID_TX_PLACE(tx_ind)] = (order << MID_SIZE_SHIFT) | -+ ((eni_dev->tx[tx_ind].send-eni_dev->ram) >> MID_LOC_SKIP); -+ eni_dev->tx[tx_ind].tx_pos = eni_dev->reg[MID_TX_DESCRSTART(tx_ind)] & -+ MID_DESCR_START; ++ writel((order << MID_SIZE_SHIFT) | ++ ((eni_dev->tx[tx_ind].send-eni_dev->ram) >> MID_LOC_SKIP), ++ eni_dev->reg+MID_TX_PLACE(tx_ind)); ++ eni_dev->tx[tx_ind].tx_pos = ++ readl(eni_dev->reg+MID_TX_DESCRSTART(tx_ind)) & MID_DESCR_START; + eni_vcc->tx = &eni_dev->tx[tx_ind]; + return 0; +} @@ -1973,8 +1635,8 @@ + * Looping a few times in here is probably far cheaper than keeping + * track of TX completions all the time, so let's poll a bit ... + */ -+ while (eni_dev->reg[MID_TX_RDPTR(eni_vcc->tx->index)] != -+ eni_dev->reg[MID_TX_DESCRSTART(eni_vcc->tx->index)]) ++ while (readl(eni_dev->reg+MID_TX_RDPTR(eni_vcc->tx->index)) != ++ readl(eni_dev->reg+MID_TX_DESCRSTART(eni_vcc->tx->index))) + schedule(); + restore_flags(flags); +#if 0 @@ -2002,7 +1664,7 @@ + eni_dev->tx_wait = NULL; + eni_dev->ubr = NULL; + skb_queue_head_init(&eni_dev->tx_queue); -+ eni_dev->reg[MID_DMA_WR_TX] = 0; ++ writel(0,eni_dev->reg+MID_DMA_WR_TX); + for (i = 0; i < NR_CHAN; i++) { + eni_dev->tx[i].send = NULL; + eni_dev->tx[i].index = i; @@ -2032,13 +1694,20 @@ + eni_dev = ENI_DEV(dev); + if (reason & MID_STAT_OVFL) { + EVENT("stat overflow\n",0,0); -+ eni_dev->lost += eni_dev->reg[MID_STAT] & MID_OVFL_TRASH; ++ eni_dev->lost += readl(eni_dev->reg+MID_STAT) & MID_OVFL_TRASH; + } + if (reason & MID_SUNI_INT) { + EVENT("SUNI int\n",0,0); + dev->phy->interrupt(dev); + foo(); + } ++ if (reason & MID_DMA_ERR_ACK) { ++ printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " ++ "error\n",dev->number); ++ EVENT("---dump ends here---\n",0,0); ++ printk(KERN_NOTICE "---recent events---\n"); ++ event_dump(); ++ } + if (reason & MID_TX_IDENT_MISM) { + printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - ident " + "mismatch\n",dev->number); @@ -2065,7 +1734,7 @@ + DPRINTK(">eni_int\n"); + dev = dev_id; + eni_dev = ENI_DEV(dev); -+ while ((reason = eni_dev->reg[MID_ISA])) { ++ while ((reason = readl(eni_dev->reg+MID_ISA))) { + DPRINTK(DEV_LABEL ": int 0x%lx\n",reason); + if (reason & MID_RX_DMA_COMPLETE) { + EVENT("INT: RX DMA complete, starting dequeue_rx\n", @@ -2094,8 +1763,8 @@ + poll_tx(dev); + /* poll_rx ? */ + } -+ if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_TX_IDENT_MISM -+ | MID_TX_DMA_OVFL)) { ++ if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK | ++ MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) { + EVENT("misc interrupt\n",0,0); + misc_int(dev,reason); + } @@ -2234,7 +1903,7 @@ + midway_eprom)); + eni_dev = ENI_DEV(dev); + for (i = 0; i < ESI_LEN; i++) -+ dev->esi[i] = eprom->mac[(i & ~3) | (3-(i & 3))]; ++ dev->esi[i] = readl(&eprom->mac+((i & ~3) | (3-(i & 3)))); + return 0; +} + @@ -2273,7 +1942,7 @@ + } + printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", + dev->number,revision,real_base,eni_dev->irq); -+ if (!(base = (unsigned long) vremap(real_base,MAP_MAX_SIZE))) { ++ if (!(base = (unsigned long) ioremap_nocache(real_base,MAP_MAX_SIZE))) { + printk("\n"); + printk(KERN_ERR DEV_LABEL "(itf %d): can't set up page " + "mapping\n",dev->number); @@ -2284,39 +1953,39 @@ + if (!eni_dev->asic) { + eprom = (struct midway_eprom *) (base+EPROM_SIZE-sizeof(struct + midway_eprom)); -+ if (eprom->magic != ENI155_MAGIC) { ++ if (readl(&eprom->magic) != ENI155_MAGIC) { + printk("\n"); + printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad " -+ "magic - expected 0x%X, got 0x%lX\n",dev->number, -+ ENI155_MAGIC,eprom->magic); ++ "magic - expected 0x%X, got 0x%X\n",dev->number, ++ ENI155_MAGIC,readl(&eprom->magic)); + return -EINVAL; + } + } -+ eni_dev->phy = (volatile unsigned long *) (base+PHY_BASE); -+ eni_dev->reg = (volatile unsigned long *) (base+REG_BASE); -+ eni_dev->ram = (volatile unsigned long *) (base+RAM_BASE); ++ eni_dev->phy = (unsigned long *) (base+PHY_BASE); ++ eni_dev->reg = (unsigned long *) (base+REG_BASE); ++ eni_dev->ram = (unsigned long *) (base+RAM_BASE); + last = (MAP_MAX_SIZE-RAM_BASE)/4; + for (i = last-RAM_INCREMENT; i >= 0; + i -= RAM_INCREMENT) { -+ eni_dev->ram[i] = 0x55555555; -+ if (eni_dev->ram[i] != 0x55555555) last = i; ++ writel(0x55555555,eni_dev->ram+i); ++ if (readl(eni_dev->ram+i) != 0x55555555) last = i; + else { -+ eni_dev->ram[i] = 0xAAAAAAAA; -+ if (eni_dev->ram[i] != 0xAAAAAAAA) last = i; -+ else eni_dev->ram[i] = i; ++ writel(0xAAAAAAAA,eni_dev->ram+i); ++ if (readl(eni_dev->ram+i) != 0xAAAAAAAA) last = i; ++ else writel(i,eni_dev->ram+i); + } + } + for (i = 0; i < last; i += RAM_INCREMENT) -+ if (eni_dev->ram[i] != i) break; ++ if (readl(eni_dev->ram+i) != i) break; + eni_dev->mem = i << 2; -+ memset((void *) eni_dev->ram,0,eni_dev->mem); ++ memset_io(eni_dev->ram,0,eni_dev->mem); + /* TODO: should shrink allocation now */ + printk("mem=%dkB (",eni_dev->mem >> 10); + /* TODO: check for non-SUNI, check for TAXI ? */ -+ if (!(eni_dev->reg[MID_RES_ID_MCON] & 0x200) != !eni_dev->asic) { ++ if (!(readl(eni_dev->reg+MID_RES_ID_MCON) & 0x200) != !eni_dev->asic) { + printk(")\n"); -+ printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%0lx\n", -+ dev->number,eni_dev->reg[MID_RES_ID_MCON]); ++ printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%0x\n", ++ dev->number,readl(eni_dev->reg+MID_RES_ID_MCON)); + return -EINVAL; + } + error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base); @@ -2325,8 +1994,8 @@ + printk("%s%02X",i ? "-" : "",dev->esi[i]); + printk(")\n"); + printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number, -+ eni_dev->reg[MID_RES_ID_MCON] & 0x200 ? "ASIC" : "FPGA", -+ media_name[eni_dev->reg[MID_RES_ID_MCON] & DAUGTHER_ID]); ++ readl(eni_dev->reg+MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA", ++ media_name[readl(eni_dev->reg+MID_RES_ID_MCON) & DAUGTHER_ID]); + return suni_init(dev); +} + @@ -2334,7 +2003,7 @@ +static int eni_start(struct atm_dev *dev) +{ + struct eni_dev *eni_dev; -+ volatile unsigned long *buf; ++ unsigned long *buf; + unsigned long buffer_mem; + int error; + @@ -2365,7 +2034,7 @@ + eni_dev->tx_dma = eni_dev->rx_dma+NR_DMA_RX*2; + eni_dev->service = eni_dev->tx_dma+NR_DMA_TX*2; + buf = eni_dev->service+NR_SERVICE; -+ DPRINTK("vci 0x%p,rx 0x%p, tx 0x%p,srv 0x%p,buf 0x%lx\n", ++ DPRINTK("vci 0x%p,rx 0x%p, tx 0x%p,srv 0x%p,buf 0x%p\n", + eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,eni_dev->service, + buf); + /* initialize memory management */ @@ -2381,7 +2050,7 @@ + } + eni_dev->free_len = 0; + eni_put_free(eni_dev,(unsigned long) buf,buffer_mem); -+ memset((void *) eni_dev->vci,0,16*NR_VCI); /* clear VCI table */ ++ memset_io(eni_dev->vci,0,16*NR_VCI); /* clear VCI table */ + /* + * byte_addr free (k) + * 0x00000000 512 VCI table @@ -2391,22 +2060,18 @@ + * 0x00007000 484 buffers + * 0x00080000 0 end (512kB) + */ -+ eni_dev->reg[MID_IE] = 0xffffffff; -+#if 0 -+MID_TX_COMPLETE_0 | MID_TX_DMA_OVFL | -+ MID_TX_IDENT_MISM | MID_RX_DMA_COMPLETE | MID_TX_DMA_COMPLETE | -+ MID_SERVICE | MID_SUNI_INT | MID_STAT_OVFL; /* enable interrupts */ -+#endif ++ writel(0xffffffff,eni_dev->reg+MID_IE); + error = start_tx(dev); + if (error) return error; + error = start_rx(dev); + if (error) return error; + error = dev->phy->start(dev); + if (error) return error; -+ eni_dev->reg[MID_MC_S] |= (1 << MID_INT_SEL_SHIFT) | -+ MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE; ++ writel(readl(eni_dev->reg+MID_MC_S) | (1 << MID_INT_SEL_SHIFT) | ++ MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE, ++ eni_dev->reg+MID_MC_S); + /* Tonga uses SBus INTReq1 */ -+ (void) eni_dev->reg[MID_ISA]; /* clear Midway interrupts */ ++ (void) readl(eni_dev->reg+MID_ISA); /* clear Midway interrupts */ + return 0; +} + @@ -2480,7 +2145,8 @@ + vcc->vci = vci; + if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) + vcc->flags |= ATM_VF_ADDR; -+ if (vcc->aal != ATM_AAL0 && vcc->aal != ATM_AAL5) return -EINVAL; ++ if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5) ++ return -EINVAL; + DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, + vcc->vci); + if (!(vcc->flags & ATM_VF_PARTIAL)) { @@ -2512,8 +2178,10 @@ +} + + -+static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,unsigned long arg) ++static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ ++ int error; ++ + if (cmd == ENI_MEMDUMP) { + dump(dev); + return 0; @@ -2521,7 +2189,9 @@ + if (cmd == ATM_SETCIRANGE) { + struct atm_cirange ci; + -+ memcpy_fromfs(&ci,(void *) arg,sizeof(struct atm_cirange)); ++ error = copy_from_user(&ci,(void *) arg, ++ sizeof(struct atm_cirange)); ++ if (error) return error; + if ((ci.vpi_bits == 0 || ci.vpi_bits == ATM_CI_MAX) && + (ci.vci_bits == NR_VCI_LD || ci.vpi_bits == ATM_CI_MAX)) + return 0; @@ -2533,7 +2203,7 @@ + + +static int eni_getsockopt(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int *optlen) ++ void *optval,int optlen) +{ +#ifdef CONFIG_MMU_HACKS + @@ -2546,26 +2216,16 @@ +static const struct atm_buffconst bcrx = { 4,0,4,0,0,0 }; + +#endif -+ int error; -+ + if (level == SOL_AAL && (optname == SO_BCTXOPT || -+ optname == SO_BCRXOPT)) { -+ if (get_fs_long(optlen) < sizeof(struct atm_buffconst)) -+ return -EINVAL; -+ put_fs_long(sizeof(struct atm_buffconst),optlen); -+ error = verify_area(VERIFY_WRITE,optval, -+ sizeof(struct atm_buffconst)); -+ if (error) return error; -+ memcpy_tofs(optval,optname == SO_BCTXOPT ? &bctx : &bcrx, -+ sizeof(struct atm_buffconst)); -+ return 0; -+ } ++ optname == SO_BCRXOPT)) ++ return copy_to_user(optval,optname == SO_BCTXOPT ? &bctx : ++ &bcrx,sizeof(struct atm_buffconst)); + return -EINVAL; +} + + +static int eni_setsockopt(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int optlen) ++ void *optval,int optlen) +{ + return -EINVAL; +} @@ -2585,7 +2245,7 @@ + dev_kfree_skb(skb,FREE_WRITE); + return -EINVAL; + } -+ if (vcc->aal == ATM_AAL0) { ++ if (vcc->qos.aal == ATM_AAL0) { + if (skb->len != ATM_CELL_SIZE-1) { + dev_kfree_skb(skb,FREE_WRITE); + return -EINVAL; @@ -2609,7 +2269,7 @@ +static int eni_sg_send(struct atm_vcc *vcc,unsigned long start, + unsigned long size) +{ -+ return vcc->aal == ATM_AAL5 && !((start | size) & 3); ++ return vcc->qos.aal == ATM_AAL5 && !((start | size) & 3); + /* don't tolerate misalignment */ +} + @@ -2617,21 +2277,19 @@ +static void eni_phy_put(struct atm_dev *dev,unsigned char value, + unsigned long addr) +{ -+ ENI_DEV(dev)->phy[addr] = value; ++ writel(value,ENI_DEV(dev)->phy+addr); +} + + + +static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr) +{ -+ volatile unsigned tmp; /* force 32 bit access */ -+ -+ tmp = ENI_DEV(dev)->phy[addr]; -+ return tmp; ++ return readl(ENI_DEV(dev)->phy+addr); +} + + +static const struct atmdev_ops ops = { ++ NULL, /* no dev_close */ + eni_open, + eni_close, + eni_ioctl, @@ -2639,7 +2297,6 @@ + eni_setsockopt, + eni_send, + eni_sg_send, -+ NULL, /* no poll */ + NULL, /* no send_oam */ + eni_phy_put, + eni_phy_get, @@ -2712,7 +2369,7 @@ + +#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/eni.h Fri Apr 4 19:58:30 1997 ++++ work/drivers/atm/eni.h Thu Jul 3 08:22:18 1997 @@ -0,0 +1,104 @@ +/* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ + @@ -2746,7 +2403,7 @@ +}; + +struct eni_tx { -+ volatile unsigned long *send; /* base, NULL if unused */ ++ unsigned long *send; /* base, NULL if unused */ + int prescaler; /* shaping prescaler */ + int resolution; /* shaping divider */ + unsigned long tx_pos; /* current TX write position */ @@ -2758,7 +2415,7 @@ + +struct eni_vcc { + int (*rx)(struct atm_vcc *vcc); /* RX function, NULL if none */ -+ volatile unsigned long *recv; /* receive buffer */ ++ unsigned long *recv; /* receive buffer */ + unsigned long words; /* its size in words */ + unsigned long descr; /* next descriptor (RX) */ + unsigned long rx_pos; /* current RX descriptor pos */ @@ -2775,13 +2432,13 @@ +struct eni_dev { + /*-------------------------------- base pointers into Midway address + space */ -+ volatile unsigned long *phy; /* PHY interface chip registers */ -+ volatile unsigned long *reg; /* register base */ -+ volatile unsigned long *ram; /* RAM base */ -+ volatile unsigned long *vci; /* VCI table */ -+ volatile unsigned long *rx_dma; /* RX DMA queue */ -+ volatile unsigned long *tx_dma; /* TX DMA queue */ -+ volatile unsigned long *service;/* service list */ ++ unsigned long *phy; /* PHY interface chip registers */ ++ unsigned long *reg; /* register base */ ++ unsigned long *ram; /* RAM base */ ++ unsigned long *vci; /* VCI table */ ++ unsigned long *rx_dma; /* RX DMA queue */ ++ unsigned long *tx_dma; /* TX DMA queue */ ++ unsigned long *service; /* service list */ + /*-------------------------------- TX part */ + struct eni_tx tx[NR_CHAN]; /* TX channels */ + struct eni_tx *ubr; /* UBR channel */ @@ -2819,7 +2476,7 @@ + +#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/midway.h Fri Nov 15 19:06:24 1996 ++++ work/drivers/atm/midway.h Wed May 14 15:34:14 1997 @@ -0,0 +1,265 @@ +/* drivers/atm/midway.h - Efficient Networks Midway (SAR) description */ + @@ -3087,8 +2744,8 @@ + +#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/suni.c Fri Nov 15 19:06:24 1996 -@@ -0,0 +1,298 @@ ++++ work/drivers/atm/suni.c Wed May 14 17:41:39 1997 +@@ -0,0 +1,305 @@ +/* drivers/atm/suni.c - PMC SUNI (PHY) driver */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -3188,6 +2845,7 @@ +} + + ++#if 0 +static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) +{ + unsigned long flags; @@ -3249,10 +2907,13 @@ + put_fs_long(set,arg); + return 0; +} ++#endif + + -+static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,unsigned long arg) ++static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void * arg) +{ ++ return -EINVAL; ++#if 0 + int error; + + switch (cmd) { @@ -3292,6 +2953,7 @@ + default: + return -EINVAL; + } ++#endif +} + + @@ -3320,7 +2982,9 @@ + (void) GET(RSOP_SIS); /* clear SUNI interrupts */ + PRIV(dev)->loop_mode = SUNI_LM_NONE; + suni_hz(0); /* clear SUNI counters */ ++#if 0 + (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ ++#endif + cli(); + if (!start_timer) restore_flags(flags); + else { @@ -3388,7 +3052,7 @@ + +#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/suni.h Wed Apr 2 22:37:11 1997 ++++ work/drivers/atm/suni.h Thu Jul 3 08:22:18 1997 @@ -0,0 +1,219 @@ +/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */ + @@ -3610,7 +3274,7 @@ + +#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/tonga.h Fri Nov 15 19:06:24 1996 ++++ work/drivers/atm/tonga.h Wed May 14 15:34:14 1997 @@ -0,0 +1,20 @@ +/* drivers/atm/tonga.h - Efficient Networks Tonga (PCI bridge) declarations */ + @@ -3632,16090 +3296,4823 @@ +#define SEPROM_ESI_BASE 64 /* start of ESI in serial EEPROM */ + +#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/uPD98401.h Fri Nov 15 19:06:25 1996 -@@ -0,0 +1,292 @@ -+/* drivers/atm/uPD98401.h - NEC uPD98401 (SAR) declarations */ -+ -+/* Written 1995 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef DRIVERS_ATM_uPD98401_H -+#define DRIVERS_ATM_uPD98401_H -+ +--- ref/drivers/block/genhd.c Thu Jul 10 14:23:18 1997 ++++ work/drivers/block/genhd.c Wed May 14 21:43:24 1997 +@@ -58,6 +58,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. +@@ -785,6 +786,9 @@ + #endif + #ifdef CONFIG_INET + net_dev_init(); ++#endif ++#ifdef CONFIG_ATM ++ (void) atmdev_init(); + #endif + #ifdef CONFIG_VT + console_map_init(); +--- ref/fs/proc/root.c Thu Jul 10 14:28:06 1997 ++++ work/fs/proc/root.c Wed May 14 21:39:13 1997 +@@ -18,6 +18,10 @@ + #include + #endif + + -+#define MAX_CRAM_SIZE (1 << 18) /* 2^18 words */ -+#define RAM_INCREMENT 1024 /* check in 4 kB increments */ ++extern void atm_proc_init(void); + -+#define uPD98401_PORTS 0x24 /* probably more ? */ + + /* + * Offset of the first process in the /proc root directory.. + */ +@@ -295,6 +299,16 @@ + return PROC_DYNAMIC_FIRST + i; + } + ++struct proc_dir_entry proc_atm = { ++ PROC_ATM, 3, "atm", ++ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, ++ 0, &proc_dir_inode_operations, ++ NULL, NULL, ++ NULL, ++ &proc_root, NULL ++}; + -+/* -+ * Commands -+ */ + -+#define uPD98401_OPEN_CHAN 0x20000000 /* open channel */ -+#define uPD98401_CHAN_ADDR 0x0003fff8 /* channel address */ -+#define uPD98401_CHAN_ADDR_SHIFT 3 -+#define uPD98401_CLOSE_CHAN 0x24000000 /* close channel */ -+#define uPD98401_CHAN_RT 0x02000000 /* RX/TX (0 TX, 1 RX) */ -+#define uPD98401_DEACT_CHAN 0x28000000 /* deactivate channel */ -+#define uPD98401_TX_READY 0x30000000 /* TX ready */ -+#define uPD98401_ADD_BAT 0x34000000 /* add batches */ -+#define uPD98401_POOL 0x000f0000 /* pool number */ -+#define uPD98401_POOL_SHIFT 16 -+#define uPD98401_POOL_NUMBAT 0x0000ffff /* number of batches */ -+#define uPD98401_NOP 0x3f000000 /* NOP */ -+#define uPD98401_IND_ACC 0x00000000 /* Indirect Access */ -+#define uPD98401_IA_RW 0x10000000 /* Read/Write (0 W, 1 R) */ -+#define uPD98401_IA_B3 0x08000000 /* Byte select, 1 enable */ -+#define uPD98401_IA_B2 0x04000000 -+#define uPD98401_IA_B1 0x02000000 -+#define uPD98401_IA_B0 0x01000000 -+#define uPD98401_IA_BALL 0x0f000000 /* whole longword */ -+#define uPD98401_IA_TGT 0x000c0000 /* Target */ -+#define uPD98401_IA_TGT_SHIFT 18 -+#define uPD98401_IA_TGT_CM 0 /* - Control Memory */ -+#define uPD98401_IA_TGT_SAR 1 /* - uPD98401 registers */ -+#define uPD98401_IA_TGT_PHY 3 /* - PHY device */ -+#define uPD98401_IA_ADDR 0x0003ffff + int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) + { + int i; +@@ -560,6 +574,10 @@ + proc_scsi = create_proc_entry("scsi", S_IFDIR, 0); + #ifdef CONFIG_SYSCTL + proc_register(&proc_root, &proc_sys_root); ++#endif ++#ifdef CONFIG_ATM ++ proc_register(&proc_root, &proc_atm); ++ atm_proc_init(); + #endif + #ifdef CONFIG_MCA + proc_register(&proc_root, &proc_mca); +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/arequipa.h Wed May 14 22:11:01 1997 +@@ -0,0 +1,60 @@ ++/* arequipa.h - Arequipa interface definitions */ ++ ++/* Written 1996,1997 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ ++ + -+/* -+ * Command Register Status -+ */ ++#ifndef _LINUX_AREQUIPA_H ++#define _LINUX_AREQUIPA_H + -+#define uPD98401_BUSY 0x80000000 /* SAR is busy */ -+#define uPD98401_LOCKED 0x40000000 /* SAR is locked by other CPU */ ++#include + -+/* -+ * Indications -+ */ + -+/* Normal (AAL5) Receive Indication */ -+#define uPD98401_AAL5_UINFO 0xffff0000 /* user-supplied information */ -+#define uPD98401_AAL5_UINFO_SHIFT 16 -+#define uPD98401_AAL5_SIZE 0x0000ffff /* PDU size (in _CELLS_ !!) */ -+#define uPD98401_AAL5_CHAN 0x7fff0000 /* Channel number */ -+#define uPD98401_AAL5_CHAN_SHIFT 16 -+#define uPD98401_AAL5_ERR 0x00008000 /* Error indication */ -+#define uPD98401_AAL5_CI 0x00004000 /* Congestion Indication */ -+#define uPD98401_AAL5_CLP 0x00002000 /* CLP (>= 1 cell had CLP=1) */ -+#define uPD98401_AAL5_ES 0x00000f00 /* Error Status */ -+#define uPD98401_AAL5_ES_SHIFT 8 -+#define uPD98401_AAL5_ES_NONE 0 /* No error */ -+#define uPD98401_AAL5_ES_FREE 1 /* Receiver free buf underflow */ -+#define uPD98401_AAL5_ES_FIFO 2 /* Receiver FIFO overrun */ -+#define uPD98401_AAL5_ES_TOOBIG 3 /* Maximum length violation */ -+#define uPD98401_AAL5_ES_CRC 4 /* CRC error */ -+#define uPD98401_AAL5_ES_ABORT 5 /* User abort */ -+#define uPD98401_AAL5_ES_LENGTH 6 /* Length violation */ -+#define uPD98401_AAL5_ES_T1 7 /* T1 error (timeout) */ -+#define uPD98401_AAL5_ES_DEACT 8 /* Deactivated with DEACT_CHAN */ -+#define uPD98401_AAL5_POOL 0x0000001f /* Free buffer pool number */ -+ -+/* Raw Cell Indication */ -+#define uPD98401_RAW_UINFO uPD98401_AAL5_UINFO -+#define uPD98401_RAW_UINFO_SHIFT uPD98401_AAL5_UINFO_SHIFT -+#define uPD98401_RAW_HEC 0x000000ff /* HEC */ -+#define uPD98401_RAW_CHAN uPD98401_AAL5_CHAN -+#define uPD98401_RAW_CHAN_SHIFT uPD98401_AAL5_CHAN_SHIFT -+ -+/* Transmit Indication */ -+#define uPD98401_TXI_CONN 0x7fff0000 /* Connection Number */ -+#define uPD98401_TXI_CONN_SHIFT 16 -+#define uPD98401_TXI_ACTIVE 0x00008000 /* Channel remains active */ -+#define uPD98401_TXI_PQP 0x00007fff /* Packet Queue Pointer */ ++enum arequipa_msg_type { amt_invalid,amt_close,amt_sync }; + -+/* -+ * Directly Addressable Registers -+ */ -+ -+#define uPD98401_GMR 0x00 /* General Mode Register */ -+#define uPD98401_GSR 0x01 /* General Status Register */ -+#define uPD98401_IMR 0x02 /* Interrupt Mask Register */ -+#define uPD98401_RQU 0x03 /* Receive Queue Underrun */ -+#define uPD98401_RQA 0x04 /* Receive Queue Alert */ -+#define uPD98401_ADDR 0x05 /* Last Burst Address */ -+#define uPD98401_VER 0x06 /* Version Number */ -+#define uPD98401_SWR 0x07 /* Software Reset */ -+#define uPD98401_CMR 0x08 /* Command Register */ -+#define uPD98401_CMR_L 0x09 /* Command Register and Lock/Unlock */ -+#define uPD98401_CER 0x0a /* Command Extension Register */ -+#define uPD98401_CER_L 0x0b /* Command Ext Reg and Lock/Unlock */ -+ -+#define uPD98401_MSH(n) (0x10+(n)) /* Mailbox n Start Address High */ -+#define uPD98401_MSL(n) (0x14+(n)) /* Mailbox n Start Address High */ -+#define uPD98401_MBA(n) (0x18+(n)) /* Mailbox n Bottom Address */ -+#define uPD98401_MTA(n) (0x1c+(n)) /* Mailbox n Tail Address */ -+#define uPD98401_MWA(n) (0x20+(n)) /* Mailbox n Write Address */ -+ -+/* GMR is at 0x00 */ -+#define uPD98401_GMR_ONE 0x80000000 /* Must be set to one */ -+#define uPD98401_GMR_SLM 0x40000000 /* Address mode (0 word, 1 byte) */ -+#define uPD98401_GMR_CPE 0x00008000 /* Control Memory Parity Enable */ -+#define uPD98401_GMR_LP 0x00004000 /* Loopback */ -+#define uPD98401_GMR_WA 0x00002000 /* Early Bus Write Abort/RDY */ -+#define uPD98401_GMR_RA 0x00001000 /* Early Read Abort/RDY */ -+#define uPD98401_GMR_SZ 0x00000f00 /* Burst Size Enable */ -+#define uPD98401_BURST16 0x00000800 /* 16-word burst */ -+#define uPD98401_BURST8 0x00000400 /* 8-word burst */ -+#define uPD98401_BURST4 0x00000200 /* 4-word burst */ -+#define uPD98401_BURST2 0x00000100 /* 2-word burst */ -+#define uPD98401_GMR_AD 0x00000080 /* Address (burst resolution) Disable */ -+#define uPD98401_GMR_BO 0x00000040 /* Byte Order (0 little, 1 big) */ -+#define uPD98401_GMR_PM 0x00000020 /* Bus Parity Mode (0 byte, 1 word)*/ -+#define uPD98401_GMR_PC 0x00000010 /* Bus Parity Control (0even,1odd) */ -+#define uPD98401_GMR_BPE 0x00000008 /* Bus Parity Enable */ -+#define uPD98401_GMR_DR 0x00000004 /* Receive Drop Mode (0drop,1don't)*/ -+#define uPD98401_GMR_SE 0x00000002 /* Shapers Enable */ -+#define uPD98401_GMR_RE 0x00000001 /* Receiver Enable */ -+ -+/* GSR is at 0x01, IMR is at 0x02 */ -+#define uPD98401_INT_PI 0x80000000 /* PHY interrupt */ -+#define uPD98401_INT_RQA 0x40000000 /* Receive Queue Alert */ -+#define uPD98401_INT_RQU 0x20000000 /* Receive Queue Underrun */ -+#define uPD98401_INT_RD 0x10000000 /* Receiver Deactivated */ -+#define uPD98401_INT_SPE 0x08000000 /* System Parity Error */ -+#define uPD98401_INT_CPE 0x04000000 /* Control Memory Parity Error */ -+#define uPD98401_INT_SBE 0x02000000 /* System Bus Error */ -+#define uPD98401_INT_IND 0x01000000 /* Initialization Done */ -+#define uPD98401_INT_RCR 0x0000ff00 /* Raw Cell Received */ -+#define uPD98401_INT_RCR_SHIFT 8 -+#define uPD98401_INT_MF 0x000000f0 /* Mailbox Full */ -+#define uPD98401_INT_MF_SHIFT 4 -+#define uPD98401_INT_MM 0x0000000f /* Mailbox Modified */ -+ -+/* VER is at 0x06 */ -+#define uPD98401_MAJOR 0x0000ff00 /* Major revision */ -+#define uPD98401_MAJOR_SHIFT 8 -+#define uPD98401_MINOR 0x000000ff /* Minor revision */ ++struct arequipa_msg { ++ enum arequipa_msg_type type; ++ void *ptr; ++}; + -+/* -+ * Indirectly Addressable Registers -+ */ + -+#define uPD98401_IM(n) (0x40000+(n)) /* Scheduler n I and M */ -+#define uPD98401_X(n) (0x40010+(n)) /* Scheduler n X */ -+#define uPD98401_Y(n) (0x40020+(n)) /* Scheduler n Y */ -+#define uPD98401_PC(n) (0x40030+(n)) /* Scheduler n P, C, p and c */ -+#define uPD98401_PS(n) (0x40040+(n)) /* Scheduler n priority and status */ -+ -+/* IM contents */ -+#define uPD98401_IM_I 0xff000000 /* I */ -+#define uPD98401_IM_I_SHIFT 24 -+#define uPD98401_IM_M 0x00ffffff /* M */ -+ -+/* PC contents */ -+#define uPD98401_PC_P 0xff000000 /* P */ -+#define uPD98401_PC_P_SHIFT 24 -+#define uPD98401_PC_C 0x00ff0000 /* C */ -+#define uPD98401_PC_C_SHIFT 16 -+#define uPD98401_PC_p 0x0000ff00 /* p */ -+#define uPD98401_PC_p_SHIFT 8 -+#define uPD98401_PC_c 0x000000ff /* c */ -+ -+/* PS contents */ -+#define uPD98401_PS_PRIO 0xf0 /* Priority level (0 high, 15 low) */ -+#define uPD98401_PS_PRIO_SHIFT 4 -+#define uPD98401_PS_S 0x08 /* Scan - must be 0 (internal) */ -+#define uPD98401_PS_R 0x04 /* Round Robin (internal) */ -+#define uPD98401_PS_A 0x02 /* Active (internal) */ -+#define uPD98401_PS_E 0x01 /* Enabled */ -+ -+#define uPD98401_TOS 0x40100 /* Top of Stack Control Memory Address */ -+#define uPD98401_SMA 0x40200 /* Shapers Control Memory Start Address */ -+#define uPD98401_PMA 0x40201 /* Receive Pool Control Memory Start Address */ -+#define uPD98401_T1R 0x40300 /* T1 Register */ -+#define uPD98401_VRR 0x40301 /* VPI/VCI Reduction Register/Recv. Shutdown */ -+#define uPD98401_TSR 0x40302 /* Time-Stamp Register */ -+ -+/* VRR is at 0x40301 */ -+#define uPD98401_VRR_SDM 0x80000000 /* Shutdown Mode */ -+#define uPD98401_VRR_SHIFT 0x000f0000 /* VPI/VCI Shift */ -+#define uPD98401_VRR_SHIFT_SHIFT 16 -+#define uPD98401_VRR_MASK 0x0000ffff /* VPI/VCI mask */ ++#define AREQUIPA_PRESET _IO('a',ATMIOC_AREQUIPA) ++#define AREQUIPA_INCOMING _IO('a',ATMIOC_AREQUIPA+1) ++#define AREQUIPA_EXPECT _IO('a',ATMIOC_AREQUIPA+2) ++#define AREQUIPA_CLOSE _IO('a',ATMIOC_AREQUIPA+3) ++#define AREQUIPA_CTRL _IO('a',ATMIOC_AREQUIPA+4) ++#define AREQUIPA_CLS3RD _IO('a',ATMIOC_AREQUIPA+5) ++#define AREQUIPA_SYNCREQ _IO('a',ATMIOC_AREQUIPA+6) ++#define AREQUIPA_SYNCACK _IO('a',ATMIOC_AREQUIPA+7) ++#define AREQUIPA_WORK _IO('a',ATMIOC_AREQUIPA+8) + -+/* -+ * TX packet descriptor -+ */ + -+#define uPD98401_TXPD_SIZE 16 /* descriptor size (in bytes) */ ++#ifdef __KERNEL__ + -+#define uPD98401_TXPD_V 0x80000000 /* Valid bit */ -+#define uPD98401_TXPD_DP 0x40000000 /* Descriptor (1) or Pointer (0) */ -+#define uPD98401_TXPD_SM 0x20000000 /* Single (1) or Multiple (0) */ -+#define uPD98401_TXPD_CLPM 0x18000000 /* CLP mode */ -+#define uPD98401_CLPM_0 0 /* 00 CLP = 0 */ -+#define uPD98401_CLPM_1 3 /* 11 CLP = 1 */ -+#define uPD98401_CLPM_LAST 1 /* 01 CLP unless last cell */ -+#define uPD98401_TXPD_CLPM_SHIFT 27 -+#define uPD98401_TXPD_PTI 0x07000000 /* PTI pattern */ -+#define uPD98401_TXPD_PTI_SHIFT 24 -+#define uPD98401_TXPD_GFC 0x00f00000 /* GFC pattern */ -+#define uPD98401_TXPD_GFC_SHIFT 20 -+#define uPD98401_TXPD_C10 0x00040000 /* insert CRC-10 */ -+#define uPD98401_TXPD_AAL5 0x00020000 /* AAL5 processing */ -+#define uPD98401_TXPD_MB 0x00010000 /* TX mailbox number */ -+#define uPD98401_TXPD_UU 0x0000ff00 /* CPCS-UU */ -+#define uPD98401_TXPD_UU_SHIFT 8 -+#define uPD98401_TXPD_CPI 0x000000ff /* CPI */ ++#include ++#include ++#include ++#include + -+/* -+ * TX buffer descriptor -+ */ + -+#define uPD98401_TXBD_SIZE 8 /* descriptor size (in bytes) */ ++extern struct atm_vcc *aqd; /* for net/atm/proc.c */ ++/* extern struct rtable arequipa_rt; - not needed */ ++extern struct device *arequipa_dev; + -+#define uPD98401_TXBD_LAST 0x80000000 /* last buffer in packet */ ++int atm_init_arequipa(void); ++int arequipa_attach(struct socket *lower,struct sock *upper, ++ unsigned long generation); + -+/* -+ * TX VC table -+ */ ++int arequipa_preset(struct socket *lower,struct sock *upper); ++int arequipa_expect(struct sock *upper,int on); ++int arequipa_incoming(struct socket *lower); ++int arequipa_close(struct sock *upper); ++void arequipa_synchronize(void); ++void arequipa_work(void); + -+/* 1st word has the same structure as in a TX packet descriptor */ -+#define uPD98401_TXVC_L 0x80000000 /* last buffer */ -+#define uPD98401_TXVC_SHP 0x0f000000 /* shaper number */ -+#define uPD98401_TXVC_SHP_SHIFT 24 -+#define uPD98401_TXVC_VPI 0x00ff0000 /* VPI */ -+#define uPD98401_TXVC_VPI_SHIFT 16 -+#define uPD98401_TXVC_VCI 0x0000ffff /* VCI */ -+#define uPD98401_TXVC_QRP 6 /* Queue Read Pointer is in word 6 */ ++int arequipad_attach(struct atm_vcc *vcc); ++void arequipa_close_vcc(struct atm_vcc *vcc); + -+/* -+ * RX free buffer pools descriptor -+ */ + -+#define uPD98401_RXFP_ALERT 0x70000000 /* low water mark */ -+#define uPD98401_RXFP_ALERT_SHIFT 28 -+#define uPD98401_RXFP_BFSZ 0x0f000000 /* buffer size, 64*2^n */ -+#define uPD98401_RXFP_BFSZ_SHIFT 24 -+#define uPD98401_RXFP_BTSZ 0x00ff0000 /* batch size, n+1 */ -+#define uPD98401_RXFP_BTSZ_SHIFT 16 -+#define uPD98401_RXFP_REMAIN 0x0000ffff /* remaining batches in pool */ ++#endif /* __KERNEL__ */ + -+/* -+ * RX VC table -+ */ ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atm.h Wed May 14 16:07:56 1997 +@@ -0,0 +1,225 @@ ++/* atm.h - general ATM declarations */ ++ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++ + -+#define uPD98401_RXVC_BTSZ 0xff000000 /* remaining free buffers in batch */ -+#define uPD98401_RXVC_BTSZ_SHIFT 24 -+#define uPD98401_RXVC_MB 0x00200000 /* RX mailbox number */ -+#define uPD98401_RXVC_POOL 0x001f0000 /* free buffer pool number */ -+#define uPD98401_RXVC_POOL_SHIFT 16 -+#define uPD98401_RXVC_UINFO 0x0000ffff /* user-supplied information */ -+#define uPD98401_RXVC_T1 0xffff0000 /* T1 timestamp */ -+#define uPD98401_RXVC_T1_SHIFT 16 -+#define uPD98401_RXVC_PR 0x00008000 /* Packet Reception, 1 if busy */ -+#define uPD98401_RXVC_DR 0x00004000 /* FIFO Drop */ -+#define uPD98401_RXVC_OD 0x00001000 /* Drop OAM cells */ -+#define uPD98401_RXVC_AR 0x00000800 /* AAL5 or raw cell; 1 if AAL5 */ -+#define uPD98401_RXVC_MAXSEG 0x000007ff /* max number of segments per PDU */ -+#define uPD98401_RXVC_REM 0xfffe0000 /* remaining words in curr buffer */ -+#define uPD98401_RXVC_REM_SHIFT 17 -+#define uPD98401_RXVC_CLP 0x00010000 /* CLP received */ -+#define uPD98401_RXVC_BFA 0x00008000 /* Buffer Assigned */ -+#define uPD98401_RXVC_BTA 0x00004000 /* Batch Assigned */ -+#define uPD98401_RXVC_CI 0x00002000 /* Congestion Indication */ -+#define uPD98401_RXVC_DD 0x00001000 /* Dropping incoming cells */ -+#define uPD98401_RXVC_DP 0x00000800 /* like PR ? */ -+#define uPD98401_RXVC_CURSEG 0x000007ff /* Current Segment count */ ++#ifndef _LINUX_ATM_H ++#define _LINUX_ATM_H + +/* -+ * RX lookup table ++ * BEGIN_xx and END_xx markers are used for automatic generation of ++ * documentation. Do not change them. + */ + -+#define uPD98401_RXLT_ENBL 0x8000 /* Enable */ ++#include ++#include + -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/uPD98402.h Fri Nov 15 19:06:25 1996 -@@ -0,0 +1,106 @@ -+/* drivers/atm/uPD98402.h - NEC uPD98402 (PHY) declarations */ -+ -+/* Written 1995 by Werner Almesberger, EPFL LRC */ + ++/* general ATM constants */ ++#define ATM_CELL_SIZE 53 /* ATM cell size incl. header */ ++#define ATM_CELL_PAYLOAD 48 /* ATM payload size */ ++#define ATM_AAL0_SDU 52 /* AAL0 SDU size */ ++#define ATM_MAX_AAL34_PDU 65535 /* maximum AAL3/4 PDU payload */ ++#define ATM_AAL5_TRAILER 8 /* AAL5 trailer size */ ++#define ATM_MAX_AAL5_PDU 65535 /* maximum AAL5 PDU payload */ ++#define ATM_MAX_CDV 9999 /* maximum (default) CDV */ ++#define ATM_NOT_RSV_VCI 32 /* first non-reserved VCI value */ + -+#ifndef DRIVERS_ATM_uPD98402_H -+#define DRIVERS_ATM_uPD98402_H ++#define ATM_MAX_VPI 255 /* maximum VPI at the UNI */ ++#define ATM_MAX_VPI_NNI 4096 /* maximum VPI at the NNI */ ++#define ATM_MAX_VCI 65535 /* maximum VCI */ + +/* -+ * Registers ++ * The following items should be added to sys/socket.h aka linux/socket.h + */ + -+#define uPD98402_CMR 0x00 /* Command Register */ -+#define uPD98402_MDR 0x01 /* Mode Register */ -+#define uPD98402_PICR 0x02 /* PHY Interrupt Cause Register */ -+#define uPD98402_PIMR 0x03 /* PHY Interrupt Mask Register */ -+#define uPD98402_ACR 0x04 /* Alarm Cause Register */ -+#define uPD98402_ACMR 0x05 /* Alarm Cause Mask Register */ -+#define uPD98402_PCR 0x06 /* Performance Cause Register */ -+#define uPD98402_PCMR 0x07 /* Performance Cause Mask Register */ -+#define uPD98402_IACM 0x08 /* Internal Alarm Cause Mask Register */ -+#define uPD98402_B1ECT 0x09 /* B1 Error Count Register */ -+#define uPD98402_B2ECT 0x0a /* B2 Error Count Register */ -+#define uPD98402_B3ECT 0x0b /* B3 Error Count Regster */ -+#define uPD98402_PFECB 0x0c /* Path FEBE Count Register */ -+#define uPD98402_LECCT 0x0d /* Line FEBE Count Register */ -+#define uPD98402_HECCT 0x0e /* HEC Error Count Register */ -+#define uPD98402_FJCT 0x0f /* Frequence Justification Count Reg */ -+#define uPD98402_PCOCR 0x10 /* Perf. Counter Overflow Cause Reg */ -+#define uPD98402_PCOMR 0x11 /* Perf. Counter Overflow Mask Reg */ -+#define uPD98402_C11T 0x20 /* C11T Data Register */ -+#define uPD98402_C12T 0x21 /* C12T Data Register */ -+#define uPD98402_C13T 0x22 /* C13T Data Register */ -+#define uPD98402_F1T 0x23 /* F1T Data Register */ -+#define uPD98402_K2T 0x25 /* K2T Data Register */ -+#define uPD98402_C2T 0x26 /* C2T Data Register */ -+#define uPD98402_F2T 0x27 /* F2T Data Register */ -+#define uPD98402_C11R 0x30 /* C11T Data Register */ -+#define uPD98402_C12R 0x31 /* C12T Data Register */ -+#define uPD98402_C13R 0x32 /* C13T Data Register */ -+#define uPD98402_F1R 0x33 /* F1T Data Register */ -+#define uPD98402_K2R 0x35 /* K2T Data Register */ -+#define uPD98402_C2R 0x36 /* C2T Data Register */ -+#define uPD98402_F2R 0x37 /* F2T Data Register */ -+ -+/* CMR is at 0x00 */ -+#define uPD98402_CMR_PFRF 0x01 /* Send path FERF */ -+#define uPD98402_CMR_LFRF 0x02 /* Send line FERF */ -+#define uPD98402_CMR_PAIS 0x04 /* Send path AIS */ -+#define uPD98402_CMR_LAIS 0x08 /* Send line AIS */ -+ -+/* MDR is at 0x01 */ -+#define uPD98402_MDR_ALP 0x01 /* ATM layer loopback */ -+#define uPD98402_MDR_TPLP 0x02 /* PMD loopback, to host */ -+#define uPD98402_MDR_RPLP 0x04 /* PMD loopback, to network */ -+#define uPD98402_MDR_SS0 0x08 /* SS0 */ -+#define uPD98402_MDR_SS1 0x10 /* SS1 */ -+#define uPD98402_MDR_SS_MASK 0x18 /* mask */ -+#define uPD98402_MDR_SS_SHIFT 3 /* shift */ -+#define uPD98402_MDR_HEC 0x20 /* disable HEC inbound processing */ -+#define uPD98402_MDR_FSR 0x40 /* disable frame scrambler */ -+#define uPD98402_MDR_CSR 0x80 /* disable cell scrambler */ -+ -+/* PICR is at 0x02, PIMR is at 0x03 */ -+#define uPD98402_INT_PFM 0x01 /* performance counter has changed */ -+#define uPD98402_INT_ALM 0x02 /* line fault */ -+#define uPD98402_INT_RFO 0x04 /* receive FIFO overflow */ -+#define uPD98402_INT_PCO 0x08 /* performance counter overflow */ -+#define uPD98402_INT_OTD 0x20 /* OTD has occurred */ -+#define uPD98402_INT_LOS 0x40 /* Loss Of Signal */ -+#define uPD98402_INT_LOF 0x80 /* Loss Of Frame */ -+ -+/* ACR is as 0x04, ACMR is at 0x05 */ -+#define uPD98402_ALM_PFRF 0x01 /* path FERF */ -+#define uPD98402_ALM_LFRF 0x02 /* line FERF */ -+#define uPD98402_ALM_PAIS 0x04 /* path AIS */ -+#define uPD98402_ALM_LAIS 0x08 /* line AIS */ -+#define uPD98402_ALM_LOD 0x10 /* loss of delineation */ -+#define uPD98402_ALM_LOP 0x20 /* loss of pointer */ -+#define uPD98402_ALM_OOF 0x40 /* out of frame */ -+ -+/* PCR is at 0x06, PCMR is at 0x07 */ -+#define uPD98402_PFM_PFEB 0x01 /* path FEBE */ -+#define uPD98402_PFM_LFEB 0x02 /* line FEBE */ -+#define uPD98402_PFM_B3E 0x04 /* B3 error */ -+#define uPD98402_PFM_B2E 0x08 /* B2 error */ -+#define uPD98402_PFM_B1E 0x10 /* B1 error */ -+#define uPD98402_PFM_FJ 0x20 /* frequency justification */ -+ -+/* IACM is at 0x08 */ -+#define uPD98402_IACM_PFRF 0x01 /* don't generate path FERF */ -+#define uPD98402_IACM_LFRF 0x02 /* don't generate line FERF */ -+ -+/* PCOCR is at 0x010, PCOMR is at 0x11 */ -+#define uPD98402_PCO_B1EC 0x01 /* B1ECT overflow */ -+#define uPD98402_PCO_B2EC 0x02 /* B2ECT overflow */ -+#define uPD98402_PCO_B3EC 0x04 /* B3ECT overflow */ -+#define uPD98402_PCO_PFBC 0x08 /* PFEBC overflow */ -+#define uPD98402_PCO_LFBC 0x10 /* LFEVC overflow */ -+#define uPD98402_PCO_HECC 0x20 /* HECCT overflow */ -+#define uPD98402_PCO_FJC 0x40 /* FJCT overflow */ -+ -+ -+int uPD98402_init(struct atm_dev *dev); -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/uPD98402.c Fri Nov 15 19:06:25 1996 -@@ -0,0 +1,228 @@ -+/* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ ++/* address families */ ++#define AF_ATMPVC 6 /* ATM PVCs */ ++#define AF_ATMSVC 7 /* ATM SVCs */ + -+#include -+#include -+#include /* for jiffies */ -+#include -+#include -+#include -+#include -+#include ++/* "protcol" values for the socket system call */ ++#define ATM_NO_AAL 0 /* AAL not specified */ ++#define ATM_AAL0 13 /* "raw" ATM cells */ ++#define ATM_AAL1 1 /* AAL1 (CBR) */ ++#define ATM_AAL2 2 /* AAL2 (VBR) */ ++#define ATM_AAL34 3 /* AAL3/4 (data) */ ++#define ATM_AAL5 5 /* AAL5 (data) */ ++#define ATM_SAAL 12 /* signaling AAL */ + -+#include "uPD98402.h" ++/* ++ * UGLY - there should only be one protocol family (PF_ATM) for both ++ * address families. A quick glance at some kernel internals seems to ++ * suggest to me that doing it the "right" way might involve some ++ * swimming against the stream ... ++ */ + ++/* protocol families */ ++#define PF_ATMPVC AF_ATMPVC ++#define PF_ATMSVC AF_ATMSVC + -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif ++/* socket option name coding functions */ + ++#define __SO_ENCODE(l,n,t) (((l) << 24) | ((n) << 16) | sizeof(t)) ++#define __SO_LEVEL(c) ((c) >> 24) ++#define __SO_NUMBER(c) (((c) >> 16) & 0xff) ++#define __SO_SIZE(c) ((c) & 0xffff) + -+struct uPD98402_priv { -+ struct sonet_stats sonet_stats; /* link diagnostics */ -+ unsigned char framing; /* SONET/SDH framing */ -+}; ++/* layers for getsockopt/setsockopt */ ++#define SOL_ATM 2 ++#define SOL_AAL 3 + ++/* ++ * ATM layer ++ */ + -+#define PRIV(dev) ((struct uPD98402_priv *) dev->phy_data) ++#define SO_SETCLP __SO_ENCODE(SOL_ATM,0,int) ++ /* set CLP bit value - TODO */ ++#define SO_CIRANGE __SO_ENCODE(SOL_ATM,1,struct atm_cirange) ++ /* connection identifier range; socket must be ++ bound or connected */ ++#define SO_ATMQOS __SO_ENCODE(SOL_ATM,2,struct atm_qos) ++ /* Quality of Service setting */ + -+#define PUT(val,reg) dev->ops->phy_put(dev,val,uPD98402_##reg) -+#define GET(reg) dev->ops->phy_get(dev,uPD98402_##reg) ++/* socket layer */ ++#define SO_BCTXOPT __SO_ENCODE(SOL_SOCKET,16,struct atm_buffconst) ++ /* not ATM specific - should go somewhere else */ ++#define SO_BCRXOPT __SO_ENCODE(SOL_SOCKET,17,struct atm_buffconst) + + -+static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero) -+{ -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT); -+ if (arg) -+ memcpy_tofs(arg,&PRIV(dev)->sonet_stats, -+ sizeof(struct sonet_stats)); -+ if (zero) { -+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); -+ PRIV(dev)->sonet_stats.corr_hcs = -1; -+ PRIV(dev)->sonet_stats.tx_cells = -1; -+ PRIV(dev)->sonet_stats.rx_cells = -1; -+ } -+ restore_flags(flags); -+ return 0; -+} ++/* for SO_BCTXOPT and SO_BCRXOPT */ + ++struct atm_buffconst { ++ unsigned long buf_fac; /* buffer alignment factor */ ++ unsigned long buf_off; /* buffer alignment offset */ ++ unsigned long size_fac; /* buffer size factor */ ++ unsigned long size_off; /* buffer size offset */ ++ unsigned long min_size; /* minimum size */ ++ unsigned long max_size; /* maximum size, 0 = unlimited */ ++}; + -+static int set_framing(struct atm_dev *dev,unsigned char framing) -+{ -+ static const unsigned char sonet[] = { 1,2,3,0 }; -+ static const unsigned char sdh[] = { 1,0,0,2 }; -+ const char *set; -+ unsigned long flags; -+ -+ switch (framing) { -+ case SONET_FRAME_SONET: -+ set = sonet; -+ break; -+ case SONET_FRAME_SDH: -+ set = sdh; -+ break; -+ default: -+ return -EINVAL; -+ } -+ save_flags(flags); -+ cli(); -+ PUT(set[0],C11T); -+ PUT(set[1],C12T); -+ PUT(set[2],C13T); -+ PUT((GET(MDR) & ~uPD98402_MDR_SS_MASK) | (set[3] << -+ uPD98402_MDR_SS_SHIFT),MDR); -+ restore_flags(flags); -+ return 0; -+} + ++/* ATM cell header (for AAL0) */ + -+static int get_sense(struct atm_dev *dev,unsigned long arg) -+{ -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ put_fs_byte(GET(C11R),arg); -+ put_fs_byte(GET(C12R),arg+1); -+ put_fs_byte(GET(C13R),arg+2); -+ put_fs_byte(0xff,arg+3); -+ put_fs_byte(0xff,arg+4); -+ put_fs_byte(0xff,arg+5); -+ restore_flags(flags); -+ return 0; -+} ++/* BEGIN_CH */ ++#define ATM_HDR_GFC_MASK 0xf0000000 ++#define ATM_HDR_GFC_SHIFT 28 ++#define ATM_HDR_VPI_MASK 0x0ff00000 ++#define ATM_HDR_VPI_SHIFT 20 ++#define ATM_HDR_VCI_MASK 0x000ffff0 ++#define ATM_HDR_VCI_SHIFT 4 ++#define ATM_HDR_PTI_MASK 0x0000000e ++#define ATM_HDR_PTI_SHIFT 1 ++#define ATM_HDR_CLP 0x00000001 ++/* END_CH */ + + -+static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd, -+ unsigned long arg) -+{ -+ switch (cmd) { ++/* PTI codings */ + -+ case SONET_GETSTATZ: -+ case SONET_GETSTAT: -+ return fetch_stats(dev,(struct sonet_stats *) arg, -+ cmd == SONET_GETSTATZ); -+ case SONET_SETFRAMING: -+ return set_framing(dev,arg); -+ case SONET_GETFRAMING: -+ put_fs_long(PRIV(dev)->framing,arg); -+ return 0; -+ case SONET_GETFRSENSE: -+ return get_sense(dev,arg); -+ default: -+ return -EINVAL; -+ } -+} ++/* BEGIN_PTI */ ++#define ATM_PTI_US0 0 /* user data cell, congestion not exp, SDU-type 0 */ ++#define ATM_PTI_US1 1 /* user data cell, congestion not exp, SDU-type 1 */ ++#define ATM_PTI_UCES0 2 /* user data cell, cong. experienced, SDU-type 0 */ ++#define ATM_PTI_UCES1 3 /* user data cell, cong. experienced, SDU-type 1 */ ++#define ATM_PTI_SEGF5 4 /* segment OAM F5 flow related cell */ ++#define ATM_PTI_E2EF5 5 /* end-to-end OAM F5 flow related cell */ ++#define ATM_PTI_RSV_RM 6 /* reserved for traffic control/resource mgmt */ ++#define ATM_PTI_RSV 7 /* reserved */ ++/* END_PTI */ + + -+static void stat_event(struct atm_dev *dev) -+{ -+ unsigned char events; ++/* ++ * The following items should stay in linux/atm.h, which should be linked to ++ * netatm/atm.h ++ */ + -+ events = GET(PCR); -+ if (events & uPD98402_PFM_PFEB) -+ if ((PRIV(dev)->sonet_stats.path_febe += GET(PFECB)) < 0) -+ PRIV(dev)->sonet_stats.path_febe = LONG_MAX; -+ if (events & uPD98402_PFM_LFEB) -+ if ((PRIV(dev)->sonet_stats.line_febe += GET(LECCT)) < 0) -+ PRIV(dev)->sonet_stats.line_febe = LONG_MAX; -+ if (events & uPD98402_PFM_B3E) -+ if ((PRIV(dev)->sonet_stats.path_bip += GET(B3ECT)) < 0) -+ PRIV(dev)->sonet_stats.path_bip = LONG_MAX; -+ if (events & uPD98402_PFM_B2E) -+ if ((PRIV(dev)->sonet_stats.line_bip += GET(B2ECT)) < 0) -+ PRIV(dev)->sonet_stats.line_bip = LONG_MAX; -+ if (events & uPD98402_PFM_B1E) -+ if ((PRIV(dev)->sonet_stats.section_bip += GET(B1ECT)) < 0) -+ PRIV(dev)->sonet_stats.section_bip = LONG_MAX; -+} ++/* Traffic description */ + ++#define ATM_NONE 0 /* no traffic */ ++#define ATM_UBR 1 ++#define ATM_CBR 2 ++#define ATM_VBR 3 ++#define ATM_ABR 4 ++#define ATM_ANYCLASS 5 /* compatible with everything */ + -+static void uPD98402_int(struct atm_dev *dev) -+{ -+ static unsigned long silence = 0; -+ unsigned char reason; ++#define ATM_MAX_PCR -1 /* maximum available PCR */ + -+ while ((reason = GET(PICR))) { -+ if (reason & uPD98402_INT_LOS) -+ printk(KERN_NOTICE "%s(itf %d): signal lost\n", -+ dev->type,dev->number); -+ if (reason & uPD98402_INT_PFM) stat_event(dev); -+ if (reason & uPD98402_INT_PCO) { -+ (void) GET(PCOCR); /* clear interrupt cause */ -+ PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT); -+ } -+ if ((reason & uPD98402_INT_RFO) && jiffies > silence) { -+ printk(KERN_WARNING "%s(itf %d): uPD98402 receive " -+ "FIFO overflow\n",dev->type,dev->number); -+ silence = jiffies+HZ/2; -+ } -+ } -+} ++struct atm_trafprm { ++ unsigned char traffic_class; /* traffic class (ATM_UBR, ...) */ ++ int max_pcr; /* maximum PCR in cells per second */ ++ int min_pcr; /* minimum PCR in cells per second */ ++ int max_cdv; /* maximum CDV in microseconds */ ++ int max_sdu; /* maximum SDU in bytes */ ++}; + ++struct atm_qos { ++ struct atm_trafprm txtp; /* parameters in TX direction */ ++ struct atm_trafprm rxtp; /* parameters in RX direction */ ++ unsigned char aal; ++}; + -+static int uPD98402_start(struct atm_dev *dev) -+{ -+DPRINTK("phy_start\n"); -+ if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL))) -+ return -ENOMEM; -+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats)); -+ (void) GET(PCR); /* clear performance events */ -+ PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */ -+ (void) GET(PCOCR); /* clear overflows */ -+ PUT(~uPD98402_PCO_HECC,PCOMR); -+ (void) GET(PICR); /* clear interrupts */ -+ PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO | -+ uPD98402_INT_LOS),PIMR); /* enable them */ -+ (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ -+ return 0; -+} ++/* PVC addressing */ + ++#define ATM_ITF_ANY -1 /* "magic" PVC address values */ ++#define ATM_VPI_ANY -1 ++#define ATM_VCI_ANY -1 ++#define ATM_VPI_UNSPEC -2 ++#define ATM_VCI_UNSPEC -2 + + -+static const struct atmphy_ops uPD98402_ops = { -+ uPD98402_start, -+ uPD98402_ioctl, /* no ioctl yet */ -+ uPD98402_int ++struct sockaddr_atmpvc { ++ unsigned short sap_family; /* address family, AF_ATMPVC */ ++ struct { /* PVC address */ ++ short itf; /* ATM interface */ ++ short vpi; /* VPI (only 8 bits at UNI) */ ++ int vci; /* VCI (only 16 bits at UNI) */ ++ } sap_addr; /* PVC address */ +}; + ++/* SVC addressing */ + -+int uPD98402_init(struct atm_dev *dev) -+{ -+DPRINTK("phy_init\n"); -+ dev->phy = &uPD98402_ops; -+ return 0; -+} ++#define ATM_ESA_LEN 20 /* ATM End System Address length */ ++#define ATM_E164_LEN 12 /* maximum E.164 number length */ + ++#define ATM_MAX_BLLI 16 /* maximum number of BLLI elements */ + -+#ifdef MODULE ++#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 */ + -+static struct symbol_table uPD98402_syms = { -+#include -+ X(uPD98402_init), -+#include ++struct sockaddr_atmsvc { ++ unsigned short sas_family; /* address family, AF_ATMSVC */ ++ struct { /* SVC address */ ++ unsigned char prv[ATM_ESA_LEN];/* private ATM address */ ++ char pub[ATM_E164_LEN+1]; /* public address (E.164) */ ++ /* unused addresses must be bzero'ed */ ++ struct atm_blli *blli; /* local SAP, low-layer information */ ++ struct atm_bhli bhli; /* local SAP, high-layer information */ ++ } sas_addr; /* SVC address */ +}; -+ -+ -+int init_module(void) -+{ -+ if (register_symtab(&uPD98402_syms)) return -EIO; -+ MOD_INC_USE_COUNT; -+ return 0; -+} + + -+void cleanup_module(void) -+{ -+ /* Nay */ -+} -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/zatm.c Fri Apr 4 19:56:49 1997 -@@ -0,0 +1,1848 @@ -+/* drivers/atm/zatm.c - ZeitNet ZN122x device driver */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++/* ++ * Some stuff for linux/sockios.h ++ */ + ++struct atmif_sioc { ++ int number; ++ int length; ++ void *arg; ++}; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* for request_region */ -+#include -+#include -+#include -+#include -+#include -+#include + -+#include "uPD98401.h" -+#include "uPD98402.h" -+#include "zeprom.h" -+#include "zatm.h" ++#define SIOCSIFATMTCP _IO('a',ATMIOC_ITF) /* set ATMTCP mode */ + + -+/* -+ * TODO: -+ * -+ * Minor features -+ * - support 64 kB SDUs (will have to use multibuffer batches then :-( ) -+ * - proper use of CDV, credit = max(1,CDVT*PCR) -+ * - AAL0 -+ * - better receive timestamps -+ * - OAM -+ */ ++#ifdef __KERNEL__ + -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif ++#include /* struct net_proto */ + + -+#ifndef CONFIG_ATM_ZATM_DEBUG ++void atmpvc_proto_init(struct net_proto *pro); ++void atmsvc_proto_init(struct net_proto *pro); + ++#endif /* __KERNEL__ */ + -+#define NULLCHECK(x) ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atm_eni.h Wed May 14 16:07:56 1997 +@@ -0,0 +1,15 @@ ++/* atm_eni.h - Driver-specific declarations of the ENI driver (for use by ++ driver-specific utilities) */ + -+#define EVENT(s,a,b) ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + -+static void event_dump(void) -+{ -+} ++#ifndef LINUX_ATM_ENI_H ++#define LINUX_ATM_ENI_H + ++#include + -+#else ++#define ENI_MEMDUMP _IOW('a',ATMIOC_SARPRV,struct atmif_sioc) ++ /* printk memory map */ ++ ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atm_tcp.h Tue Jul 1 10:44:17 1997 +@@ -0,0 +1,27 @@ ++/* atm_tcp.h - Driver-specific declarations of the ATMTCP driver (for use by ++ driver-specific utilities) */ + ++/* Written 1997 by Werner Almesberger, EPFL LRC */ + -+/* -+ * NULL pointer checking -+ */ + -+#define NULLCHECK(x) \ -+ if ((unsigned long) (x) < 0x30) printk(KERN_CRIT #x "==0x%x\n", (int) (x)) ++#ifndef LINUX_ATM_ENI_H ++#define LINUX_ATM_ENI_H + +/* -+ * Very extensive activity logging. Greatly improves bug detection speed but -+ * costs a few Mbps if enabled. ++ * All values are in network byte order + */ + -+#define EV 64 -+ -+static const char *ev[EV]; -+static unsigned long ev_a[EV],ev_b[EV]; -+static int ec = 0; ++struct atmtcp_hdr { ++ unsigned short vpi; ++ unsigned short vci; ++ unsigned long length; /* ... of data part */ ++}; + + -+static void EVENT(const char *s,unsigned long a,unsigned long b) -+{ -+ ev[ec] = s; -+ ev_a[ec] = a; -+ ev_b[ec] = b; -+ ec = (ec+1) % EV; -+} ++#ifdef __KERNEL__ + ++int atmtcp_attach(struct atm_vcc *vcc); + -+static void event_dump(void) -+{ -+ int n,i; ++#endif + -+ printk(KERN_NOTICE "----- event dump follows -----\n"); -+ for (n = 0; n < EV; n++) { -+ i = (ec+n) % EV; -+ printk(KERN_NOTICE); -+ printk(ev[i] ? ev[i] : "(null)",ev_a[i],ev_b[i]); -+ } -+ printk(KERN_NOTICE "----- event dump ends here -----\n"); -+} ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmarp.h Thu Jul 3 08:57:41 1997 +@@ -0,0 +1,96 @@ ++/* atmarp.h - ATM ARP protocol and kernel-demon interface definitions */ ++ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++ + ++#ifndef _LINUX_ATMARP_H ++#define _LINUX_ATMARP_H + -+#endif /* CONFIG_ATM_ZATM_DEBUG */ ++#include ++#include ++#include + + -+#define RING_BUSY 1 /* indication from do_tx that PDU has to be -+ backlogged */ ++/* RFC 1577 ATM ARP header */ + -+static struct atm_dev *zatm_boards = NULL; -+static unsigned long dummy[2] = {0,0}; ++struct atmarphdr { ++ unsigned short ar_hrd; /* Hardware type */ ++ unsigned short ar_pro; /* Protocol type */ ++ unsigned char ar_shtl;/* Type & length of source ATM number (q) */ ++ unsigned char ar_sstl;/* Type & length of source ATM subaddress (r) */ ++ unsigned short ar_op; /* Operation code (request, reply, or NAK) */ ++ unsigned char ar_spln;/* Length of source protocol address (s) */ ++ unsigned char ar_thtl;/* Type & length of target ATM number (x) */ ++ unsigned char ar_tstl;/* Type & length of target ATM subaddress (y) */ ++ unsigned char ar_tpln;/* Length of target protocol address (z) */ ++ /* ar_sha, at_ssa, ar_spa, ar_tha, ar_tsa, ar_tpa */ ++ unsigned char data[1]; ++}; + ++#define TL_LEN 0x3f /* ATMARP Type/Length field structure */ ++#define TL_E164 0x40 + -+#define zin_n(r) inl(zatm_dev->base+r*4) -+#define zin(r) inl(zatm_dev->base+uPD98401_##r*4) -+#define zout(v,r) outl(v,zatm_dev->base+uPD98401_##r*4) -+#define zwait while (zin(CMR) & uPD98401_BUSY) + -+/* RX0, RX1, TX0, TX1 */ -+static const int mbx_entries[NR_MBX] = { 1024,1024,1024,1024 }; -+static const int mbx_esize[NR_MBX] = { 16,16,4,4 }; /* entry size in bytes */ ++#define ATF_NULL 0x1000 /* use NULL encapsulation */ ++#define ATF_ARPSRV 0x2000 /* entry describes ARP server */ ++#define ATF_DEFQOS 0x4000 /* entry defines default QOS */ + -+#define MBX_SIZE(i) (mbx_entries[i]*mbx_esize[i]) + ++#define MAX_ATMARP_SIZE (sizeof(struct atmarphdr)-1+2*(ATM_E164_LEN+ \ ++ ATM_ESA_LEN+4)) + -+/*-------------------------------- utilities --------------------------------*/ ++#define ATMARP_RETRY_DELAY 30 /* request next resolution or forget ++ NAK after 30 sec - should go into ++ atmclip.h */ + + -+static void zpokel(struct zatm_dev *zatm_dev,unsigned long value, -+ unsigned long addr) -+{ -+ zwait; -+ zout(value,CER); -+ zout(uPD98401_IND_ACC | uPD98401_IA_BALL | -+ (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); -+} ++#define ATMARPD_CTRL _IO('a',ATMIOC_CLIP+1) /* become atmarpd ctrl sock */ ++#define ATMARP_MKIP _IO('a',ATMIOC_CLIP+2) /* attach socket to IP */ ++#define ATMARP_SETENTRY _IO('a',ATMIOC_CLIP+3) /* fill or hide ARP entry */ ++#define ATMARP_ENCAP _IO('a',ATMIOC_CLIP+5) /* change encapsulation */ + ++/* ++ * ATMARP ioctl request. Mimics the structure of struct arpreq in ++ * include/linux/if_arp.h ++ */ + -+static unsigned long zpeekl(struct zatm_dev *zatm_dev,unsigned long addr) -+{ -+ zwait; -+ zout(uPD98401_IND_ACC | uPD98401_IA_BALL | uPD98401_IA_RW | -+ (uPD98401_IA_TGT_CM << uPD98401_IA_TGT_SHIFT) | addr,CMR); -+ zwait; -+ return zin(CER); -+} ++struct atmarpreq { ++ struct sockaddr arp_pa; /* protocol address */ ++ struct sockaddr dummy; /* hw addr in struct arpreq */ ++ int arp_flags; /* flags */ ++ struct sockaddr arp_netmask; /* netmask */ ++ char arp_dev[16]; /* device name */ ++ struct sockaddr_atmsvc arp_ha; /* PVC or SVC address */ ++ struct atm_qos arp_qos; /* requested QOS */ ++}; + + -+/*------------------------------- free lists --------------------------------*/ ++struct atmarp_arpsioc { ++ struct sockaddr pa; /* protocol address */ ++ int aa_len; /* size of ATM address */ ++ struct sockaddr_atmsvc aa; /* SVC address */ ++}; + + -+#define HEAD_SIZE (3*sizeof(void *)) ++#define ATMARP_CTRL_MAGIC 0xac /* put this into the magic byte */ + ++enum atmarp_ctrl_type { ++ act_invalid, /* catch uninitialized structures */ ++ act_need, /* need address resolution */ ++ act_create, /* interface has been created */ ++ act_up, /* interface is coming up */ ++ act_down, /* interface is going down */ ++ act_ioctl, /* ioctl follows */ ++ act_complete /* demon indicates completion */ ++}; + -+static void refill_pool(struct atm_dev *dev,int pool) -+{ -+ struct zatm_dev *zatm_dev; -+ struct sk_buff *skb,*first; -+ unsigned long flags; -+ int align,offset,free,count,size; ++struct atmarp_ctrl { ++ unsigned char magic; /* constant */ ++ enum atmarp_ctrl_type type; /* message type */ ++ volatile int *reply; /* reply address, NULL is asynch */ ++ int itf_num;/* interface number (if present) */ ++ unsigned long arg; /* argument, e.g. IP address */ ++ unsigned char data[1];/* optional data */ ++}; + -+ EVENT("refill_pool\n",0,0); -+ zatm_dev = ZATM_DEV(dev); -+ size = (64 << (pool <= ZATM_AAL5_POOL_BASE ? 0 : -+ pool-ZATM_AAL5_POOL_BASE))+HEAD_SIZE; -+ if (size < PAGE_SIZE) { -+ align = 32; /* for 32 byte alignment */ -+ offset = HEAD_SIZE; -+ } -+ else { -+ align = 4096; -+ offset = zatm_dev->pool_info[pool].offset+HEAD_SIZE; -+ } -+ size += align; -+ save_flags(flags); -+ cli(); -+ free = zpeekl(zatm_dev,zatm_dev->pool_base+2*pool) & -+ uPD98401_RXFP_REMAIN; -+ restore_flags(flags); -+ if (free >= zatm_dev->pool_info[pool].low_water) return; -+ EVENT("starting ... POOL: 0x%08lx, 0x%08lx\n", -+ zpeekl(zatm_dev,zatm_dev->pool_base+2*pool), -+ zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1)); -+ EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); -+ count = 0; -+ first = NULL; -+ while (free < zatm_dev->pool_info[pool].high_water) { -+ skb = alloc_skb(size,GFP_ATOMIC); -+ if (!skb) { -+ printk(KERN_WARNING DEV_LABEL "(Itf %d): got no new " -+ "skb (%d) with %d free\n",dev->number,size,free); -+ break; -+ } -+ if (!first) first = skb; -+ count++; -+ /* -+ * 2nd skb head structure: -+ * [0] pointer to buffer (for SAR) -+ * [1] buffer descr link pointer (for SAR) -+ * [2] back pointer to skb (for poll_rx) -+ * [3] data -+ * ... -+ */ -+ skb->free = 1; -+ skb_reserve(skb,(unsigned char *) ((((unsigned long) skb->data+ -+ align+offset-1) & ~(align-1))-offset)-skb->data); -+ ((void **) skb->data)[0] = skb->data+HEAD_SIZE; -+ ((void **) skb->data)[1] = NULL; -+ ((void **) skb->data)[2] = skb; -+ EVENT("enq skb 0x%08lx/0x%08lx\n",(unsigned long) skb, -+ (unsigned long) skb->data); -+ cli(); -+ if (zatm_dev->last_free[pool]) -+ ((void **) zatm_dev->last_free[pool]->data)[-2] = -+ skb->data; -+ zatm_dev->last_free[pool] = skb; -+ skb->data += HEAD_SIZE; -+ skb_queue_tail(&zatm_dev->pool[pool],skb); -+ restore_flags(flags); -+ free++; -+ } -+ if (first) { -+ cli(); -+ zwait; -+ zout((unsigned long) first->data-HEAD_SIZE,CER); -+ zout(uPD98401_ADD_BAT | (pool << uPD98401_POOL_SHIFT) | count, -+ CMR); -+ restore_flags(flags); -+ EVENT ("POOL: 0x%08lx, 0x%08lx\n", -+ zpeekl(zatm_dev,zatm_dev->pool_base+2*pool), -+ zpeekl(zatm_dev,zatm_dev->pool_base+2*pool+1)); -+ EVENT("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); -+ } -+} ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmclip.h Fri May 16 12:58:34 1997 +@@ -0,0 +1,21 @@ ++/* atmclip.h - Classical IP over ATM */ ++ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++ + ++#ifndef LINUX_ATMCLIP_H ++#define LINUX_ATMCLIP_H + -+static void drain_free(struct atm_dev *dev,int pool) -+{ -+ struct sk_buff *skb; ++#include ++#include + -+ while ((skb = skb_dequeue(&ZATM_DEV(dev)->pool[pool]))) -+ kfree_skb(skb,FREE_READ); -+} + ++#define RFC1483LLC_LEN 8 /* LLC+OUI+PID = 8 */ ++#define RFC1626_MTU 9180 /* RFC1626 default MTU */ + -+static int pool_index(int max_pdu) -+{ -+ int i; ++#define CLIP_DEFAULT_IDLETIMER 1200 /* 20 minutes, see RFC1755 */ ++#define CLIP_CHECK_INTERVAL 10 /* check every ten seconds */ + -+ if (max_pdu % ATM_CELL_PAYLOAD) -+ printk(KERN_ERR DEV_LABEL ": driver error in pool_index: " -+ "max_pdu is %d\n",max_pdu); -+ if (max_pdu > 65536) return -1; -+ for (i = 0; (64 << i) < max_pdu; i++); -+ return i+ZATM_AAL5_POOL_BASE; -+} ++#define SIOCMKCLIP _IO('a',ATMIOC_CLIP) /* create IP interface */ + ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmdev.h Wed Jul 2 11:31:31 1997 +@@ -0,0 +1,259 @@ ++/* atmdev.h - ATM device driver declarations */ ++ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++ + -+/* use_pool isn't reentrant */ ++#ifndef LINUX_ATMDEV_H ++#define LINUX_ATMDEV_H + + -+static void use_pool(struct atm_dev *dev,int pool) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned long flags; -+ int size; ++#include ++#include ++#include ++#include + -+ zatm_dev = ZATM_DEV(dev); -+ if (!(zatm_dev->pool_info[pool].ref_count++)) { -+ skb_queue_head_init(&zatm_dev->pool[pool]); -+ size = pool-ZATM_AAL5_POOL_BASE; -+ if (size < 0) size = 0; /* 64B... */ -+ else if (size > 10) size = 10; /* ... 64kB */ -+ save_flags(flags); -+ cli(); -+ zpokel(zatm_dev,((zatm_dev->pool_info[pool].low_water/4) << -+ uPD98401_RXFP_ALERT_SHIFT) | -+ (1 << uPD98401_RXFP_BTSZ_SHIFT) | -+ (size << uPD98401_RXFP_BFSZ_SHIFT), -+ zatm_dev->pool_base+pool*2); -+ zpokel(zatm_dev,(unsigned long) dummy,zatm_dev->pool_base+ -+ pool*2+1); -+ restore_flags(flags); -+ zatm_dev->last_free[pool] = NULL; -+ refill_pool(dev,pool); -+ } -+ DPRINTK("pool %d: %d\n",pool,zatm_dev->pool_info[pool].ref_count); -+} + ++#define ESI_LEN 6 + -+static void unuse_pool(struct atm_dev *dev,int pool) -+{ -+ if (!(--ZATM_DEV(dev)->pool_info[pool].ref_count)) -+ drain_free(dev,pool); -+} ++#define ATM_OC3_PCR (155520000/270*260/8/53) ++ /* OC3 link rate: 155520000 bps ++ SONET overhead: /270*260 (9 section, 1 path) ++ bits per cell: /8/53 ++ max cell rate: 353207.547 cells/sec */ + ++#define ATM_SD(s) ((struct atm_vcc *) ((s)->sk)) + -+static void zatm_feedback(struct atm_vcc *vcc,struct sk_buff *skb, -+ unsigned long start,unsigned long dest,int len) -+{ -+ struct zatm_pool_info *pool; -+ unsigned long offset,flags; + -+ DPRINTK("start 0x%08lx dest 0x%08lx len %d\n",start,dest,len); -+ if (len < PAGE_SIZE) return; -+ pool = &ZATM_DEV(vcc->dev)->pool_info[ZATM_VCC(vcc)->pool]; -+ offset = (dest-start) & (PAGE_SIZE-1); -+ save_flags(flags); -+ cli(); -+ if (!offset || pool->offset == offset) { -+ pool->next_cnt = 0; -+ return; -+ } -+ if (offset != pool->next_off) { -+ pool->next_off = offset; -+ pool->next_cnt = 0; -+ return; -+ } -+ if (++pool->next_cnt >= pool->next_thres) { -+ pool->offset = pool->next_off; -+ pool->next_cnt = 0; -+ } -+ restore_flags(flags); -+} ++struct atm_aal_stats { ++ long tx,tx_err; /* TX okay and errors */ ++ long rx,rx_err; /* RX okay and errors */ ++ long rx_drop; /* RX out of memory */ ++}; ++ ++ ++struct atm_dev_stats { ++ struct atm_aal_stats aal0; ++ struct atm_aal_stats aal34; ++ struct atm_aal_stats aal5; ++}; ++ + ++#define ATM_GETNAMES _IOW('a',ATMIOC_ITF+3,struct atm_iobuf) ++ /* get interface names (numbers) */ ++#define ATM_GETTYPE _IOW('a',ATMIOC_ITF+4,struct atmif_sioc) ++ /* get interface type name */ ++#define ATM_GETESI _IOW('a',ATMIOC_ITF+5,struct atmif_sioc) ++ /* get interface ESI */ ++#define ATM_GETADDR _IOW('a',ATMIOC_ITF+6,struct atmif_sioc) ++ /* get itf's local ATM addr. list */ ++#define ATM_RSTADDR _IOW('a',ATMIOC_ITF+7,struct atmif_sioc) ++ /* reset itf's ATM address list */ ++#define ATM_ADDADDR _IOW('a',ATMIOC_ITF+8,struct atmif_sioc) ++ /* add a local ATM address */ ++#define ATM_DELADDR _IOW('a',ATMIOC_ITF+9,struct atmif_sioc) ++ /* remove a local ATM address */ ++#define ATM_GETCIRANGE _IOW('a',ATMIOC_ITF+10,struct atmif_sioc) ++ /* get connection identifier range */ ++#define ATM_SETCIRANGE _IOW('a',ATMIOC_ITF+11,struct atmif_sioc) ++ /* set connection identifier range */ ++#define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) ++ /* get AAL layer statistics */ ++#define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) ++ /* get AAL layer statistics and zero */ ++#define ATM_SETSC _IOW('a',ATMIOC_SPECIAL+1,int) ++ /* enable or disable single-copy */ + -+/*----------------------- high-precision timestamps -------------------------*/ ++/* for ATM_GETTYPE */ ++#define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */ + + -+#ifdef CONFIG_ATM_ZATM_EXACT_TS + -+static struct timer_list sync_timer = { NULL, NULL, 0L, 0L, NULL }; ++struct atm_iobuf { ++ int length; ++ void *buffer; ++}; + ++/* for ATM_GETCIRANGE / ATM_SETCIRANGE */ + -+/* -+ * Note: the exact time is not normalized, i.e. tv_usec can be > 1000000. -+ * This must be handled by higher layers. -+ */ ++#define ATM_CI_MAX -1 /* use maximum range of VPI/VCI */ ++ ++struct atm_cirange { ++ char vpi_bits; /* 1..8, ATM_CI_MAX (-1) for maximum */ ++ char vci_bits; /* 1..16, ATM_CI_MAX (-1) for maximum */ ++}; + -+static inline struct timeval exact_time(struct zatm_dev *zatm_dev,u32 ticks) -+{ -+ struct timeval tmp; ++/* for ATM_SETSC; actually taken from the ATM_VF number space */ + -+ tmp = zatm_dev->last_time; -+ tmp.tv_usec += ((s64) (ticks-zatm_dev->last_clk)* -+ (s64) zatm_dev->factor) >> TIMER_SHIFT; -+ return tmp; -+} ++#define ATM_SC_RX 1024 /* enable RX single-copy */ ++#define ATM_SC_TX 2048 /* enable TX single-copy */ + ++#define ATM_BACKLOG_DEFAULT 32 /* if we get more, we're likely to time out ++ anyway */ + -+static void zatm_clock_sync(unsigned long dummy) -+{ -+ struct atm_dev *atm_dev; -+ struct zatm_dev *zatm_dev; ++#ifdef __KERNEL__ + -+ for (atm_dev = zatm_boards; atm_dev; atm_dev = zatm_dev->more) { -+ unsigned long flags,interval; -+ int diff; -+ struct timeval now,expected; -+ u32 ticks; ++#include /* struct wait_queue */ ++#include /* struct timeval */ ++#include ++#include /* struct sk_buff */ ++#include + -+ zatm_dev = ZATM_DEV(atm_dev); -+ save_flags(flags); -+ cli(); -+ ticks = zpeekl(zatm_dev,uPD98401_TSR); -+ do_gettimeofday(&now); -+ restore_flags(flags); -+ expected = exact_time(zatm_dev,ticks); -+ diff = 1000000*(expected.tv_sec-now.tv_sec)+ -+ (expected.tv_usec-now.tv_usec); -+ zatm_dev->timer_history[zatm_dev->th_curr].real = now; -+ zatm_dev->timer_history[zatm_dev->th_curr].expected = expected; -+ zatm_dev->th_curr = (zatm_dev->th_curr+1) & -+ (ZATM_TIMER_HISTORY_SIZE-1); -+ interval = 1000000*(now.tv_sec-zatm_dev->last_real_time.tv_sec) -+ +(now.tv_usec-zatm_dev->last_real_time.tv_usec); -+ if (diff >= -ADJ_REP_THRES && diff <= ADJ_REP_THRES) -+ zatm_dev->timer_diffs = 0; -+ else -+#ifndef AGGRESSIVE_DEBUGGING -+ if (++zatm_dev->timer_diffs >= ADJ_MSG_THRES) -+#endif -+ { -+ zatm_dev->timer_diffs = 0; -+ printk(KERN_INFO DEV_LABEL ": TSR update after %ld us:" -+ " calculation differed by %d us\n",interval,diff); -+#ifdef AGGRESSIVE_DEBUGGING -+ printk(KERN_DEBUG " %d.%08d -> %d.%08d (%lu)\n", -+ zatm_dev->last_real_time.tv_sec, -+ zatm_dev->last_real_time.tv_usec, -+ now.tv_sec,now.tv_usec,interval); -+ printk(KERN_DEBUG " %u -> %u (%d)\n", -+ zatm_dev->last_clk,ticks,ticks-zatm_dev->last_clk); -+ printk(KERN_DEBUG " factor %u\n",zatm_dev->factor); -+#endif -+ } -+ if (diff < -ADJ_IGN_THRES || diff > ADJ_IGN_THRES) { -+ /* filter out any major changes (e.g. time zone setup and -+ such) */ -+ zatm_dev->last_time = now; -+ zatm_dev->factor = -+ (1000 << TIMER_SHIFT)/(zatm_dev->khz+1); -+ } -+ else { -+ zatm_dev->last_time = expected; -+ /* -+ * Is the accuracy of udelay really only about 1:300 on -+ * a 90 MHz Pentium ? Well, the following line avoids -+ * the problem, but ... -+ * -+ * What it does is simply: -+ * -+ * zatm_dev->factor = (interval << TIMER_SHIFT)/ -+ * (ticks-zatm_dev->last_clk); -+ */ -+#define S(x) #x /* "stringification" ... */ -+#define SX(x) S(x) -+ asm("movl %2,%%ebx\n\t" -+ "subl %3,%%ebx\n\t" -+ "xorl %%edx,%%edx\n\t" -+ "shldl $" SX(TIMER_SHIFT) ",%1,%%edx\n\t" -+ "shl $" SX(TIMER_SHIFT) ",%1\n\t" -+ "divl %%ebx\n\t" -+ : "=eax" (zatm_dev->factor) -+ : "eax" (interval-diff),"g" (ticks), -+ "g" (zatm_dev->last_clk) -+ : "ebx","edx","cc"); -+#undef S -+#undef SX -+#ifdef AGGRESSIVE_DEBUGGING -+ printk(KERN_DEBUG " (%ld << %d)/(%u-%u) = %u\n", -+ interval,TIMER_SHIFT,ticks,zatm_dev->last_clk, -+ zatm_dev->factor); ++#ifdef CONFIG_AREQUIPA ++#include /* for struct sock */ +#endif -+ } -+ zatm_dev->last_real_time = now; -+ zatm_dev->last_clk = ticks; -+ } -+ del_timer(&sync_timer); -+ sync_timer.expires += POLL_INTERVAL*HZ; -+ add_timer(&sync_timer); -+} + + -+static void zatm_clock_init(struct zatm_dev *zatm_dev) -+{ -+ static int start_timer = 1; -+ unsigned long flags; ++#define ATM_VF_ADDR 1 /* Address is in use. Set by anybody, cleared ++ by device driver. */ ++#define ATM_VF_READY 2 /* VC is ready to transfer data. Set by device ++ driver, cleared by anybody. */ ++#define ATM_VF_PARTIAL 4 /* resources are bound to PVC (partial PVC ++ setup), controlled by socket layer */ ++#define ATM_VF_BOUND 4 /* local SAP is set, controlled by SVC socket ++ layer */ ++#define ATM_VF_REGIS 8 /* registered with demon, controlled by SVC ++ socket layer */ ++#define ATM_VF_RELEASED 16 /* demon has indicated/requested release, ++ controlled by SVC socket layer */ ++#define ATM_VF_HASQOS 32 /* QOS parameters have been set */ ++#define ATM_VF_LISTEN 64 /* socket is used for listening */ ++#define ATM_VF_META 128 /* SVC socket isn't used for normal data ++ traffic and doesn't depend on signaling ++ to be available */ ++#define ATM_VF_AQREL 256 /* Arequipa VC is being released */ ++#define ATM_VF_AQDANG 512 /* VC is in Arequipa's dangling list */ ++#define ATM_VF_SCRX ATM_SC_RX /* 1024; allow single-copy in the RX dir. */ ++#define ATM_VF_SCTX ATM_SC_TX /* 2048; allow single-copy in the TX dir. */ + -+ zatm_dev->factor = (1000 << TIMER_SHIFT)/(zatm_dev->khz+1); -+ zatm_dev->timer_diffs = 0; -+ memset(zatm_dev->timer_history,0,sizeof(zatm_dev->timer_history)); -+ zatm_dev->th_curr = 0; -+ save_flags(flags); -+ cli(); -+ do_gettimeofday(&zatm_dev->last_time); -+ zatm_dev->last_clk = zpeekl(zatm_dev,uPD98401_TSR); -+ if (start_timer) { -+ start_timer = 0; -+ sync_timer.expires = jiffies+POLL_INTERVAL*HZ; -+ sync_timer.function = zatm_clock_sync; -+ add_timer(&sync_timer); -+ } -+ restore_flags(flags); -+} ++#define ATM_DF_CLOSE 1 /* close device when last VCC is closed */ + + ++struct atm_vcc { ++ unsigned short flags; /* VCC flags (ATM_VF_*) */ ++ unsigned char family; /* address family; 0 if unused */ ++ short vpi; /* VPI and VCI (types must be equal */ ++ /* with sockaddr) */ ++ int vci; ++ unsigned long aal_options; /* AAL layer options */ ++ unsigned long atm_options; /* ATM layer options */ ++ struct atm_dev *dev; /* device back pointer */ ++ struct atm_qos qos; /* QOS */ ++ unsigned long tx_quota,rx_quota; /* buffer quotas */ ++ atomic_t tx_inuse,rx_inuse; /* buffer space in use */ ++ void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); ++ void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ ++ struct sk_buff *(*peek)(struct atm_vcc *vcc,unsigned long pdu_size, ++ __u32 (*fetch)(struct atm_vcc *vcc,int i)); ++ /* super-efficient xfers; note that */ ++ /* PDU_SIZE may be rounded */ ++ struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size); ++ /* TX allocation routine - can be */ ++ /* modified by protocol or by driver.*/ ++ /* NOTE: this interface will change */ ++ int (*push_oam)(struct atm_vcc *vcc,void *cell); ++ void *dev_data; /* per-device data */ ++ void *proto_data; /* per-protocol data */ ++ struct timeval timestamp; /* AAL timestamps */ ++ struct sk_buff_head recvq; /* receive queue */ ++ struct atm_aal_stats *stats; /* pointer to AAL stats group */ ++ struct wait_queue *sleep; /* if socket is busy */ ++ struct wait_queue *wsleep; /* if waiting for write buffer space */ ++ struct atm_vcc *prev,*next; ++ /* SVC part --- may move later */ ++ short itf; /* interface number */ ++ struct sockaddr_atmsvc local; ++ struct sockaddr_atmsvc remote; ++ void (*callback)(struct atm_vcc *vcc); ++ struct sk_buff_head listenq; ++ int backlog_quota; /* number of connection requests we */ ++ /* can still accept */ ++ int reply; ++ void *user_back; /* user backlink - not touched */ ++#ifdef CONFIG_ATM_CLIP ++ struct device *ip_dev; /* IP source device */ ++ struct atm_vcc *more; ++#endif ++#ifdef CONFIG_AREQUIPA ++ struct sock *upper; /* our "master" */ ++ struct socket *sock; /* back pointer to our own socket */ ++ struct atm_vcc *aq_next,*aq_prev; /* for consistency checks */ ++ unsigned long generation; /* generation number */ +#endif ++}; + + -+/*----------------------------------- RX ------------------------------------*/ ++struct atm_dev_addr { ++ struct sockaddr_atmsvc addr; /* ATM address */ ++ struct atm_dev_addr *next; /* next address */ ++}; + + -+#if 0 -+static void exception(struct atm_vcc *vcc) -+{ -+ static int count = 0; -+ struct zatm_dev *zatm_dev = ZATM_DEV(vcc->dev); -+ struct zatm_vcc *zatm_vcc = ZATM_VCC(vcc); -+ unsigned long *qrp; -+ int i; -+ -+ if (count++ > 2) return; -+ for (i = 0; i < 8; i++) -+ printk("TX%d: 0x%08lx\n",i, -+ zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+i)); -+ for (i = 0; i < 5; i++) -+ printk("SH%d: 0x%08lx\n",i, -+ zpeekl(zatm_dev,uPD98401_IM(zatm_vcc->shaper)+16*i)); -+ qrp = (unsigned long *) zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+ -+ uPD98401_TXVC_QRP); -+ printk("qrp=0x%08lx\n",(unsigned long) qrp); -+ for (i = 0; i < 4; i++) printk("QRP[%d]: 0x%08lx",i,qrp[i]); -+} ++struct atm_dev { ++ const struct atmdev_ops *ops; /* device operations; NULL if unused */ ++ const struct atmphy_ops *phy; /* PHY operations, may be undefined */ ++ /* (NULL) */ ++ const char *type; /* device type name */ ++ int number; /* device index */ ++ struct atm_vcc *vccs; /* VCC table (or NULL) */ ++ struct atm_vcc *last; /* last VCC (or undefined) */ ++ void *dev_data; /* per-device data */ ++ void *phy_data; /* private PHY date */ ++ unsigned long flags; /* device flags, TBD */ ++ struct atm_dev_addr *local; /* local ATM addresses */ ++ unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ ++ struct atm_cirange ci_range; /* VPI/VCI range */ ++ struct atm_dev_stats stats; /* statistics */ ++ struct atm_dev *prev,*next; /* linkage */ ++}; ++ ++ ++/* ++ * ioctl, getsockopt, setsockopt, and sg_send are optional and can be set to ++ * NULL. */ ++ ++#define ATM_OF_IMMED 1 /* Attempt immediate delivery */ ++#define ATM_OF_INRATE 2 /* Attempt in-rate delivery */ ++ ++struct atmdev_ops { /* only send is required */ ++ void (*dev_close)(struct atm_dev *dev); ++ int (*open)(struct atm_vcc *vcc,short vpi,int vci); ++ void (*close)(struct atm_vcc *vcc); ++ int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg); ++ int (*getsockopt)(struct atm_vcc *vcc,int level,int optname, ++ void *optval,int optlen); ++ int (*setsockopt)(struct atm_vcc *vcc,int level,int optname, ++ void *optval,int optlen); ++ int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); ++ int (*sg_send)(struct atm_vcc *vcc,unsigned long start, ++ unsigned long size); ++#if 0 /* keep the current hack for now */ ++ int (*send_iovec)(struct atm_vcc *vcc,struct iovec *iov,int size, ++ void (*discard)(struct atm_vcc *vcc,void *user),void *user); +#endif ++ int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags); ++ void (*phy_put)(struct atm_dev *dev,unsigned char value, ++ unsigned long addr); ++ unsigned char (*phy_get)(struct atm_dev *dev,unsigned long addr); ++ void (*feedback)(struct atm_vcc *vcc,struct sk_buff *skb, ++ unsigned long start,unsigned long dest,int len); ++ int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos); ++ void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb); ++ /* @@@ temporary hack */ ++}; + + -+static const char *err_txt[] = { -+ "No error", -+ "RX buf underflow", -+ "RX FIFO overrun", -+ "Maximum len violation", -+ "CRC error", -+ "User abort", -+ "Length violation", -+ "T1 error", -+ "Deactivated", -+ "???", -+ "???", -+ "???", -+ "???", -+ "???", -+ "???", -+ "???" ++struct atmphy_ops { ++ int (*start)(struct atm_dev *dev); ++ int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg); ++ void (*interrupt)(struct atm_dev *dev); +}; + + -+static void poll_rx(struct atm_dev *dev,int mbx) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned long pos,x; -+ int error; ++struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, ++ unsigned long flags); ++void atm_dev_deregister(struct atm_dev *dev); ++int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci); ++ ++#endif /* __KERNEL__ */ + -+ EVENT("poll_rx\n",0,0); -+ zatm_dev = ZATM_DEV(dev); -+ pos = (zatm_dev->mbx_start[mbx] & ~0xffff) | zin(MTA(mbx)); -+ while (x = zin(MWA(mbx)), (pos & 0xffff) != x) { -+ unsigned long *here; -+ struct sk_buff *skb; -+ struct atm_vcc *vcc; -+ int cells,size,chan; -+ -+ EVENT("MBX: host 0x%lx, nic 0x%lx\n",pos,x); -+ here = (unsigned long *) pos; -+ if (((pos += 16) & 0xffff) == zatm_dev->mbx_end[mbx]) -+ pos = zatm_dev->mbx_start[mbx]; -+ cells = here[0] & uPD98401_AAL5_SIZE; -+#if 0 -+{ -+unsigned long *x; -+printk("RX IND: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",here[0],here[1],here[2], -+ here[3]); -+ printk("POOL: 0x%08lx, 0x%08lx\n",zpeekl(zatm_dev, -+ zatm_dev->pool_base), -+ zpeekl(zatm_dev,zatm_dev->pool_base+1)); -+ x = (unsigned long *) here[2]; -+ printk("[0..3] = 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n", -+ x[0],x[1],x[2],x[3]); -+} +#endif -+ error = 0; -+ if (here[3] & uPD98401_AAL5_ERR) { -+ error = (here[3] & uPD98401_AAL5_ES) >> -+ uPD98401_AAL5_ES_SHIFT; -+ if (error == uPD98401_AAL5_ES_DEACT || -+ error == uPD98401_AAL5_ES_FREE) continue; -+ } -+EVENT("error code 0x%x/0x%x\n",(here[3] & uPD98401_AAL5_ES) >> -+ uPD98401_AAL5_ES_SHIFT,error); -+ skb = (struct sk_buff *) ((void **) here[2])[2]; -+#ifdef CONFIG_ATM_ZATM_EXACT_TS -+ skb->atm.timestamp = exact_time(zatm_dev,here[1]); -+#else -+ skb->atm.timestamp = xtime; -+#endif -+#if 0 -+printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3], -+ ((unsigned *) skb->data)[-2],((unsigned *) skb->data)[-1], -+ ((unsigned *) skb->data)[0]); -+#endif -+ EVENT("skb 0x%08lx, here 0x%08lx\n",(unsigned long) skb, -+ (unsigned long) here); -+#if 0 -+printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]); -+#endif -+ size = error ? 0 : ntohs(((unsigned short *) skb->data)[cells* -+ ATM_CELL_PAYLOAD/sizeof(unsigned short)-3]); -+ EVENT("got skb 0x%p, size %d\n",skb,size); -+ chan = (here[3] & uPD98401_AAL5_CHAN) >> -+ uPD98401_AAL5_CHAN_SHIFT; -+ if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) { -+ vcc = zatm_dev->rx_map[chan]; -+ if (skb == zatm_dev->last_free[ZATM_VCC(vcc)->pool]) -+ zatm_dev->last_free[ZATM_VCC(vcc)->pool] = NULL; -+ skb_unlink(skb); -+ } -+ else { -+ printk(KERN_ERR DEV_LABEL "(itf %d): RX indication " -+ "for non-existing channel\n",dev->number); -+ size = 0; -+ vcc = NULL; -+ event_dump(); -+ } -+ if (error) { -+ static unsigned long silence = 0; -+ static int last_error = 0; +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmioc.h Wed May 14 16:07:56 1997 +@@ -0,0 +1,32 @@ ++/* atmioc.h - ranges for ATM-related ioctl numbers */ ++ ++/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ ++ + -+ if (error != last_error || jiffies > silence) { -+ 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; -+ } -+ size = 0; -+ } -+ if (size && (size > cells*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER || -+ size <= (cells-1)*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER)) { -+ printk(KERN_ERR DEV_LABEL "(itf %d): size %d with %d " -+ "cells\n",dev->number,size,cells); -+ size = 0; -+ event_dump(); -+ } -+ if (size > ATM_MAX_AAL5_PDU) { -+ printk(KERN_ERR DEV_LABEL "(itf %d): size too big " -+ "(%d)\n",dev->number,size); -+ size = 0; -+ event_dump(); -+ } -+ if (!size) { -+ kfree_skb(skb,FREE_READ); -+ if (vcc) vcc->stats->rx_err++; -+ } -+ else { -+ skb->len = size; -+ skb->atm.vcc = vcc; -+ vcc->push(skb->atm.vcc,skb); -+ vcc->stats->rx++; -+ } -+#if 0 -+if (vcc && size == 2) exception(vcc); -+#endif -+ } -+ zout(pos & 0xffff,MTA(mbx)); -+#if 0 /* probably a stupid idea */ -+ refill_pool(dev,zatm_vcc->pool); -+ /* maybe this saves us a few interrupts */ -+#endif -+} ++#ifndef _LINUX_ATMIOC_H ++#define _LINUX_ATMIOC_H + ++#include ++ /* everybody including atmioc.h will also need _IO{,R,W,WR} */ + -+static int open_rx_first(struct atm_vcc *vcc) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ unsigned long flags; -+ unsigned short chan; -+ int cells; ++#define ATMIOC_PHYCOM 0x00 /* PHY device common ioctls, globally unique */ ++#define ATMIOC_PHYCOM_END 0x0f ++#define ATMIOC_PHYTYP 0x10 /* PHY dev type ioctls, unique per PHY type */ ++#define ATMIOC_PHYTYP_END 0x2f ++#define ATMIOC_PHYPRV 0x30 /* PHY dev private ioctls, unique per driver */ ++#define ATMIOC_PHYPRV_END 0x4f ++#define ATMIOC_SARCOM 0x50 /* SAR device common ioctls, globally unique */ ++#define ATMIOC_SARCOM_END 0x50 ++#define ATMIOC_SARPRV 0x60 /* SAR dev private ioctls, unique per driver */ ++#define ATMIOC_SARPRV_END 0x7f ++#define ATMIOC_ITF 0x80 /* Interface ioctls, globally unique */ ++#define ATMIOC_ITF_END 0x8f ++/* 0x90-0xbf: Reserved for future use */ ++#define ATMIOC_AREQUIPA 0xc0 /* Application requested IP over ATM, glob. u. */ ++#define ATMIOC_LANE 0xd0 /* LAN Emulation, globally unique */ ++#define ATMIOC_CLIP 0xe0 /* Classical IP over ATM control, globally u. */ ++#define ATMIOC_CLIP_END 0xef ++#define ATMIOC_SPECIAL 0xf0 /* Special-purpose controls, globally unique */ ++#define ATMIOC_SPECIAL_END 0xff + -+ DPRINTK("open_rx_first (0x%x)\n",inb_p(0xc053)); -+ zatm_dev = ZATM_DEV(vcc->dev); -+ zatm_vcc = ZATM_VCC(vcc); -+ zatm_vcc->rx_chan = 0; -+ if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; -+ if (vcc->aal == ATM_AAL5) { -+ if (vcc->qos.rxtp.max_sdu > 65464) -+ vcc->qos.rxtp.max_sdu = 65464; -+ /* fix this - we may want to receive 64kB SDUs -+ later */ -+ cells = (vcc->qos.rxtp.max_sdu+ATM_AAL5_TRAILER+ -+ ATM_CELL_PAYLOAD-1)/ATM_CELL_PAYLOAD; -+ zatm_vcc->pool = pool_index(cells*ATM_CELL_PAYLOAD); -+ } -+ else { -+ cells = 1; -+ zatm_vcc->pool = ZATM_AAL0_POOL; -+ } -+ if (zatm_vcc->pool < 0) return -EMSGSIZE; -+ save_flags(flags); -+ cli(); -+ zwait; -+ zout(uPD98401_OPEN_CHAN,CMR); -+ zwait; -+ DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); -+ chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; -+ restore_flags(flags); -+ DPRINTK("chan is %d\n",chan); -+ if (!chan) return -EAGAIN; -+ use_pool(vcc->dev,zatm_vcc->pool); -+ DPRINTK("pool %d\n",zatm_vcc->pool); -+ /* set up VC descriptor */ -+ cli(); -+ zpokel(zatm_dev,zatm_vcc->pool << uPD98401_RXVC_POOL_SHIFT, -+ chan*VC_SIZE/4); -+ zpokel(zatm_dev,uPD98401_RXVC_OD | (vcc->aal == ATM_AAL5 ? -+ uPD98401_RXVC_AR : 0) | cells,chan*VC_SIZE/4+1); -+ zpokel(zatm_dev,0,chan*VC_SIZE/4+2); -+ zatm_vcc->rx_chan = chan; -+ zatm_dev->rx_map[chan] = vcc; -+ restore_flags(flags); -+ return 0; -+} ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmsap.h Wed May 14 16:07:56 1997 +@@ -0,0 +1,124 @@ ++/* atmsap.h - ATM Service Access Point addressing definitions */ + ++/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ + -+static int open_rx_second(struct atm_vcc *vcc) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ unsigned long flags; -+ int pos,shift; + -+ DPRINTK("open_rx_second (0x%x)\n",inb_p(0xc053)); -+ zatm_dev = ZATM_DEV(vcc->dev); -+ zatm_vcc = ZATM_VCC(vcc); -+ if (!zatm_vcc->rx_chan) return 0; -+ save_flags(flags); -+ cli(); -+ /* should also handle VPI @@@ */ -+ pos = vcc->vci >> 1; -+ shift = (1-(vcc->vci & 1)) << 4; -+ zpokel(zatm_dev,(zpeekl(zatm_dev,pos) & ~(0xffff << shift)) | -+ ((zatm_vcc->rx_chan | uPD98401_RXLT_ENBL) << shift),pos); -+ restore_flags(flags); -+ return 0; -+} ++#ifndef _LINUX_ATMSAP_H ++#define _LINUX_ATMSAP_H + ++/* ++ * BEGIN_xx and END_xx markers are used for automatic generation of ++ * documentation. Do not change them. ++ */ + -+static void close_rx(struct atm_vcc *vcc) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ unsigned long flags; -+ int pos,shift; + -+ zatm_vcc = ZATM_VCC(vcc); -+ zatm_dev = ZATM_DEV(vcc->dev); -+ if (!zatm_vcc->rx_chan) return; -+ DPRINTK("close_rx\n"); -+ /* disable receiver */ -+ save_flags(flags); -+ if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) { -+ cli(); -+ pos = vcc->vci >> 1; -+ shift = (1-(vcc->vci & 1)) << 4; -+ zpokel(zatm_dev,zpeekl(zatm_dev,pos) & ~(0xffff << shift),pos); -+ zwait; -+ zout(uPD98401_NOP,CMR); -+ zwait; -+ zout(uPD98401_NOP,CMR); -+ restore_flags(flags); -+ } -+ cli(); -+ zwait; -+ zout(uPD98401_DEACT_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << -+ uPD98401_CHAN_ADDR_SHIFT),CMR); -+ zwait; -+ udelay(10); /* why oh why ... ? */ -+ zout(uPD98401_CLOSE_CHAN | uPD98401_CHAN_RT | (zatm_vcc->rx_chan << -+ uPD98401_CHAN_ADDR_SHIFT),CMR); -+ zwait; -+ if (!(zin(CMR) & uPD98401_CHAN_ADDR)) -+ printk(KERN_CRIT DEV_LABEL "(itf %d): can't close RX channel " -+ "%d\n",vcc->dev->number,zatm_vcc->rx_chan); -+ restore_flags(flags); -+ zatm_dev->rx_map[zatm_vcc->rx_chan] = NULL; -+ zatm_vcc->rx_chan = 0; -+ unuse_pool(vcc->dev,zatm_vcc->pool); -+} ++/* ++ * Layer 2 protocol identifiers ++ */ + ++/* BEGIN_L2 */ ++#define ATM_L2_NONE 0 /* L2 not specified */ ++#define ATM_L2_ISO1745 0x01 /* Basic mode ISO 1745 */ ++#define ATM_L2_Q291 0x02 /* ITU-T Q.291 (Rec. I.441) */ ++#define ATM_L2_X25_LL 0x06 /* ITU-T X.25, link layer */ ++#define ATM_L2_X25_ML 0x07 /* ITU-T X.25, multilink */ ++#define ATM_L2_LAPB 0x08 /* Extended LAPB, half-duplex (Rec. T.71) */ ++#define ATM_L2_HDLC_ARM 0x09 /* HDLC ARM (ISO/IEC 4335) */ ++#define ATM_L2_HDLC_NRM 0x0a /* HDLC NRM (ISO/IEC 4335) */ ++#define ATM_L2_HDLC_ABM 0x0b /* HDLC ABM (ISO/IEC 4335) */ ++#define ATM_L2_ISO8802 0x0c /* LAN LLC (ISO/IEC 8802/2) */ ++#define ATM_L2_X75 0x0d /* ITU-T X.75, SLP */ ++#define ATM_L2_Q922 0x0e /* ITU-T Q.922 */ ++#define ATM_L2_USER 0x10 /* user-specified */ ++#define ATM_L2_ISO7776 0x11 /* ISO 7776 DTE-DTE */ ++/* END_L2 */ + -+static int start_rx(struct atm_dev *dev) -+{ -+ struct zatm_dev *zatm_dev; -+ int size,i; + -+DPRINTK("start_rx\n"); -+ zatm_dev = ZATM_DEV(dev); -+ size = sizeof(struct atm_vcc *)*zatm_dev->chans; -+ zatm_dev->rx_map = (struct atm_vcc **) kmalloc(size,GFP_KERNEL); -+ if (!zatm_dev->rx_map) return -ENOMEM; -+ memset(zatm_dev->rx_map,0,size); -+ /* set VPI/VCI split (use all VCIs and give what's left to VPIs) */ -+ zpokel(zatm_dev,(1 << dev->ci_range.vci_bits)-1,uPD98401_VRR); -+ /* prepare free buffer pools */ -+ for (i = 0; i <= ZATM_LAST_POOL; i++) { -+ zatm_dev->pool_info[i].ref_count = 0; -+ zatm_dev->pool_info[i].rqa_count = 0; -+ zatm_dev->pool_info[i].rqu_count = 0; -+ zatm_dev->pool_info[i].low_water = LOW_MARK; -+ zatm_dev->pool_info[i].high_water = HIGH_MARK; -+ zatm_dev->pool_info[i].offset = 0; -+ zatm_dev->pool_info[i].next_off = 0; -+ zatm_dev->pool_info[i].next_cnt = 0; -+ zatm_dev->pool_info[i].next_thres = OFF_CNG_THRES; -+ } -+ return 0; -+} ++/* ++ * Layer 3 protocol identifiers ++ */ + ++/* BEGIN_L3 */ ++#define ATM_L3_NONE 0 /* L3 not specified */ ++#define ATM_L3_X25 0x06 /* ITU-T X.25, packet layer */ ++#define ATM_L3_ISO8208 0x07 /* ISO/IEC 8208 */ ++#define ATM_L3_X223 0x08 /* ITU-T X.223 | ISO/IEC 8878 */ ++#define ATM_L3_ISO8473 0x09 /* ITU-T X.223 | ISO/IEC 8473 */ ++#define ATM_L3_T70 0x0a /* ITU-T T.70 minimum network layer */ ++#define ATM_L3_TR9577 0x0b /* ISO/IEC TR 9577 */ ++#define ATM_L3_USER 0x10 /* user-specified */ ++/* END_L3 */ + -+/*----------------------------------- TX ------------------------------------*/ + ++/* ++ * High layer identifiers ++ */ + -+static int do_tx(struct sk_buff *skb) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ unsigned long *dsc; -+ unsigned long flags; ++/* BEGIN_HL */ ++#define ATM_HL_NONE 0 /* HL not specified */ ++#define ATM_HL_ISO 0x01 /* ISO */ ++#define ATM_HL_USER 0x02 /* user-specific */ ++#if defined(UNI30) || defined(ALLOW_UNI30) ++#define ATM_HL_HLP 0x03 /* high layer profile - UNI 3.0 only */ ++#endif ++#define ATM_HL_VENDOR 0x04 /* vendor-specific application identifier */ ++/* END_HL */ + -+ EVENT("do_tx\n",0,0); -+ DPRINTK("sending skb %p\n",skb); -+ zatm_dev = ZATM_DEV(skb->atm.vcc->dev); -+ zatm_vcc = ZATM_VCC(skb->atm.vcc); -+ EVENT("iovcnt=%d\n",skb->atm.iovcnt,0); -+ save_flags(flags); -+ cli(); -+ if (!skb->atm.iovcnt) { -+ if (zatm_vcc->txing == RING_ENTRIES-1) { -+ restore_flags(flags); -+ return RING_BUSY; -+ } -+ zatm_vcc->txing++; -+ dsc = zatm_vcc->ring+zatm_vcc->ring_curr; -+ zatm_vcc->ring_curr = (zatm_vcc->ring_curr+RING_WORDS) & -+ (RING_ENTRIES*RING_WORDS-1); -+ dsc[1] = 0; -+ dsc[2] = skb->len; -+ dsc[3] = (unsigned long) skb->data; -+ mb(); -+ dsc[0] = uPD98401_TXPD_V | uPD98401_TXPD_DP | uPD98401_TXPD_SM -+ | (skb->atm.vcc->aal == ATM_AAL5 ? uPD98401_TXPD_AAL5 : 0); -+ EVENT("dsc (0x%08lx)\n",(unsigned long) dsc,0); -+ } -+ else { -+printk("NONONONOO!!!!\n"); -+#if 0 -+ unsigned long *put; -+ int i; + -+ dsc = (unsigned long *) kmalloc(uPD98401_TXPD_SIZE*2+ -+ uPD98401_TXBD_SIZE*skb->atm.iovcnt,GFP_ATOMIC); -+ if (!dsc) { -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EAGAIN; -+ } -+ /* @@@ should check alignment */ -+ put = dsc+8; -+ dsc[0] = uPD98401_TXPD_V | uPD98401_TXPD_DP | -+ (skb->atm.vcc->aal == ATM_AAL5 ? uPD98401_TXPD_AAL5 : 0); -+ dsc[1] = 0; -+ dsc[2] = skb->atm.iovcnt*uPD98401_TXBD_SIZE; -+ dsc[3] = (unsigned long) put; -+ for (i = 0; i < skb->atm.iovcnt; i++) { -+ *put++ = ((struct iovec *) skb->data)[i].iov_len; -+ *put++ = (unsigned long) ((struct iovec *) -+ skb->data)[i].iov_base; -+ } -+ put[-2] |= uPD98401_TXBD_LAST; -+#endif -+ } -+ skb->atm.pos = (unsigned long) dsc; -+ skb_queue_tail(&zatm_vcc->tx_queue,skb); -+ DPRINTK("QRP=0x%08lx\n",zpeekl(zatm_dev,zatm_vcc->tx_chan*VC_SIZE/4+ -+ uPD98401_TXVC_QRP)); -+ zwait; -+ zout(uPD98401_TX_READY | (zatm_vcc->tx_chan << -+ uPD98401_CHAN_ADDR_SHIFT),CMR); -+ restore_flags(flags); -+ EVENT("done\n",0,0); -+ return 0; -+} ++/* ++ * ITU-T coded mode of operation ++ */ ++ ++/* BEGIN_IMD */ ++#define ATM_IMD_NONE 0 /* mode not specified */ ++#define ATM_IMD_NORMAL 1 /* normal mode of operation */ ++#define ATM_IMD_EXTENDED 2 /* extended mode of operation */ ++/* END_IMD */ + + -+static inline void dequeue_tx(struct atm_vcc *vcc) -+{ -+ struct zatm_vcc *zatm_vcc; -+ struct sk_buff *skb; ++/* ++ * SAP structures ++ */ + -+ EVENT("dequeue_tx\n",0,0); -+ zatm_vcc = ZATM_VCC(vcc); -+ skb = skb_dequeue(&zatm_vcc->tx_queue); -+ if (!skb) { -+ printk(KERN_CRIT DEV_LABEL "(itf %d): dequeue_tx but not " -+ "txing\n",vcc->dev->number); -+ return; -+ } -+if (*(unsigned long *) skb->atm.pos != (uPD98401_TXPD_V | uPD98401_TXPD_DP | -+ uPD98401_TXPD_SM | uPD98401_TXPD_AAL5)) printk("@#*$!!!! (%08lx)\n", -+ *(unsigned long *) skb->atm.pos); -+ *(unsigned long *) skb->atm.pos = 0; /* mark as invalid */ -+ zatm_vcc->txing--; -+ if (vcc->pop) vcc->pop(vcc,skb); -+ else dev_kfree_skb(skb,FREE_WRITE); -+ while ((skb = skb_dequeue(&zatm_vcc->backlog))) -+ if (do_tx(skb) == RING_BUSY) { -+ skb_queue_head(&zatm_vcc->backlog,skb); -+ break; -+ } -+ vcc->stats->tx++; -+ wake_up(&zatm_vcc->tx_wait); -+} ++#define ATM_MAX_HLI 7 /* maximum high-layer information length */ + + -+static void poll_tx(struct atm_dev *dev,int mbx) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned long pos,x; ++struct atm_blli { ++ unsigned char l2_proto; /* layer 2 protocol */ ++ union { ++ struct { ++ unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */ ++ /* absent */ ++ unsigned char window; /* window size (k), 1-127 (0 to omit) */ ++ } itu; /* ITU-T encoding */ ++ unsigned char user; /* user-specified l2 information */ ++ } l2; ++ unsigned char l3_proto; /* layer 3 protocol */ ++ union { ++ struct { ++ unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */ ++ /* absent */ ++ unsigned char def_size; /* default packet size (log2), 4-12 (0 to */ ++ /* omit) */ ++ unsigned char window;/* packet window size, 1-127 (0 to omit) */ ++ } itu; /* ITU-T ecoding */ ++ unsigned char user; /* user specified l3 information */ ++ struct { /* if l3_proto = ATM_L3_TR9577 */ ++ unsigned char ipi; /* initial protocol id */ ++ unsigned char snap[5];/* IEEE 802.1 SNAP identifier */ ++ /* (only if ipi == NLPID_IEEE802_1_SNAP) */ ++ } tr9577; ++ } l3; ++ struct atm_blli *next; /* next BLLI or NULL (undefined when used in */ ++ /* atmsvc_msg) */ ++}; + -+ EVENT("poll_tx\n",0,0); -+ zatm_dev = ZATM_DEV(dev); -+ pos = (zatm_dev->mbx_start[mbx] & ~0xffff) | zin(MTA(mbx)); -+ while (x = zin(MWA(mbx)), (pos & 0xffff) != x) { -+ int chan; + -+#if 1 -+ unsigned long data,*addr; ++struct atm_bhli { ++ unsigned char hl_type; /* high layer information type */ ++ unsigned char hl_length; /* length (only if hl_type == ATM_HL_USER || */ ++ /* hl_type == ATM_HL_ISO) */ ++ unsigned char hl_info[ATM_MAX_HLI];/* high layer information */ ++}; + -+ EVENT("MBX: host 0x%lx, nic 0x%lx\n",pos,x); -+ addr = (unsigned long *) pos; -+ data = *addr; -+ chan = (data & uPD98401_TXI_CONN) >> uPD98401_TXI_CONN_SHIFT; -+ EVENT("addr = 0x%08lx, data = 0x%08lx,",(unsigned long) addr, -+ data); -+ EVENT("chan = %d\n",chan,0); -+#else -+NO ! -+ chan = (zatm_dev->mbx_start[mbx][pos >> 2] & uPD98401_TXI_CONN) -+ >> uPD98401_TXI_CONN_SHIFT; +#endif -+ if (chan < zatm_dev->chans && zatm_dev->tx_map[chan]) -+ dequeue_tx(zatm_dev->tx_map[chan]); -+ else { -+ printk(KERN_CRIT DEV_LABEL "(itf %d): TX indication " -+ "for non-existing channel %d\n",dev->number,chan); -+ event_dump(); -+ } -+ if (((pos += 4) & 0xffff) == zatm_dev->mbx_end[mbx]) -+ pos = zatm_dev->mbx_start[mbx]; -+ } -+ zout(pos & 0xffff,MTA(mbx)); -+} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmsvc.h Wed May 14 16:07:56 1997 +@@ -0,0 +1,50 @@ ++/* atmsvc.h - ATM signaling kernel-demon interface definitions */ ++ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++ + ++#ifndef _LINUX_ATMSVC_H ++#define _LINUX_ATMSVC_H + -+static int alloc_shaper(struct atm_dev *dev,int *pcr,int min,int max,int ubr) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned long flags; -+ unsigned long i,m,c; -+ int shaper; -+ -+ DPRINTK("alloc_shaper (min = %d, max = %d)\n",min,max); -+ zatm_dev = ZATM_DEV(dev); -+ if (!zatm_dev->free_shapers) return -EAGAIN; -+ for (shaper = 0; !((zatm_dev->free_shapers >> shaper) & 1); shaper++); -+ zatm_dev->free_shapers &= ~1 << shaper; -+ if (ubr) { -+ c = 5; -+ i = m = 1; -+ zatm_dev->ubr_ref_cnt++; -+ zatm_dev->ubr = shaper; -+ } -+ else { -+ if (min) { -+ if (min <= 255) { -+ i = min; -+ m = ATM_OC3_PCR; -+ } -+ else { -+ i = 255; -+ m = ATM_OC3_PCR*255/min; -+ } -+ } -+ else { -+ if (max > zatm_dev->tx_bw) max = zatm_dev->tx_bw; -+ if (max <= 255) { -+ i = max; -+ m = ATM_OC3_PCR; -+ } -+ else { -+ i = 255; -+ m = (ATM_OC3_PCR*255+max-1)/max; -+ } -+ } -+ if (i > m) { -+ printk(KERN_CRIT DEV_LABEL "shaper algorithm botched " -+ "[%d,%d] -> i=%ld,m=%ld\n",min,max,i,m); -+ m = i; -+ } -+ *pcr = i*ATM_OC3_PCR/m; -+ c = 20; /* @@@ should use max_cdv ! */ -+ if ((min && *pcr < min) || (max && *pcr > max)) return -EINVAL; -+ if (zatm_dev->tx_bw < *pcr) return -EAGAIN; -+ zatm_dev->tx_bw -= *pcr; -+ } -+ save_flags(flags); -+ cli(); -+ DPRINTK("i = %d, m = %d, PCR = %d\n",i,m,*pcr); -+ zpokel(zatm_dev,(i << uPD98401_IM_I_SHIFT) | m,uPD98401_IM(shaper)); -+ zpokel(zatm_dev,c << uPD98401_PC_C_SHIFT,uPD98401_PC(shaper)); -+ zpokel(zatm_dev,0,uPD98401_X(shaper)); -+ zpokel(zatm_dev,0,uPD98401_Y(shaper)); -+ zpokel(zatm_dev,uPD98401_PS_E,uPD98401_PS(shaper)); -+ restore_flags(flags); -+ return shaper; -+} -+ -+ -+static void dealloc_shaper(struct atm_dev *dev,int shaper) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned long flags; -+ -+ zatm_dev = ZATM_DEV(dev); -+ if (shaper == zatm_dev->ubr) { -+ if (--zatm_dev->ubr_ref_cnt) return; -+ zatm_dev->ubr = -1; -+ } -+ save_flags(flags); -+ cli(); -+ zpokel(zatm_dev,zpeekl(zatm_dev,uPD98401_PS(shaper)) & ~uPD98401_PS_E, -+ uPD98401_PS(shaper)); -+ restore_flags(flags); -+ zatm_dev->free_shapers |= 1 << shaper; -+} -+ -+ -+static void close_tx(struct atm_vcc *vcc) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ unsigned long flags; -+ int chan; -+struct sk_buff *skb; -+int once = 1; -+ -+ zatm_vcc = ZATM_VCC(vcc); -+ zatm_dev = ZATM_DEV(vcc->dev); -+ chan = zatm_vcc->tx_chan; -+ if (!chan) return; -+ DPRINTK("close_tx\n"); -+ save_flags(flags); -+ cli(); -+ while (skb_peek(&zatm_vcc->backlog)) { -+if (once) { -+printk("waiting for backlog to drain ...\n"); -+event_dump(); -+once = 0; -+} -+ sleep_on(&zatm_vcc->tx_wait); -+ } -+once = 1; -+ while ((skb = skb_peek(&zatm_vcc->tx_queue))) { -+if (once) { -+printk("waiting for TX queue to drain ... %p\n",skb); -+event_dump(); -+once = 0; -+} -+ DPRINTK("waiting for TX queue to drain ... %p\n",skb); -+ sleep_on(&zatm_vcc->tx_wait); -+ } -+#if 0 -+ zwait; -+ zout(uPD98401_DEACT_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); -+#endif -+ zwait; -+ zout(uPD98401_CLOSE_CHAN | (chan << uPD98401_CHAN_ADDR_SHIFT),CMR); -+ zwait; -+ if (!(zin(CMR) & uPD98401_CHAN_ADDR)) -+ printk(KERN_CRIT DEV_LABEL "(itf %d): can't close TX channel " -+ "%d\n",vcc->dev->number,chan); -+ restore_flags(flags); -+ zatm_vcc->tx_chan = 0; -+ zatm_dev->tx_map[chan] = NULL; -+ if (zatm_vcc->shaper != zatm_dev->ubr) { -+ zatm_dev->tx_bw += vcc->qos.txtp.min_pcr; -+ dealloc_shaper(vcc->dev,zatm_vcc->shaper); -+ } -+ if (zatm_vcc->ring) kfree(zatm_vcc->ring); -+} ++#include ++#include + + -+static int open_tx_first(struct atm_vcc *vcc) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ unsigned long flags,*loop; -+ unsigned short chan; -+ int pcr,unlimited; -+ -+ DPRINTK("open_tx_first\n"); -+ zatm_dev = ZATM_DEV(vcc->dev); -+ zatm_vcc = ZATM_VCC(vcc); -+ zatm_vcc->tx_chan = 0; -+ if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; -+ save_flags(flags); -+ cli(); -+ zwait; -+ zout(uPD98401_OPEN_CHAN,CMR); -+ zwait; -+ DPRINTK("0x%x 0x%x\n",zin(CMR),zin(CER)); -+ chan = (zin(CMR) & uPD98401_CHAN_ADDR) >> uPD98401_CHAN_ADDR_SHIFT; -+ restore_flags(flags); -+ DPRINTK("chan is %d\n",chan); -+ if (!chan) return -EAGAIN; -+ unlimited = vcc->qos.txtp.traffic_class == ATM_UBR && -+ (!vcc->qos.txtp.max_pcr || vcc->qos.txtp.max_pcr == ATM_MAX_PCR || -+ vcc->qos.txtp.max_pcr >= ATM_OC3_PCR); -+ if (unlimited && zatm_dev->ubr != -1) zatm_vcc->shaper = zatm_dev->ubr; -+ else { -+ if (unlimited) vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU; -+ if ((zatm_vcc->shaper = alloc_shaper(vcc->dev,&pcr, -+ vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,unlimited)) -+ < 0) { -+ close_tx(vcc); -+ return zatm_vcc->shaper; -+ } -+ if (pcr > ATM_OC3_PCR) pcr = ATM_OC3_PCR; -+ vcc->qos.txtp.min_pcr = vcc->qos.txtp.max_pcr = pcr; -+ } -+ zatm_vcc->tx_chan = chan; -+ skb_queue_head_init(&zatm_vcc->tx_queue); -+ zatm_vcc->tx_wait = NULL; -+ /* initialize ring */ -+ zatm_vcc->ring = kmalloc(RING_SIZE,GFP_KERNEL); -+ if (!zatm_vcc->ring) return -ENOMEM; -+ memset(zatm_vcc->ring,0,RING_SIZE); -+ loop = zatm_vcc->ring+RING_ENTRIES*RING_WORDS; -+ loop[0] = uPD98401_TXPD_V; -+ loop[1] = loop[2] = 0; -+ loop[3] = (unsigned long) zatm_vcc->ring; -+ zatm_vcc->ring_curr = 0; -+ zatm_vcc->txing = 0; -+ skb_queue_head_init(&zatm_vcc->backlog); -+ zpokel(zatm_dev,(unsigned long) zatm_vcc->ring, -+ chan*VC_SIZE/4+uPD98401_TXVC_QRP); -+ return 0; -+} ++#define ATMSIGD_CTRL _IO('a',ATMIOC_SPECIAL) ++ /* become ATM signaling demon control socket */ + ++enum atmsvc_msg_type { as_catch_null,as_bind,as_connect,as_accept,as_reject, ++ as_listen,as_okay,as_error,as_indicate,as_close,as_itf_notify }; + -+static int open_tx_second(struct atm_vcc *vcc) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ unsigned long flags; ++struct atmsvc_msg { ++ enum atmsvc_msg_type type; ++ unsigned long vcc; ++ unsigned long listen_vcc; /* indicate */ ++ int reply; /* for okay and close: */ ++ /* < 0: error before active */ ++ /* (sigd has discarded ctx) */ ++ /* ==0: success */ ++ /* > 0: error when active (still */ ++ /* need to close) */ ++ struct sockaddr_atmpvc pvc; /* indicate, okay (connect) */ ++ struct sockaddr_atmsvc local; /* local SVC address */ ++ struct atm_qos qos; /* QOS parameters */ ++ struct sockaddr_atmsvc svc; /* MUST BE BEFORE "blli", SVC address */ ++ struct atm_blli blli[1]; /* MUST BE LAST */ ++}; + -+ DPRINTK("open_tx_second\n"); -+ zatm_dev = ZATM_DEV(vcc->dev); -+ zatm_vcc = ZATM_VCC(vcc); -+ if (!zatm_vcc->tx_chan) return 0; -+ save_flags(flags); -+ /* set up VC descriptor */ -+ cli(); -+ zpokel(zatm_dev,0,zatm_vcc->tx_chan*VC_SIZE/4); -+ zpokel(zatm_dev,uPD98401_TXVC_L | (zatm_vcc->shaper << -+ uPD98401_TXVC_SHP_SHIFT) | (vcc->vpi << uPD98401_TXVC_VPI_SHIFT) | -+ vcc->vci,zatm_vcc->tx_chan*VC_SIZE/4+1); -+ zpokel(zatm_dev,0,zatm_vcc->tx_chan*VC_SIZE/4+2); -+ restore_flags(flags); -+ zatm_dev->tx_map[zatm_vcc->tx_chan] = vcc; -+ return 0; -+} ++/* ++ * Message contents: see ftp://lrcftp.epfl.ch/pub/linux/atm/docs/isp-*.tar.gz ++ */ + ++/* ++ * Some policy stuff for atmsigd and for net/atm/svc.c. Both have to agree on ++ * what PCR is used to request bandwidth from the device driver. net/atm/svc.c ++ * tries to do better than that, but only if there's no routing decision (i.e. ++ * if signaling only uses one ATM interface). ++ */ + -+static int start_tx(struct atm_dev *dev) -+{ -+ struct zatm_dev *zatm_dev; -+ int i; ++#define SELECT_TOP_PCR(tp) ((tp).max_pcr && (tp).max_pcr != ATM_MAX_PCR ? \ ++ (tp).max_pcr : (tp).min_pcr ? (tp).min_pcr : ATM_MAX_PCR) + -+ DPRINTK("start_tx\n"); -+ zatm_dev = ZATM_DEV(dev); -+ zatm_dev->tx_map = (struct atm_vcc **) kmalloc(sizeof(struct atm_vcc *)* -+ zatm_dev->chans,GFP_KERNEL); -+ if (!zatm_dev->tx_map) return -ENOMEM; -+ zatm_dev->tx_bw = ATM_OC3_PCR; -+ zatm_dev->free_shapers = (1 << NR_SHAPERS)-1; -+ zatm_dev->ubr = -1; -+ zatm_dev->ubr_ref_cnt = 0; -+ /* initialize shapers */ -+ for (i = 0; i < NR_SHAPERS; i++) zpokel(zatm_dev,0,uPD98401_PS(i)); -+ return 0; -+} ++#endif +--- ref/include/linux/if_arp.h Fri Apr 4 22:16:57 1997 ++++ work/include/linux/if_arp.h Tue Jul 1 07:57:29 1997 +@@ -35,6 +35,7 @@ + #define ARPHRD_ARCNET 7 /* ARCnet */ + #define ARPHRD_APPLETLK 8 /* APPLEtalk */ + #define ARPHRD_DLCI 15 /* Frame Relay DLCI */ ++#define ARPHRD_ATM 19 /* ATM */ + #define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ + + /* Dummy types for non ARP hardware */ +@@ -64,6 +65,9 @@ + #define ARPOP_REPLY 2 /* ARP reply */ + #define ARPOP_RREQUEST 3 /* RARP request */ + #define ARPOP_RREPLY 4 /* RARP reply */ ++#define ARPOP_InREQUEST 8 /* InARP request */ ++#define ARPOP_InREPLY 9 /* InARP reply */ ++#define ARPOP_NAK 10 /* (ATM)ARP NAK */ + + + /* ARP ioctl request. */ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/mmuio.h Wed May 14 18:40:05 1997 +@@ -0,0 +1,25 @@ ++/* mmuio.h - MMU-supported high-speed I/O */ + ++/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ + -+/*------------------------------- interrupts --------------------------------*/ + ++#ifndef _LINUX_MMUIO_H ++#define _LINUX_MMUIO_H + -+static void zatm_int(int irq,void *dev_id,struct pt_regs *regs) -+{ -+ struct atm_dev *dev; -+ struct zatm_dev *zatm_dev; -+ unsigned long reason; ++#include + -+ dev = dev_id; -+ zatm_dev = ZATM_DEV(dev); -+ while ((reason = zin(GSR))) { -+ EVENT("reason 0x%lx\n",reason,0); -+ if (reason & uPD98401_INT_PI) { -+ EVENT("PHY int\n",0,0); -+ dev->phy->interrupt(dev); -+ } -+ if (reason & uPD98401_INT_RQA) { -+ unsigned long pools; -+ int i; -+ -+ pools = zin(RQA); -+ EVENT("RQA (0x%08lx)\n",pools,0); -+ for (i = 0; pools; i++) { -+ if (pools & 1) { -+ refill_pool(dev,i); -+ zatm_dev->pool_info[i].rqa_count++; -+ } -+ pools >>= 1; -+ } -+ } -+ if (reason & uPD98401_INT_RQU) { -+ unsigned long pools; -+ int i; -+ pools = zin(RQU); -+ printk(KERN_WARNING DEV_LABEL "(itf %d): RQU 0x%08lx\n", -+ dev->number,pools); -+ event_dump(); -+ for (i = 0; pools; i++) { -+ if (pools & 1) { -+ refill_pool(dev,i); -+ zatm_dev->pool_info[i].rqu_count++; -+ } -+ pools >>= 1; -+ } -+ } -+ /* don't handle RD */ -+ if (reason & uPD98401_INT_SPE) -+ printk(KERN_ALERT DEV_LABEL "(itf %d): system parity " -+ "error at 0x%08x\n",dev->number,zin(ADDR)); -+ if (reason & uPD98401_INT_CPE) -+ printk(KERN_ALERT DEV_LABEL "(itf %d): control memory " -+ "parity error at 0x%08x\n",dev->number,zin(ADDR)); -+ if (reason & uPD98401_INT_SBE) { -+ printk(KERN_ALERT DEV_LABEL "(itf %d): system bus " -+ "error at 0x%08x\n",dev->number,zin(ADDR)); -+ event_dump(); -+ } -+ /* don't handle IND */ -+ if (reason & uPD98401_INT_MF) { -+ printk(KERN_CRIT DEV_LABEL "(itf %d): mailbox full " -+ "(0x%lx)\n",dev->number,(reason & uPD98401_INT_MF) -+ >> uPD98401_INT_MF_SHIFT); -+ event_dump(); -+ /* @@@ should try to recover */ -+ } -+ if (reason & uPD98401_INT_MM) { -+ if (reason & 1) poll_rx(dev,0); -+ if (reason & 2) poll_rx(dev,1); -+ if (reason & 4) poll_tx(dev,2); -+ if (reason & 8) poll_tx(dev,3); -+ } -+ /* @@@ handle RCRn */ -+ } -+} ++#ifdef CONFIG_MMU_HACKS + ++#include ++#include + -+/*----------------------------- (E)EPROM access -----------------------------*/ ++void free_range(unsigned long start,unsigned long size); ++void mmucp_tofs(unsigned long user,unsigned long size,struct sk_buff *skb, ++ unsigned long kernel); ++int lock_user(unsigned long start,unsigned long size,int iov_max, ++ struct iovec *iov); ++void unlock_user(int iovcnt,struct iovec *iov); + ++#endif + -+static void eprom_set(struct zatm_dev *zatm_dev,unsigned long value, -+ unsigned short cmd) -+{ -+ int error; ++#endif +--- ref/include/linux/proc_fs.h Thu Jul 10 14:28:47 1997 ++++ work/include/linux/proc_fs.h Tue Jul 1 07:51:28 1997 +@@ -36,6 +36,7 @@ + PROC_KSYMS, + PROC_DMA, + PROC_IOPORTS, ++ PROC_ATM, + #ifdef __SMP_PROF__ + PROC_SMP_PROF, + #endif +@@ -199,6 +200,16 @@ + #define PROC_OPENPROMD_FIRST (PROC_OPENPROM_FIRST+PROC_NOPENPROM) + #define PROC_NOPENPROMD 4096 + ++enum atm_directory_inos { ++ PROC_ATM_DEVICES = 384, ++ PROC_ATM_ARP, ++ PROC_ATM_LEC, ++ PROC_ATM_SVC, ++ PROC_ATM_PVC, ++ PROC_ATM_AREQUIPA, ++ PROC_ATM_LAST ++}; + -+ if ((error = pcibios_write_config_dword(zatm_dev->bus,zatm_dev->dev_fn, -+ cmd,value))) -+ printk(KERN_ERR DEV_LABEL ": PCI write failed (%s)\n", -+ pcibios_strerror(error)); -+} + #define PROC_SUPER_MAGIC 0x9fa0 + + /* +@@ -242,6 +253,7 @@ + extern struct proc_dir_entry proc_root; + extern struct proc_dir_entry *proc_net; + extern struct proc_dir_entry *proc_scsi; ++extern struct proc_dir_entry proc_atm; + extern struct proc_dir_entry proc_sys; + extern struct proc_dir_entry proc_openprom; + extern struct proc_dir_entry proc_pid; +@@ -350,6 +362,7 @@ + extern struct inode_operations proc_kmsg_inode_operations; + extern struct inode_operations proc_link_inode_operations; + extern struct inode_operations proc_fd_inode_operations; ++extern struct inode_operations proc_atm_inode_operations; + #if CONFIG_AP1000 + extern struct inode_operations proc_ringbuf_inode_operations; + #endif +--- ref/include/linux/skbuff.h Thu Jul 10 14:28:49 1997 ++++ work/include/linux/skbuff.h Tue Jul 1 07:51:39 1997 +@@ -121,6 +121,24 @@ + __u32 shapestamp; /* Stamp for shaper */ + __u16 shapepend; /* Pending */ + #endif ++#ifdef CONFIG_ATM ++ struct { ++ int size; /* PDU size (adapter too) */ ++ unsigned long pos; /* adapter data */ ++ struct atm_vcc *vcc; /* ATM VCC */ ++ int iovcnt; /* 0 for "normal" operation */ ++#ifdef CONFIG_ATM_NICSTAR ++ void *recycle_buffer; /* set when buffer should be */ ++ /* recycled; points to vcc */ ++#endif ++ int encap; /* non-zero if encapsulated */ ++ /* for ATMARP */ ++#ifdef CONFIG_AREQUIPA ++ int generation; /* generation number */ ++#endif ++ } atm; ++#endif + + }; + + /* These are just the default values. This is run time configurable. +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/sonet.h Wed May 14 17:39:07 1997 +@@ -0,0 +1,52 @@ ++/* sonet.h - SONET/SHD physical layer control */ ++ ++/* Written 1995 by Werner Almesberger, EPFL LRC */ ++ + -+static unsigned long eprom_get(struct zatm_dev *zatm_dev,unsigned short cmd) -+{ -+ unsigned int value; -+ int error; ++#ifndef LINUX_SONET_H ++#define LINUX_SONET_H + -+ if ((error = pcibios_read_config_dword(zatm_dev->bus,zatm_dev->dev_fn, -+ cmd,&value))) -+ printk(KERN_ERR DEV_LABEL ": PCI read failed (%s)\n", -+ pcibios_strerror(error)); -+ return value; -+} ++struct sonet_stats { ++ long section_bip; /* section parity errors (B1) */ ++ long line_bip; /* line parity errors (B2) */ ++ long path_bip; /* path parity errors (B3) */ ++ long line_febe; /* line parity errors at remote */ ++ long path_febe; /* path parity errors at remote */ ++ long corr_hcs; /* correctable header errors */ ++ long uncorr_hcs; /* uncorrectable header errors */ ++ long tx_cells; /* cells sent */ ++ long rx_cells; /* cells received */ ++}; + ++#define SONET_GETSTAT _IOR('a',ATMIOC_PHYTYP,struct sonet_stats) ++ /* get statistics */ ++#define SONET_GETSTATZ _IOR('a',ATMIOC_PHYTYP+1,struct sonet_stats) ++ /* ... and zero counters */ ++#define SONET_SETDIAG _IOWR('a',ATMIOC_PHYTYP+2,int) ++ /* set error insertion */ ++#define SONET_CLRDIAG _IOWR('a',ATMIOC_PHYTYP+3,int) ++ /* clear error insertion */ ++#define SONET_GETDIAG _IOR('a',ATMIOC_PHYTYP+4,int) ++ /* query error insertion */ ++#define SONET_SETFRAMING _IO('a',ATMIOC_PHYTYP+5) ++ /* set framing mode (SONET/SDH) */ ++#define SONET_GETFRAMING _IOR('a',ATMIOC_PHYTYP+6,int) ++ /* get framing mode */ ++#define SONET_GETFRSENSE _IOR('a',ATMIOC_PHYTYP+7, \ ++ unsigned char[SONET_FRSENSE_SIZE]) /* get framing sense information */ + -+static void eprom_put_bits(struct zatm_dev *zatm_dev,unsigned long data, -+ int bits,unsigned short cmd) -+{ -+ unsigned long value; -+ int i; ++#define SONET_INS_SBIP 1 /* section BIP */ ++#define SONET_INS_LBIP 2 /* line BIP */ ++#define SONET_INS_PBIP 4 /* path BIP */ ++#define SONET_INS_FRAME 8 /* out of frame */ ++#define SONET_INS_LOS 16 /* set line to zero */ ++#define SONET_INS_LAIS 32 /* line alarm indication signal */ ++#define SONET_INS_PAIS 64 /* path alarm indication signal */ ++#define SONET_INS_HCS 128 /* insert HCS error */ + -+ for (i = bits-1; i >= 0; i--) { -+ value = ZEPROM_CS | (((data >> i) & 1) ? ZEPROM_DI : 0); -+ eprom_set(zatm_dev,value,cmd); -+ eprom_set(zatm_dev,value | ZEPROM_SK,cmd); -+ eprom_set(zatm_dev,value,cmd); -+ } -+} ++#define SONET_FRAME_SONET 0 /* SONET STS-3 framing */ ++#define SONET_FRAME_SDH 1 /* SDH STM-1 framing */ + ++#define SONET_FRSENSE_SIZE 6 /* C1[3],H1[3] (0xff for unknown) */ + -+static void eprom_get_byte(struct zatm_dev *zatm_dev,unsigned char *byte, -+ unsigned short cmd) -+{ -+ int i; ++#endif +--- ref/include/net/arp.h Fri Apr 4 22:20:10 1997 ++++ work/include/net/arp.h Wed Jul 2 11:27:49 1997 +@@ -45,4 +45,6 @@ + extern int arp_bind_cache(struct hh_cache ** hhp, struct device *dev, unsigned short type, __u32 daddr); + extern int arp_update_cache(struct hh_cache * hh); + extern struct neighbour *arp_find_neighbour(struct dst_entry *dst, int); ++extern int arp_update (u32 sip, char *sha, struct device * dev, ++ unsigned long updated, int grat, void ***ll_priv); + #endif /* _ARP_H */ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/net/atmclip.h Sat May 17 00:54:08 1997 +@@ -0,0 +1,37 @@ ++/* net/atm/atmarp.h - RFC1577 ATM ARP */ ++ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ ++ ++ ++#ifndef _ATMCLIP_H ++#define _ATMCLIP_H + -+ *byte = 0; -+ for (i = 8; i; i--) { -+ eprom_set(zatm_dev,ZEPROM_CS,cmd); -+ eprom_set(zatm_dev,ZEPROM_CS | ZEPROM_SK,cmd); -+ *byte <<= 1; -+ if (eprom_get(zatm_dev,cmd) & ZEPROM_DO) *byte |= 1; -+ eprom_set(zatm_dev,ZEPROM_CS,cmd); -+ } -+} ++#include ++#include ++#include ++#include ++#include + + -+static unsigned char eprom_try_esi(struct atm_dev *dev,unsigned short cmd, -+ int offset,int swap) -+{ -+ unsigned char buf[ZEPROM_SIZE]; -+ struct zatm_dev *zatm_dev; -+ int i; ++#define PRIV(dev) ((struct clip_priv *) ((struct device *) (dev)+1)) + -+ zatm_dev = ZATM_DEV(dev); -+ for (i = 0; i < ZEPROM_SIZE; i += 2) { -+ eprom_set(zatm_dev,ZEPROM_CS,cmd); /* select EPROM */ -+ eprom_put_bits(zatm_dev,ZEPROM_CMD_READ,ZEPROM_CMD_LEN,cmd); -+ eprom_put_bits(zatm_dev,i >> 1,ZEPROM_ADDR_LEN,cmd); -+ eprom_get_byte(zatm_dev,buf+i+swap,cmd); -+ eprom_get_byte(zatm_dev,buf+i+1-swap,cmd); -+ eprom_set(zatm_dev,0,cmd); /* deselect EPROM */ -+ } -+ memcpy(dev->esi,buf+offset,ESI_LEN); -+ return memcmp(dev->esi,"\0\0\0\0\0",ESI_LEN); /* assumes ESI_LEN == 6 */ -+} + ++struct clip_priv { ++ char name[8]; /* interface name */ ++ int number; /* for convenience ... */ ++ struct enet_statistics stats; ++ struct device *next; /* next CLIP interface */ ++}; + -+static void eprom_get_esi(struct atm_dev *dev) -+{ -+ if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return; -+ (void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0); -+} + ++extern struct atm_vcc *atmarpd; /* ugly */ + -+/*--------------------------------- entries ---------------------------------*/ + ++int clip_create(int number); ++int clip_mkip(struct atm_vcc *vcc); ++int clip_setentry(struct atm_vcc *vcc,u32 ip); ++int clip_encap(struct atm_vcc *vcc,int mode); ++int clip_ioctl(struct device *dev,unsigned int cmd,void *arg); ++void clip_resolve(struct device *dev,u32 ip); + -+static int zatm_init(struct atm_dev *dev) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned short command; -+ unsigned char revision; -+ int error,i,last; -+ unsigned long t0,t1,t2; ++#endif +--- ref/include/net/neighbour.h Thu Jul 10 14:10:05 1997 ++++ work/include/net/neighbour.h Tue Jul 1 08:12:50 1997 +@@ -32,6 +32,7 @@ + atomic_t refcnt; + struct neigh_ops *ops; + struct sk_buff_head arp_queue; ++ void *ll_priv; /* link-layer private data */ + char primary_key[0]; + }; + +--- ref/net/Config.in Fri Mar 21 03:17:12 1997 ++++ work/net/Config.in Fri May 16 22:58:54 1997 +@@ -51,4 +51,18 @@ + # fi + tristate 'WAN router' CONFIG_WAN_ROUTER + fi ++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ bool 'Asynchronous Transfer Mode (ATM)' CONFIG_ATM y ++ if [ "$CONFIG_ATM" = "y" ]; then ++# bool ' Enable single-copy' CONFIG_MMU_HACKS n ++# if [ "$CONFIG_MMU_HACKS" = "y" ]; then ++# bool ' Extended debugging for single-copy' CONFIG_MMU_HACKS_DEBUG y ++# fi ++ if [ "$CONFIG_INET" = "y" ]; then ++ bool ' Classical IP over ATM' CONFIG_ATM_CLIP y ++# bool ' Application REQUested IP over ATM' CONFIG_AREQUIPA y ++ fi ++# bool ' LANE support' CONFIG_ATM_LANE y ++ fi ++fi + endmenu +--- ref/net/Makefile Sat Apr 5 22:14:21 1997 ++++ work/net/Makefile Wed May 14 16:17:43 1997 +@@ -7,9 +7,9 @@ + # + # Note 2! The CFLAGS definition is now in the main makefile... + +-MOD_SUB_DIRS := ipv4 ++MOD_SUB_DIRS := ipv4 atm + ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ +- netrom rose lapb x25 wanrouter sunrpc #decnet ++ netrom rose lapb x25 wanrouter sunrpc atm #decnet + SUB_DIRS := core ethernet unix + MOD_LIST_NAME := NET_MISC_MODULES + +@@ -103,6 +103,10 @@ + ifeq ($(CONFIG_SUNRPC),m) + MOD_SUB_DIRS += sunrpc + endif ++endif + -+ DPRINTK(">zatm_init\n"); -+ zatm_dev = ZATM_DEV(dev); -+ if ((error = pcibios_read_config_word(zatm_dev->bus,zatm_dev->dev_fn, -+ PCI_COMMAND,&command)) || (error = pcibios_read_config_dword( -+ zatm_dev->bus,zatm_dev->dev_fn,PCI_BASE_ADDRESS_0,&zatm_dev->base)) -+ || (error = pcibios_read_config_byte(zatm_dev->bus,zatm_dev->dev_fn, -+ PCI_INTERRUPT_LINE,&zatm_dev->irq)) || (error = -+ pcibios_read_config_byte(zatm_dev->bus,zatm_dev->dev_fn, -+ PCI_REVISION_ID,&revision))) { -+ printk(KERN_ERR DEV_LABEL "(itf %d): init error %s\n", -+ dev->number,pcibios_strerror(error)); -+ return -EINVAL; -+ } -+ zatm_dev->base &= PCI_BASE_ADDRESS_IO_MASK; -+ if ((error = pcibios_write_config_word(zatm_dev->bus,zatm_dev->dev_fn, -+ PCI_COMMAND,command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) { -+ printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (%s)\n", -+ dev->number,pcibios_strerror(error)); -+ return error; -+ } -+ eprom_get_esi(dev); -+ printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", -+ dev->number,revision,zatm_dev->base,zatm_dev->irq); -+ /* reset uPD98401 */ -+ zout(0,SWR); -+ while (!(zin(GSR) & uPD98401_INT_IND)); -+ zout(uPD98401_GMR_ONE /*uPD98401_BURST4*/,GMR); -+ last = MAX_CRAM_SIZE; -+ for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) { -+ zpokel(zatm_dev,0x55555555,i); -+ if (zpeekl(zatm_dev,i) != 0x55555555) last = i; -+ else { -+ zpokel(zatm_dev,0xAAAAAAAA,i); -+ if (zpeekl(zatm_dev,i) != 0xAAAAAAAA) last = i; -+ else zpokel(zatm_dev,i,i); -+ } -+ } -+ for (i = 0; i < last; i += RAM_INCREMENT) -+ if (zpeekl(zatm_dev,i) != i) break; -+ zatm_dev->mem = i << 2; -+ while (i) zpokel(zatm_dev,0,--i); -+ /* reset again to rebuild memory pointers */ -+ zout(0,SWR); -+ while (!(zin(GSR) & uPD98401_INT_IND)); -+ zout(uPD98401_GMR_ONE | uPD98401_BURST8 | uPD98401_BURST4 | -+ uPD98401_BURST2 | uPD98401_GMR_PM | uPD98401_GMR_DR,GMR); -+ /* TODO: should shrink allocation now */ -+ printk("mem=%dkB,%s (",zatm_dev->mem >> 10,zatm_dev->copper ? "UTP" : -+ "MMF"); -+ for (i = 0; i < ESI_LEN; i++) -+ printk("%02X%s",dev->esi[i],i == ESI_LEN-1 ? ")\n" : "-"); -+ do { -+ unsigned long flags; ++ifeq ($(CONFIG_ATM),y) ++SUB_DIRS += atm + endif + + # We must attach netsyms.o to socket.o, as otherwise there is nothing +--- ref/net/protocols.c Thu Jan 2 14:13:29 1997 ++++ work/net/protocols.c Wed May 14 16:18:07 1997 +@@ -65,6 +65,10 @@ + extern void rif_init(struct net_proto *); + #endif + ++#ifdef CONFIG_ATM ++#include ++#endif + -+ save_flags(flags); -+ cli(); -+ t0 = zpeekl(zatm_dev,uPD98401_TSR); -+ udelay(10); -+ t1 = zpeekl(zatm_dev,uPD98401_TSR); -+ udelay(1010); -+ t2 = zpeekl(zatm_dev,uPD98401_TSR); -+ restore_flags(flags); -+ } -+ while (t0 > t1 || t1 > t2); /* loop if wrapping ... */ -+ zatm_dev->khz = t2-2*t1+t0; -+ printk(KERN_NOTICE DEV_LABEL "(itf %d): uPD98401 %d.%d at %d.%03d " -+ "MHz\n",dev->number, -+ (zin(VER) & uPD98401_MAJOR) >> uPD98401_MAJOR_SHIFT, -+ zin(VER) & uPD98401_MINOR,zatm_dev->khz/1000,zatm_dev->khz % 1000); -+#ifdef CONFIG_ATM_ZATM_EXACT_TS -+ zatm_clock_init(zatm_dev); + #ifdef NEED_LLC + #define NEED_802 + #include +@@ -93,6 +97,11 @@ + #ifdef CONFIG_TR + { "RIF", rif_init }, /* RIF for Token ring */ + #endif ++ ++#ifdef CONFIG_ATM ++ { "ATMPVC", atmpvc_proto_init }, /* ATM PVCs */ ++ { "ATMSVC", atmsvc_proto_init }, /* ATM SVCs */ ++#endif + + #ifdef NEED_LLC + { "802.2LLC", llc_init }, /* 802.2 LLC */ +--- ref/net/ipv4/arp.c Thu Jul 10 14:29:22 1997 ++++ work/net/ipv4/arp.c Wed Jul 9 18:36:07 1997 +@@ -105,6 +105,9 @@ + #include + #endif + #endif ++#ifdef CONFIG_ATM_CLIP ++#include ++#endif + #include + #ifdef CONFIG_ARPD + #include +@@ -254,8 +257,6 @@ + #endif + + static void arp_check_expire (unsigned long); +-static int arp_update (u32 sip, char *sha, struct device * dev, +- unsigned long updated, int grat); + + static struct timer_list arp_timer = + { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire }; +@@ -385,6 +386,22 @@ + } + + ++static __inline__ void arp_request(struct device *dev, unsigned long ip, ++ unsigned char *dest_hw) ++{ ++ /* ++ * this really ought to be a callback, but I don't want to start the ++ * struct device redesign bloodshed now ... ++ */ ++ if (dev->type != ARPHRD_ATM) ++ arp_send(ARPOP_REQUEST, ETH_P_ARP, ip, dev, dev->pa_addr, ++ dest_hw, dev->dev_addr, NULL); ++#ifdef CONFIG_ATM_CLIP ++ else clip_resolve(dev,ip); +#endif -+ return uPD98402_init(dev); +} + + -+static int zatm_start(struct atm_dev *dev) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned long curr; -+ int pools,vccs,rx; -+ int error,i,ld; + #ifdef CONFIG_ARPD + + /* +@@ -484,13 +501,13 @@ + /* + * Invalid mapping: drop it and send ARP broadcast. + */ +- arp_send(ARPOP_REQUEST, ETH_P_ARP, retreq->ip, dev, dev->pa_addr, NULL, +- dev->dev_addr, NULL); ++ arp_request(dev, retreq->ip, NULL); + } + else + { + start_bh_atomic(); +- arp_update(retreq->ip, retreq->ha, dev, retreq->updated, 0); ++ arp_update(retreq->ip, retreq->ha, dev, retreq->updated, 0, ++ NULL); + end_bh_atomic(); + } + +@@ -657,9 +674,7 @@ + del_timer(&entry->timer); + entry->timer.expires = jiffies + ARP_CONFIRM_TIMEOUT; + add_timer(&entry->timer); +- arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, +- dev, dev->pa_addr, entry->u.neigh.ha, +- dev->dev_addr, NULL); ++ arp_request(dev, entry->ip, entry->u.neigh.ha); + #if RT_CACHE_DEBUG >= 2 + printk("arp_expire: %08x requires confirmation\n", entry->ip); + #endif +@@ -710,9 +725,8 @@ + /* Set new timer. */ + entry->timer.expires = jiffies + sysctl_arp_res_time; + add_timer(&entry->timer); +- arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, +- entry->retries > sysctl_arp_max_tries ? entry->u.neigh.ha : NULL, +- dev->dev_addr, NULL); ++ arp_request(dev, entry->ip, entry->retries > ++ sysctl_arp_max_tries ? entry->u.neigh.ha : NULL); + return; + } + +@@ -749,8 +763,7 @@ + + entry->timer.expires = jiffies + sysctl_arp_dead_res_time; + add_timer(&entry->timer); +- arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, +- NULL, dev->dev_addr, NULL); ++ arp_request(dev, entry->ip, NULL); + return; + } + +@@ -869,9 +882,8 @@ + } + + +-static int +-arp_update (u32 sip, char *sha, struct device * dev, +- unsigned long updated, int grat) ++int arp_update (u32 sip, char *sha, struct device * dev, ++ unsigned long updated, int grat, void ***ll_priv) + { + struct arp_table * entry; + unsigned long hash; +@@ -890,6 +902,7 @@ + + if (entry) + { ++ if (ll_priv) *ll_priv = &entry->u.neigh.ll_priv; + /* + * Entry found; update it only if it is not a permanent entry. + */ +@@ -935,6 +948,8 @@ + entry->flags = ATF_COM; + memcpy(entry->u.neigh.ha, sha, dev->addr_len); + entry->u.neigh.dev = dev; ++ entry->u.neigh.ll_priv = NULL; ++ if (ll_priv) *ll_priv = &entry->u.neigh.ll_priv; + entry->hatype = dev->type; + entry->last_updated = updated; + +@@ -1005,8 +1020,7 @@ + arpd_lookup(entry->ip, dev); + else + #endif +- arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, +- dev->pa_addr, NULL, dev->dev_addr, NULL); ++ arp_request(dev, entry->ip, NULL); + } + + /* +@@ -1494,7 +1508,8 @@ + } + + start_bh_atomic(); +- arp_update(sip, sha, dev, 0, !RT_LOCALADDR(rt->rt_flags) && dev->type != ARPHRD_METRICOM); ++ arp_update(sip, sha, dev, 0, ++ !RT_LOCALADDR(rt->rt_flags) && dev->type != ARPHRD_METRICOM, NULL); + end_bh_atomic(); + kfree_skb(skb, FREE_READ); + return 0; +@@ -1825,6 +1840,17 @@ + if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) + return -EINVAL; + } + -+ DPRINTK("zatm_start\n"); -+ zatm_dev = ZATM_DEV(dev); -+ if (request_irq(zatm_dev->irq,&zatm_int,0,DEV_LABEL,dev)) { -+ printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", -+ dev->number,zatm_dev->irq); -+ return -EAGAIN; ++#ifdef CONFIG_ATM_CLIP ++ if (!dev) { ++ struct rtable *rt; ++ ++ if (!ip_route_output(&rt, ++ ((struct sockaddr_in *) &r.arp_pa)->sin_addr.s_addr, 0, 1, ++ dev)) dev = rt->u.dst.dev; + } -+ request_region(zatm_dev->base,uPD98401_PORTS,DEV_LABEL); -+ /* define memory regions */ -+ pools = NR_POOLS; -+ if (NR_SHAPERS*SHAPER_SIZE > pools*POOL_SIZE) -+ pools = NR_SHAPERS*SHAPER_SIZE/POOL_SIZE; -+ vccs = (zatm_dev->mem-NR_SHAPERS*SHAPER_SIZE-pools*POOL_SIZE)/ -+ (2*VC_SIZE+RX_SIZE); -+ ld = -1; -+ for (rx = 1; rx < vccs; rx <<= 1) ld++; -+ dev->ci_range.vpi_bits = 0; /* @@@ no VPI for now */ -+ dev->ci_range.vci_bits = ld; -+ zatm_dev->chans = vccs; /* ??? */ -+ curr = rx*RX_SIZE/4; -+ DPRINTK("RX pool 0x%08lx\n",curr); -+ zpokel(zatm_dev,curr,uPD98401_PMA); /* receive pool */ -+ zatm_dev->pool_base = curr; -+ curr += pools*POOL_SIZE/4; -+ DPRINTK("Shapers 0x%08lx\n",curr); -+ zpokel(zatm_dev,curr,uPD98401_SMA); /* shapers */ -+ curr += NR_SHAPERS*SHAPER_SIZE/4; -+ DPRINTK("Free 0x%08lx\n",curr); -+ zpokel(zatm_dev,curr,uPD98401_TOS); /* free pool */ -+ printk(KERN_INFO DEV_LABEL "(itf %d): %d shapers, %d pools, %d RX, " -+ "%ld VCs\n",dev->number,NR_SHAPERS,pools,rx, -+ (zatm_dev->mem-curr*4)/VC_SIZE); -+ /* create mailboxes */ -+ for (i = 0; i < NR_MBX; i++) zatm_dev->mbx_start[i] = 0; -+ for (i = 0; i < NR_MBX; i++) -+ if (mbx_entries[i]) { -+ unsigned long here; -+ -+ here = (unsigned long) kmalloc(2*MBX_SIZE(i), -+ GFP_KERNEL); -+ if (!here) return -ENOMEM; -+ if ((here^(here+MBX_SIZE(i))) & ~0xffff) /* paranoia */ -+ here = (here & ~0xffff)+0x10000; -+ DPRINTK("mbx@0x%08lx-0x%08lx\n",here,here+MBX_SIZE(i)); -+ zatm_dev->mbx_start[i] = here; -+ zatm_dev->mbx_end[i] = (here+MBX_SIZE(i)) & 0xffff; -+ zout(here >> 16,MSH(i)); -+ zout(here,MSL(i)); -+ zout((here+MBX_SIZE(i)) & 0xffff,MBA(i)); -+ zout(here & 0xffff,MTA(i)); -+ zout(here & 0xffff,MWA(i)); -+ } -+ error = start_tx(dev); -+ if (error) return error; -+ error = start_rx(dev); -+ if (error) return error; -+ error = dev->phy->start(dev); -+ if (error) return error; -+ zout(0xffffffff,IMR); /* enable interrupts */ -+ /* enable TX & RX */ -+ zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR); -+ return 0; -+} ++ if (dev && dev->type == ARPHRD_ATM) return clip_ioctl(dev,cmd,arg); ++#endif + + switch(cmd) + { +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/Makefile Fri May 16 22:58:23 1997 +@@ -0,0 +1,49 @@ ++# ++# Makefile for the ATM Protocol Families. ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++# ++# Note 2! The CFLAGS definition is now in the main makefile... ++ ++include ../../.config + ++CFLAGS += -g + -+static void zatm_close(struct atm_vcc *vcc) -+{ -+ DPRINTK(">zatm_close\n"); -+ if (!ZATM_VCC(vcc)) return; -+ vcc->flags &= ~ATM_VF_READY; -+ close_rx(vcc); -+EVENT("close_tx\n",0,0); -+ close_tx(vcc); -+ DPRINTK("zatm_close: done waiting\n"); -+ /* deallocate memory */ -+ kfree(ZATM_VCC(vcc)); -+ ZATM_VCC(vcc) = NULL; -+ vcc->flags &= ~ATM_VF_ADDR; -+} ++ifeq ($(CONFIG_ATM),y) + ++OBJS = addr.o common.o pvc.o raw.o resources.o signaling.o svc.o # mmuio.c + -+static int zatm_open(struct atm_vcc *vcc,short vpi,int vci) -+{ -+ struct zatm_dev *zatm_dev; -+ struct zatm_vcc *zatm_vcc; -+ int error; ++ifeq ($(CONFIG_ATM_CLIP),y) ++OBJS += clip.o ++NEED_IPCOM = ipcommon.o ++endif + -+ DPRINTK(">zatm_open\n"); -+ zatm_dev = ZATM_DEV(vcc->dev); -+ if (!(vcc->flags & ATM_VF_PARTIAL)) ZATM_VCC(vcc) = NULL; -+ error = atm_find_ci(vcc,&vpi,&vci); -+ if (error) return error; -+ vcc->vpi = vpi; -+ vcc->vci = vci; -+ if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) -+ vcc->flags |= ATM_VF_ADDR; -+ if (vcc->aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */ -+ DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, -+ vcc->vci); -+ if (!(vcc->flags & ATM_VF_PARTIAL)) { -+ zatm_vcc = kmalloc(sizeof(struct zatm_vcc),GFP_KERNEL); -+ if (!zatm_vcc) { -+ vcc->flags &= ~ATM_VF_ADDR; -+ return -ENOMEM; -+ } -+ ZATM_VCC(vcc) = zatm_vcc; -+ ZATM_VCC(vcc)->tx_chan = 0; /* for zatm_close after open_rx */ -+ if ((error = open_rx_first(vcc))) { -+ zatm_close(vcc); -+ return error; -+ } -+ if ((error = open_tx_first(vcc))) { -+ zatm_close(vcc); -+ return error; -+ } -+ } -+ if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return 0; -+ if ((error = open_rx_second(vcc))) { -+ zatm_close(vcc); -+ return error; -+ } -+ if ((error = open_tx_second(vcc))) { -+ zatm_close(vcc); -+ return error; -+ } -+ vcc->flags |= ATM_VF_READY; -+ return 0; -+} ++ifeq ($(CONFIG_AREQUIPA),y) ++OBJS += arequipa.o ++NEED_IPCOM = ipcommon.o ++endif + ++OBJS += $(NEED_IPCOM) + -+static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,unsigned long arg) -+{ -+ struct zatm_dev *zatm_dev; -+ unsigned long flags; -+ int error; ++ifeq ($(CONFIG_PROC_FS),y) ++OBJS += proc.o ++endif + -+ zatm_dev = ZATM_DEV(dev); -+ switch (cmd) { -+ case ZATM_GETPOOLZ: -+ if (!suser()) return -EPERM; -+ /* fall through */ -+ case ZATM_GETPOOL: -+ { -+ int pool; ++ifeq ($(CONFIG_ATM_LANE),y) ++OBJS += lec.o lec_arpc.o ++endif + -+ error = verify_area(VERIFY_WRITE,(void *) arg, -+ sizeof(struct zatm_pool_req)); -+ if (error) return error; -+ error = verify_area(VERIFY_READ,(void *) arg, -+ sizeof(struct zatm_pool_req)); -+ /* paranoia ? */ -+ if (error) return error; -+ pool = get_fs_long(&((struct zatm_pool_req *) -+ arg)->pool_num); -+ if (pool < 0 || pool > ZATM_LAST_POOL) -+ return -EINVAL; -+ save_flags(flags); -+ cli(); -+ memcpy_tofs(&((struct zatm_pool_req *) arg)-> -+ info,&zatm_dev->pool_info[pool], -+ sizeof(struct zatm_pool_info)); -+ if (cmd == ZATM_GETPOOLZ) { -+ zatm_dev->pool_info[pool].rqa_count = 0; -+ zatm_dev->pool_info[pool].rqu_count = 0; -+ } -+ restore_flags(flags); -+ return 0; -+ } -+ case ZATM_SETPOOL: -+ { -+ int pool,low,high,next_thres; ++atm.o: $(OBJS) ++ $(LD) -r -o atm.o $(OBJS) + -+ if (!suser()) return -EPERM; -+ error = verify_area(VERIFY_READ,(void *) arg, -+ sizeof(struct zatm_pool_req)); -+ if (error) return error; -+ pool = get_fs_long(&((struct zatm_pool_req *) -+ arg)->pool_num); -+ if (pool < 0 || pool > ZATM_LAST_POOL) -+ return -EINVAL; -+ low = get_fs_long(&((struct zatm_pool_req *) -+ arg)->info.low_water); -+ high = get_fs_long(&((struct zatm_pool_req *) -+ arg)->info.high_water); -+ next_thres = get_fs_long( -+ &((struct zatm_pool_req *) arg)->info. -+ next_thres); -+ if (!low) -+ low = zatm_dev->pool_info[pool]. -+ low_water; -+ if (!high) -+ high = zatm_dev->pool_info[pool]. -+ high_water; -+ if (!next_thres) -+ next_thres = zatm_dev->pool_info[pool]. -+ next_thres; -+ if (low >= high || low < 0) return -EINVAL; -+ save_flags(flags); -+ cli(); -+ zatm_dev->pool_info[pool].low_water = low; -+ zatm_dev->pool_info[pool].high_water = high; -+ zatm_dev->pool_info[pool].next_thres = -+ next_thres; -+ restore_flags(flags); -+ return 0; -+ } -+#ifdef CONFIG_ATM_ZATM_EXACT_TS -+ case ZATM_GETTHIST: -+ { -+ int i; ++else + -+ error = verify_area(VERIFY_READ,(void *) arg, -+ sizeof(struct zatm_thist)* -+ ZATM_TIMER_HISTORY_SIZE); -+ if (error) return error; -+ save_flags(flags); -+ cli(); -+ for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++) { -+ memcpy_tofs((struct zatm_thist *) arg+i, -+ &zatm_dev->timer_history[ -+ (zatm_dev->th_curr+i) & -+ (ZATM_TIMER_HISTORY_SIZE-1)], -+ sizeof(struct zatm_thist)); -+ } -+ restore_flags(flags); -+ return 0; -+ } -+#endif -+ default: -+ if (!dev->phy->ioctl) return -EINVAL; -+ return dev->phy->ioctl(dev,cmd,arg); -+ } -+} ++atm.o: ++ $(AR) rcs atm.o + ++endif + -+static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int *optlen) -+{ -+#ifdef CONFIG_MMU_HACKS + -+static const struct atm_buffconst bctx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; -+static const struct atm_buffconst bcrx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; ++include $(TOPDIR)/Rules.make +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/addr.c Wed May 14 15:31:25 1997 +@@ -0,0 +1,157 @@ ++/* net/atm/addr.c - Local ATM address registry */ + -+#else ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+static const struct atm_buffconst bctx = { 4,0,4,0,0,0 }; -+static const struct atm_buffconst bcrx = { 4,0,4,0,0,0 }; + -+#endif -+ int error; ++#include ++#include ++#include ++#include + -+ if (level == SOL_AAL && (optname == SO_BCTXOPT || -+ optname == SO_BCRXOPT)) { -+ if (get_fs_long(optlen) < sizeof(struct atm_buffconst)) -+ return -EINVAL; -+ put_fs_long(sizeof(struct atm_buffconst),optlen); -+ error = verify_area(VERIFY_WRITE,optval, -+ sizeof(struct atm_buffconst)); -+ if (error) return error; -+ memcpy_tofs(optval,optname == SO_BCTXOPT ? &bctx : &bcrx, -+ sizeof(struct atm_buffconst)); -+ return 0; -+ } -+ return -EINVAL; -+} ++#include "signaling.h" ++#include "addr.h" + + -+static int zatm_setsockopt(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int optlen) ++static int check_addr(struct sockaddr_atmsvc *addr) +{ ++ int i; ++ ++ if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; ++ if (!*addr->sas_addr.pub) ++ if (!*addr->sas_addr.prv) return -EINVAL; ++ else return 0; ++ for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's \0-terminated */ ++ if (!addr->sas_addr.pub[i]) return 0; + return -EINVAL; +} + + -+#if 0 -+static int zatm_sg_send(struct atm_vcc *vcc,unsigned long start, -+ unsigned long size) ++static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b) +{ -+ return vcc->aal == ATM_AAL5; -+ /* @@@ should check size and maybe alignment*/ ++ if (*a->sas_addr.prv) ++ if (memcmp(a->sas_addr.prv,b->sas_addr.prv,ATM_ESA_LEN)) ++ return 0; ++ if (!*a->sas_addr.pub) return !*b->sas_addr.pub; ++ if (!*b->sas_addr.pub) return 0; ++ return !strcmp(a->sas_addr.pub,b->sas_addr.pub); +} -+#endif + + -+static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+ int error; ++/* ++ * Avoid modification of any list of local interfaces while reading it ++ * (which may involve page faults and therefore rescheduling) ++ */ + -+ EVENT(">zatm_send 0x%08x\n",(unsigned long) skb,0); -+ if (!ZATM_VCC(vcc)->tx_chan || !(vcc->flags & ATM_VF_READY)) { -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } -+ if (!skb) { -+ printk(KERN_CRIT "!skb in zatm_send ?\n"); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } -+ skb->atm.vcc = vcc; -+ error = do_tx(skb); -+ if (error != RING_BUSY) return error; -+ skb_queue_tail(&ZATM_VCC(vcc)->backlog,skb); -+ return 0; -+} + ++static volatile int local_lock = 0; ++static struct wait_queue *local_wait = NULL; + -+static void zatm_phy_put(struct atm_dev *dev,unsigned char value, -+ unsigned long addr) ++ ++static void lock_local(void) +{ -+ struct zatm_dev *zatm_dev; ++ while (local_lock) sleep_on(&local_wait); ++ local_lock = 1; ++} ++ + -+ zatm_dev = ZATM_DEV(dev); -+ zwait; -+ zout(value,CER); -+ zout(uPD98401_IND_ACC | uPD98401_IA_B0 | -+ (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); ++static void unlock_local(void) ++{ ++ local_lock = 0; ++ wake_up(&local_wait); +} + + -+static unsigned char zatm_phy_get(struct atm_dev *dev,unsigned long addr) ++static void notify_sigd(struct atm_dev *dev) +{ -+ struct zatm_dev *zatm_dev; ++ struct sockaddr_atmpvc pvc; + -+ zatm_dev = ZATM_DEV(dev); -+ zwait; -+ zout(uPD98401_IND_ACC | uPD98401_IA_B0 | uPD98401_IA_RW | -+ (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR); -+ zwait; -+ return zin(CER) & 0xff; ++ pvc.sap_addr.itf = dev->number; ++ sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL); +} + + -+static const struct atmdev_ops ops = { -+ zatm_open, -+ zatm_close, -+ zatm_ioctl, -+ zatm_getsockopt, -+ zatm_setsockopt, -+ zatm_send, -+ NULL /*zatm_sg_send*/, -+ NULL, /* no poll */ -+ NULL, /* no send_oam */ -+ zatm_phy_put, -+ zatm_phy_get, -+ zatm_feedback, -+ NULL, /* no change_qos */ -+ NULL /* no free_rx_skb */ -+}; ++void reset_addr(struct atm_dev *dev) ++{ ++ struct atm_dev_addr *this; ++ ++ lock_local(); ++ while (dev->local) { ++ this = dev->local; ++ dev->local = this->next; ++ kfree(this); ++ } ++ unlock_local(); ++ notify_sigd(dev); ++} + + -+int zatm_detect(void) ++int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +{ -+ struct atm_dev *dev; -+ struct zatm_dev *zatm_dev; -+ int devs,type,index; ++ struct atm_dev_addr **walk; ++ int error; + -+ if (!pcibios_present()) { -+ printk(KERN_ERR DEV_LABEL " driver but no PCI BIOS ?\n"); -+ return 0; -+ } -+ zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct zatm_dev), -+ GFP_KERNEL); -+ if (!zatm_dev) return -ENOMEM; -+ devs = 0; -+ for (type = 0; type < 2; type++) { -+ index = 0; -+ while (!pcibios_find_device(PCI_VENDOR_ID_ZEITNET,type ? -+ PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221, -+ index,&zatm_dev->bus,&zatm_dev->dev_fn)) { -+ dev = atm_dev_register(DEV_LABEL,&ops,0); -+ if (!dev) break; -+ ZATM_DEV(dev) = zatm_dev; -+ zatm_dev->copper = type; -+ if (zatm_init(dev) || zatm_start(dev)) { -+ atm_dev_deregister(dev); -+ break; -+ } -+ zatm_dev->more = zatm_boards; -+ zatm_boards = dev; -+ index++; -+ devs++; -+ zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct -+ zatm_dev),GFP_KERNEL); -+ if (!zatm_dev) break; ++ error = check_addr(addr); ++ if (error) return error; ++ lock_local(); ++ for (walk = &dev->local; *walk; walk = &(*walk)->next) ++ if (identical(&(*walk)->addr,addr)) { ++ unlock_local(); ++ return -EEXIST; + } ++ *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL); ++ if (!*walk) { ++ unlock_local(); ++ return -ENOMEM; + } -+ return devs; ++ (*walk)->addr = *addr; ++ (*walk)->next = NULL; ++ unlock_local(); ++ notify_sigd(dev); ++ return 0; +} + + -+#ifdef MODULE -+ -+int init_module(void) ++int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) +{ -+ if (!zatm_detect()) { -+ printk(KERN_ERR DEV_LABEL ": no adapter found\n"); -+ return -ENXIO; ++ struct atm_dev_addr **walk,*this; ++ int error; ++ ++ error = check_addr(addr); ++ if (error) return error; ++ lock_local(); ++ for (walk = &dev->local; *walk; walk = &(*walk)->next) ++ if (identical(&(*walk)->addr,addr)) break; ++ if (!*walk) { ++ unlock_local(); ++ return -ENOENT; + } -+ MOD_INC_USE_COUNT; ++ this = *walk; ++ *walk = this->next; ++ kfree(this); ++ unlock_local(); ++ notify_sigd(dev); + return 0; +} -+ -+ -+void cleanup_module(void) ++ ++ ++int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) +{ -+ /* -+ * Well, there's no way to get rid of the driver yet, so we don't -+ * have to clean up, right ? :-) -+ */ ++ struct atm_dev_addr *walk; ++ int total,error; ++ ++ lock_local(); ++ total = 0; ++ for (walk = dev->local; walk; walk = walk->next) { ++ total += sizeof(struct sockaddr_atmsvc); ++ if (total > size) { ++ unlock_local(); ++ return -E2BIG; ++ } ++ error = copy_to_user(u_buf,&walk->addr, ++ sizeof(struct sockaddr_atmsvc)); ++ if (error) return error; ++ u_buf++; ++ } ++ unlock_local(); ++ return total; +} -+ -+#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/zatm.h Fri Apr 4 19:56:15 1997 -@@ -0,0 +1,124 @@ -+/* drivers/atm/zatm.h - ZeitNet ZN122x device driver declarations */ ++++ work/net/atm/addr.h Thu Jul 3 08:25:18 1997 +@@ -0,0 +1,18 @@ ++/* net/atm/addr.h - Local ATM address registry */ + +/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + -+#ifndef DRIVER_ATM_ZATM_H -+#define DRIVER_ATM_ZATM_H ++#ifndef NET_ATM_ADDR_H ++#define NET_ATM_ADDR_H + -+#include +#include +#include -+#include -+ + -+#define DEV_LABEL "zatm" + -+#define MAX_AAL5_PDU 10240 /* allocate for AAL5 PDUs of this size */ -+#define MAX_RX_SIZE_LD 14 /* ceil(log2((MAX_AAL5_PDU+47)/48)) */ -+ -+#define LOW_MARK 12 /* start adding new buffers if less than 12 */ -+#define HIGH_MARK 30 /* stop adding buffers after reaching 30 */ -+#define OFF_CNG_THRES 5 /* threshold for offset changes */ -+ -+#define RX_SIZE 2 /* RX lookup entry size (in bytes) */ -+#define NR_POOLS 32 /* number of free buffer pointers */ -+#define POOL_SIZE 8 /* buffer entry size (in bytes) */ -+#define NR_SHAPERS 16 /* number of shapers */ -+#define SHAPER_SIZE 4 /* shaper entry size (in bytes) */ -+#define VC_SIZE 32 /* VC dsc (TX or RX) size (in bytes) */ -+ -+#define RING_ENTRIES 32 /* ring entries (without back pointer) */ -+#define RING_WORDS 4 /* ring element size */ -+#define RING_SIZE (sizeof(unsigned long)*(RING_ENTRIES+1)*RING_WORDS) -+ -+#define NR_MBX 4 /* four mailboxes */ -+#define MBX_RX_0 0 /* mailbox indices */ -+#define MBX_RX_1 1 -+#define MBX_TX_0 2 -+#define MBX_TX_1 3 -+ -+ -+#ifdef CONFIG_ATM_ZATM_EXACT_TS -+#define POLL_INTERVAL 60 /* TSR poll interval in seconds; must be <= -+ (2^31-1)/clock */ -+#define TIMER_SHIFT 20 /* scale factor for fixed-point arithmetic; -+ 1 << TIMER_SHIFT must be -+ (1) <= (2^64-1)/(POLL_INTERVAL*clock), -+ (2) >> clock/10^6, and -+ (3) <= (2^32-1)/1000 */ -+#define ADJ_IGN_THRES 1000000 /* don't adjust if we're off by more than that -+ many usecs - this filters clock corrections, -+ time zone changes, etc. */ -+#define ADJ_REP_THRES 20000 /* report only differences of more than that -+ many usecs (don't mention single lost timer -+ ticks; 10 msec is only 0.03% anyway) */ -+#define ADJ_MSG_THRES 5 /* issue complaints only if getting that many -+ significant timer differences in a row */ -+#endif -+ -+ -+struct zatm_vcc { -+ /*-------------------------------- RX part */ -+ int rx_chan; /* RX channel, 0 if none */ -+ int pool; /* free buffer pool */ -+ /*-------------------------------- TX part */ -+ int tx_chan; /* TX channel, 0 if none */ -+ int shaper; /* shaper, <0 if none */ -+ struct sk_buff_head tx_queue; /* list of buffers in transit */ -+ struct wait_queue *tx_wait; /* for close */ -+ unsigned long *ring; /* transmit ring */ -+ int ring_curr; /* current write position */ -+ int txing; /* number of transmits in progress */ -+ struct sk_buff_head backlog; /* list of buffers waiting for ring */ -+}; -+ -+struct zatm_dev { -+ /*-------------------------------- TX part */ -+ int tx_bw; /* remaining bandwidth */ -+ unsigned long free_shapers; /* bit set */ -+ int ubr; /* UBR shaper; -1 if none */ -+ int ubr_ref_cnt; /* number of VCs using UBR shaper */ -+ /*-------------------------------- RX part */ -+ int pool_ref[NR_POOLS]; /* free buffer pool usage counters */ -+ volatile struct sk_buff *last_free[NR_POOLS]; -+ /* last entry in respective pool */ -+ struct sk_buff_head pool[NR_POOLS];/* free buffer pools */ -+ struct zatm_pool_info pool_info[NR_POOLS]; /* pool information */ -+ /*-------------------------------- maps */ -+ struct atm_vcc **tx_map; /* TX VCCs */ -+ struct atm_vcc **rx_map; /* RX VCCs */ -+ int chans; /* map size, must be 2^n */ -+ /*-------------------------------- mailboxes */ -+ unsigned long mbx_start[NR_MBX];/* start addresses */ -+ unsigned short mbx_end[NR_MBX]; /* end offset (in bytes) */ -+ /*-------------------------------- other pointers */ -+ unsigned long pool_base; /* Free buffer pool dsc (word addr) */ -+ /*-------------------------------- ZATM links */ -+ struct atm_dev *more; /* other ZATM devices */ -+#ifdef CONFIG_ATM_ZATM_EXACT_TS -+ /*-------------------------------- timestamp calculation */ -+ u32 last_clk; /* results of last poll: clock, */ -+ struct timeval last_time; /* virtual time and */ -+ struct timeval last_real_time; /* real time */ -+ u32 factor; /* multiplication factor */ -+ int timer_diffs; /* number of significant deviations */ -+ struct zatm_thist timer_history[ZATM_TIMER_HISTORY_SIZE]; -+ /* record of timer synchronizations */ -+ int th_curr; /* current position */ -+#endif -+ /*-------------------------------- general information */ -+ int mem; /* RAM on board (in bytes) */ -+ int khz; /* timer clock */ -+ int copper; /* PHY type */ -+ unsigned char irq; /* IRQ */ -+ unsigned int base; /* IO base address */ -+ unsigned char bus; /* PCI stuff */ -+ unsigned char dev_fn; -+}; -+ -+ -+#define ZATM_DEV(d) ((struct zatm_dev *) (d)->dev_data) -+#define ZATM_VCC(d) ((struct zatm_vcc *) (d)->dev_data) -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/zeprom.h Fri Nov 15 19:06:27 1996 -@@ -0,0 +1,34 @@ -+/* drivers/atm/zeprom.h - ZeitNet ZN122x EEPROM (NM93C46) declarations */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef DRIVER_ATM_ZEPROM_H -+#define DRIVER_ATM_ZEPROM_H -+ -+/* Different versions use different control registers */ -+ -+#define ZEPROM_V1_REG PCI_VENDOR_ID /* PCI register */ -+#define ZEPROM_V2_REG 0x40 -+ -+/* Bits in contol register */ -+ -+#define ZEPROM_SK 0x80000000 /* strobe (probably on raising edge) */ -+#define ZEPROM_CS 0x40000000 /* Chip Select */ -+#define ZEPROM_DI 0x20000000 /* Data Input */ -+#define ZEPROM_DO 0x10000000 /* Data Output */ -+ -+#define ZEPROM_SIZE 32 /* 32 bytes */ -+#define ZEPROM_V1_ESI_OFF 24 /* ESI offset in EEPROM (V1) */ -+#define ZEPROM_V2_ESI_OFF 4 /* ESI offset in EEPROM (V2) */ -+ -+#define ZEPROM_CMD_LEN 3 /* commands are three bits */ -+#define ZEPROM_ADDR_LEN 6 /* addresses are six bits */ -+ -+/* Commands (3 bits) */ -+ -+#define ZEPROM_CMD_READ 6 -+ -+/* No other commands are needed. */ ++void reset_addr(struct atm_dev *dev); ++int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); ++int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); ++int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size); + +#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/tneta1570.h Wed Apr 2 22:38:00 1997 -@@ -0,0 +1,390 @@ -+/* drivers/atm/tneta1570.h - TI TNETA1570 (SAR) declarations */ -+ -+/* Written 1996 by Rolf Fiedler -+ * based on the atm drivers by Werner Almesberger, EPFL LRC -+ */ -+ -+#ifndef DRIVERS_ATM_TNETA1570_H -+#define DRIVERS_ATM_TNETA1570_H ++++ work/net/atm/clip.c Thu Jul 10 19:11:52 1997 +@@ -0,0 +1,476 @@ ++/* atmarp.c - RFC1577 ATM ARP */ + -+#include ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+#ifdef __KERNEL__ + ++#include ++#include ++#include /* for UINT_MAX */ ++#include ++#include ++#include ++#include ++#include /* for some manifest constants */ ++#include +#include +#include -+#include -+#include -+#include ++#include ++#include ++#include /* for net/route.h */ ++#include /* for struct sockaddr_in */ ++#include /* for IFF_UP */ ++#include /* for struct rtable and ip_rt_route */ ++#include /* for arp_find_1 */ ++#include /* for HZ */ ++#include /* for htons etc. */ ++#include /* save/restore_flags */ ++#include ++#include + -+#define NR_VCI 256 -+#define NR_VCI_LD 8 -+#define NR_VPI 32 -+#define NR_VPI_LD 5 -+#define MAX_VCI 255 -+#define MAX_VPI 255 -+ -+/* this is better put in pci.h, but I want to keep my driver independent */ -+#define MEM_VALID 0xfffffff0 -+#ifndef PCI_VENDOR_ID_TI -+#define PCI_VENDOR_ID_TI 0x104c -+#endif -+#ifndef PCI_DEVICE_ID_TI_TNETA1570 -+#define PCI_DEVICE_ID_TI_TNETA1570 0xa001 -+#endif -+#ifndef PCI_DEVICE_ID_TI_TNETA1575 -+#define PCI_DEVICE_ID_TI_TNETA1575 0xa102 -+#endif ++#include "common.h" ++#include "tunable.h" ++#include "protocols.h" /* for atm_push_raw */ ++#include "ipcommon.h" ++#include + + -+#define DEV_LABEL "tneta157x" -+#define RAM_INCREMENT 1024 /* check in 4 kB increments */ -+ -+#ifdef CONFIG_ALPHA_CIA -+#define TNETA1570_MEM_OFFSET CIA_DENSE_MEM -+#define TNETA_ALIGN 7 -+#elif CONFIG_ALPHA_LCA -+#define TNETA1570_MEM_OFFSET LCA_DENSE_MEM -+#define TNETA_ALIGN 7 ++#if 0 ++#define DPRINTK(format,args...) printk(format,##args) +#else -+#define TNETA1570_MEM_OFFSET 0 -+#define TNETA_ALIGN 3 ++#define DPRINTK(format,args...) +#endif + + -+/*---------------------------------------------------------*/ -+ -+/* transmit DMA state table, in control memory */ -+struct tneta_tx_dma_state_table{ -+ unsigned int control; -+ unsigned int current_buffer_ptr; -+ unsigned int atm_header; -+ unsigned int dma_state_flag; /* only initialized value */ -+ unsigned int next_buffer_ptr; -+ unsigned int start_of_buffer_address; -+ unsigned int partial_AAL5_tx_CRC; -+ unsigned int AAL5_control_length_field; -+}; -+ -+/* receive DMA state table, in control memory */ -+#define RX_DMA_CONTROL_AAL5 ((1<<29)|(1<<26)) -+#define RX_DMA_CONTROL_AAL0 ((1<<29)|(1<<27)) -+#define RX_TIME_OUT (0xfff<<12) -+#define DMA_ON (1<<31) -+#define DMA_FILTER (1<<30) -+struct tneta_rx_dma_state_table{ -+ unsigned int control; /* needs initialization */ -+ unsigned int current_buffer_ptr; -+ unsigned int sob_ptr; -+ unsigned int EOP; -+ unsigned int sop_ptr; -+ unsigned int AAL0_cells; /* needs initialization if AAL0 */ -+ unsigned int dma_on_idx; /* needs initialization */ -+ unsigned int rx_timeout; /* needs initialization */ -+}; -+ -+#define MAX_AAL5_PDU 9600 /* max size for AAL5 PDUs buffers */ -+#define MAX_AAL5_CELLS 200 -+#define MAX_AAL0_PDU 48 -+#define MAX_AAL0_CELLS 1 -+#define AAL0_BUFS 32 -+#define AAL5_BUFS 16 -+#define FBR_AAL0_32 ((2<<16) | (1<<10) | (0)) -+#define FBR_AAL5_16 ((MAX_AAL5_CELLS<<16) | (0<<10) | (0)) -+#define RX_HDR 20 -+#define MAX_FBR_ENTRIES 256 -+struct tneta_rx_fbrptr { -+ unsigned int buf_ptr; -+ unsigned int buf_size; -+}; -+ -+#define AAL5_IND (1<<26) -+#define PAKET_OVERFLOW (1<<31) -+#define CRC_ERROR (1<<30) -+#define BUFFER_STARV (1<<29) -+#define RX_TIMEOUT (1<<28) -+#define RX_ABORT (1<<27) -+#define RX_ERRORCOND 0xf000 -+ -+struct tneta_rx_compl { -+ unsigned int atm_header; -+ unsigned int error; -+ unsigned int buf_ptr; -+ unsigned int trailer; -+ unsigned int control; /* needs initialization */ -+ unsigned int res1; -+ unsigned int res2; -+ unsigned int res3; -+}; -+ -+/* device dependent vcc data */ -+#define TX_SEG_RING_SIZE 256 -+ -+struct tneta1570_vcc { -+ /*-------------------------------- RX part */ -+ int (*rx)(struct atm_vcc *vcc); -+ int rxing; /* pending cells */ -+ struct wait_queue * rx_wait; /* for close */ -+ int dma_channel; /* for close */ -+ int fbr_idx; -+ /*-------------------------------- TX part */ -+ struct wait_queue * tx_wait; /* for close */ -+ int txing; /* cells to be tx'd */ -+ int scheduler_idx; /* index in scheduler table */ -+ unsigned int * seg_ring; /* size aligned 1K */ -+ unsigned int * seg_ring_mptr; /* word aligned */ -+ int seg_ring_idx; -+ -+ struct atm_vcc *next; /* next pending rx */ -+ struct sk_buff *last; /* last PDU */ -+}; -+ -+ -+/* device dependent data */ -+#define TXCMPLR_SZ_IRQ 256 /* size aligned */ -+#define TXCMPLR_SZ_NOI 128 /* size aligned */ -+#define RXCMPLR_SZ_IRQ 128 /* size aligned */ -+#define RXCMPLR_SZ_NOI 64 /* size aligned */ -+#define SAR_REG_WORD(dev, x) (dev->reg[x]) -+#define SAR_REG_SHORT(dev, x) (((unsigned short *)dev->reg)[x]) -+#define MAX_SCHED_ENTRIES 1022 -+#define MAX_TXDMA_ENTRIES 1022 -+#define TX_CMPL_R_IRQ(dev) (dev->txcmplringptr_irq[dev->txcmpl_ring_idx_irq]) -+#define TX_CMPL_R_NOI(dev) (dev->txcmplringptr_noi[dev->txcmpl_ring_idx_noi]) -+#define RX_CMPL_R_IRQ(dev) (dev->rxcmplringptr_irq[dev->rxcmpl_ring_idx_irq]) -+#define RX_CMPL_R_NOI(dev) (dev->rxcmplringptr_noi[dev->rxcmpl_ring_idx_noi]) ++struct device *clip_devs = NULL; ++struct atm_vcc *atmarpd = NULL; ++static struct wait_queue *atmarpd_sleep = NULL; + -+struct tneta1570_dev { -+ /*-------------------------------- TX part */ -+ int txcmpl_ring_idx_noi, txcmpl_ring_idx_irq; -+ unsigned int *txcmplringptr_noi, *txcmplringptr_irq; -+ unsigned int *txcmpl_ring; -+ -+ /*-------------------------------- RX part */ -+ int rxcmpl_ring_idx_noi, rxcmpl_ring_idx_irq; -+ struct tneta_rx_compl *rxcmplringptr_noi, *rxcmplringptr_irq; -+ struct tneta_rx_compl *rxcmpl_ring; -+ -+ /*-------------------------------- maps */ -+ int oam_fbr_idx; -+ -+ /*-------------------------------- stats */ -+ unsigned int lost; /* lost rx cells */ -+ /*-------------------------------- other pointers */ + -+ /*-------------------------------- TNETA links */ -+ struct atm_dev *more; /* other TNETA devices */ -+ /*-------------------------------- general information */ -+ -+ volatile unsigned int *ram; /* base of phy device */ -+ volatile unsigned int *scheduler; /* base of scheduler table */ -+ volatile unsigned int *reg; /* base of sar regs device */ -+ volatile struct tneta_rx_fbrptr *free_buf_ptr; /* free buffer pointers */ -+ volatile unsigned int *rx_vpi_vci; /* rx vpi vci table */ -+ volatile struct tneta_tx_dma_state_table *tx_dma_state; /* tx dma state table */ -+ volatile struct tneta_rx_dma_state_table *rx_dma_state; /* rx dma state table */ -+ volatile unsigned int *phy; /* base of phy device */ -+ -+ int mem; /* RAM on board (in bytes) */ -+ void * base; /* board base address */ -+ unsigned long base_diff; /* virtual - phy base address */ -+ unsigned int pci_map_size; /* pci map size of board */ -+ unsigned char irq; /* IRQ */ -+ unsigned char chiptype; /* 1570 = 0, 1575 = 1 */ -+ unsigned char bus; /* PCI stuff */ -+ unsigned char dev_fn; -+}; ++#define WAITING 1 /* see also signaling.h */ + + -+#define TNETA1570_DEV(d) ((struct tneta1570_dev *) (d)->dev_data) -+#define TNETA1570_VCC(d) ((struct tneta1570_vcc *) (d)->dev_data) ++static int atmarpd_send(struct atm_vcc *vcc,struct sk_buff *skb) ++{ ++ struct atmarp_ctrl *ctrl; + -+/*---------------------------------------------------------*/ ++ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); ++ ctrl = (struct atmarp_ctrl *) skb->data; ++ if (ctrl->magic != ATMARP_CTRL_MAGIC) { ++ printk(KERN_ALERT "atmarpd_send: bad magic 0x%x\n", ++ ctrl->magic); ++ return -EPROTO; ++ } ++ if (ctrl->type != act_complete) { ++ printk(KERN_ALERT "atmarpd_send: bad type 0x%x\n",ctrl->type); ++ return -EPROTO; ++ } ++ if (!ctrl->reply) { ++ printk(KERN_ALERT "atmarpd_send: no reply\n"); ++ return -EPROTO; ++ } ++ *ctrl->reply = ctrl->arg; ++ wake_up(&atmarpd_sleep); ++ dev_kfree_skb(skb,FREE_WRITE); ++ return 0; ++} + -+#include + -+#define TNETA_LOOP _IOW('a',ATMIOC_SARPRV+1,int) -+ /* set/reset tneta loopback mode*/ -+#define TNETA_INVHEC _IOW('a',ATMIOC_SARPRV+2,long) -+ /* set/reset inverse HEC generation */ -+#define TNETA_ENTX _IOW('a',ATMIOC_SARPRV+3,long) -+ /* enable/disab txing */ -+#define TNETA_ENRX _IOW('a',ATMIOC_SARPRV+4,long) -+ /* enable/disabable rxing */ -+#define TNETA_BP _IOW('a',ATMIOC_SARPRV+5,long) -+ /* intr per paket or per buffer ring */ -+#define TNETA_RAT _IOW('a',ATMIOC_SARPRV+6,int) -+ /* enable/disable rx aging timer*/ -+#define TNETA_RXUNKN _IOR('a',ATMIOC_SARPRV+7,unsigned long) -+ /* header of an unknown received cell */ -+#define TNETA_HECERR _IOR('a',ATMIOC_SARPRV+8, unsigned long) -+ /* number of HEC errors received */ -+#define TNETA_AAL5DISC _IOR('a',ATMIOC_SARPRV+9, unsigned long) -+ /* number of AAL 5 pdus discarded by tneta */ -+#define TNETA_RXCELL _IOR('a',ATMIOC_SARPRV+10, unsigned long) -+ /* number of cells received */ -+#define TNETA_TXCELL _IOR('a',ATMIOC_SARPRV+11, unsigned long) -+ /* number of cells transmitted */ ++static int send_demon(enum atmarp_ctrl_type type,int itf,unsigned long arg, ++ void *data,int length) ++{ ++ struct atmarp_ctrl *ctrl; ++ struct sk_buff *skb; ++ int size,need_reply; ++ volatile int reply; + ++ DPRINTK("send_demon(%d)\n",type); ++ if (!atmarpd) return -EUNATCH; ++ size = sizeof(struct atmarp_ctrl)+(data ? length : 0); ++ skb = alloc_skb(size,GFP_ATOMIC); ++ if (!skb) return -ENOMEM; ++ ctrl = (struct atmarp_ctrl *) skb_put(skb,size); ++ need_reply = type == act_ioctl || type == act_create; ++ ctrl = (struct atmarp_ctrl *) skb->data; ++ ctrl->magic = ATMARP_CTRL_MAGIC; ++ ctrl->type = type; ++ ctrl->reply = need_reply ? &reply : NULL; ++ ctrl->itf_num = itf; ++ ctrl->arg = arg; ++ if (data) memcpy(ctrl->data,data,length); ++ reply = WAITING; ++ atomic_add(skb->truesize+ATM_PDU_OVHD,&atmarpd->rx_inuse); ++ skb_queue_tail(&atmarpd->recvq,skb); ++ wake_up(&atmarpd->sleep); ++ if (!need_reply) return 0; ++ while (reply == WAITING && atmarpd) sleep_on(&atmarpd_sleep); ++ return atmarpd ? reply : -EUNATCH; ++} + -+ -+ -+/* -+ * Directly Addressable Registers, memory mapped -+ */ -+#define TNETA_REG_BASE_OFFSET 0x3200 /* offset PCI base to registers */ -+#define TNETA_CONFIG 0 /* configuration register */ -+#define TNETA_STATUS 1 /* status register */ -+#define TNETA_INT_MASK 2 /* interrupt mask register */ -+#define TNETA_S_RAT 6 /* 3L RAT cycle # rx DMA state table */ -+#define TNETA_S_RGT 7 /* 3H global reass. timer */ -+#define TNETA_RXUNKNOWN 4 /* rx unknown register */ -+#define TNETA_S_TXCOMPLSIZEI 10 /* 5L TX compl. ring size W/ interrupt */ -+#define TNETA_S_TXCOMPLSIZE 11 /* 5H TX compl. ring size W/O interrupt */ -+#define TNETA_S_RXCOMPLSIZEI 12 /* 6L RX completion ring size W/ interrupt */ -+#define TNETA_S_RXCOMPLSIZE 13 /* 6H RX completion ring size W/O interrupt */ -+#define TNETA_S_FIFO_FREE 14 /* 7L FIFO free-buffer-size */ -+#define TNETA_S_TXSEGSIZE 15 /* 7H Segmentation ring size */ -+#define TNETA_S_AAL_DISCARD 16 /* 8L discarded AAL5 rx cell counter */ -+#define TNETA_S_HEC_ERR 17 /* 8H HEC error counter */ -+#define TNETA_UNKNOWN_P 9 /* Unknown Protocols RX # */ -+#define TNETA_CELL_RXC 10 /* ATM Cells RX'd # */ -+#define TNETA_CELL_TXC 11 /* ATM Cells TX'd # */ -+#define TNETA_S_TXM_RXM 24 /* 12L TX FIFO & RX FIFO max occupancy */ -+#define TNETA_TXM_RXM 12 /* TX FIFO & RX FIFO for 1575 */ -+#define TNETA_S_VCIM 25 /* 12H VCI mask */ -+#define TNETA_S_SCHEDSIZE 26 /* 13L scheduler-table-size register */ -+#define TNETA_SCHEDSIZE 13 /* scheduler-table-size register 1575 only */ -+#define TNETA_RESET 14 /* software reset register */ -+#define TNETA_TXQUEUE 15 /* TX queue register 1575 only*/ -+#define TNETA_RXCOMPLCNT 16 /* RX compl ring count 1575 only */ -+#define TNETA_SIDEFBR1CNT 17 /* sideband free buffer ring cnt 1575 only */ -+#define TNETA_SIDEFBR2CNT 18 /* sideband free buffer ring cnt1575 only */ -+#define TNETA_RXTRES 19 /* rx compl ring threshold 1575 only */ -+#define TNETA_SIDERXTRES 20 /* sideband free buffer ring thresh 1575 only */ -+#define TNETA_SIDEFBR1PTR 21 /* sideband free buffer ring ptr 1575 only */ -+#define TNETA_SIDEFBR2PTR 22 /* sideband free buffer ring ptr 1575 only */ -+#define TNETA_SIDEFBR1SIZE 23 /* sideband free buffer ring size 1575 only */ -+#define TNETA_SIDEFBR2SIZE 24 /* sideband free buffer ring size 1575 only */ -+#define TNETA_CHNLADD1 25 /* channel add/del register 1 1575 only */ -+#define TNETA_CHNLADD2 26 /* channel add/del register 2 1575 only */ -+#define TNETA_TXPAUSE 27 /* transmit pause 1575 only */ -+#define TNETA_DMACOUNT 28 /* dma channel count 1575 only */ -+ -+#define TNETA_TXCOMPLNOI 128 /* TX completion ring W/O interrupt pointer */ -+#define TNETA_TXCOMPLIRQ 129 /* TX completion ring W/ interrupt pointer */ -+#define TNETA_RXCOMPLNOI 130 /* RX completion ring W/O interrupt pointer */ -+#define TNETA_RXCOMPLIRQ 131 /* RX completion ring W/ interrupt pointer */ -+ -+/* configuration register bits */ -+#define TNETA_R0_TXBLOCK 0x40000 /* block txing 1575 only */ -+#define TNETA_R0_ENBBUS 0x20000 /* enable bus reports 1575 only */ -+#define TNETA_R0_NOPOLLTX 0x10000 /* enable performance tx 1575 only */ -+#define TNETA_R0_NOPOLLRX 0x8000 /* enable performance rx 1575 only */ -+#define TNETA_R0_COPRO 0x4000 /* coprocessor present 1575 only */ -+#define TNETA_R0_UNI 0x2000 /* uni / nni */ -+#define TNETA_R0_MAX_RETRY (0xf << 9) /* 1111 max retry master */ -+#define TNETA_R0_LOOP 0x0100 /* set to loop-back (reset!, no enable) */ -+#define TNETA_R0_TX_HECERR 0x0080 /* force HEC error */ -+#define TNETA_R0_SMALL_MAP 0x0040 -+#define TNETA_R0_TX_ENABLE 0x0020 -+#define TNETA_R0_RX_ENABLE 0x0010 -+#define TNETA_R0_ENDIAN (0x0 << 3) /* 00 little endian */ -+#define TNETA_R0_PERBUFFER 0x002 -+#define TNETA_R0_RAT_ENABL 0x001 /* enable reass. aging timer */ -+#define TNETA_R0_STANDARD_MODE 0x00002000 -+ -+/* status register bits */ -+ -+#define TNETA_R1_LOCALBUS 0x8000 /* local bus interrupt ? 1575 only */ -+#define TNETA_R1_COPRO 0x4000 /* copro interrupt ? 1575 only */ -+#define TNETA_R1_SIDE1 0x2000 /* rx sideband 1 interrupt? 1575 only */ -+#define TNETA_R1_SIDE2 0x1000 /* rx sideband 2 interrupt? 1575 only */ -+#define TNETA_R1_RXCOMP 0x800 /* rx compl half inter. ? 1575 only */ -+#define TNETA_R1_RXHALF 0x400 /* Rx fifo half full 1575 only */ -+#define TNETA_R1_PCI_MODE 0x400 /* 32/64 bit */ -+#define TNETA_R1_RX_FREEZE 0x200 /* rx ring overflow */ -+#define TNETA_R1_TX_FREEZE 0x100 /* tx ring overflow */ -+#define TNETA_R1_CP_RX 0x080 /* packet reassembly completed */ -+#define TNETA_R1_RX_IRR 0x040 /* rx-unknown written */ -+#define TNETA_R1_HEC_OVER 0x020 /* HEC error counter overflow */ -+#define TNETA_R1_UP_OVER 0x010 /* unknown proto counter overflow */ -+#define TNETA_R1_APD_OVER 0x008 /* AAL5 PDU discard counter overflow */ -+#define TNETA_R1_ACR_OVER 0x004 /* ATM cell rxd counter overflow */ -+#define TNETA_R1_ACT_OVER 0x002 /* ATM cell txd counter overflow */ -+#define TNETA_R1_CP_TX 0x001 /* packet segmentation completed */ -+#define TNETA_R2_STANDARD_INTS (TNETA_R1_RX_FREEZE | \ -+ TNETA_R1_TX_FREEZE | \ -+ TNETA_R1_RX_IRR | \ -+ TNETA_R1_CP_RX | \ -+ TNETA_R1_CP_TX) -+/* control memory map offsets */ -+#define TNETA_SCHED_TABLE 0x0 -+#define TNETA_FREE_BUFFER_POINTERS 0x3800 -+#define TNETA_RX_VPIVCI_DMA_POINTERS 0x4000 -+#define TNETA_TX_DMA_STATE_TABLE 0x8000 -+#define TNETA_RX_DMA_STATE_TABLE 0x10000 -+#define TNETA_SUNI_OFFSET (0x20000 << 2) -+ -+/* reserved control memory area */ -+#define RESERVED_LL 0xc00 /* lower limit */ -+#define RESERVED_UL 0xe00 /* upper limit */ -+ -+#define TNETA_SUNI_RDREQ 0x00100 -+#define TNETA_SUNI_RD_D_AV (0x10) -+ -+#define OWN (0x1 << 31) /* own bit, set to 1 if owned by tneta1570 */ -+#define SEG_PTR(x) (0x3fffff00 & ((unsigned int)virt_to_bus(x) >> 2)) -+#define BUF_PTR(x) (((unsigned int)x >> 2) & 0x3fffffff) -+ /* pointer to tx data buffer header, aligned to 4 byte */ -+ -+/* tx data buffer header */ -+struct tx_buffer_descriptor{ -+ unsigned int control; -+ unsigned int next_buffer; -+ unsigned int atm_header; -+ unsigned int AAL5_control; -+}; -+ -+/* control word layout */ -+#define TNETA_TXDBH_CTRL_RDY (0x1 << 31) -+#define TNETA_TXDBH_CTRL_SOP (0x1 << 30) -+#define TNETA_TXDBH_CTRL_EOP (0x1 << 29) -+#define TNETA_TXDBH_CTRL_ABORT (0x1 << 28) -+#define TNETA_TXDBH_CTRL_AAL0_PTI (0x0 << 26) -+#define TNETA_TXDBH_CTRL_AAL5 (0x1 << 26) -+#define TNETA_TXDBH_CTRL_AAL0_NOPTI (0x2 << 26) -+#define TNETA_TXDBH_CTRL_INT_NOINT (0x1 << 25) -+#define TNETA_TXDBH_CTRL_BUF_OFFSET (0xff << 16) -+#define TNETA_TXDBH_CTRL_BYTE_COUNT (0xffff << 0) -+ -+#define AAL5_PDU_INT (TNETA_TXDBH_CTRL_RDY | \ -+ TNETA_TXDBH_CTRL_SOP | \ -+ TNETA_TXDBH_CTRL_EOP | \ -+ TNETA_TXDBH_CTRL_AAL5 | \ -+ TNETA_TXDBH_CTRL_INT_NOINT) -+ -+#define AAL0_PDU_INT (TNETA_TXDBH_CTRL_RDY | \ -+ TNETA_TXDBH_CTRL_SOP | \ -+ TNETA_TXDBH_CTRL_EOP | \ -+ TNETA_TXDBH_CTRL_AAL0_PTI) -+ -+/* ATM header */ -+#define TNETA_TXDBH_ATMH_GFC (0xff << 24) -+#define TNETA_TXDBH_ATMH_VPI (0xff << 16) -+#define TNETA_TXDBH_ATMH_VCI (0xffff << 4) -+#define TNETA_TXDBH_ATMH_PTI (0x7 << 1) -+#define TNETA_TXDBH_ATMH_CLP (0x1 << 0) -+ -+/* AAL5 control */ -+#define TNETA_TXDBH_AAL5_CPCS_UU (0xff << 24) -+#define TNETA_TXDBH_AAL5_CPI (0xffff << 16) -+#define TNETA_TXDBH_AAL5_USER (0xffff << 0) -+ -+/* TX completion rings */ -+#define TNETA_TXCR_OWN (0x1 << 31) -+#define TNETA_TXCR_ABORT (0x1 << 30) -+#define TNETA_TXCR_BUFADDR (0x3fffffff << 0) -+ -+#endif __KERNEL__ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/tneta1570.c Thu Feb 6 19:26:48 1997 -@@ -0,0 +1,1626 @@ -+/* drivers/atm/tneta1570.c - ti tneta1570 atm driver -+ * -+ * Copyright (c) 1996 University of Technology Chemnitz -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Written 1996 by Rolf Fiedler (atm@infotech.tu-chemnitz.de) -+ * -+ * 08/08/1996 adapted to axp, phy access, 64 bit bus access -+ * some minor bugs in dma allocation,segring overflow, -+ * timeout,... removed -+ * (paetz@infotech.tu-chemnitz.de) -+ * 10/01/1996 bug in dma channel allocattion fixed (multiple channels) -+ * -+*/ -+ -+#include /* for extended debugging options */ + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* for xtime */ -+#include -+#include -+#include -+#include -+#include -+#include ++static void clip_push(struct atm_vcc *vcc,struct sk_buff *skb) ++{ ++ DPRINTK("clip push\n"); ++ if (!skb) { ++ DPRINTK("removing AE\n"); ++ /* @@@ panic ... */ ++ return; ++ } ++ skb->dev = vcc->ip_dev; ++ skb->mac.raw = skb->data; ++ if (!skb->dev->hard_header_len) skb->protocol = htons(ETH_P_IP); ++ else if (skb->len < RFC1483LLC_LEN || memcmp(skb->data,llc_oui, ++ sizeof(llc_oui))) skb->protocol = 0; ++ /* probably wrong encap ... */ ++ else { ++ skb->protocol = ((unsigned short *) skb->data)[3]; ++ skb_pull(skb,RFC1483LLC_LEN); ++ if (vcc && skb->protocol == htons(ETH_P_ARP)) { ++ PRIV(skb->dev)->stats.rx_packets++; ++ atm_push_raw(vcc,skb); ++ return; ++ } ++ } ++ PRIV(skb->dev)->stats.rx_packets++; ++ netif_rx(skb); ++} + -+#include "tneta1570.h" -+#include "suni.h" + -+#define SLOW_DOWN_FACTOR 8 -+#define TNETA1570_TIMEOUT 5*HZ -+/* -+ * KNOWN BUGS: -+ * OAM support ??? , various vci/vpis -+ * doesn't work a bit -+ */ ++static int clip_hard_header(struct sk_buff *skb,struct device *dev, ++ unsigned short type,void *daddr,void *saddr,unsigned len) ++{ ++ void *here; + -+inline void write_sched_tab(struct tneta1570_dev * dev, int i, unsigned int v); -+inline int read_sched_tab(struct tneta1570_dev * dev, int i); -+static void dequeue_OAM(struct atm_dev *dev); /* dequeue OAM cells */ -+static void dequeue_AAL0(struct atm_dev *dev); /* dequeue AAL0 cells */ -+static void dequeue_AAL5(struct atm_dev *dev); /* dequeue AAL5 cells */ -+static int alloc_dma(struct atm_vcc *vcc); -+static unsigned char tneta1570_phy_get(struct atm_dev *,unsigned long); -+static void tneta1570_phy_put(struct atm_dev *,unsigned char, unsigned long); ++ DPRINTK("clip_hard_header\n"); ++ here = skb_push(skb,RFC1483LLC_LEN); ++ memcpy(here,llc_oui,sizeof(llc_oui)); ++ ((unsigned short *) here)[3] = htons(type); ++ skb->atm.encap = 1; ++ return RFC1483LLC_LEN; ++} + + ++static int clip_rebuild_header(struct sk_buff *skb) ++{ ++ DPRINTK("clip_rebuild_header\n"); ++ return 0; +#if 0 -+#define DPRINTK(format,args...) printk(format,args...) -+#else -+#define DPRINTK(format,args...) ++ if (!skb->dst || !skb->dst->neighbour) return 0; ++ return skb->dst->neighbour->ops->resolve(skb->data,skb); +#endif -+ -+#ifndef CONFIG_ATM_TNETA1570_DEBUG -+ -+ -+#define NULLCHECK(x) -+ -+#define EVENT(s,a,b) -+ -+ -+static inline void event_dump(void) -+{ +} + + ++static int clip_hard_header_cache(struct dst_entry *dst, ++ struct neighbour *neigh,struct hh_cache *hh) ++{ ++ DPRINTK("clip_hard_header_cache\n"); ++ if (hh->hh_type != ETH_P_IP) { ++ printk("clip: what is type %x ??\n",htons(hh->hh_type)); ++ hh->hh_uptodate = 0; ++ } ++#ifdef CONFIG_INET ++ hh->hh_uptodate = arp_find_1((unsigned char *) hh->hh_data,dst,neigh); +#else ++ hh->hh_uptodate = 0; ++#endif ++ return 0; ++} + + -+/* -+ * NULL pointer checking -+ */ -+ -+#define NULLCHECK(x) \ -+ if ((unsigned long) (x) < 0x30) printk(#x "==0x%x\n", (int) (x)) -+ -+/* -+ * Very extensive activity logging. Greatly improves bug detection speed but -+ * costs a few Mbps if enabled. -+ */ -+ -+#define EV 64 -+ -+static const char *ev[EV]; -+static unsigned long ev_a[EV],ev_b[EV]; -+static int ec = 0; -+ -+static void EVENT(const char *s,unsigned long a,unsigned long b) ++static void clip_header_cache_update(struct hh_cache *hh,struct device *dev, ++ unsigned char *haddr) +{ -+ ev[ec] = s; -+ ev_a[ec] = a; -+ ev_b[ec] = b; -+ ec = (ec+1) % EV; ++ DPRINTK("clip_header_cache_update\n"); ++ if (hh->hh_type != ETH_P_IP) { ++ printk("clip: what is type %x ??\n",htons(hh->hh_type)); ++ return; ++ } ++ memcpy(hh->hh_data,haddr,dev->addr_len); ++ hh->hh_uptodate = 1; +} + + -+static void event_dump(void) ++static int clip_start_xmit(struct sk_buff *skb,struct device *dev) +{ -+ int n,i; -+ -+ for (n = 0; n < EV; n++) { -+ i = (ec+n) % EV; -+ printk(ev[i] ? ev[i] : "(null)",ev_a[i],ev_b[i]); ++int i; ++if (!skb->dst) printk("GRRR: no dst\n"); ++else if (!skb->dst->neighbour) printk("GRRR: no neighbour\n"); ++ else skb->atm.vcc = (struct atm_vcc *) skb->dst->neighbour->ll_priv; ++ if (!skb->atm.vcc) { ++ printk(KERN_ERR "clip: argl, !atm.vcc\n"); ++ dev_kfree_skb(skb,FREE_WRITE); ++ return 0; + } ++ /* @@@ undo encap if not needed */ ++ atomic_add(skb->truesize,&skb->atm.vcc->tx_inuse); ++ skb->atm.iovcnt = 0; ++#if 0 ++printk("skb<%p>->atm.vcc<%p>->dev<%p>->ops<%p>->send<%p>\n", ++ skb,skb->atm.vcc,skb->atm.vcc->dev,skb->atm.vcc->dev->ops, ++ skb->atm.vcc->dev->ops->send); ++#endif ++ skb->atm.vcc->dev->ops->send(skb->atm.vcc,skb); ++#if 0 ++for (i = 0; i < skb->len && i < 25; i++) { ++ printk("%02x ",((unsigned char *) skb->data)[i]); ++#endif ++} ++ PRIV(dev)->stats.tx_packets++; ++ return 0; +} + + -+#endif /* CONFIG_ATM_TNETA1570_DEBUG */ ++static struct enet_statistics *clip_get_stats(struct device *dev) ++{ ++ return &PRIV(dev)->stats; ++} + + -+static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0, -+ backlogged = 0,rx_enqueued = 0,rx_dequeued = 0,pushed = 0,submitted = 0, -+ putting = 0; ++int clip_mkip(struct atm_vcc *vcc) ++{ ++ struct sk_buff_head copy; ++ struct sk_buff *skb; ++ unsigned long flags; + -+static struct atm_dev *tneta1570_boards = NULL; ++ save_flags(flags); ++ cli(); ++ vcc->ip_dev = clip_devs; /* arbitrary default */ ++ vcc->push = clip_push; ++ skb_migrate(&vcc->recvq,©); ++ atomic_set(&vcc->rx_inuse,0); ++ restore_flags(flags); ++ while ((skb = skb_dequeue(©))) clip_push(vcc,skb); ++ return 0; ++} + + -+/*-------------------------------- utilities --------------------------------*/ ++int clip_setentry(struct atm_vcc *vcc,u32 ip) ++{ ++ struct device *dev; ++ struct rtable *rt; ++ int error; ++ void **ll_priv; ++ ++ error = ip_route_output(&rt,ip,0,1,NULL); ++ if (error) return error; ++ dev = rt->u.dst.dev; ++ ip_rt_put(rt); ++ vcc->ip_dev = dev; ++printk("setting (&vcc %p, vcc %p, vcc->dev %p)\n",&vcc,vcc,vcc->dev); ++ ll_priv = NULL; ++ error = arp_update(ip,(void *) llc_oui,dev,0,0,&ll_priv); ++ /* @@@ should change arp_update, arpd_update, and arpd_send to ++ use const, but since most of the ARP stuff is changing ++ anyway, I don't want to bother for now */ ++ if (error < 0) return error; ++ if (!ll_priv) { ++ printk(KERN_ERR "clip_setentry: no ll_priv ??\n"); ++ return -EINVAL; ++ } ++ vcc->more = *ll_priv; ++ *ll_priv = vcc; ++ return 0; ++} + + -+static void dump_mem(struct tneta1570_dev *tneta1570_dev) ++void clip_resolve(struct device *dev,u32 ip) +{ ++ send_demon(act_need,PRIV(dev)->number,ip,NULL,0); +} + + -+static void dump(struct atm_dev *dev) ++int clip_ioctl(struct device *dev,unsigned int cmd,void *arg) +{ -+ struct tneta1570_dev *tneta1570_dev; ++ struct atmarpreq req; ++ __u32 *ip; ++ int error; + -+ tneta1570_dev = TNETA1570_DEV(dev); -+ printk("\nFree memory\n"); -+ dump_mem(tneta1570_dev); -+ printk("TX buffers\n"); ++ DPRINTK("clip_ioctl\n"); ++ error = copy_from_user(&req,arg,sizeof(struct atmarpreq)); ++ if (error) return error; ++ if (req.arp_pa.sa_family != AF_INET) return -EPFNOSUPPORT; ++ ip = &((struct sockaddr_in *) &req.arp_pa)->sin_addr.s_addr; ++ if (!(*ip & ~dev->pa_mask) && !(req.arp_flags & (ATF_ARPSRV | ++ ATF_DEFQOS))) ++ return -EINVAL; ++ switch (cmd) { ++ case SIOCSARP: ++ case SIOCDARP: ++ case SIOCGARP: ++ return send_demon(act_ioctl,PRIV(dev)->number,cmd,&req, ++ sizeof(struct atmarpreq)); ++ /* @@@ get will need special treatment */ ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} + -+ printk("RX buffers\n"); + -+ printk("----\n"); ++static int clip_open(struct device *dev) ++{ ++ printk("clip_open called\n"); ++ return 0; +} + -+/* --------------------------memory allocation-------------------------------*/ -+ + -+/* -+ * allocate a skbuff with enough room for the SDU header -+ */ -+static struct sk_buff *tneta1570_alloc_tx(struct atm_vcc *vcc, unsigned int size) -+{ -+ struct sk_buff *ptr; -+ -+ ptr = alloc_skb(size + 48, GFP_KERNEL); -+ if(ptr == NULL) return NULL; -+ skb_reserve(ptr, 48); /* room for push */ -+ return ptr; -+} -+ -+/*------------------------------ utopia phy dummies ------------------------ */ -+static int utopia_start(struct atm_dev *dev) -+{return 0;} -+static void utopia_int(struct atm_dev *dev) -+{} -+static int utopia_ioctl(struct atm_dev *dev, unsigned cmd, unsigned long arg) -+{return 0;} -+static const struct atmphy_ops utopia_ops = { -+ utopia_start, -+ utopia_ioctl, -+ utopia_int -+}; -+int utopia_init(struct atm_dev *dev) ++static int clip_stop(struct device *dev) +{ -+ dev->phy = &utopia_ops; + return 0; +} + -+/*----------------------------------- RX ------------------------------------*/ + -+/* -+ * alloc_dma -+ * find entry in dma state table for this vpi/vci -+ * if vpi already open increase valid vci range -+ * else open vpi, set vci range to vci -+ * return index to dma channel, return 0 on error -+ */ -+static int alloc_dma(struct atm_vcc *vcc) ++static int clip_init(struct device *dev) +{ -+ unsigned char sorted[0x78]; -+ unsigned int x; -+ int i; -+ struct tneta1570_dev *tneta1570_dev; -+ -+ EVENT(">alloc_rx_dma\n",0,0); -+ -+ tneta1570_dev = TNETA1570_DEV(vcc->dev); -+ -+ x = tneta1570_dev->rx_vpi_vci[vcc->vpi]; -+ if(x != 0) { -+ x = 0x7fff & (x >> 16); -+ return x + vcc->vci - 0x800; /* idx = value - offset */ -+ } else { -+ for(i=0;i<0x78;i++) -+ sorted[i]=0x00; -+ /* create a new vpi entry */ -+ /* first, find dma channel range */ -+ for(i=0; i<=MAX_VPI; i++) { -+ if(tneta1570_dev->rx_vpi_vci[i] & OWN) { -+ x = tneta1570_dev->rx_vpi_vci[i]; -+ sorted[(0x7f & (x >> 24))-8]=1; -+ } -+ } -+ for(i=0; i< 0x78; i++) { -+ if(sorted[i] == 0) -+ break; -+ } -+ if(i == 0x78) return 0; -+ tneta1570_dev->rx_vpi_vci[vcc->vpi]=OWN|((i+8)<<24)|(MAX_VCI); -+ return 256*i + vcc->vci; -+ } ++ printk("init %s\n",dev->name); ++ dev->hard_start_xmit = clip_start_xmit; ++ /* sg_xmit ... */ ++ dev->open = clip_open; ++ dev->stop = clip_stop; ++ ether_setup(dev); ++ dev->type = ARPHRD_ATM; ++ dev->tbusy = 0; /* @@@ check */ ++ dev->hard_header = clip_hard_header; ++ dev->rebuild_header = clip_rebuild_header; ++ dev->hard_header_cache = clip_hard_header_cache; ++ dev->header_cache_update = clip_header_cache_update; ++ dev->do_ioctl = NULL; ++ dev->change_mtu = NULL; ++ dev->get_stats = clip_get_stats; ++ dev->hard_header_len = RFC1483LLC_LEN; ++ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); ++ dev->mtu = RFC1626_MTU; ++ return send_demon(act_create,PRIV(dev)->number,0,NULL,0); +} + + -+ -+/* -+ * interrupt driven dequeue for rx buffer -+ * -> for each and every post in the completion ring do -+ * increment completion ring ptr (modulo RXCMPLR_SIZE_IRQ) -+ * get skb address from buffer address -+ * get free-buffer ring address from tneta1570_vcc -+ * prepare skb with header information -+ * vcc->push skb -+ * alloc (ATOMIC) new skb for this vci, put in free-buffer ring -+ * increment free-buffer ring index (modulo FBR_SIZE) -+ */ -+static void dequeue_rx(struct atm_dev * dev) ++int clip_create(int number) +{ -+ struct tneta1570_dev * tneta1570_dev; -+ -+ EVENT(">dequeue_rx\n",0,0); -+ NULLCHECK(dev); -+ tneta1570_dev = TNETA1570_DEV(dev); -+ NULLCHECK(tneta1570_dev); -+ -+ /* find here completion ring entries */ -+ DPRINTK(">completion ring post: %08x, %d\n", -+ (unsigned int)&RX_CMPL_R_IRQ(tneta1570_dev).atm_header, -+ tneta1570_dev->rxcmpl_ring_idx_irq); -+ while(!(RX_CMPL_R_IRQ(tneta1570_dev).control & OWN)) { -+ if((RX_CMPL_R_IRQ(tneta1570_dev).error & BUFFER_STARV)) { -+ printk(DEV_LABEL " rx starvation error \n"); -+ cli(); -+ RX_CMPL_R_IRQ(tneta1570_dev).control = OWN; -+ tneta1570_dev->rxcmpl_ring_idx_irq++; -+ tneta1570_dev->rxcmpl_ring_idx_irq %= RXCMPLR_SZ_IRQ; -+ sti(); -+ continue; -+ } -+ cli(); -+ if((RX_CMPL_R_IRQ(tneta1570_dev).control & 0xff) == 0) { -+ dequeue_OAM(dev); -+ } else { -+ if((RX_CMPL_R_IRQ(tneta1570_dev).error & AAL5_IND)) { -+ if((RX_CMPL_R_IRQ(tneta1570_dev).buf_ptr & (1<<31))) -+ dequeue_AAL5(dev); -+ } else { -+ dequeue_AAL0(dev); ++ struct device *dev; + -+ } -+ } -+ RX_CMPL_R_IRQ(tneta1570_dev).control = OWN; -+ tneta1570_dev->rxcmpl_ring_idx_irq++; -+ tneta1570_dev->rxcmpl_ring_idx_irq %= RXCMPLR_SZ_IRQ; -+ sti(); -+ } -+ return ; -+} -+ -+ -+ -+static void dequeue_OAM(struct atm_dev *dev) /* dequeue AAL0 cells */ -+{ -+ struct tneta1570_dev * tneta1570_dev; -+ struct sk_buff *skb, *new_skb; -+ unsigned int *p, *fbr; -+ -+ EVENT(">dequeue_rx_OAM\n",0,0); -+ NULLCHECK(dev); -+ tneta1570_dev = TNETA1570_DEV(dev); -+ NULLCHECK(tneta1570_dev); -+ -+ -+ -+ p = (unsigned int *)bus_to_virt(RX_CMPL_R_IRQ(tneta1570_dev).buf_ptr << 2); -+ skb = (struct sk_buff *)phys_to_virt(*(p-1)); /* get skb */ -+ -+ /* get new buffer before dequeueing old -+ */ -+ new_skb = alloc_skb(MAX_AAL0_PDU+RX_HDR, GFP_ATOMIC); -+ if(new_skb == NULL) { -+ /* add just received buffer to free list, drop pdu :-( */ -+ fbr = bus_to_virt((unsigned long)tneta1570_dev->free_buf_ptr[0].buf_ptr); -+ fbr[tneta1570_dev->oam_fbr_idx] = OWN | (virt_to_bus(p) >> 2); -+ tneta1570_dev->oam_fbr_idx++; -+ tneta1570_dev->oam_fbr_idx %= AAL0_BUFS; -+ return; -+ } -+ -+ /* add newly allocated buffer to free list */ -+ fbr = bus_to_virt((unsigned long)tneta1570_dev->free_buf_ptr[0].buf_ptr); -+ fbr[tneta1570_dev->oam_fbr_idx] = OWN | (virt_to_bus(new_skb->data+4) >> 2); -+ *(struct sk_buff **)(new_skb->data) = new_skb; -+ tneta1570_dev->oam_fbr_idx++; -+ tneta1570_dev->oam_fbr_idx %= AAL0_BUFS; -+ -+ /* push received buffer to protocol */ -+ -+ skb->data[16] = skb->data[12]; -+ skb->data[17] = skb->data[13]; -+ skb->data[18] = skb->data[14]; -+ skb->data[19] = skb->data[15]; -+ skb->data += 4*4; /* skip header */ -+ skb->len = 52; -+ /* should check for multiple buffers @@@@ */ -+ skb->tail = skb->data + skb->len; -+ -+ if (/*vcc->push*/1) { -+ dev_kfree_skb(skb, GFP_ATOMIC); -+/* printk(DEV_LABEL " Don't know how to call push !\n"); */ -+/* vcc->push(vcc,skb); */ -+ } else { -+ dev_kfree_skb(skb, GFP_ATOMIC); -+ printk(DEV_LABEL "(itf %d) No push in protocol.\n", -+ dev->number); -+ } -+} -+ -+ -+static void dequeue_AAL0(struct atm_dev *dev) /* dequeue AAL0 cells */ -+{ -+ struct tneta1570_dev * tneta1570_dev; -+ struct tneta1570_vcc * tneta1570_vcc; -+ struct atm_vcc *vcc; -+ struct sk_buff *skb, *new_skb; -+ unsigned int *p, v, *fbr; -+ -+ EVENT(">dequeue_rx_AAL0\n",0,0); -+ NULLCHECK(dev); -+ tneta1570_dev = TNETA1570_DEV(dev); -+ NULLCHECK(tneta1570_dev); -+ -+ p = (unsigned int *)bus_to_virt(RX_CMPL_R_IRQ(tneta1570_dev).buf_ptr << 2); -+ skb = (struct sk_buff *)phys_to_virt(*(p-1)); /* get skb */ -+ -+ vcc = skb->atm.vcc; -+ NULLCHECK(vcc); -+ tneta1570_vcc = TNETA1570_VCC(vcc); -+ NULLCHECK(tneta1570_vcc); -+ /* get new buffer before dequeueing old -+ * if error in peek drop pdu -+ */ -+ new_skb = vcc->peek(vcc, MAX_AAL0_PDU+RX_HDR, NULL); -+ if(new_skb == NULL) { -+ /* add just received buffer to free list, drop pdu :-( */ -+ v = RX_CMPL_R_IRQ(tneta1570_dev).control; -+ fbr = bus_to_virt((unsigned long)tneta1570_dev->free_buf_ptr[0xff & v].buf_ptr); -+ fbr[tneta1570_vcc->fbr_idx] = OWN | (virt_to_bus(p) >> 2); -+ tneta1570_vcc->fbr_idx++; -+ tneta1570_vcc->fbr_idx %= AAL0_BUFS; -+ return; -+ } -+ -+ /* add newly allocated buffer to free list */ -+ -+ v = RX_CMPL_R_IRQ(tneta1570_dev).control; -+ fbr = bus_to_virt((unsigned long)tneta1570_dev->free_buf_ptr[0xff & v].buf_ptr); -+ fbr[tneta1570_vcc->fbr_idx] = OWN | (virt_to_bus(new_skb->data+4) >> 2); -+ *(struct sk_buff **)(new_skb->data) = new_skb; -+ new_skb->atm.vcc = vcc; /* link vcc info */ -+ tneta1570_vcc->fbr_idx++; -+ tneta1570_vcc->fbr_idx %= AAL0_BUFS; -+ -+ /* push received buffer to protocol */ -+ -+ skb->data[16] = skb->data[12]; -+ skb->data[17] = skb->data[13]; -+ skb->data[18] = skb->data[14]; -+ skb->data[19] = skb->data[15]; -+ skb->data += 4*4; /* skip header */ -+ skb->len = 52; -+ /* should check for multiple buffers @@@@ */ -+ skb->tail = skb->data + skb->len; -+ skb->free = 1; /* set free flag, is there need for it? */ -+ -+ if (vcc->push) { -+ vcc->push(vcc,skb); -+ } else { -+ printk(DEV_LABEL "(itf %d) No push in protocol.\n", -+ dev->number); ++ if (number != -1) { ++ for (dev = clip_devs; dev; dev = PRIV(dev)->next) ++ if (PRIV(dev)->number == number) return -EEXIST; + } -+ /* update statistics */ -+ vcc->stats->rx++; -+rx_dequeued++; -+} -+ -+ -+ -+static void dequeue_AAL5(struct atm_dev *dev) /* dequeue AAL5 PDU */ -+{ -+ struct tneta1570_dev *tneta1570_dev; -+ struct tneta1570_vcc *tneta1570_vcc; -+ struct atm_vcc *vcc; -+ struct sk_buff *skb, *new_skb; -+ unsigned int *p, v, *fbr; -+ -+ EVENT(">dequeue_rx_AAL5\n",0,0); -+ NULLCHECK(dev); -+ tneta1570_dev = TNETA1570_DEV(dev); -+ NULLCHECK(tneta1570_dev); -+ p = (unsigned int *)bus_to_virt(RX_CMPL_R_IRQ(tneta1570_dev).buf_ptr << 2); -+ skb = (struct sk_buff *)phys_to_virt(*(p-1)); /* get skb */ -+ -+ DPRINTK(" p %08x, skb %08x, head %08x, err %08x, sop %08x, trailer %08x, idx %08x", -+ p, skb, -+ RX_CMPL_R_IRQ(tneta1570_dev).atm_header, -+ RX_CMPL_R_IRQ(tneta1570_dev).error, -+ RX_CMPL_R_IRQ(tneta1570_dev).buf_ptr, -+ RX_CMPL_R_IRQ(tneta1570_dev).trailer, -+ RX_CMPL_R_IRQ(tneta1570_dev).control); -+ -+ vcc = skb->atm.vcc; -+ DPRINTK(" vcc %08x", vcc); -+ -+ NULLCHECK(vcc); -+ tneta1570_vcc = TNETA1570_VCC(vcc); -+ NULLCHECK(tneta1570_vcc); -+ /* get new buffer before dequeueing old -+ * if error in peek drop pdu -+ */ -+ new_skb=NULL; -+ -+ if((RX_CMPL_R_IRQ(tneta1570_dev).error & CRC_ERROR)) { -+ DPRINTK(DEV_LABEL " rx crc error.\n\n"); -+ } -+ if((RX_CMPL_R_IRQ(tneta1570_dev).error & RX_TIMEOUT)) { -+ DPRINTK(DEV_LABEL " rx time out.\n"); -+ } -+ if((RX_CMPL_R_IRQ(tneta1570_dev).error & PAKET_OVERFLOW)) { -+ DPRINTK(DEV_LABEL " rx packet overflow.\n"); -+ } -+ if(!(RX_CMPL_R_IRQ(tneta1570_dev).error & (CRC_ERROR | RX_TIMEOUT | PAKET_OVERFLOW))) -+ new_skb = vcc->peek(vcc, MAX_AAL5_PDU+RX_HDR, NULL); -+ if(new_skb == NULL) { -+ /* add just received buffer to free list :-( */ -+ v = RX_CMPL_R_IRQ(tneta1570_dev).control; -+ fbr = bus_to_virt((unsigned long)tneta1570_dev->free_buf_ptr[(0xffff & v)].buf_ptr); -+ fbr[tneta1570_vcc->fbr_idx] = OWN | (virt_to_bus(p) >> 2); -+ tneta1570_vcc->fbr_idx++; -+ tneta1570_vcc->fbr_idx %= AAL5_BUFS; -+ return; -+ } -+ /* add newly allocated buffer to free list */ -+ -+ v = RX_CMPL_R_IRQ(tneta1570_dev).control; -+ fbr = bus_to_virt((unsigned long)tneta1570_dev->free_buf_ptr[(v & 0xffff)].buf_ptr); -+ v=virt_to_bus(new_skb->data+4); -+ fbr[tneta1570_vcc->fbr_idx] = OWN | (v >> 2); -+ *(struct sk_buff **)(new_skb->data) = new_skb; -+ new_skb->atm.vcc = vcc; /* link context info */ -+ tneta1570_vcc->fbr_idx++; -+ tneta1570_vcc->fbr_idx %= AAL5_BUFS; -+ -+ /* push received buffer to protocol */ -+ skb->data += 5*4; /* skip header */ -+ skb->len = RX_CMPL_R_IRQ(tneta1570_dev).trailer & 0xffff; -+ /* should check for multiple buffers @@@@ */ -+ skb->tail = skb->data + skb->len; -+ skb->free = 1; /* set free flag, is there need for it? */ -+ -+ if (vcc->push) { -+ vcc->push(vcc,skb); -+ } else { -+ printk(DEV_LABEL "(itf %d) No push in protocol.\n", -+ dev->number); ++ else { ++ number = 0; ++ for (dev = clip_devs; dev; dev = PRIV(dev)->next) ++ if (PRIV(dev)->number >= number) ++ number = PRIV(dev)->number+1; + } -+ /* update statistics */ -+ vcc->stats->rx++; -+rx_dequeued++; ++ dev = kmalloc(sizeof(struct device)+sizeof(struct clip_priv), ++ GFP_KERNEL); ++ if (!dev) return -ENOMEM; ++ memset(dev,0,sizeof(struct device)+sizeof(struct clip_priv)); ++ dev->name = PRIV(dev)->name; ++ sprintf(dev->name,"atm%d",number); ++ dev->init = clip_init; ++ PRIV(dev)->number = number; ++ if (register_netdev(dev)) return -EIO; /* free dev ? */ ++ PRIV(dev)->next = clip_devs; ++ clip_devs = dev; ++ printk("registered (net:%s)\n",dev->name); ++ return number; +} + -+ -+/* -+ * --- bring rx up --- -+ * init vpi/vci table - well, already done by tneta1570_init -+ * kmalloc completion rings -+ * write ptrs to completion rings into sar regs -+ * init completion rings to all OWN -+ * write completion ring related data to device structure, set index to 0 -+ * init dma channels 0, 1, 2 for reception of OAM cells -+ */ -+static int start_rx(struct atm_dev *dev) -+{ -+ int i; -+ unsigned long x; -+ unsigned int *ptr; -+ struct sk_buff *buf; -+ struct tneta1570_dev *tneta1570_dev; -+ -+ EVENT(">start_rx\n",0,0); -+ tneta1570_dev = TNETA1570_DEV(dev); -+ tneta1570_dev->lost = 0; -+ -+ /* init rx completion rings */ -+ tneta1570_dev->rxcmpl_ring = -+ kmalloc(2*RXCMPLR_SZ_IRQ*sizeof(struct tneta_rx_compl), -+ GFP_KERNEL); -+ DPRINTK("RX_CMPL_R->%08x", tneta1570_dev->rxcmpl_ring); -+ if(!tneta1570_dev->rxcmpl_ring) { -+ printk(DEV_LABEL "(itf %d) malloc on rx start failed.\n", dev->number); -+ return -ENOMEM; -+ } -+ /* align completion-ring with irq to its size */ -+ x = (unsigned long)(&tneta1570_dev->rxcmpl_ring[RXCMPLR_SZ_IRQ]); -+ tneta1570_dev->rxcmplringptr_irq = (struct tneta_rx_compl *) -+ (x & (~(RXCMPLR_SZ_IRQ*sizeof(struct tneta_rx_compl) - 1))); -+ /* the rest is for the completion ring w/o irq */ -+ if((tneta1570_dev->rxcmplringptr_irq - RXCMPLR_SZ_NOI) -+ > tneta1570_dev->rxcmpl_ring) { -+ tneta1570_dev->rxcmplringptr_noi = -+ tneta1570_dev->rxcmplringptr_irq - RXCMPLR_SZ_NOI; -+ } else { -+ tneta1570_dev->rxcmplringptr_noi = -+ tneta1570_dev->rxcmplringptr_irq + RXCMPLR_SZ_IRQ; -+ } -+ EVENT(">init rx completion ring irq\n",0,0); -+ for(i=0; irxcmplringptr_irq[i].control = OWN; -+ EVENT(">init tx completion ring noi\n",0,0); -+ for(i=0; irxcmplringptr_noi[i].control = OWN; -+ -+ tneta1570_dev->rxcmpl_ring_idx_noi = 0; -+ tneta1570_dev->rxcmpl_ring_idx_irq = 0; -+ -+ SAR_REG_SHORT(tneta1570_dev, TNETA_S_RXCOMPLSIZEI) = RXCMPLR_SZ_IRQ-1; -+ SAR_REG_SHORT(tneta1570_dev, TNETA_S_RXCOMPLSIZE) = RXCMPLR_SZ_NOI-1; -+ SAR_REG_WORD(tneta1570_dev, TNETA_RXCOMPLNOI) = (unsigned int)virt_to_bus(tneta1570_dev->rxcmplringptr_noi); -+ SAR_REG_WORD(tneta1570_dev, TNETA_RXCOMPLIRQ) = (unsigned int)virt_to_bus(tneta1570_dev->rxcmplringptr_irq); -+ -+ /* init dma 0,1,2 for oam */ -+ -+ /* alloc memory for oam fbr & buffers */ -+ ptr = kmalloc(AAL0_BUFS*4, GFP_KERNEL); -+ if(ptr == NULL) printk(DEV_LABEL "PANIC on start rx \n"); -+ for(i=0; idata) = buf; /* link */ -+ ptr[i] = OWN | ((unsigned int)virt_to_bus(buf->data + 4) >> 2); -+ } -+ -+ tneta1570_dev->oam_fbr_idx = 0; -+ /* oam cells use fbr 0 */ -+ tneta1570_dev->free_buf_ptr[0].buf_ptr = (unsigned int)virt_to_bus(ptr); -+ tneta1570_dev->free_buf_ptr[0].buf_size = FBR_AAL0_32; -+ -+ tneta1570_dev->rx_dma_state[0].control = RX_DMA_CONTROL_AAL0; -+ tneta1570_dev->rx_dma_state[0].AAL0_cells = MAX_AAL0_CELLS; -+ tneta1570_dev->rx_dma_state[0].rx_timeout = RX_TIME_OUT; -+ tneta1570_dev->rx_dma_state[0].dma_on_idx = DMA_ON + 0; -+ tneta1570_dev->rx_dma_state[1].control = RX_DMA_CONTROL_AAL0; -+ tneta1570_dev->rx_dma_state[1].AAL0_cells = MAX_AAL0_CELLS; -+ tneta1570_dev->rx_dma_state[1].rx_timeout = RX_TIME_OUT; -+ tneta1570_dev->rx_dma_state[1].dma_on_idx = DMA_ON + 0; -+ tneta1570_dev->rx_dma_state[2].control = RX_DMA_CONTROL_AAL0; -+ tneta1570_dev->rx_dma_state[2].AAL0_cells = MAX_AAL0_CELLS; -+ tneta1570_dev->rx_dma_state[2].rx_timeout = RX_TIME_OUT; -+ tneta1570_dev->rx_dma_state[2].dma_on_idx = DMA_ON + 0; -+ -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= TNETA_R0_RX_ENABLE; + -+ return 0; -+} -+ -+/* -+ * open vpi/vci for rx -+ * alloc 16 words for free-buffer ring -+ * alloc 16 skbs, size: if AAL5 -+ * IP-MTU + a little something (64K SDUs need multiple bufs) -+ * else -+ * 48 + a little something -+ * enter pointers to skbs in free-buffer ring -+ * find unused free-buffer ring-pointer table entry -+ * put pointer to free-buffer ring in ring-pointer table & tneta1570_vcc -+ * check if vpi has already alloc'd a dma table range -+ * if not, alloc range in dma table for vpi (size is 256*8 words) -+ * if AAL5 -> set dma state table to AAL5 -+ * else use counter terminated AAL0 (cell count 1) -+ * prepare dma state table entry for this vpi/vci (may turn rx for this vci on) -+ * if range < vci -> set range to vci (max) (this definitely turns it on) -+ */ -+static int open_rx(struct atm_vcc *vcc) ++static int clip_device_event(struct notifier_block *this,unsigned long event, ++ void *dev) +{ -+ int i, dma_idx, fbr_idx; -+ struct sk_buff *skb; -+ unsigned int *ptr; -+ struct tneta1570_dev *tneta1570_dev; -+ struct tneta1570_vcc *tneta1570_vcc; -+ -+ EVENT(">open_rx\n",0,0); -+ -+ tneta1570_dev = TNETA1570_DEV(vcc->dev); -+ tneta1570_vcc = TNETA1570_VCC(vcc); -+ -+ tneta1570_vcc->rx_wait = NULL; -+ -+ tneta1570_vcc->dma_channel = alloc_dma(vcc); -+ if(!tneta1570_vcc->dma_channel) return -1; -+ -+ dma_idx = tneta1570_vcc->dma_channel; -+ -+ for(fbr_idx = 0; fbr_idxfree_buf_ptr[fbr_idx].buf_ptr == 0) -+ break; -+ if(fbr_idx == MAX_FBR_ENTRIES) return -1; -+ -+ if(vcc->aal == ATM_AAL0) { -+ /* alloc memory for fbr & buffers */ -+ ptr = kmalloc(AAL0_BUFS*4, -+ GFP_KERNEL); -+ if(ptr == NULL) printk(DEV_LABEL "PANIC on open rx \n"); -+ for(i=0; ipeek(vcc, MAX_AAL0_PDU+RX_HDR, NULL); -+ if(skb == NULL) printk(DEV_LABEL "PANIC on open rx \n"); -+ *(struct sk_buff **)(skb->data) = skb; /* link */ -+ skb->atm.vcc = vcc; /* link vcc info */ -+ ptr[i] = OWN | ((unsigned int)virt_to_bus(skb->data+4) >> 2); -+ } -+ -+ tneta1570_vcc->fbr_idx = 0; -+ tneta1570_dev->free_buf_ptr[fbr_idx].buf_ptr = virt_to_bus(ptr); -+ tneta1570_dev->free_buf_ptr[fbr_idx].buf_size = FBR_AAL0_32; -+ -+ tneta1570_dev->rx_dma_state[dma_idx].control = RX_DMA_CONTROL_AAL0; -+ tneta1570_dev->rx_dma_state[dma_idx].AAL0_cells = MAX_AAL0_CELLS; -+ tneta1570_dev->rx_dma_state[dma_idx].rx_timeout = RX_TIME_OUT; -+ tneta1570_dev->rx_dma_state[dma_idx].dma_on_idx = DMA_ON + fbr_idx; -+ -+ } else if(vcc->aal == ATM_AAL5) { -+ /* alloc memory for fbr & buffers */ -+ ptr = kmalloc(AAL5_BUFS*4, -+ GFP_KERNEL); -+ if(ptr == NULL) printk(DEV_LABEL "PANIC on open rx \n"); -+ for(i=0; ipeek(vcc, MAX_AAL5_PDU+RX_HDR, NULL); -+ if(skb == NULL) printk(DEV_LABEL "PANIC on open rx \n"); -+ *(struct sk_buff **)(skb->data) = skb; /* link */ -+ skb->atm.vcc = vcc; /* link vcc info */ -+ ptr[i] = OWN | ((unsigned int)virt_to_bus(skb->data+4) >> 2); -+ } -+ -+ tneta1570_vcc->fbr_idx = 0; -+ tneta1570_dev->free_buf_ptr[fbr_idx].buf_ptr = virt_to_bus(ptr); -+ tneta1570_dev->free_buf_ptr[fbr_idx].buf_size = FBR_AAL5_16; -+ -+ tneta1570_dev->rx_dma_state[dma_idx].control = RX_DMA_CONTROL_AAL5; -+ tneta1570_dev->rx_dma_state[dma_idx].rx_timeout = RX_TIME_OUT; -+ tneta1570_dev->rx_dma_state[dma_idx].dma_on_idx = DMA_ON + fbr_idx; -+ -+ } else return -1; -+ return 0; ++ /* ignore non-CLIP devices */ ++ if (((struct device *) dev)->init != clip_init) return NOTIFY_DONE; ++ switch (event) { ++ case NETDEV_UP: ++ (void) send_demon(act_up,PRIV(dev)->number,0,NULL,0); ++ break; ++ case NETDEV_DOWN: ++ DPRINTK("clip_device_event NETDEV_DOWN\n"); ++ (void) send_demon(act_down,PRIV(dev)->number,0,NULL,0); ++ break; ++ case NETDEV_REBOOT: ++ /* ignore */ ++ break; ++ default: ++ printk(KERN_ERR "clip_device_event: unknown event " ++ "%ld\n",event); ++ break; ++ } ++ return NOTIFY_DONE; +} + -+/* -+ * close vpi/vci for rx -+ * -+ * get free-buffer ring table address -+ * clear dma state table entry (rx for vci off) -+ * get free-buffer ring address -+ * wait for rx to drain -+ * free all remaining skbs (the ones with own enabled, e.g. all) -+ * free free-buffer ring -+ * set free-buffer-ring ptr to 0 to indicate 'freeness' -+ * check if vpi has another vci enabled -+ * -> yes: if other_vci > this_vci -> do nothing -+ * else -> set max vci to highest other vci -+ * -> no: set vci in vpi/vci table to 0 -+ */ -+static void close_rx(struct atm_vcc *vcc) -+{ -+ int i, fbr_idx, dma_idx, x; -+ struct sk_buff *skb; -+ unsigned int *buf, *ptr; -+ struct tneta1570_dev *tneta1570_dev; -+ struct tneta1570_vcc *tneta1570_vcc; -+ -+ EVENT(">close_rx\n",0,0); -+ -+ tneta1570_dev = TNETA1570_DEV(vcc->dev); -+ tneta1570_vcc = TNETA1570_VCC(vcc); -+ -+ dma_idx = tneta1570_vcc->dma_channel; -+ fbr_idx = tneta1570_dev->rx_dma_state[dma_idx].dma_on_idx & 0xff; -+ /* wait for EOP */ -+ while(tneta1570_dev->rx_dma_state[dma_idx].control & OWN); -+ tneta1570_dev->rx_dma_state[dma_idx].dma_on_idx = 0; /* off */ -+ /* mark as empty */ -+ ptr = bus_to_virt((unsigned long)tneta1570_dev->free_buf_ptr[fbr_idx].buf_ptr); -+ tneta1570_dev->free_buf_ptr[fbr_idx].buf_ptr = 0; /* mark fbr free */ -+ x = tneta1570_dev->free_buf_ptr[fbr_idx].buf_size; -+ x = x >> 10; /* ring size */ -+ x &= 0x3f; -+ x++; -+ x = 16 * x; -+ for(i=0; ifree = 1; /* ???? */ -+ kfree_skb(skb, FREE_READ); -+ } -+ } -+ kfree(ptr); + -+ /* if last vci on this vpi is closed, close vpi */ -+ -+} ++static struct notifier_block clip_dev_notifier = { ++ clip_device_event, ++ NULL, ++ 0 ++}; + + -+/*----------------------------------- TX ------------------------------------*/ + -+/* -+ * -- bring tx up -- -+ * init scheduler table to all 0s -+ * kmalloc tx completion rings -+ * write ptrs to completion rings into sar regs -+ * init completion rings to all 0x80000000s -+ * write completion ring related data to device structure, set index to 0 -+ * enable tx in sar -+ */ -+static int start_tx(struct atm_dev *dev) ++static void atmarpd_close(struct atm_vcc *vcc) +{ -+ int i; -+ unsigned int *seg_ring, *seg_ring_mptr; -+ unsigned long x; -+ struct tneta1570_dev *tneta1570_dev; -+ -+ EVENT(">start_tx\n",0,0); -+ -+ tneta1570_dev = TNETA1570_DEV(dev); -+ -+ /* init tx completion rings */ -+ tneta1570_dev->txcmpl_ring=kmalloc(2*TXCMPLR_SZ_IRQ*4, GFP_KERNEL); -+ if(!tneta1570_dev->txcmpl_ring) { -+ printk(DEV_LABEL "(itf %d) malloc on tx start failed.\n", dev->number); -+ return -ENOMEM; -+ } -+ DPRINTK("TX_CMPL_R->%08x", tneta1570_dev->txcmpl_ring); -+ /* align completion-ring with irq to its size */ -+ x = (unsigned long)(&tneta1570_dev->txcmpl_ring[TXCMPLR_SZ_IRQ]); -+ tneta1570_dev->txcmplringptr_irq = (unsigned int *)(x & (~(TXCMPLR_SZ_IRQ*4 - 1))); -+ /* the rest is for the completion ring w/o irq */ -+ if((tneta1570_dev->txcmplringptr_irq - TXCMPLR_SZ_NOI) > tneta1570_dev->txcmpl_ring) { -+ tneta1570_dev->txcmplringptr_noi = tneta1570_dev->txcmplringptr_irq - TXCMPLR_SZ_NOI; -+ } else { -+ tneta1570_dev->txcmplringptr_noi = tneta1570_dev->txcmplringptr_irq + TXCMPLR_SZ_IRQ; -+ } -+ EVENT(">init tx completion ring irq\n",0,0); -+ for(i=0; itxcmplringptr_irq[i] = OWN; -+ EVENT(">init tx completion ring noi\n",0,0); -+ for(i=0; itxcmplringptr_noi[i] = OWN; -+ -+ tneta1570_dev->txcmpl_ring_idx_noi = 0; -+ tneta1570_dev->txcmpl_ring_idx_irq = 0; -+ -+ /* dma state reread bug fix - allocate dma 1 */ -+ seg_ring_mptr=kmalloc(2*TX_SEG_RING_SIZE*4, GFP_KERNEL); -+ if(!seg_ring_mptr) { -+ printk(DEV_LABEL "(itf %d) malloc on tx open failed.\n", -+ dev->number); -+ return -ENOMEM; -+ } -+ x = (unsigned long)(seg_ring_mptr + TX_SEG_RING_SIZE); -+ seg_ring = (unsigned int *)(x & ~(TX_SEG_RING_SIZE * 4 - 1)); -+ -+ for(i=0; itx_dma_state[1].dma_state_flag = (OWN | SEG_PTR(seg_ring)); -+ -+ /* init registers */ -+ SAR_REG_SHORT(tneta1570_dev, TNETA_S_TXCOMPLSIZEI) = TXCMPLR_SZ_IRQ - 1; -+ SAR_REG_SHORT(tneta1570_dev, TNETA_S_TXCOMPLSIZE) = TXCMPLR_SZ_NOI - 1; -+ SAR_REG_SHORT(tneta1570_dev, TNETA_S_TXSEGSIZE) = TX_SEG_RING_SIZE - 1; -+ SAR_REG_SHORT(tneta1570_dev, TNETA_S_SCHEDSIZE) = 2 + SLOW_DOWN_FACTOR; -+ -+ SAR_REG_WORD(tneta1570_dev, TNETA_TXCOMPLNOI) = (unsigned int)virt_to_bus((void*)tneta1570_dev->txcmplringptr_noi); -+ SAR_REG_WORD(tneta1570_dev, TNETA_TXCOMPLIRQ) = (unsigned int)virt_to_bus((void*)tneta1570_dev->txcmplringptr_irq); -+ -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= TNETA_R0_TX_ENABLE; ++ struct sk_buff *skb; + -+ return 0; ++ DPRINTK("atmarpd_close\n"); ++ atmarpd = NULL; /* assumed to be atomic */ ++ barrier(); ++ unregister_netdevice_notifier(&clip_dev_notifier); ++ wake_up(&atmarpd_sleep); ++ if (skb_peek(&vcc->recvq)) ++ printk(KERN_ERR "atmarpd_close: closing with requests " ++ "pending\n"); ++ while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb,FREE_READ); ++ DPRINTK("(done)\n"); +} -+ -+/* -+ * -- open vpi/vci -- -+ * find free entry in scheduler table -+ * init tx_dma_state table for this vpi/vci -+ * kmalloc tx_seg_ring, init with all 0s -+ * add entry to scheduler table -+ */ -+static int open_tx(struct atm_vcc *vcc) -+{ -+ int scheduler_idx, i; -+ unsigned long x; -+ struct tneta1570_dev *tneta1570_dev; -+ struct tneta1570_vcc *tneta1570_vcc; -+ -+ EVENT(">open_tx\n",0,0); -+ -+ tneta1570_dev = TNETA1570_DEV(vcc->dev); -+ tneta1570_vcc = TNETA1570_VCC(vcc); -+ -+ tneta1570_vcc->tx_wait = NULL; -+ -+ if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; -+ -+ tneta1570_vcc->seg_ring_mptr=kmalloc(2*TX_SEG_RING_SIZE*4, GFP_KERNEL); -+ if(!tneta1570_vcc->seg_ring_mptr) { -+ printk(DEV_LABEL "(itf %d) malloc on tx open failed.\n", -+ vcc->dev->number); -+ return -ENOMEM; -+ } -+ /* align seg-ring to its size */ -+ x = (unsigned long)(tneta1570_vcc->seg_ring_mptr + TX_SEG_RING_SIZE); -+ tneta1570_vcc->seg_ring = (unsigned int *)(x & ~(TX_SEG_RING_SIZE * 4 - 1)); -+ -+ EVENT("> seg ring is at phy %x\n", (unsigned int)tneta1570_vcc->seg_ring,0); -+ for(i=0; iseg_ring[i]=0; -+ tneta1570_vcc->seg_ring_idx = 0; -+ -+ /* find free scheduler table entry */ -+ scheduler_idx=0; -+ while(read_sched_tab(tneta1570_dev, scheduler_idx) != 0) { -+ scheduler_idx++; -+ if(scheduler_idx >= MAX_SCHED_ENTRIES) { -+ printk(DEV_LABEL "(itf %d) tx scheduler full on open.\n", -+ vcc->dev->number); -+ return -ENOMEM; -+ } -+ } -+ -+ if((scheduler_idx < SLOW_DOWN_FACTOR) && -+ (scheduler_idx + SLOW_DOWN_FACTOR < MAX_SCHED_ENTRIES)) -+ SAR_REG_SHORT(tneta1570_dev, TNETA_S_SCHEDSIZE) = -+ scheduler_idx + SLOW_DOWN_FACTOR; -+ else SAR_REG_SHORT(tneta1570_dev, TNETA_S_SCHEDSIZE) =scheduler_idx; -+ -+ tneta1570_vcc->scheduler_idx = scheduler_idx; -+ write_sched_tab(tneta1570_dev, scheduler_idx, scheduler_idx+1); /* 1 in entry 0 */ -+ -+ tneta1570_dev->tx_dma_state[scheduler_idx+1].dma_state_flag = -+ (OWN | SEG_PTR(tneta1570_vcc->seg_ring)); + -+ tneta1570_vcc->txing = 0; /* init txing flag */ + -+ return 0; -+} ++static struct atmdev_ops atmarpd_dev_ops = { ++ NULL, /* no dev_close */ ++ NULL, /* no open */ ++ atmarpd_close, /* close */ ++ NULL, /* no ioctl */ ++ NULL, /* no getsockopt */ ++ NULL, /* no setsockopt */ ++ atmarpd_send, /* send */ ++ NULL, /* no sg_send */ ++ NULL, /* no send_oam */ ++ NULL, /* no phy_put */ ++ NULL, /* no phy_get */ ++ NULL, /* no feedback */ ++ NULL, /* no change_qos */ ++ NULL /* no free_rx_skb */ ++}; + -+/* -+ * -- close vpi/vci -- -+ * remove scheduler table entry -+ * free tx_seg_ring -+ */ -+static void close_tx(struct atm_vcc *vcc) -+{ -+ struct tneta1570_dev *tneta1570_dev; -+ struct tneta1570_vcc *tneta1570_vcc; + -+ EVENT(">close_tx\n",0,0); -+ -+ tneta1570_dev = TNETA1570_DEV(vcc->dev); -+ tneta1570_vcc = TNETA1570_VCC(vcc); -+ -+ current->timeout=jiffies+TNETA1570_TIMEOUT; -+ while(tneta1570_vcc->txing) { -+ interruptible_sleep_on(&tneta1570_vcc->tx_wait); /* wait for tx to drain */ -+ if(!current->timeout){ -+ printk(DEV_LABEL " timed out while closing (%d)\n", -+ tneta1570_vcc->txing); -+ break; -+ } -+ } -+ -+ /* remove ptr to segmentation ring */ -+ -+ tneta1570_dev->tx_dma_state[tneta1570_vcc->scheduler_idx+1].dma_state_flag = 0; -+ write_sched_tab(tneta1570_dev, tneta1570_vcc->scheduler_idx, 0); -+ -+ kfree(tneta1570_vcc->seg_ring_mptr); -+} ++static struct atm_dev atmarpd_dev = { ++ &atmarpd_dev_ops, ++ NULL, /* no PHY */ ++ "arpd", /* type */ ++ 999, /* dummy device number */ ++ NULL,NULL, /* pretend not to have any VCCs */ ++ NULL,NULL, /* no data */ ++ 0, /* no flags */ ++ NULL, /* no local address */ ++ { 0 } /* no ESI, no statistics */ ++}; + -+/* -+ * -- send skb -- -+ * prepare buffer with header data -+ * set entry in segmentation ring for vpi/vci and increment index -+ * smile ;-) -+ */ -+static int do_tx(struct sk_buff * skb) ++ ++int atm_init_atmarp(struct atm_vcc *vcc) +{ -+ struct atm_vcc *vcc=0; -+ struct tneta1570_dev *tneta1570_dev=0; -+ struct tneta1570_vcc *tneta1570_vcc=0; -+ unsigned int seg_ring_entry, i; -+ unsigned int *buffer; -+ -+ NULLCHECK(skb); -+ EVENT(">do_tx: skb=0x%lx, %d bytes\n",(unsigned long) skb,skb->len); -+ vcc = skb->atm.vcc; -+ NULLCHECK(vcc); -+ tneta1570_dev = TNETA1570_DEV(vcc->dev); -+ NULLCHECK(tneta1570_dev); -+ tneta1570_vcc = TNETA1570_VCC(vcc); -+ if(tneta1570_vcc->txing>=TX_SEG_RING_SIZE-1) -+ interruptible_sleep_on(&tneta1570_vcc->tx_wait); -+ if ((unsigned long) skb->data & TNETA_ALIGN) { -+ printk(DEV_LABEL "(itf %d): VCI %d has mis-aligned TX data\n", -+ vcc->dev->number,vcc->vci); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } -+ /* ping seems to be a problem here, its not using my alloc function */ -+ /* prepare buffer descriptor */ -+ if((skb->data - skb->head) < 24) { -+ DPRINTK(DEV_LABEL "(itf %d): skbuff push impossible (%d)\n", -+ vcc->dev->number, skb->data - skb->head); -+ /* copy the data if push not possible */ -+ if(!(buffer=kmalloc(skb->len + 24, GFP_ATOMIC))) { -+ printk(DEV_LABEL "(itf %d): malloc on send failed.\n", -+ vcc->dev->number); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -ENOMEM; -+ } -+ EVENT(">tx mem alloc'd at %08x\n", (unsigned int)buffer,0); -+ NULLCHECK(skb->data); -+ if(vcc->aal == ATM_AAL0) { -+ buffer[3] = 0; -+ buffer[4] = ((unsigned int *)skb->data)[0]; /* copy atm header */ -+ buffer[5] = 0; -+ for(i=0; ilen/4+1; i++) -+ buffer[6+i] = ((unsigned int *)skb->data)[1+i]; -+ buffer[2] = AAL0_PDU_INT | (0xffff & skb->len); /* offset 0 */ -+ } else { -+ buffer[3] = 0; -+ buffer[4] = (vcc->vpi << 20) | (vcc->vci << 4); /* prepare atm header */ -+ buffer[5] = 0; -+ for(i=0; ilen/4+1; i++) -+ buffer[6+i] = ((unsigned int *)skb->data)[i]; -+ buffer[2] = AAL5_PDU_INT | (0xffff & skb->len); -+ } -+ buffer[1] = (unsigned int)virt_to_bus(skb); -+ buffer[0] = 0; /* push size */ -+ EVENT(">data copied\n",0,0); -+ } else { /* push skb and put header in front of sdu */ -+ if(vcc->aal == ATM_AAL0) { /* sdu contains header */ -+ buffer = (unsigned int *)skb_push(skb, 20); /* make room for 1+4 words header */ -+ buffer[3] = 0; -+ buffer[4] = buffer[5]; /* copy atm header */ -+ buffer[5] = 0; -+ buffer[2] = AAL0_PDU_INT | (0xffff & (skb->len-20)); /* offset 0 */ -+ buffer[0] = 20; /* push size */ -+ } else { -+ buffer = (unsigned int *)skb_push(skb, 24); /* make room for 1+4 words header */ -+ buffer[3] = 0; -+ buffer[4] = (vcc->vpi << 20) | (vcc->vci << 4); /* prepare atm header */ -+ buffer[5] = 0; -+ buffer[2] = AAL5_PDU_INT | (0xffff & (skb->len-24)); -+ buffer[0] = 24; /* push size */ -+ } -+ buffer[1] = (unsigned int)virt_to_bus(skb); /* store skb ptr for dequeue */ -+ } -+ -+ seg_ring_entry = ((unsigned int)virt_to_bus(&buffer[2]) >> 2) | OWN; -+ tneta1570_vcc->seg_ring[tneta1570_vcc->seg_ring_idx] = seg_ring_entry; -+ DPRINTK(">zippered up"); -+ DPRINTK(">sched %d," -+ ">dma %08x," -+ ">sridx %d >seg_r %08x (%08x)," -+ ">buffer %08x, (%08x)," -+ "atm header %08x\n", -+ read_sched_tab(tneta1570_dev, tneta1570_vcc->scheduler_idx), -+ tneta1570_dev->tx_dma_state[tneta1570_vcc->scheduler_idx+1].dma_state_flag, -+ tneta1570_vcc->seg_ring_idx, -+ tneta1570_vcc->seg_ring, -+ tneta1570_vcc->seg_ring[tneta1570_vcc->scheduler_idx], -+ &buffer[2], buffer[2], buffer[4]); -+ -+ /* index to seg.ring entry for next SDU */ -+ cli(); /*@@@ restore flags ??*/ -+ tneta1570_vcc->seg_ring_idx++; -+ tneta1570_vcc->seg_ring_idx %= TX_SEG_RING_SIZE; -+ tneta1570_vcc->txing++; -+ sti(); -+ return 0; ++ struct device *dev; ++ ++ if (atmarpd) return -EADDRINUSE; ++ atmarpd = vcc; ++ vcc->flags |= ATM_VF_READY | ATM_VF_META; ++ /* allow replies and avoid getting closed if signaling dies */ ++ vcc->dev = &atmarpd_dev; ++ vcc->push = NULL; ++ vcc->peek = NULL; /* crash */ ++ vcc->pop = NULL; /* crash */ ++ vcc->push_oam = NULL; /* crash */ ++ register_netdevice_notifier(&clip_dev_notifier); ++ for (dev = clip_devs; dev; dev = PRIV(dev)->next) ++ if (dev->flags & IFF_UP) ++ (void) send_demon(act_up,PRIV(dev)->number,0,NULL,0); ++ return 0; +} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/common.c Tue Jul 1 12:26:27 1997 +@@ -0,0 +1,831 @@ ++/* net/atm/common.c - ATM sockets (common part for PVC and SVC) */ + -+/* -+ * -- dequeue tx buffer on tx complete interrupt -- -+ * check completion ring -+ * while valid entry -+ * dequeue skb (needs a bit of backtracking) -+ * increment completion ring index -+ */ -+static void dequeue_tx(struct atm_dev * dev) -+{ -+ struct tneta1570_dev *tneta1570_dev; -+ struct atm_vcc *vcc; -+ struct sk_buff *skb; -+ unsigned int * p, v; ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+ EVENT(">dequeue_tx\n",0,0); -+ -+ NULLCHECK(dev); -+ tneta1570_dev = TNETA1570_DEV(dev); -+ NULLCHECK(tneta1570_dev); -+ cli(); -+ /* find here completion ring entries */ -+ EVENT(">completion ring post: %08x, %d\n", TX_CMPL_R_IRQ(tneta1570_dev), -+ tneta1570_dev->txcmpl_ring_idx_irq); -+ while(!(TX_CMPL_R_IRQ(tneta1570_dev) & OWN)) { -+ p = (unsigned int *)bus_to_virt(TX_CMPL_R_IRQ(tneta1570_dev) << 2); -+ TX_CMPL_R_IRQ(tneta1570_dev) = OWN; -+ tneta1570_dev->txcmpl_ring_idx_irq++; -+ tneta1570_dev->txcmpl_ring_idx_irq %= TXCMPLR_SZ_IRQ; -+ skb = (struct sk_buff *)bus_to_virt(*(p-1)); /* get skb */ -+ v = *(p-2); /* get skb push size */ -+ -+ if(v==0) { /* free copy area */ -+ kfree(p-2); -+ } else { /* correct skb */ -+ skb_pull(skb, v); -+ } -+ -+ vcc = skb->atm.vcc; -+ NULLCHECK(vcc); -+ if (vcc->pop) vcc->pop(vcc,skb); -+ else dev_kfree_skb(skb,FREE_WRITE); + -+ vcc->stats->tx++; -+ TNETA1570_VCC(vcc)->txing--; -+ wake_up_interruptible(&(TNETA1570_VCC(vcc)->tx_wait)); -+dma_complete++; -+ }; -+sti(); -+} ++#include ++#include /* struct socket, struct net_proto, struct ++ proto_ops */ ++#include /* ATM stuff */ ++#include ++#include /* CLIP_*ENCAP */ ++#include /* manifest constants */ ++#include /* for ioctls */ ++#include /* SOL_SOCKET */ ++#include /* error codes */ ++#include /* suser */ ++#include /* verify_area */ ++#include ++#include /* struct timeval */ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AREQUIPA ++#include ++#endif + ++#ifdef CONFIG_ATM_LANE ++#include ++#include "lec.h" ++#include "lec_arpc.h" ++#endif + ++#ifdef CONFIG_ATM_TCP ++#include ++#endif + -+/*--------------------------------- common ----------------------------------*/ ++#include "resources.h" /* atm_find_dev */ ++#include "common.h" /* prototypes */ ++#include "protocols.h" /* atm_init_ */ ++#include "tunable.h" /* tunable parameters */ ++#include "addr.h" /* address registry */ ++#ifdef CONFIG_ATM_CLIP ++#include /* for clip_create */ ++#endif ++#include "signaling.h" /* for WAITING and sigd_attach */ + + -+static void foo(void) -+{ -+printk("tx_complete=%d,dma_complete=%d,queued=%d,requeued=%d,sub=%d,\n" -+ "backlogged=%d,rx_enqueued=%d,rx_dequeued=%d,putting=%d,pushed=%d\n", -+ tx_complete,dma_complete,queued,requeued,submitted,backlogged, -+ rx_enqueued,rx_dequeued,putting,pushed); -+printk("loss: %d\n",TNETA1570_DEV(tneta1570_boards)->lost); -+} ++#if 0 ++#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) ++#else ++#define DPRINTK(format,args...) ++#endif + + -+static void tneta1570_int(int irq,void *dev_id,struct pt_regs *regs) ++static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) +{ -+ struct atm_dev *dev; -+ struct tneta1570_dev *tneta1570_dev; -+ unsigned int reason; ++ struct sk_buff *skb; + -+ EVENT(">tneta_int\n",0,0); -+ dev = dev_id; -+ tneta1570_dev = TNETA1570_DEV(dev); -+ while ( (reason = 0x3ff & SAR_REG_WORD(tneta1570_dev, TNETA_STATUS)) ) { -+ DPRINTK(DEV_LABEL ": int 0x%08x\n",reason); -+ if (reason & TNETA_R1_RX_IRR) { -+ DPRINTK(DEV_LABEL " Unknown PDU %d.%d\n", -+ (SAR_REG_WORD(tneta1570_dev,TNETA_RXUNKNOWN) & 0x3f00) >> 16, -+ SAR_REG_WORD(tneta1570_dev,TNETA_RXUNKNOWN) & 0x0ff); -+ } /* unknown cell received */ -+ if (reason & TNETA_R1_RX_FREEZE) { -+ EVENT("INT: RX Freeze - RX ring overflow\n",0,0); -+ } /* ? */ -+ if (reason & TNETA_R1_TX_FREEZE) { -+ EVENT("INT: TX Freeze - TX ring overflow\n",0,0); -+ dequeue_tx(dev); -+ } /* ? */ -+ if (reason & TNETA_R1_CP_RX) { -+ EVENT("INT: RX Complete - RX buffer completed\n",0,0); -+ dequeue_rx(dev); -+ } /* ? */ -+ if (reason & TNETA_R1_CP_TX) { -+ EVENT("INT: TX Complete - TX Buffer completed\n",0,0); -+ dequeue_tx(dev); -+ /* pop buffers which have been completed */ -+ } -+ } ++ if (atomic_read(&vcc->tx_inuse) && size+atomic_read(&vcc->tx_inuse)+ ++ ATM_PDU_OVHD > vcc->tx_quota) return NULL; ++ while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); ++ DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->tx_inuse),skb->truesize); ++ atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); ++ return skb; +} + -+/* -+ * perform SAR software reset -+ */ -+static int reset_sar(struct tneta1570_dev * tneta1570_dev) ++ ++int atm_create(struct socket *sock,int protocol) +{ -+ int i; -+ unsigned int pci_config[64]; -+ -+ for(i=0; i<64; i++) -+ if(pcibios_read_config_dword(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, -+ i*4, -+ &pci_config[i]) -+ !=PCIBIOS_SUCCESSFUL) return -1; -+ -+ SAR_REG_WORD(tneta1570_dev, TNETA_RESET) = 0; /* reset sar */ -+ -+ for(i=0; i<64; i++) -+ if(pcibios_write_config_dword(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, -+ i*4, -+ pci_config[i]) -+ !=PCIBIOS_SUCCESSFUL) return -1; -+ return 0; -+ ++ struct atm_vcc *vcc; ++ ++ ATM_SD(sock) = NULL; ++ if (sock->type == SOCK_STREAM) return -EINVAL; ++ if (!(vcc = alloc_atm_vcc())) return -ENOMEM; ++#ifdef CONFIG_AREQUIPA ++ vcc->upper = NULL; ++ vcc->sock = sock; ++#endif ++ vcc->flags = ATM_VF_SCRX | ATM_VF_SCTX; ++ vcc->dev = NULL; ++ vcc->family = sock->ops->family; ++ vcc->alloc_tx = alloc_tx; ++ vcc->callback = NULL; ++ memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); ++ memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); ++ vcc->tx_quota = ATM_TXBQ_DEF; ++ vcc->rx_quota = ATM_RXBQ_DEF; ++ atomic_set(&vcc->tx_inuse,0); ++ atomic_set(&vcc->rx_inuse,0); ++ vcc->push = NULL; ++ vcc->peek = NULL; ++ vcc->pop = NULL; ++ vcc->push_oam = NULL; ++ vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ ++ vcc->atm_options = vcc->aal_options = 0; ++ vcc->timestamp.tv_sec = vcc->timestamp.tv_usec = 0; ++ vcc->sleep = vcc->wsleep = NULL; ++ skb_queue_head_init(&vcc->recvq); ++ skb_queue_head_init(&vcc->listenq); ++ ATM_SD(sock) = vcc; ++ return 0; +} + + -+inline void write_sched_tab(struct tneta1570_dev * dev, int i, unsigned int v) -+{ -+ if(1 & i) -+ dev->scheduler[i>>1] = (dev->scheduler[i>>1] & 0xffff) | (v << 16); -+ else -+ dev->scheduler[i>>1] = (dev->scheduler[i>>1] & 0xffff0000) | (v & 0xffff); -+} -+ -+inline int read_sched_tab(struct tneta1570_dev * dev, int i) -+{ -+ if(1 & i) -+ return (dev->scheduler[i>>1] >> 16); -+ else -+ return (0xffff & dev->scheduler[i>>1]); ++int atm_release_vcc(struct atm_vcc *vcc,int free_vcc) ++{ ++ struct sk_buff *skb; ++ ++ vcc->flags &= ~ATM_VF_READY; ++ if (vcc->dev) { ++ if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); ++ if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ ++ while ((skb = skb_dequeue(&vcc->recvq))) { ++ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse); ++ if (vcc->dev->ops->free_rx_skb) ++ vcc->dev->ops->free_rx_skb(vcc,skb); ++ else kfree_skb(skb,FREE_READ); ++ } ++ if (atomic_read(&vcc->rx_inuse)) ++ printk(KERN_WARNING "atm_release_vcc: strange ... " ++ "rx_inuse == %d after closing\n", ++ atomic_read(&vcc->rx_inuse)); ++ bind_vcc(vcc,NULL); ++ } ++ if (free_vcc) free_atm_vcc(vcc); ++ return 0; +} + -+/*--------------------------------- entries ---------------------------------*/ + ++extern void atm_push_clip(struct atm_vcc *vcc,struct sk_buff *skb); + -+static int tneta1570_init(struct atm_dev *dev) -+{ -+ struct tneta1570_dev *tneta1570_dev; -+ unsigned long base; -+ unsigned int real_base; -+ unsigned short command; -+ unsigned char revision; -+ int error,i,last; + -+ EVENT(">tneta1570_init\n",0,0); ++int atm_release(struct socket *sock,struct socket *peer) ++{ ++ struct atm_vcc *vcc; + -+ dev->ci_range.vpi_bits = NR_VPI_LD; -+ dev->ci_range.vci_bits = NR_VCI_LD; -+ tneta1570_dev = TNETA1570_DEV(dev); ++ vcc = ATM_SD(sock); ++ if (!vcc) return 0; ++ return atm_release_vcc(vcc,1); ++} + -+ if ((error = pcibios_read_config_word(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, PCI_COMMAND,&command)) -+ || (error = pcibios_read_config_dword(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn,PCI_BASE_ADDRESS_0,&real_base)) -+ || (error = pcibios_read_config_byte(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, PCI_INTERRUPT_LINE,&tneta1570_dev->irq)) -+ || (error = pcibios_read_config_byte(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, PCI_REVISION_ID,&revision))) { -+ printk(DEV_LABEL "(itf %d): init error %s\n",dev->number, -+ pcibios_strerror(error)); -+ return -EINVAL; -+ } + -+ /* find mapping size of board */ -+ if(pcibios_write_config_dword(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, -+ PCI_BASE_ADDRESS_0, -+ 0xffffffff)!=PCIBIOS_SUCCESSFUL) -+ { -+ printk(DEV_LABEL "(itf %d): init error %s\n",dev->number, -+ pcibios_strerror(error)); -+ return -EINVAL; -+ } ++static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) ++{ ++ int max_sdu; + -+ if(pcibios_read_config_dword(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, -+ PCI_BASE_ADDRESS_0, -+ &(tneta1570_dev->pci_map_size))!=PCIBIOS_SUCCESSFUL) -+ { -+ printk(DEV_LABEL "(itf %d): init error %s\n",dev->number, -+ pcibios_strerror(error)); ++ if (!tp->traffic_class) return 0; ++ if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->max_pcr) + return -EINVAL; -+ } -+ tneta1570_dev->pci_map_size=~tneta1570_dev->pci_map_size+1; -+ -+ if(pcibios_write_config_dword(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, -+ PCI_BASE_ADDRESS_0, -+ real_base)!=PCIBIOS_SUCCESSFUL) -+ { -+ printk(DEV_LABEL "(itf %d): init error %s\n",dev->number, -+ pcibios_strerror(error)); -+ return -EINVAL; -+ } -+ -+ -+ real_base &= MEM_VALID; /* strip flags */ -+ if ((error = pcibios_write_config_word(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, -+ PCI_COMMAND, -+ PCI_COMMAND_MEMORY))) -+ { -+ printk(DEV_LABEL "(itf %d): can't enable memory (%s)\n", -+ dev->number,pcibios_strerror(error)); -+ return error; -+ } -+ printk(DEV_LABEL "(itf %d): rev.%d,irq=%d,",dev->number, -+ revision,tneta1570_dev->irq); -+ if (!(base = (unsigned long) vremap((unsigned long)real_base+TNETA1570_MEM_OFFSET,tneta1570_dev->pci_map_size))) { -+ printk(DEV_LABEL "(itf %d): can't set up page mapping\n", -+ dev->number); -+ return error; -+ } -+ tneta1570_dev->base_diff = real_base-base; -+ tneta1570_dev->reg = (volatile unsigned int *) (base+TNETA_REG_BASE_OFFSET); -+ tneta1570_dev->scheduler = (volatile unsigned int *) (base+TNETA_SCHED_TABLE); -+ tneta1570_dev->ram = (volatile unsigned int *) (base+TNETA_SCHED_TABLE); -+ tneta1570_dev->free_buf_ptr = (volatile struct tneta_rx_fbrptr *) (base+TNETA_FREE_BUFFER_POINTERS); -+ tneta1570_dev->rx_vpi_vci = (volatile unsigned int *) (base+TNETA_RX_VPIVCI_DMA_POINTERS); -+ tneta1570_dev->tx_dma_state = (volatile struct tneta_tx_dma_state_table *) (base+TNETA_TX_DMA_STATE_TABLE); -+ tneta1570_dev->rx_dma_state = (volatile struct tneta_rx_dma_state_table *) (base+TNETA_RX_DMA_STATE_TABLE); -+ tneta1570_dev->phy = (volatile unsigned int *) (base+TNETA_SUNI_OFFSET); -+ -+ tneta1570_dev->txcmpl_ring_idx_noi = 0; -+ tneta1570_dev->txcmpl_ring_idx_irq = 0; -+ tneta1570_dev->rxcmpl_ring_idx_noi = 0; -+ tneta1570_dev->rxcmpl_ring_idx_irq = 0; -+ -+ /* test board memory, find amount of memory installed */ -+ last = (TNETA_SUNI_OFFSET)/4; /* max up to phy ctrl */ -+ for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) { -+ if(i>RESERVED_UL || iram[i] = 0x55555555; -+ if (tneta1570_dev->ram[i] != 0x55555555) last = i; -+ else { -+ tneta1570_dev->ram[i] = 0xAAAAAAAA; -+ if (tneta1570_dev->ram[i] != 0xAAAAAAAA) last = i; -+ else tneta1570_dev->ram[i] = i; -+ } -+ } ++ switch (aal) { ++ case ATM_AAL0: ++ max_sdu = ATM_CELL_SIZE-1; ++ break; ++ case ATM_AAL34: ++ max_sdu = ATM_MAX_AAL34_PDU; ++ break; ++ default: ++ printk(KERN_WARNING "ATM: AAL problems ... " ++ "(%d)\n",aal); ++ /* fall through */ ++ case ATM_AAL5: ++ max_sdu = ATM_MAX_AAL5_PDU; + } -+ for (i = 0; i < last; i += RAM_INCREMENT) -+ if(i>RESERVED_UL || iram[i] != i) break; -+ -+ tneta1570_dev->mem = i << 2; /* byte count */ -+ /* init control memory with all 0s (including regs) */ -+ last = i; -+ /* bring sar up */ -+ for(i=0; iRESERVED_UL || iram[i] = 0; -+ -+ (tneta1570_dev->reg[TNETA_STATUS] & 0x00000400)? -+ printk("mem=%dkB,mode=64 bit,",tneta1570_dev->mem >> 10): -+ printk("mem=%dkB,mode=32 bit,",tneta1570_dev->mem >> 10); -+ -+ /* reset SAR */ -+ reset_sar(tneta1570_dev); -+ -+ for(i=0; iRESERVED_UL || iram[i] = 0; -+ ++ if (!tp->max_sdu) tp->max_sdu = max_sdu; ++ else if (tp->max_sdu > max_sdu) return -EINVAL; ++ if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV; + return 0; +} + + -+static int tneta1570_start(struct atm_dev *dev) -+{ -+ struct tneta1570_dev *tneta1570_dev; -+ int error; -+ unsigned char phy; -+ -+ EVENT(">tneta1570_start\n",0,0); -+ tneta1570_dev = TNETA1570_DEV(dev); -+ if (request_irq(tneta1570_dev->irq,&tneta1570_int,0,DEV_LABEL,dev)) { -+ printk(DEV_LABEL "(itf %d): IRQ%d is already in use\n", -+ dev->number,tneta1570_dev->irq); -+ return -EAGAIN; -+ } -+ /* @@@ should release IRQ on error */ -+ -+ if ((error = pcibios_write_config_word(tneta1570_dev->bus, -+ tneta1570_dev->dev_fn, -+ PCI_COMMAND, -+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER))) -+ { -+ printk(DEV_LABEL "(itf %d): can't enable memory+master (%s)\n", -+ dev->number,pcibios_strerror(error)); -+ return error; -+ } -+ -+ if((phy=tneta1570_phy_get(dev,0))==0x30) { -+ printk("pm5346,rev.%d \n",phy&0x0f); -+ suni_init(dev); -+ } else { -+ printk("utopia,rev.%d \n",phy&0x0f); -+ utopia_init(dev); -+ } -+ -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) = TNETA_R0_STANDARD_MODE; -+ SAR_REG_WORD(tneta1570_dev, TNETA_INT_MASK) = TNETA_R2_STANDARD_INTS; -+ -+ error = dev->phy->start(dev); -+ if (error) return error; -+ error = start_tx(dev); -+ if (error) return error; -+ error = start_rx(dev); -+ if (error) return error; -+ -+ return 0; -+} -+ -+ -+ -+static void tneta1570_close(struct atm_vcc *vcc) -+{ -+ EVENT(">tneta1570_close\n",0,0); -+ if (!TNETA1570_VCC(vcc)) return; -+ vcc->flags &= ~ATM_VF_READY; -+ close_rx(vcc); -+ close_tx(vcc); -+ EVENT("tneta1570_close: done waiting\n",0,0); -+ /* deallocate memory */ -+ kfree(TNETA1570_VCC(vcc)); -+ TNETA1570_VCC(vcc) = NULL; -+ vcc->flags &= ~ATM_VF_ADDR; -+ /*foo();*/ -+} -+ -+ -+static int tneta1570_open(struct atm_vcc *vcc,short vpi,int vci) ++static int check_ci(struct atm_vcc *vcc,short vpi,int vci) +{ -+ struct tneta1570_dev *tneta1570_dev; -+ struct tneta1570_vcc *tneta1570_vcc; -+ int error; ++ struct atm_vcc *walk; + -+ EVENT(">tneta1570_open\n",0,0); -+ TNETA1570_VCC(vcc) = NULL; -+ vcc->alloc_tx = tneta1570_alloc_tx; /* set my skb_alloc function */ -+ -+ tneta1570_dev = TNETA1570_DEV(vcc->dev); -+ error = atm_find_ci(vcc,&vpi,&vci); /* get connection id */ -+ if (error) return error; -+ vcc->vpi = vpi; -+ vcc->vci = vci; -+ if (vcc->aal != ATM_AAL0 && vcc->aal != ATM_AAL5) return -EINVAL; -+ tneta1570_vcc = kmalloc(sizeof(struct tneta1570_vcc),GFP_KERNEL); -+ if (!tneta1570_vcc) return -ENOMEM; -+ TNETA1570_VCC(vcc) = tneta1570_vcc; -+ DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, -+ vcc->vci); -+ vcc->flags |= ATM_VF_ADDR; /* set flag */ -+ if ((error = open_rx(vcc))) { /* open rx */ -+ tneta1570_close(vcc); /* close on error */ -+ return error; -+ } -+ if ((error = open_tx(vcc))) { /* open tx */ -+ tneta1570_close(vcc); -+ return error; -+ } -+ vcc->flags |= ATM_VF_READY; /* set IF ready */ -+ /* should power down SUNI while !ref_count @@@ */ ++ for (walk = vcc->dev->vccs; walk; walk = walk->next) ++ if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi && ++ walk->vci == vci && ((walk->qos.txtp.traffic_class != ++ ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) || ++ (walk->qos.rxtp.traffic_class != ATM_NONE && ++ vcc->qos.rxtp.traffic_class != ATM_NONE))) ++ return -EADDRINUSE; ++ /* allow VCCs with same VPI/VCI iff they don't collide on ++ TX/RX (but we may refuse such sharing for other reasons, ++ e.g. if protocol requires to have both channels) */ + return 0; +} + + -+static int tneta1570_ioctl(struct atm_dev *dev,unsigned int cmd,unsigned long arg) ++int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) +{ -+ struct tneta1570_dev *tneta1570_dev; ++ static short p = 0; /* poor man's per-device cache */ ++ static int c = 0; ++ short old_p; ++ int old_c; + -+ tneta1570_dev = TNETA1570_DEV(dev); -+ printk(DEV_LABEL "ioctl \n"); -+ switch (cmd) { -+ case TNETA_LOOP: -+ if(arg) -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= -+ TNETA_R0_LOOP; -+ else -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) &= -+ ~TNETA_R0_LOOP; -+ return 0; -+ case TNETA_INVHEC: -+ if(arg) -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= -+ TNETA_R0_TX_HECERR; -+ else -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) &= -+ ~TNETA_R0_TX_HECERR; -+ return 0; -+ case TNETA_ENTX: -+ if(arg) -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= -+ TNETA_R0_TX_ENABLE; -+ else -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) &= -+ ~TNETA_R0_TX_ENABLE; -+ return 0; -+ case TNETA_ENRX: -+ if(arg) -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= -+ TNETA_R0_RX_ENABLE; -+ else -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) &= -+ ~TNETA_R0_RX_ENABLE; -+ return 0; -+ case TNETA_BP: -+ if(arg) -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= -+ TNETA_R0_PERBUFFER; -+ else -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) &= -+ ~TNETA_R0_PERBUFFER; -+ return 0; -+ case TNETA_RAT: -+ if(arg) -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) |= -+ TNETA_R0_RAT_ENABL; -+ else -+ SAR_REG_WORD(tneta1570_dev, TNETA_CONFIG) &= -+ ~TNETA_R0_RAT_ENABL; ++ if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) ++ return check_ci(vcc,*vpi,*vci); ++ /* last scan may have left values out of bounds for current device */ ++ if (*vpi != ATM_VPI_ANY) p = *vpi; ++ else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; ++ if (*vci != ATM_VCI_ANY) c = *vci; ++ else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits) ++ c = ATM_NOT_RSV_VCI; ++ old_p = p; ++ old_c = c; ++ do { ++ if (!check_ci(vcc,p,c)) { ++ *vpi = p; ++ *vci = c; + return 0; -+ case TNETA_RXUNKN: -+ return(SAR_REG_SHORT(tneta1570_dev, TNETA_UNKNOWN_P)); -+ case TNETA_HECERR: -+ return(SAR_REG_SHORT(tneta1570_dev, TNETA_S_HEC_ERR)); -+ case TNETA_AAL5DISC: -+ return(SAR_REG_SHORT(tneta1570_dev, TNETA_S_AAL_DISCARD)); -+ case TNETA_RXCELL: -+ return(SAR_REG_WORD(tneta1570_dev, TNETA_CELL_RXC)); -+ case TNETA_TXCELL: -+ return(SAR_REG_WORD(tneta1570_dev, TNETA_CELL_TXC)); -+ default: -+ if (!dev->phy->ioctl) return -EINVAL; -+ return dev->phy->ioctl(dev,cmd,arg); + } ++ if (*vci == ATM_VCI_ANY) { ++ c++; ++ if (c >= 1 << vcc->dev->ci_range.vci_bits) ++ c = ATM_NOT_RSV_VCI; ++ } ++ if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) && ++ *vpi == ATM_VPI_ANY) { ++ p++; ++ if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; ++ } ++ } ++ while (old_p != p || old_c != c); ++ return -EADDRINUSE; +} + + -+static int tneta1570_getsockopt(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int *optlen) -+{ -+ return -EINVAL; -+} -+ -+ -+static int tneta1570_setsockopt(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int optlen) ++static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, ++ int vci) +{ -+ return -EINVAL; -+} ++ int error; + -+/* -+ * -- send a PDU (AAL5 or AAL0) -+ */ -+static int tneta1570_send(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+ EVENT(">tneta1570_send\n",0,0); -+ if (!skb) { -+ printk("!skb in tneta1570_send ?\n"); -+ dev_kfree_skb(skb,FREE_WRITE); ++ if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY && ++ vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC && ++ vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits)) + return -EINVAL; ++ if (vci > 0 && vci < ATM_NOT_RSV_VCI && !suser()) return -EPERM; ++ error = 0; ++ switch (vcc->qos.aal) { ++ case ATM_AAL0: ++ error = atm_init_aal0(vcc); ++ vcc->stats = &dev->stats.aal0; ++ break; ++ case ATM_AAL34: ++ error = atm_init_aal34(vcc); ++ vcc->stats = &dev->stats.aal34; ++ break; ++ case ATM_NO_AAL: ++ /* ATM_AAL5 is also used in the "0 for default" case */ ++ vcc->qos.aal = ATM_AAL5; ++ /* fall through */ ++ case ATM_AAL5: ++ error = atm_init_aal5(vcc); ++ vcc->stats = &dev->stats.aal5; ++ break; ++ default: ++ error = -EPROTOTYPE; + } -+ if (vcc->aal == ATM_AAL0) { -+ if (skb->len != ATM_CELL_SIZE-1) { -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; ++ if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal); ++ if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal); ++ if (error) return error; ++ bind_vcc(vcc,dev); ++ DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal); ++ DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class, ++ vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu); ++ DPRINTK(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class, ++ vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu); ++ if (dev->ops->open) { ++ error = dev->ops->open(vcc,vpi,vci); ++ if (error) { ++ bind_vcc(vcc,NULL); ++ return error; + } -+ *(unsigned long *) skb->data = htonl(*(unsigned long *) -+ skb->data); -+ /* correct byte order of an AAL0 header */ + } -+ -+submitted++; -+ skb->atm.vcc = vcc; -+ -+ return do_tx(skb); -+} -+ -+ -+static void tneta1570_phy_put(struct atm_dev *dev,unsigned char value, -+ unsigned long addr) -+{ -+ int i=0; -+ TNETA1570_DEV(dev)->phy[addr+TNETA_SUNI_RDREQ]=0; -+ while(i++<20 && !(TNETA1570_DEV(dev)->phy[addr+TNETA_SUNI_RDREQ] & 0x10)); -+ TNETA1570_DEV(dev)->phy[addr] = value; ++ return 0; +} + + -+ -+static unsigned char tneta1570_phy_get(struct atm_dev *dev,unsigned long addr) ++static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci) +{ -+ volatile unsigned tmp; /* force 32 bit access */ -+ int i=0; -+ /* set address */ -+ TNETA1570_DEV(dev)->phy[addr+TNETA_SUNI_RDREQ]=0; -+ while(i++<20 && !(TNETA1570_DEV(dev)->phy[addr+TNETA_SUNI_RDREQ] & 0x10)); -+ TNETA1570_DEV(dev)->phy[addr+TNETA_SUNI_RDREQ]=i=0; -+ while(i++<20 && !(TNETA1570_DEV(dev)->phy[addr+TNETA_SUNI_RDREQ] & 0x08)); -+ tmp=TNETA1570_DEV(dev)->phy[addr]; ++ struct atm_dev *dev; + -+ return (unsigned char)(0xff & tmp); ++ dev = atm_find_dev(itf); ++ if (!dev) return -ENODEV; ++ return atm_do_connect_dev(vcc,dev,vpi,vci); +} + + -+static struct atmdev_ops ops = { -+ tneta1570_open, -+ tneta1570_close, -+ tneta1570_ioctl, -+ tneta1570_getsockopt, -+ tneta1570_setsockopt, -+ tneta1570_send, -+ NULL, /* no tneta1570_sg_send */ -+ NULL, /* no poll */ -+ NULL, /* no send_oam ???? */ -+ tneta1570_phy_put, -+ tneta1570_phy_get, -+ NULL, /* no feedback */ -+ NULL, /* no change_qos */ -+ NULL /* no free_rx_skb */ -+}; -+ -+ -+int tneta1570_detect(void) ++int atm_connect(struct socket *sock,int itf,short vpi,int vci) +{ -+ struct atm_dev *dev; -+ struct tneta1570_dev *tneta1570_dev; -+ int index; ++ struct atm_vcc *vcc; ++ int error; + -+ if (!pcibios_present()) { -+ printk(DEV_LABEL " driver but no PCI BIOS ?\n"); -+ return 0; -+ } -+ tneta1570_dev = (struct tneta1570_dev *) kmalloc(sizeof(struct tneta1570_dev), -+ GFP_KERNEL); -+ if (!tneta1570_dev) return -ENOMEM; -+ index = 0; -+ while (!pcibios_find_device(PCI_VENDOR_ID_TI, -+ PCI_DEVICE_ID_TI_TNETA1570, -+ index, -+ &tneta1570_dev->bus, -+ &tneta1570_dev->dev_fn) -+ || !pcibios_find_device(PCI_VENDOR_ID_TI, -+ PCI_DEVICE_ID_TI_TNETA1575, -+ index, -+ &tneta1570_dev->bus, -+ &tneta1570_dev->dev_fn)) -+ { -+ dev = atm_dev_register(DEV_LABEL,&ops,0); -+ if (!dev) break; -+ TNETA1570_DEV(dev) = tneta1570_dev; -+ -+ if (tneta1570_init(dev) || tneta1570_start(dev)) { -+ atm_dev_deregister(dev); -+ break; -+ } -+ tneta1570_dev->more = tneta1570_boards; -+ tneta1570_boards = dev; -+ index++; -+ tneta1570_dev = (struct tneta1570_dev *) kmalloc(sizeof(struct tneta1570_dev), -+ GFP_KERNEL); -+ if (!tneta1570_dev) break; -+ ++ DPRINTK("atm_connect (vpi %d, vci %d)\n",vpi,vci); ++ if (sock->state == SS_CONNECTED) return -EISCONN; ++ if (sock->state != SS_UNCONNECTED) return -EINVAL; ++ if (!(vpi || vci)) return -EINVAL; ++ vcc = ATM_SD(sock); ++ if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) ++ vcc->flags &= ~ATM_VF_PARTIAL; ++ else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL; ++ printk("atm_connect (TX: cl %d,bw %d-%d,sdu %d; RX: cl %d,bw %d-%d," ++ "sdu %d,AAL %d)\n",vcc->qos.txtp.traffic_class, ++ vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, ++ vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr, ++ vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,vcc->qos.aal); ++ if (!vcc->qos.txtp.traffic_class && !vcc->qos.rxtp.traffic_class) ++ return -EINVAL; ++ if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || ++ vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) ++ return -EINVAL; ++ if (itf != ATM_ITF_ANY) { ++ error = atm_do_connect(vcc,itf,vpi,vci); ++ if (error) return error; + } -+ return index; -+} -+ -+#ifdef MODULE ++ else { ++ struct atm_dev *dev; + -+int init_module(void) -+{ -+ if (!tneta1570_detect()) { -+ printk(DEV_LABEL ": no adapter found\n"); -+ return -ENXIO; ++ for (dev = atm_devs; dev; dev = dev->next) ++ if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break; ++ if (!dev) return -ENODEV; + } -+ MOD_INC_USE_COUNT; ++ if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) ++ vcc->flags |= ATM_VF_PARTIAL; ++ else sock->state = SS_CONNECTED; + return 0; +} -+void cleanup_module(void){ -+ -+/* not yet */ -+} -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/fore200.c Fri Nov 15 19:06:28 1996 -@@ -0,0 +1,26 @@ -+/* drivers/atm/fore200.c - This is just a test, not a real driver */ -+ -+/* Written 1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include + + -+int fore200_detect(void) ++int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, ++ int flags,struct scm_cookie *scm) +{ -+ struct linux_sbus *bus; -+ struct linux_sbus_device *sdev = 0; -+ -+ for_each_sbus(bus) { -+ for_each_sbusdev(sdev, bus) { -+ if (strcmp(sdev->prom_name,"FORE,sba-200") == 0) { -+ printk(KERN_NOTICE "fore200: found an SBA-200 " -+ "in slot %x,offset=%08lx,irq=%d", -+ sdev->slot,sdev->offset,sdev->irqs->pri); -+ } -+ } -+ } -+ return 0; -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/nicstar.h Wed Jan 29 19:24:54 1997 -@@ -0,0 +1,319 @@ -+/* nicstar.h, M. Welsh (matt.welsh@cl.cam.ac.uk) -+ * Definitions for IDT77201. -+ * -+ * Copyright (c) 1996 University of Cambridge Computer Laboratory -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * M. Welsh, 6 July 1996 -+ * -+ * -+ * Configuration notes: -+ * Driver can be configured by defining/undefining -+ * the configuration options below. -+ * Supported VPI/VCI range can be adjusted; search for -+ * CFG_VPIVCI for more info. -+ * A 128k x 32 SRAM board might require adjusting some constants -+ * below; see IDT 77201 NICStAR User's Manual -+ * -+ * If you want to use a different size for the small free buffers, -+ * be sure to set SM_BUFSZ to the actual buffer size + 4 -+ * -+ * I'm not convinced that the CBR support is "accurate"; if you want -+ * to find out what's wrong, feel free. -+ * -+ * S. Daniel, Nov. 25, 1996 -+ * -+ */ ++ struct atm_vcc *vcc; ++ struct sk_buff *skb; ++ unsigned long cpu_flags; ++ int eff_len,error; + -+#ifndef _LINUX_NICSTAR_H -+#define _LINUX_NICSTAR_H ++ void *buff; ++ int size; + -+#include -+#include -+ -+/* User definitions *********************************************************/ -+ -+#define NICSTAR_DEV_MAJOR 35 -+ -+/* misc configuration options */ -+#define NICSTAR_FASTXMIT 1 /* Lies about buffer lengths to speed xmit -+ possibly insecure (see nicstar.c) */ -+#define NICSTAR_CBR 1 /* Constant bit rate support */ -+#undef NICSTAR_RCQ /* Raw cell queue support; just prints out raw cells */ -+#define NICSTAR_PARANOID 1 /* adds some extra checks */ -+#undef TEST_LOOPBACK /* enables PHY-level loopback */ -+#undef ATM_013 /* should be removed soon; compat w/ ATM rel 0.13 */ -+#undef NICSTAR_LBUFCNT /* for debugging; keeps count of length of LGBUF_Q */ -+ -+/* Kernel definitions ******************************************************/ -+ -+#ifdef __KERNEL__ -+ -+#define NICSTAR_MAX_DEVS 5 -+#define NICSTAR_IO_SIZE (4*1024) -+ -+#define SM_BUFSZ 52 -+#define SM_BUF_DATALEN (SM_BUFSZ - 4) -+#define NUM_SM_BUFS 170 -+#define LG_BUFSZ 16384 -+#define LG_BUFMSK 0x06000000 /* 16k = 0x06000000 -+ 8k = 0x04000000 -+ 4k = 0x02000000 -+ 2k = 0x00000000 */ -+#define RAWCELLSZ 64 -+#define NUM_LG_BUFS 32 -+#define MAX_SDU_BUFS 32 /* Max number of buffers in an AAL5 SDU */ -+#define NUM_RX_SKB 32 /* Number of SKB's to allocate for receive */ -+#define NUM_SCQ_TRAIL 32 /* Number of outstanding SCQ entries */ -+#define TST_SIZE 200 /* Size of the Transmit Schedule Table -+ This determines resolution for CBR, -+ and thus lower bound on available BW */ -+#define IDT_25_PCR (25600000/270*260/8/53) -+ /* Link rate: 25600000 bps -+ SONET overhead: /270*260 (9 section, 1 path) -+ bits per cell: /8/53 -+ max cell rate: 58141.16 cells/sec */ -+ -+/* TST entry values */ -+#define TSTE_NULL 0x0 /* force NULL cell xmit */ -+#define TSTE_CBR 0x20000000 /* transmit CBR cell */ -+#define TSTE_VBR 0x40000000 /* transmit VBR cell */ -+#define TSTE_JUMP 0x60000000 /* Jump to SRAM addr */ -+ -+ -+enum nicstar_regs { -+ DR0 = 0x00, -+ DR1 = 0x04, -+ DR2 = 0x08, -+ DR3 = 0x0c, -+ CMD = 0x10, -+ CFG = 0x14, -+ STAT = 0x18, -+ RSQB = 0x1c, -+ RSQT = 0x20, -+ RSQH = 0x24, -+ CDC = 0x28, -+ VPEC = 0x2c, -+ ICC = 0x30, -+ RAWCT = 0x34, -+ TMR = 0x38, -+ TSTB = 0x3c, -+ TSQB = 0x40, -+ TSQT = 0x44, -+ TSQH = 0x48, -+ GP = 0x4c, -+ VPM = 0x50 -+}; -+ -+/* SRAM locations */ -+#define NICSTAR_VBR_SCD0 (0x1e7f4) -+#define NICSTAR_VBR_SCD1 (0x1e7e8) -+#define NICSTAR_VBR_SCD2 (0x1e7dc) -+#define NICSTAR_TST_REGION (0x1c000) /* For 32k SRAM */ -+#define NICSTAR_SCD_REGION (0x1d000) /* Arbitrary value */ -+ -+typedef struct nicstar_rcte { -+ u32 status; -+ u32 buf_handle; -+ u32 dma_addr; -+ u32 crc; -+} nicstar_rcte; -+#define RX_CTABLE_SIZE (16 * 1024) /* 16k words */ -+ -+typedef struct nicstar_fbd { -+ u32 buf_handle; -+ u32 dma_addr; -+} nicstar_fbd; -+ -+#define RSQE_GFC_MASK 0x00004000 -+#define RSQE_CLP_MASK 0x00000400 -+ -+typedef struct nicstar_rsqe { -+ u32 vpi_vci; -+ u32 buf_handle; -+ u32 crc; -+ u32 status; -+} nicstar_rsqe; -+#define RX_STATQ_ENTRIES (512) -+ -+typedef struct nicstar_tbd { -+ u32 status; -+ u32 buf_addr; -+ u32 ctl_len; -+ u32 cell_hdr; -+} nicstar_tbd; -+ -+#define TBD_SIZE (16) -+#ifdef NICSTAR_FASTXMIT -+/* following apply to NIC_TBD_DESC */ -+#define TBD_ENDPDU 0x40000000 /* 1 => last buffer of -+ AAL5 CS_PDU */ -+#define TBD_AAL0 0x00000000 /* 000 = AAL0 */ -+#define TBD_AAL34 0x04000000 /* 001 = AAL3/4 */ -+#define TBD_AAL5 0x08000000 /* 010 = AAL5 */ -+ -+#endif -+ /* for CBR, set M and N to all 0 */ -+#define TBD_UBR_M 0x00800000 /* M value timer count, VBR */ -+#define TBD_UBR_N 0x00010000 /* N value timer count, VBR */ -+ -+#define SCQ_SIZE (8192) /* Number of bytes actually allocated */ -+#define SCQ_ENTRIES (SCQ_SIZE / TBD_SIZE) /* Variable-rate SCQ */ /* XXX 511 */ -+#define CBRSCQ_SIZE (1024) /* space to reserve for each */ -+#define CBRSCQ_ENTRIES (CBRSCQ_SIZE / TBD_SIZE) /* # entries in a CBR SCQ */ -+#ifdef NICSTAR_CBR -+/* magic #s must be non-zero; restrict to high two bits to support -+ largest possible receive table (8 VPI bits, 6 VCI bits) -+ Magic #s must be non-zero to distinguish them from the timestamp -+ overflow */ -+#define SCQFULL_MAGIC (0xc0000000) -+#define CBRSCQFULL_MAGIC (0x80000000) -+#define CBRSCQFULL_MAGIC_CLOSE (0x40000000) -+#else -+#define SCQFULL_MAGIC (0xfeed0000) -+#endif -+#define SCQFULL_TIMEOUT (3 * HZ) -+ -+typedef struct nicstar_scd { -+ u32 base_addr; -+ u32 tail_addr; -+ u32 crc; -+ u32 rsvd; -+ struct nicstar_tbd cache_a; -+ struct nicstar_tbd cache_b; -+} nicstar_scd; -+ -+typedef struct nicstar_tsi { -+ u32 status; -+ u32 timestamp; -+} nicstar_tsi; -+#define TX_STATQ_ENTRIES (1024) -+ -+typedef struct nicstar_scq_shadow { -+#ifndef NICSTAR_FASTXMIT -+ unsigned char cell[48]; -+#endif -+ struct sk_buff *skb; -+} nicstar_scq_shadow; -+ -+typedef struct nicstar_scq { -+ struct nicstar_tbd *orig; -+ struct nicstar_tbd *base; -+ struct nicstar_tbd *next; -+ struct nicstar_tbd *last; -+ struct nicstar_tbd *tail; -+ struct wait_queue *scqfull_waitq; -+ u32 id; -+ u32 scd; /* SRAM address of paired SCD */ -+ int closing; -+ nicstar_scq_shadow scq_shadow[SCQ_ENTRIES]; -+ volatile int full; -+} nicstar_scq; -+ -+typedef struct nicstar_vcimap { -+ int tx:1; -+ int rx:1; -+ struct atm_vcc *tx_vcc; -+ struct atm_vcc *rx_vcc; -+ struct sk_buff *rx_skb; -+ /* Pointer to SCQ for channel if CBR */ -+#ifdef NICSTAR_CBR -+ nicstar_scq *scq; -+#endif -+} nicstar_vcimap; -+ -+/* Valid combinations for VPI/VCI: -+ 4k table, no VPI, 12b VCI (set CFG_VPIVCI to 0x00000) -+ 4k table, 1b VPI, 11b VCI (set CFG_VPIVCI to 0x40000) -+ 4k table, 2b VPI, 10b VCI (set CFG_VPIVCI to 0x80000) -+ 4k table, 8b VPI, 4b VCI (set CFG_VPIVCI to 0xc0000) -+ *** below only for boards with 128k x 32b SRAM *** -+ 8k table, no VPI, 13b VCI (set CFG_VPIVCI to 0x10000) -+ 8k table, 1b VPI, 12b VCI (set CFG_VPIVCI to 0x50000) -+ 8k table, 2b VPI, 11b VCI (set CFG_VPIVCI to 0x90000) -+ 8k table, 8b VPI, 5b VCI (set CFG_VPIVCI to 0xd0000) -+ 16k table, no VPI, 14b VCI (set CFG_VPIVCI to 0x20000) -+ 16k table, 1b VPI, 13b VCI (set CFG_VPIVCI to 0x60000) -+ 16k table, 2b VPI, 12b VCI (set CFG_VPIVCI to 0xa0000) -+ 16k table, 8b VPI, 6b VCI (set CFG_VPIVCI to 0xe0000) -+ You will need to define each of the below to match the desired config -+ */ -+#define CFG_VPIVCI 0x40000 -+#define NUM_VCI (2048) /* Size of Rx conn table, indexed by VCI only */ -+#define NUM_VCI_BITS (11) /* Num sig bits */ -+#define NUM_VPI (2) /* Only VPI 0 currently defined */ -+#define NUM_VPI_BITS (1) /* Number of bits required for above */ -+ -+typedef struct nicstar_buf_list { -+ caddr_t buf_addr; -+ struct nicstar_buf_list *next; -+} nicstar_buf_list; -+ -+ -+#if NICSTAR_RCQ -+typedef struct nicstar_rcq { /* Raw cell queue */ -+ u32 rcq_head; /* pointer to current head of queue */ -+ u32 rcq_base; /* pointer to current buffer */ -+} nicstar_rcq; -+#endif -+ -+typedef struct sk_buff *skb_ptr; -+ -+typedef struct nicstar_dev { -+ -+ int index; /* Device index */ -+ unsigned long iobase, membase; /* I/O and memory addresses */ -+ unsigned char modid, revid; /* PCI module and revision ID */ -+ unsigned char pci_bus, pci_devfn; /* PCI params */ -+ int irq; /* IRQ line */ -+ int inuse; -+ int rev_C3; /* True if chip is rev. C3 */ -+ -+ nicstar_rsqe *rx_statq, *rx_statq_last; -+ volatile nicstar_rsqe *rx_statq_next; -+ caddr_t rx_statq_orig; -+ nicstar_tsi *tx_statq, *tx_statq_next, *tx_statq_last; -+ caddr_t tx_statq_orig; -+ -+ u32 *host_tst; -+ int available_slots; /* VBR slots in TST */ -+ int max_pcr; /* Maximum PCR for the PHY */ -+ -+#if NICSTAR_RCQ -+ nicstar_rcq rcq; -+#endif -+ -+ caddr_t sm_bufs, lg_bufs; -+ struct sk_buff_head rx_skb_queue; -+ -+ nicstar_scq *scq; -+ caddr_t scq_orig; -+ -+ skb_ptr rx_lg_skb[NUM_LG_BUFS]; -+ -+ struct atm_dev *dev; -+ nicstar_vcimap vci_map[NUM_VPI * NUM_VCI]; -+ unsigned char tmp_cell[48]; ++ if (sock->state != SS_CONNECTED) return -ENOTCONN; ++ if (flags & ~MSG_DONTWAIT) return -EOPNOTSUPP; ++ if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ ++ buff = m->msg_iov->iov_base; ++ size = m->msg_iov->iov_len; ++ vcc = ATM_SD(sock); ++ save_flags(cpu_flags); ++ cli(); ++ while (!(skb = skb_dequeue(&vcc->recvq))) { ++ if (vcc->flags & ATM_VF_RELEASED) return vcc->reply; ++ if (!(vcc->flags & ATM_VF_READY)) return 0; ++ if (flags & MSG_DONTWAIT) { ++ restore_flags(cpu_flags); ++ return -EAGAIN; ++ } ++ interruptible_sleep_on(&vcc->sleep); ++ if (current->signal & ~current->blocked) { ++ restore_flags(cpu_flags); ++ return -ERESTARTSYS; ++ } ++ } ++ restore_flags(cpu_flags); ++ vcc->timestamp = skb->stamp; ++ eff_len = skb->len > size ? size : skb->len; ++ if (vcc->dev->ops->feedback) ++ vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data, ++ (unsigned long) buff,eff_len); ++ DPRINTK("RcvM %d -= %d\n",vcc->rx_inuse,skb->truesize); ++ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse); ++ if (skb->atm.iovcnt) { /* @@@ hack */ ++ /* iovcnt set, use scatter-gather for receive */ ++ int el, cnt; ++ struct iovec *iov = (struct iovec *)skb->data; ++ unsigned char *p = (unsigned char *)buff; + -+#ifdef NICSTAR_LBUFCNT -+ int lbuf_cnt; ++ el = eff_len; ++ error = 0; ++ for (cnt = 0; (cnt < skb->atm.iovcnt) && el; cnt++) { ++printk("s-g???: %p -> %p (%d)\n",iov->iov_base,p,iov->iov_len); ++ error = copy_to_user(p,iov->iov_base, ++ (iov->iov_len > el) ? el : iov->iov_len); ++ if (error) break; ++ p += iov->iov_len; ++ el -= (iov->iov_len > el)?el:iov->iov_len; ++ iov++; ++ } ++ if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb,FREE_READ); ++ else vcc->dev->ops->free_rx_skb(vcc, skb); ++ return error ? error : eff_len; ++ } ++#ifdef CONFIG_MMU_HACKS ++ if (vcc->flags & ATM_VF_SCRX) ++ mmucp_tofs((unsigned long) buff,eff_len,skb, ++ (unsigned long) skb->data); ++ else +#endif -+ -+} nicstar_dev, *nicstar_devp; -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _LINUX_NICSTAR_H_ */ ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/drivers/atm/nicstar.c Tue Mar 11 12:21:57 1997 -@@ -0,0 +1,2074 @@ -+/* nicstar.c, M. Welsh (matt.welsh@cl.cam.ac.uk) -+ * -+ * Linux driver for the IDT77201 NICStAR PCI ATM controller. -+ * PHY component is expected to be 155 Mbps S/UNI-Lite or IDT 77155; -+ * see init_nicstar() for PHY initialization to change this. This driver -+ * expects the Linux ATM stack to support scatter-gather lists -+ * (skb->atm.iovcnt != 0) for Rx skb's passed to vcc->push. -+ * -+ * Implementing minimal-copy of received data: -+ * IDT always receives data into a small buffer, then large buffers -+ * as needed. This means that data must always be copied to create -+ * the linear buffer needed by most non-ATM protocol stacks (e.g. IP) -+ * Fix is simple: make large buffers large enough to hold entire -+ * SDU, and leave bytes empty at the start. Then -+ * copy small buffer contents to head of large buffer. -+ * Trick is to avoid fragmenting Linux, due to need for a lot of large -+ * buffers. This is done by 2 things: -+ * 1) skb->destructor / skb->atm.recycle_buffer -+ * combined, allow nicstar_free_rx_skb to be called to -+ * recycle large data buffers -+ * 2) skb_clone of received buffers -+ * See nicstar_free_rx_skb and linearize_buffer for implementation -+ * details. -+ * -+ * Copyright (c) 1996 University of Cambridge Computer Laboratory -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * M. Welsh, 6 July 1996 -+ * -+ */ -+/* -+static char _modversion[] = "@(#) nicstar.c, $Id: nicstar.c,v 1.35 1997/01/08 22:27:12 swdaniel Exp $"; -+*/ ++ { ++ error = copy_to_user(buff,skb->data,eff_len); ++ if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb,FREE_READ); ++ else vcc->dev->ops->free_rx_skb(vcc, skb); ++ } ++ return error ? error : eff_len; ++} + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include + -+#include -+char kernel_version[] = UTS_RELEASE; ++int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, ++ struct scm_cookie *scm) ++{ ++ struct atm_vcc *vcc; ++ struct sk_buff *skb; ++ int eff,error; + -+#include "nicstar.h" -+#include "../../net/atm/protocols.h" /* hack! */ ++ const void *buff; ++ int size; + -+#undef NICSTAR_DEBUG /* Define for verbose debugging output */ -+#define NICSTAR_RC_FLAG 1 ++ if (sock->state != SS_CONNECTED) return -ENOTCONN; ++ if (m->msg_name) return -EISCONN; ++ if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ ++ buff = m->msg_iov->iov_base; ++ size = m->msg_iov->iov_len; ++ vcc = ATM_SD(sock); ++ if (vcc->flags & ATM_VF_RELEASED) return vcc->reply; ++ if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; ++ if (!size) return 0; ++ /* verify_area is done by net/socket.c */ ++#ifdef CONFIG_MMU_HACKS ++ if ((vcc->flags & ATM_VF_SCTX) && vcc->dev->ops->sg_send && ++ vcc->dev->ops->sg_send(vcc,(unsigned long) buff,size)) { ++ int res,max_iov; + -+#ifdef NICSTAR_DEBUG -+#define PRINTK(args...) printk(args) -+#else -+#define PRINTK(args...) ++ max_iov = 2+size/PAGE_SIZE; ++ /* ++ * Doesn't use alloc_tx yet - this will change later. @@@ ++ */ ++ while (!(skb = alloc_skb(sizeof(struct iovec)*max_iov, ++ GFP_KERNEL))) { ++ if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN; ++ interruptible_sleep_on(&vcc->wsleep); ++ if (current->signal & ~current->blocked) ++ return -ERESTARTSYS; ++ } ++ skb_put(skb,size); ++ res = lock_user((unsigned long) buff,size,max_iov, ++ (struct iovec *) skb->data); ++ if (res < 0) { ++ kfree_skb(skb,FREE_WRITE); ++ if (res != -EAGAIN) return res; ++ } ++ else { ++ DPRINTK("res is %d\n",res); ++ DPRINTK("Asnd %d += %d\n",vcc->tx_inuse,skb->truesize); ++ atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); ++ skb->atm.iovcnt = res; ++ error = vcc->dev->ops->send(vcc,skb); ++ /* FIXME: security: may send up to 3 "garbage" bytes */ ++ return error ? error : size; ++ } ++ } +#endif -+ -+#define SLEEP_ON(x) interruptible_sleep_on(x) -+#define WAKE_UP(x) wake_up_interruptible(x) -+ -+#define TRUE 1 -+#define FALSE 0 -+#define MIN(a,b) ((a)<(b)?(a):(b)) -+#define MAX(a,b) ((a)>(b)?(a):(b)) -+ -+#define CMD_BUSY(node) (readl((node)->membase + STAT) & 0x0200) -+ -+/* For timing */ -+unsigned long get_usec(void) { -+ struct timeval t; -+ do_gettimeofday(&t); -+ return (unsigned long)((1e6 * t.tv_sec) + t.tv_usec); ++ eff = (size+3) & ~3; /* align to word boundary */ ++ while (!(skb = vcc->alloc_tx(vcc,eff))) { ++ if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN; ++ interruptible_sleep_on(&vcc->wsleep); ++ if (current->signal & ~current->blocked) ++ return -ERESTARTSYS; ++ if (vcc->flags & ATM_VF_RELEASED) return vcc->reply; ++ if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; ++ } ++ skb->atm.iovcnt = 0; ++ error = copy_from_user(skb_put(skb,size),buff,size); ++ if (error) { ++ kfree_skb(skb,FREE_WRITE); ++ return error; ++ } ++ if (eff != size) memset(skb->data+size,0,eff-size); ++ error = vcc->dev->ops->send(vcc,skb); ++ return error ? error : size; +} + -+/* Global definitions ******************************************************/ -+static struct nicstar_dev *nicstar_devs[NICSTAR_MAX_DEVS]; -+static int num_found = 0; -+#if 0 -+static int nicstar_rx_count = 0; -+static u32 nicstar_timer = 0; -+#endif -+ -+/* Global/static function declarations *************************************/ -+static int init_nicstar(struct nicstar_dev *node); -+static void nicstar_interrupt(int irq, void *dev_id, struct pt_regs *regs); -+static void process_tx_statq(nicstar_devp node); -+static void process_rx_statq(nicstar_devp node); -+#ifdef NICSTAR_RCQ -+static void process_rx_rawcellq(nicstar_devp node); -+static void dequeue_rawcell(u32 *cell); -+#endif -+static void push_rxbufs(nicstar_devp node, int lg, -+ u32 handle1, u32 addr1, u32 handle2, u32 addr2); -+static void open_rx_connection(nicstar_devp node,int index, -+ u32 status); -+static void close_rx_connection(nicstar_devp node, int index); -+static void push_scq_entry(nicstar_devp node, struct nicstar_scq *scq, -+ nicstar_tbd *entry, int xmit_now); -+int init_module(void); -+void cleanup_module(void); -+static int get_ci(nicstar_devp node, struct atm_vcc *vcc, -+ short *vpi, int *vci); -+static void dequeue_rx(nicstar_devp node); -+static void nicstar_free_rx_skb(struct atm_vcc *vcc, struct sk_buff *skb); -+static void drain_scq(nicstar_devp node, struct nicstar_scq *scq, int index); -+static void free_rx_buf(nicstar_devp node, int lg, u32 buf_addr); -+#if NICSTAR_CBR -+static void alloc_tx(nicstar_devp node, struct atm_vcc *vcc); -+static void close_cbr (nicstar_devp node, struct atm_vcc *vcc); -+static void close_cbr_final (nicstar_devp node, struct atm_vcc *vcc); -+#endif -+static int create_scq (struct nicstar_scq **scq, int size); -+static u32 linearize_buffer (struct nicstar_dev *node, struct sk_buff *skb, -+ struct atm_vcc *vcc); -+ -+/* Module entry points *****************************************************/ -+ -+static int nicstar_open(struct atm_vcc *vcc, short vpi, int vci) { -+ nicstar_devp node; -+ int error; -+ -+ node = vcc->dev->dev_data; -+ -+ /* XXX AAL5 and AAL0 only supported */ -+ if ((vcc->aal != ATM_AAL5) && (vcc->aal != ATM_AAL0)) -+ return -EINVAL; -+ -+ error = get_ci(node, vcc, &vpi, &vci); -+ if (error) return error; -+ vcc->vpi = vpi; -+ vcc->vci = vci; -+ vcc->dev_data = &(node->vci_map[(vpi << NUM_VCI_BITS) | vci]); -+ vcc->flags |= ATM_VF_ADDR; -+ -+#if NICSTAR_CBR -+#ifndef ATM_013 -+ if (vcc->qos.txtp.traffic_class == ATM_CBR) { -+#else -+ if (vcc->txtp.class == ATM_CBR) { -+#endif -+ PRINTK("Opening CBR connection on vpci %d.%d\n",vpi,vci); -+ alloc_tx(node,vcc); -+ } -+#endif -+ -+ if (!(vcc->flags & ATM_VF_PARTIAL)) { -+ -+#ifndef ATM_013 -+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) { -+#else -+ if (vcc->rxtp.class != ATM_NONE) { -+#endif -+ u32 status = 0x8000; -+ switch (vcc->aal) { -+ case ATM_AAL0 : break; -+ case ATM_AAL34 : status |= 0x10000; break; -+ case ATM_AAL5 : status |= 0x20000; break; -+ default : -+ printk ("nicstar%d: invalid AAL %d on open",node->index,vcc->aal); -+ return -EINVAL; -+ } -+ open_rx_connection(node, (vpi << NUM_VCI_BITS) | vci, status); -+ } -+ -+ vcc->flags |= ATM_VF_PARTIAL; -+ -+ } + -+ vcc->flags |= ATM_VF_READY; ++unsigned int atm_poll(struct socket *sock,poll_table *wait) ++{ ++ struct atm_vcc *vcc; ++ unsigned int mask; + -+ return 0; -+ ++ vcc = ATM_SD(sock); ++ poll_wait(&vcc->sleep,wait); ++ poll_wait(&vcc->wsleep,wait); ++ mask = 0; ++ if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq)) ++ mask |= POLLIN | POLLRDNORM; ++ if (vcc->flags & ATM_VF_RELEASED) mask |= POLLHUP; ++ if (sock->state != SS_CONNECTING) { ++ if (vcc->qos.txtp.traffic_class != ATM_NONE && ++ vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+ ++ ATM_PDU_OVHD <= vcc->tx_quota) ++ mask |= POLLOUT | POLLWRNORM; ++ } ++ else { ++printk("vcc->reply = %d\n",vcc->reply); ++if (vcc->reply != WAITING) mask |= POLLERR; ++} ++ return mask; +} + -+static void nicstar_close(struct atm_vcc *vcc) { -+ nicstar_devp node; -+ nicstar_vcimap *mapval; -+ -+ node = vcc->dev->dev_data; -+ mapval = vcc->dev_data; -+ -+ vcc->flags &= ~ATM_VF_READY; -+ -+#ifndef ATM_013 -+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) { -+#else -+ if (vcc->rxtp.class != ATM_NONE) { -+#endif -+ close_rx_connection(node, (vcc->vpi << NUM_VCI_BITS) | vcc->vci); -+ vcc->flags &= ~ATM_VF_PARTIAL; -+ mapval->rx = 0; -+ } -+ -+#ifndef ATM_013 -+ if (vcc->qos.txtp.traffic_class != ATM_NONE) { -+#else -+ if (vcc->txtp.class != ATM_NONE) { -+#endif -+ mapval->tx = 0; -+#ifndef ATM_013 -+ if (vcc->qos.txtp.traffic_class == ATM_CBR) { -+#else -+ if (vcc->txtp.class == ATM_CBR) { -+#endif -+#if NICSTAR_CBR -+ close_cbr(node,vcc); -+#endif -+ } -+ } + -+ vcc->flags &= ~ATM_VF_ADDR; -+} ++static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero) ++{ ++ unsigned long flags; ++ int error; + -+static int nicstar_ioctl(struct atm_dev *dev, unsigned int cmd, -+ unsigned long arg) { -+ if (!dev->phy->ioctl) return -EINVAL; -+ return dev->phy->ioctl(dev,cmd,arg); -+} -+ -+static int nicstar_getsockopt(struct atm_vcc *vcc, -+ int level, -+ int optname, -+ char *optval, -+ int *optlen) { -+ return -EINVAL; -+} -+ -+static int nicstar_setsockopt(struct atm_vcc *vcc, int level, -+ int optname, char *optval, int optlen) { -+ struct atm_cirange ci; -+ int error; -+ -+ if (level != SOL_ATM) return -EINVAL; -+ switch (optname) { -+ case SO_CIRANGE: -+ if (!suser()) return -EPERM; -+ if (optlen != sizeof(struct atm_cirange)) -+ return -EINVAL; -+ error = verify_area(VERIFY_READ,optval,sizeof(struct atm_cirange)); -+ if (error) return error; -+ memcpy_fromfs(&ci,optval,sizeof(struct atm_cirange)); -+ if ((ci.vpi_bits == 0 || ci.vpi_bits == ATM_CI_MAX) && -+ (ci.vci_bits == NUM_VCI_BITS || ci.vci_bits == ATM_CI_MAX)) return 0; -+ return -EINVAL; -+ break; -+ -+ default: -+ return -EINVAL; -+ } ++ error = 0; ++ save_flags(flags); ++ cli(); ++ if (arg) ++ error = copy_to_user(arg,&dev->stats, ++ sizeof(struct atm_dev_stats)); ++ if (zero) ++ memset(&dev->stats,0,sizeof(struct atm_dev_stats)); ++ restore_flags(flags); ++ return error; +} + -+/* XXX It is possible here that when pushing multiple TBD's, the -+ * next TSI will be placed between them, causing an incomplete PDU xmit. -+ * Probably fix by not allowing a TSI to be pushed onto the SCQ when -+ * force_xmit == 0. -+ */ -+static int nicstar_send(struct atm_vcc *vcc, struct sk_buff *skb) { -+ nicstar_devp node; -+ int pad, sindex, vci; -+ nicstar_tbd tbd1; -+ nicstar_scq *scq; -+ u32 rate; -+#ifdef NICSTAR_FASTXMIT -+ int len; -+ int len_buf = 0; -+#else -+ nicstar_tbd tbd2, tbd3; -+#endif + -+ node = vcc->dev->dev_data; ++#ifdef CONFIG_AREQUIPA + -+ if (!((nicstar_vcimap *)vcc->dev_data)->tx) { -+ printk("nicstar%d: Tx on a non-Tx VC?\n", -+ ((nicstar_devp)vcc->dev->dev_data)->index); -+ vcc->stats->tx_err++; -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } -+#ifndef NICSTAR_CBR -+#ifndef ATM_013 -+ if (vcc->qos.txtp.traffic_class == ATM_CBR) { -+#else -+ if (vcc->txtp.class == ATM_CBR) { -+#endif /* ATM_013*/ -+ printk("nicstar: Sorry - CBR support in progress.\n"); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } -+#endif /* NICSTAR_CBR */ ++/* @@@ stolen from net/socket.c - should be in a common header file */ + -+ /* Verify AAL is supported */ -+ if ((vcc->aal != ATM_AAL5) && (vcc->aal != ATM_AAL0)) { -+ printk("nicstar%d: Only AAL5 and AAL0 supported, sorry.\n", -+ ((nicstar_devp)vcc->dev->dev_data)->index); -+ vcc->stats->tx_err++; -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } + -+ /* Verify that we have a linear buffer to transmit */ -+ if (skb->atm.iovcnt) { -+ printk("nicstar%d: S/G not supported, sorry.\n", -+ ((nicstar_devp)vcc->dev->dev_data)->index); -+ vcc->stats->tx_err++; -+ dev_kfree_skb(skb,FREE_WRITE); -+ return -EINVAL; -+ } ++struct socket *sockfd_lookup(int fd) ++{ ++ struct file *file; ++ struct inode *inode; + -+ skb->atm.vcc = vcc; ++ if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd])) ++ return NULL; ++ inode = file->f_inode; ++ if (!inode || !inode->i_sock) return NULL; ++ return &inode->u.socket_i; ++} + -+ vci = (vcc->vpi << NUM_VCI_BITS) | vcc->vci; -+#ifndef ATM_013 -+ if (vcc->qos.txtp.traffic_class == ATM_CBR) { -+#else -+ if (vcc->txtp.class == ATM_CBR) { -+#endif -+#ifdef NICSTAR_CBR -+ scq = (node->vci_map[vci]).scq; -+ rate = 0; +#endif -+ } -+ else { -+ scq = node->scq; -+ rate = TBD_UBR_M | TBD_UBR_N; -+ } -+ sindex = scq->next - scq->base; + + -+ /* AAL-dependent transmits */ -+ if (vcc->aal == ATM_AAL0) { -+ /* size is always 48 bytes */ -+ len = ATM_CELL_PAYLOAD & ~3; -+ /* create tbd */ -+ tbd1.status = TBD_AAL0 | TBD_ENDPDU | rate | len; -+ tbd1.buf_addr = (u32)(skb->data + 4); -+ tbd1.ctl_len = 0x0; -+ tbd1.cell_hdr = (u32)(*((u32 *)skb->data)); -+ push_scq_entry(node,scq,&tbd1,1); -+ } -+ else if (vcc->aal == ATM_AAL5) { /* Transmit AAL 5 */ -+#ifdef NICSTAR_FASTXMIT -+ /* Speed up and simplify transmission by "cheating". -+ Basic problem is that rev C3 only supports mod 48 -+ buffer sizes; Matt's original uses shadow cells -+ to provide this. We cheat, instead, and simply -+ lie about the length of the buffer. This may -+ have security implications and problems from -+ going over the end of a buffer. -+ -+ For rev D or better, there is a better way; these -+ chips support mod 4 buffer sizes. Thus, we simply -+ pad the entire PDU length to mod 48 by adding a -+ pointer to the zero'd tmp_cell buffer. (SWD) */ -+ len = (((skb->len + 8 + 47) / 48) * 48); -+ pad = len - skb->len; -+ PRINTK ("new len %d skb len %ld skb end %x skb tail %x\n",len,skb->len,(u32)skb->end,(u32)skb->tail); -+ -+ if (!(node->rev_C3)) { /* SAR supports mod 4 buffer sizes */ -+ len_buf = (((skb->len + 3) / 4) * 4); -+ if (pad == 0) { -+ tbd1.status = TBD_AAL5 | TBD_ENDPDU | rate | skb->len; -+ } -+ else { -+ tbd1.status = TBD_AAL5 | rate | len_buf; -+ } -+ } -+ else { -+ tbd1.status = TBD_AAL5 | TBD_ENDPDU | rate | len; -+ if (skb->end - pad < skb->tail) { -+ PRINTK ("nicstar%d: Whoops. overpadding a buffer!\n",node->index); -+ } -+ } -+ -+ tbd1.buf_addr = (u32)skb->data; -+ tbd1.ctl_len = skb->len; -+ tbd1.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ scq->scq_shadow[sindex].skb = skb; -+ -+ if (!(node->rev_C3) && (pad != 0)) { -+ push_scq_entry(node, scq, &tbd1, 0); -+ tbd1.status = TBD_AAL5 | TBD_ENDPDU | rate | (len - len_buf); -+ tbd1.buf_addr = (u32)node->tmp_cell; -+ tbd1.ctl_len = skb->len; -+ tbd1.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ push_scq_entry(node, scq, &tbd1, 1); -+ } -+ else { -+ push_scq_entry(node, scq, &tbd1, 1); -+ } ++int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ++{ ++ struct atm_dev *dev; ++ struct atm_vcc *vcc; ++ void *buf; ++ int error,len,size,number; + -+#else -+ if (skb->len > 48) { -+ /* YYY If we transmit a buffer where pad == 48, an extra cell -+ is transmitted under this scheme if skb->len > 48 (SWD) */ -+ -+ pad = 48 - ((skb->len + 8) % 48); -+ if (pad <= 40) { -+ memcpy(node->scq->scq_shadow[sindex].cell, -+ skb->data + (skb->len) - (40 - pad), -+ 40 - pad); -+ -+ /* Need to do this unless we want to send garbage at -+ * end of last cell ... only bad for security */ -+ memset(node->scq->scq_shadow[sindex].cell + (40 - pad), 0, pad); -+ -+ tbd1.status = 0x08810000 | (((skb->len - (40 - pad))/sizeof(u32)) << 2); -+ tbd1.buf_addr = (u32)skb->data; -+ tbd1.ctl_len = skb->len; -+ tbd1.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ node->scq->scq_shadow[sindex].skb = skb; -+ push_scq_entry(node, node->scq, &tbd1, 0); -+ -+ tbd2.status = 0x48810030; -+ tbd2.buf_addr = (u32)(node->scq->scq_shadow[sindex].cell); -+ tbd2.ctl_len = skb->len; -+ tbd2.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ push_scq_entry(node, node->scq, &tbd2, 1); -+ -+ } else { -+ /* Pad > 40 */ -+ pad = pad - 40; /* Pad of second-to-last cell */ -+ memcpy(node->scq->scq_shadow[sindex].cell, -+ skb->data + (skb->len) - (48 - pad), 48 - pad); -+ memset(node->scq->scq_shadow[sindex].cell + (48 - pad), 0, pad); -+ -+ tbd1.status = 0x08810000 | (((skb->len - (48 - pad))/sizeof(u32)) << 2); -+ tbd1.buf_addr = (u32)skb->data; -+ tbd1.ctl_len = skb->len; -+ tbd1.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ node->scq->scq_shadow[sindex].skb = skb; -+ push_scq_entry(node, node->scq, &tbd1, 0); -+ -+ tbd2.status = 0x08810030; -+ tbd2.buf_addr = (u32)(node->scq->scq_shadow[sindex].cell); -+ tbd2.ctl_len = skb->len; -+ tbd2.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ push_scq_entry(node, node->scq, &tbd2, 0); -+ -+ tbd3.status = 0x48810030; -+ tbd3.buf_addr = (u32)(node->tmp_cell); -+ tbd3.ctl_len = skb->len; -+ tbd3.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ push_scq_entry(node, node->scq, &tbd3, 1); -+ } -+ -+ } else if (skb->len <= 40) { -+ -+ pad = 48 - (skb->len + 8); -+ memcpy(node->scq->scq_shadow[sindex].cell, -+ skb->data, skb->len); -+ memset(node->scq->scq_shadow[sindex].cell + skb->len, 0, pad); -+ tbd1.status = 0x48810030; -+ tbd1.buf_addr = (u32)(node->scq->scq_shadow[sindex].cell); -+ tbd1.ctl_len = skb->len; -+ tbd1.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ node->scq->scq_shadow[sindex].skb = skb; -+ push_scq_entry(node, node->scq, &tbd1, 1); -+ -+ } else { -+ -+ /* 41 .. 48 inclusive */ -+ pad = 48 - (skb->len); -+ memcpy(node->scq->scq_shadow[sindex].cell, -+ skb->data, skb->len); -+ memset(node->scq->scq_shadow[sindex].cell + skb->len, 0, pad); -+ -+ tbd1.status = 0x08810030; -+ tbd1.buf_addr = (u32)(node->scq->scq_shadow[sindex].cell); -+ tbd1.ctl_len = skb->len; -+ tbd1.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ node->scq->scq_shadow[sindex].skb = skb; -+ push_scq_entry(node, node->scq, &tbd1, 0); -+ -+ tbd2.status = 0x48810030; -+ tbd2.buf_addr = (u32)(node->tmp_cell); -+ tbd2.ctl_len = skb->len; -+ tbd2.cell_hdr = (vcc->vpi << 20) | (vcc->vci << 4); -+ -+ push_scq_entry(node, node->scq, &tbd2, 1); -+ -+ } -+#endif /* NICSTAR_FASTXMIT */ -+ } -+ -+ vcc->stats->tx++; -+ return 0; -+ -+} -+ -+static struct atmdev_ops atm_ops = { -+ nicstar_open, /* open */ -+ nicstar_close, /* close */ -+ nicstar_ioctl, /* ioctl */ -+ nicstar_getsockopt, /* getsockopt */ -+ nicstar_setsockopt, /* setsockopt */ -+ nicstar_send, /* send */ -+ NULL, /* sg_send */ -+ NULL, /* poll */ -+ NULL, /* send_oam */ -+ NULL, /* phy_put */ -+ NULL, /* phy_get */ -+ NULL, /* feedback */ -+#ifndef ATM_013 -+ NULL, /* change_qos */ ++ vcc = ATM_SD(sock); ++ switch (cmd) { ++ case ATM_GETNAMES: ++ error = get_user(buf, ++ &((struct atm_iobuf *) arg)->buffer); ++ if (error) return error; ++ error = get_user(len, ++ &((struct atm_iobuf *) arg)->length); ++ if (error) return error; ++ size = 0; ++ for (dev = atm_devs; dev; dev = dev->next) { ++ size += sizeof(int); ++ if (size > len) return -E2BIG; ++ error = put_user(dev->number,(int *) buf); ++ ((int *) buf)++; ++ /* @@@ race if page fault */ ++ } ++ return put_user(size, ++ &((struct atm_iobuf *) arg)->length); ++ case SIOCGSTAMP: /* borrowed from IP */ ++ if (!vcc->timestamp.tv_sec) return -ENOENT; ++ vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000; ++ vcc->timestamp.tv_usec %= 1000000; ++ return copy_to_user((void *) arg,&vcc->timestamp, ++ sizeof(struct timeval)); ++ case ATM_SETSC: ++ if (arg & ~(ATM_VF_SCRX | ATM_VF_SCTX)) return -EINVAL; ++ /* @@@ race condition - should split flags into ++ "volatile" and non-volatile part */ ++ vcc->flags = (vcc->flags & ~(ATM_VF_SCRX | ++ ATM_VF_SCTX)) | arg; ++ return 0; ++ case ATMSIGD_CTRL: ++ if (!suser()) return -EPERM; ++ error = sigd_attach(vcc); ++ if (!error) sock->state = SS_CONNECTED; ++ return error; ++#ifdef CONFIG_ATM_CLIP ++ case SIOCMKCLIP: ++ if (!suser()) return -EPERM; ++ return clip_create(arg); ++ case ATMARPD_CTRL: ++ if (!suser()) return -EPERM; ++ error = atm_init_atmarp(vcc); ++ if (!error) sock->state = SS_CONNECTED; ++ return error; ++ case ATMARP_MKIP: ++ if (!suser()) return -EPERM; ++ return clip_mkip(vcc); ++ case ATMARP_SETENTRY: ++ if (!suser()) return -EPERM; ++ return clip_setentry(vcc,arg); ++#if 0 ++ case ATMARP_ENCAP: ++ if (!suser()) return -EPERM; ++ return clip_encap(vcc,arg); +#endif -+ nicstar_free_rx_skb, /* free_rx_skb */ -+}; -+ -+static int do_detect(void) { ++#endif ++#ifdef CONFIG_AREQUIPA ++ case AREQUIPA_PRESET: ++ { ++ struct socket *upper; + -+ int error; -+ static unsigned char pci_bus, pci_devfn; -+ int pci_index; -+ struct nicstar_dev *node; -+ unsigned short pci_command; -+ unsigned char pci_latency; -+ unsigned char irq; -+ int i; -+ u32 gp; -+ -+ PRINTK("nicstar: init_module called\n"); -+ -+ if (!pcibios_present()) { -+ printk("nicstar: Fatal error: No PCI BIOS present\n"); -+ return -EIO; -+ } ++ if (!(upper = sockfd_lookup(arg))) ++ return -ENOTSOCK; ++ if (upper->ops->family != PF_INET) ++ return -EPROTOTYPE; ++ return arequipa_preset(sock, ++ (struct sock *) upper->data); ++ } ++ case AREQUIPA_INCOMING: ++ return arequipa_incoming(sock); ++ case AREQUIPA_CTRL: ++ if (!suser()) return -EPERM; ++ error = arequipad_attach(vcc); ++ if (!error) sock->state = SS_CONNECTED; ++ return error; ++ case AREQUIPA_CLS3RD: ++ if (!suser()) return -EPERM; ++ arequipa_close_vcc((struct atm_vcc *) arg); ++ return 0; ++ case AREQUIPA_SYNCACK: ++ if (!suser()) return -EPERM; ++ wake_up((struct wait_queue **) arg); ++ return 0; ++#endif ++#ifdef CONFIG_ATM_LANE ++ case ATMLEC_CTRL: ++ if (!suser()) return -EPERM; ++ error = lecd_attach(vcc, (int)arg); ++ if (error >=0) sock->state = SS_CONNECTED; ++ return error; ++ case ATMLEC_MCAST: ++ if (!suser()) return -EPERM; ++ return lec_mcast_attach(vcc, (int)arg); ++ case ATMLEC_DATA: ++ if (!suser()) return -EPERM; ++ return lec_vcc_attach(vcc, (void*)arg); ++#endif ++#ifdef CONFIG_ATM_TCP ++ case SIOCSIFATMTCP: ++ if (!suser()) return -EPERM; ++ error = atmtcp_attach(vcc); ++ if (error >= 0) sock->state = SS_CONNECTED; ++ return error; ++#endif ++ default: ++ break; ++ } ++ error = get_user(buf,&((struct atmif_sioc *) arg)->arg); ++ if (error) return error; ++ error = get_user(len,&((struct atmif_sioc *) arg)->length); ++ if (error) return error; ++ error = get_user(number,&((struct atmif_sioc *) arg)->number); ++ if (error) return error; ++ if (!(dev = atm_find_dev(number))) return -ENODEV; ++ size = 0; ++ switch (cmd) { ++ case ATM_GETTYPE: ++ size = strlen(dev->type)+1; ++ error = copy_to_user(buf,dev->type,size); ++ break; ++ case ATM_GETESI: ++ size = ESI_LEN; ++ error = copy_to_user(buf,dev->esi,size); ++ break; ++ case ATM_GETSTATZ: ++ if (!suser()) return -EPERM; ++ /* fall through */ ++ case ATM_GETSTAT: ++ size = sizeof(struct atm_dev_stats); ++ error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ); ++ break; ++ case ATM_GETCIRANGE: ++ size = sizeof(sizeof(struct atm_cirange)); ++ error = copy_to_user(buf,&dev->ci_range,size); ++ break; ++ case ATM_RSTADDR: ++ if (!suser()) return -EPERM; ++ reset_addr(dev); ++ break; ++ case ATM_ADDADDR: ++ case ATM_DELADDR: ++ if (!suser()) return -EPERM; ++ { ++ struct sockaddr_atmsvc addr; + -+ for (i = 0; i < NICSTAR_MAX_DEVS; i++) -+ nicstar_devs[i] = NULL; ++ error = copy_from_user(&addr,buf,sizeof(addr)); ++ if (error) return error; ++ if (cmd == ATM_ADDADDR) ++ return add_addr(dev,&addr); ++ else return del_addr(dev,&addr); ++ } ++ case ATM_GETADDR: ++ size = get_addr(dev,buf,len); ++ if (size < 0) return size; ++ /* may return 0, but later on size == 0 means "don't ++ write the length" */ ++ return put_user(size, ++ &((struct atmif_sioc *) arg)->length); ++ case ATM_SETCIRANGE: ++ case SONET_GETSTATZ: ++ case SONET_SETDIAG: ++ case SONET_CLRDIAG: ++ case SONET_SETFRAMING: ++ if (!suser()) return -EPERM; ++ /* fall through */ ++ default: ++ if (!dev->ops->ioctl) return -EINVAL; ++ size = dev->ops->ioctl(dev,cmd,buf); ++ if (size < 0) return size; ++ } ++ if (error || !size) return error; ++ return put_user(size,&((struct atmif_sioc *) arg)->length); ++} + -+ PRINTK("nicstar: Searching for IDT77201 NICStAR: vendor 0x%x, device 0x%x\n", -+ PCI_VENDOR_ID_IDT, -+ PCI_DEVICE_ID_IDT_IDT77201); -+ -+ for (pci_index = 0; pci_index < 8; pci_index++) { -+ -+ if ((error = pcibios_find_device(PCI_VENDOR_ID_IDT, -+ PCI_DEVICE_ID_IDT_IDT77201, -+ pci_index, &pci_bus, &pci_devfn)) -+ != PCIBIOS_SUCCESSFUL) -+ break; -+ -+ /* Allocate a device structure */ -+ node = kmalloc(sizeof(struct nicstar_dev),GFP_KERNEL); -+ if (node == NULL) { -+ printk("nicstar: Can't allocate device struct for device %d!\n",pci_index); -+ return -EIO; -+ } -+ nicstar_devs[num_found] = node; -+ node->index = num_found; -+ node->pci_bus = pci_bus; -+ node->pci_devfn = pci_devfn; -+ -+ error = pcibios_read_config_byte(pci_bus,pci_devfn,PCI_REVISION_ID, -+ &(node->revid)); -+ if (error) { -+ printk("nicstar: Can't read REVID from device %d\n",pci_index); -+ return -EIO; -+ } -+ -+ error = pcibios_read_config_dword(pci_bus,pci_devfn,PCI_BASE_ADDRESS_0, -+ (unsigned int *)&(node->iobase)); -+ if (error) { -+ printk("nicstar: Can't read iobase from device %d.\n",pci_index); -+ return -EIO; -+ } -+ -+ error = pcibios_read_config_dword(pci_bus,pci_devfn,PCI_BASE_ADDRESS_1, -+ (unsigned int *)&(node->membase)); -+ if (error) { -+ printk("nicstar: Can't read membase from device %d.\n",pci_index); -+ return -EIO; -+ } -+ -+ if (pcibios_read_config_byte(pci_bus,pci_devfn,PCI_INTERRUPT_LINE, -+ (unsigned char *)&irq)) { -+ printk("nicstar: Can't read INTLN from device %d.\n",pci_index); -+ return -EIO; -+ } -+ node->irq = irq; -+ -+ node->iobase &= PCI_BASE_ADDRESS_IO_MASK; -+ node->membase &= PCI_BASE_ADDRESS_MEM_MASK; -+ -+ node->membase = (unsigned long)vremap((unsigned int)node->membase,NICSTAR_IO_SIZE); -+ if ((unsigned long *)node->membase == NULL) { -+ printk("nicstar: Can't remap membase for board %d.\n",node->index); -+ return -EIO; -+ } -+ -+ printk("nicstar: Found device index %d, bus %d, function %d.\n", -+ pci_index,pci_bus,pci_devfn); -+ printk("nicstar: Revision 0x%x, using IRQ %d.\n",node->revid,node->irq); -+ printk("nicstar: iobase: 0x%lx, membase: 0x%lx\n",node->iobase,node->membase); -+ -+ /* Enable memory space and busmastering */ -+ if (pcibios_read_config_word(pci_bus,pci_devfn,PCI_COMMAND,&pci_command)) { -+ printk("nicstar: Can't read PCI_COMMAND from device %d.\n",pci_index); -+ return -EIO; -+ } -+ -+ pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_SPECIAL | PCI_COMMAND_MASTER); -+ error = pcibios_write_config_word(pci_bus,pci_devfn,PCI_COMMAND, -+ pci_command); -+ -+ if (error) { -+ printk("nicstar: Can't enable board memory for device %d.\n",pci_index); -+ return -EIO; -+ } -+ -+ /* Check latency timer */ -+ if (pcibios_read_config_byte(pci_bus,pci_devfn,PCI_LATENCY_TIMER,&pci_latency)) { -+ printk("nicstar: Can't read latency timer from device %d.\n",pci_index); -+ return -EIO; -+ } -+ if (pci_latency < 32) { -+ printk("nicstar: Setting latency timer from %d to 32 clocks.\n",pci_latency); -+ pcibios_write_config_byte(pci_bus,pci_devfn,PCI_LATENCY_TIMER,32); -+ } -+ -+ num_found++; -+ -+ /* Check for SAR, revision C3; on this revision, bit 15/GP is -+ not writable, only readable. */ -+ gp = readl(node->membase + GP); -+ writel(gp | 0x8000,node->membase + GP); -+ node->rev_C3 = (readl(node->membase + GP) & 0x8000) ? 0 : 1; -+ if (node->rev_C3) { -+ printk("nicstar%d: Revision C3 77201 detected\n",node->index); -+ } -+ else { -+ printk("nicstar%d: Revision D or later 77201 detected\n",node->index); -+ } -+ writel(gp,node->membase + GP); /* restore original contents */ -+ -+ /* Initialize random things */ -+ node->inuse = 0; -+ -+ /* Get IRQ */ -+ if (request_irq(node->irq, &nicstar_interrupt, SA_INTERRUPT, "nicstar", node)) { -+ printk("nicstar: Can't allocate IRQ %d.\n",node->irq); -+ return -EIO; -+ } -+ -+ if (init_nicstar(node)) { -+ printk("nicstar: Error initializing device %d.\n",pci_index); -+ free_irq(node->irq, node); -+ return -EIO; -+ } -+ -+ /* Register device */ -+ node->dev = atm_dev_register("nicstar", &atm_ops, 0); -+ if (node->dev == NULL) { -+ printk("nicstar: Can't register device %d.\n",node->index); -+ free_irq(node->irq, node); -+ return -EIO; -+ } -+ node->dev->esi[0] = '\0'; -+ node->dev->esi[1] = '\34'; -+ node->dev->esi[2] = '\100'; -+ node->dev->esi[3] = '\0'; -+ node->dev->esi[4] = '\17'; -+ node->dev->esi[5] = '\110'; -+ node->dev->dev_data = node; + -+ node->dev->ci_range.vpi_bits = NUM_VPI_BITS; -+ node->dev->ci_range.vci_bits = NUM_VCI_BITS; ++static int atm_do_setsockopt(struct socket *sock,int level,int optname, ++ void *optval,int optlen) ++{ ++ struct atm_vcc *vcc; ++ unsigned long value; ++ int error; + -+ } -+ -+ if (num_found == 0) return -EIO; ++ vcc = ATM_SD(sock); ++ switch (optname) { ++ case SO_SNDBUF: ++ error = get_user(value,(unsigned long *) optval); ++ if (error) return error; ++ if (!value) value = ATM_TXBQ_DEF; ++ if (value < ATM_TXBQ_MIN) value = ATM_TXBQ_MIN; ++ if (value > ATM_TXBQ_MAX) value = ATM_TXBQ_MAX; ++ vcc->tx_quota = value; ++ return 0; ++ case SO_RCVBUF: ++ error = get_user(value,(unsigned long *) optval); ++ if (error) return error; ++ if (!value) value = ATM_RXBQ_DEF; ++ if (value < ATM_RXBQ_MIN) value = ATM_RXBQ_MIN; ++ if (value > ATM_RXBQ_MAX) value = ATM_RXBQ_MAX; ++ vcc->rx_quota = value; ++ return 0; ++ case SO_ATMQOS: ++ { ++ struct atm_qos qos; + -+ printk("nicstar: %d devices found.\n",num_found); -+ return num_found; -+ ++ error = copy_from_user(&qos,optval,sizeof(qos)); ++ if (error) return error; ++ if (sock->state == SS_CONNECTED && ++ sock->ops->family == AF_ATMPVC) { ++ if (!vcc->dev->ops->change_qos) ++ return -EOPNOTSUPP; ++ return vcc->dev->ops->change_qos(vcc, ++ &qos); ++ } ++ if (sock->state != SS_UNCONNECTED) ++ return -EBADFD; ++ vcc->qos = qos; ++ vcc->flags |= ATM_VF_HASQOS; ++ return 0; ++ } ++ default: ++ if (level == SOL_SOCKET) return -EINVAL; ++ break; ++ } ++ if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL; ++ return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen); +} + + -+#ifndef MODULE -+ -+ -+int nicstar_detect(void) ++static int atm_do_getsockopt(struct socket *sock,int level,int optname, ++ void *optval,int optlen) +{ -+ int devs; ++ struct atm_vcc *vcc; + -+ devs = do_detect(); -+ return devs < 0 ? 0 : devs; ++ vcc = ATM_SD(sock); ++ switch (optname) { ++ case SO_SNDBUF: ++ return put_user(vcc->tx_quota,(unsigned long *) optval); ++ case SO_RCVBUF: ++ return put_user(vcc->rx_quota,(unsigned long *) optval); ++ case SO_BCTXOPT: ++ /* fall through */ ++ case SO_BCRXOPT: ++ break; ++ case SO_ATMQOS: ++ if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL; ++ return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)); ++ default: ++ if (level == SOL_SOCKET) return -EINVAL; ++ break; ++ } ++ if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; ++ return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen); +} + + -+#else ++int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, ++ int optlen) ++{ ++ if (level == __SO_LEVEL(optname) && optlen != __SO_SIZE(optname)) ++ return -EINVAL; ++ return atm_do_setsockopt(sock,level,optname,optval,optlen); ++} + + -+int init_module(void) { -+ int devs; ++int atm_getsockopt(struct socket *sock,int level,int optname, ++ char *optval,int *optlen) ++{ ++ int error,len; + -+ printk("nicstar: Installing %s of %s %s.\n",__FILE__,__DATE__,__TIME__); -+ devs = do_detect(void); -+ if (!devs) { -+ printk(KERN_ERR "nicstar: no adapter found\n"); -+ return -ENXIO; -+ } -+ return 0; ++ error = get_user(len,optlen); ++ if (error) return error; ++ if (level == __SO_LEVEL(optname) && len != __SO_SIZE(optname)) ++ return -EINVAL; ++ return atm_do_getsockopt(sock,level,optname,optval,len); +} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/common.h Thu May 29 12:07:28 1997 +@@ -0,0 +1,33 @@ ++/* net/atm/common.h - ATM sockets (common part for PVC and SVC) */ ++ ++/* Written 1995 by Werner Almesberger, EPFL LRC */ + + -+void cleanup_module(void) { -+ int i, error; -+ nicstar_devp node; -+ unsigned short pci_command; -+ -+ PRINTK("nicstar: cleanup_module called\n"); -+ -+ if (MOD_IN_USE) -+ PRINTK("nicstar: Device busy, remove delayed.\n"); -+ -+ /* Free up the device resources */ -+ for (i = 0; i < NICSTAR_MAX_DEVS; i++) { -+ if (nicstar_devs[i] != NULL) { -+ node = nicstar_devs[i]; -+ /* Turn everything off */ -+ writel(0x00000000, (node->membase)+CFG); -+ -+ /* Disable PCI busmastering */ -+ if (pcibios_read_config_word(node->pci_bus,node->pci_devfn,PCI_COMMAND,&pci_command)) { -+ printk("nicstar: Can't read PCI_COMMAND from device %d.\n",node->index); -+ continue; -+ } -+ pci_command &= ~PCI_COMMAND_MASTER; -+ error = pcibios_write_config_word(node->pci_bus,node->pci_devfn, -+ PCI_COMMAND, pci_command); -+ if (error) { -+ printk("nicstar: Can't disable busmastering for device %d.\n",node->index); -+ continue; -+ } -+ -+ drain_scq(node,node->scq,node->scq->next - node->scq->base); -+ kfree(node->rx_statq_orig); -+ kfree(node->tx_statq_orig); -+ kfree(node->sm_bufs); -+ kfree(node->lg_bufs); -+ kfree(node->scq->orig); -+ kfree(node->scq); -+ free_irq(node->irq, node); -+ -+ { -+ struct sk_buff *skb; -+ while ((skb = skb_dequeue(&node->rx_skb_queue))) -+ dev_kfree_skb(skb, FREE_READ); -+ } ++#ifndef NET_ATM_COMMON_H ++#define NET_ATM_COMMON_H + -+ atm_dev_deregister(node->dev); ++#include + -+ kfree(nicstar_devs[i]); -+ } -+ } ++int atm_create(struct socket *sock,int protocol); ++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, ++ int flags,struct scm_cookie *scm); ++int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, ++ struct scm_cookie *scm); ++unsigned int atm_poll(struct socket *sock,poll_table *wait); ++int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg); ++int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, ++ int optlen); ++int atm_getsockopt(struct socket *sock,int level,int optname,char *optval, ++ int *optlen); + -+ printk("nicstar: Module cleanup succeeded.\n"); ++int atm_release_vcc(struct atm_vcc *vcc,int free_vcc); ++void atm_shutdown_dev(struct atm_dev *dev); + -+} ++/* SVC */ + ++int copy_svc_addr(struct sockaddr_atmsvc *to,struct sockaddr_atmsvc *from); ++void svc_callback(struct atm_vcc *vcc); + +#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/ipcommon.c Thu Jul 10 17:58:06 1997 +@@ -0,0 +1,52 @@ ++/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */ + ++/* Written 1996,1997 by Werner Almesberger, EPFL LRC */ + -+/* NICStAR functions *******************************************************/ + -+static inline u32 read_sram(nicstar_devp node, u32 addr) { -+ u32 data; -+ unsigned long flags; -+ -+ save_flags(flags); cli(); -+ while (CMD_BUSY(node)) ; -+ writel(((0x50000000) | ((addr & 0x1ffff) << 2)), node->membase + CMD); -+ while (CMD_BUSY(node)) ; -+ data = readl(node->membase + DR0); -+ restore_flags(flags); -+ return data; -+} ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+static inline void write_sram(nicstar_devp node, int count, u32 addr, -+ u32 d0, u32 d1, u32 d2, u32 d3) { -+ unsigned long flags; ++#include "common.h" ++#include "ipcommon.h" + -+ save_flags(flags); cli(); -+ while (CMD_BUSY(node)); -+ switch (count) { -+ case 4: -+ writel(d3, node->membase + DR3); -+ case 3: -+ writel(d2, node->membase + DR2); -+ case 2: -+ writel(d1, node->membase + DR1); -+ case 1: -+ writel(d0, node->membase + DR0); -+ break; -+ default: -+ restore_flags(flags); -+ return; -+ } + -+ writel((0x40000000) | ((addr & 0x1ffff) << 2) | (count-1), node->membase+CMD); -+ restore_flags(flags); -+ return; -+} -+ -+static int init_nicstar(struct nicstar_dev *node) { -+ u32 i, d; -+ unsigned short pci_command; -+ int error; -+ u32 tmp; -+ -+ d = readl(node->membase + STAT); -+ /* Clear timer if overflow */ -+ if (d & 0x00000800) { -+ writel(0x00000800, node->membase+STAT); -+ } ++#if 0 ++#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) ++#else ++#define DPRINTK(format,args...) ++#endif + -+ /* S/W reset */ -+ writel(0x80000000, node->membase+CFG); -+ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO; -+ writel(0x00000000, node->membase+CFG); -+ -+ /* Turn everything off, but use 4k recv status queue */ -+ writel(0x00400000, node->membase+CFG); -+ d = readl(node->membase + CFG); -+ -+ /* Determine PHY type/speed by reading PHY reg 0 (from IDT) */ -+ /* YYY This tested only for 77105 (SWD) */ -+ writel(0x80000200,node->membase + CMD); /* read PHY reg 0 command */ -+ while (CMD_BUSY(node)) ; -+ tmp = readl(node->membase + DR0); -+ if (tmp == 0x9) { -+ node->max_pcr = IDT_25_PCR; -+ printk ("nicstar%d: PHY device appears to be 25Mbps\n",node->index); -+ } -+ else if (tmp == 0x30) { -+ node->max_pcr = ATM_OC3_PCR; -+ printk ("nicstar%d: PHY device appears to be 155Mbps\n",node->index); -+ } + -+#ifdef TEST_LOOPBACK -+ /* PHY reset */ -+ d = readl(node->membase+GP); -+ writel(d & 0xfffffff7, node->membase+GP); /* Out of reset */ -+ { int j; for (j = 0; j < 100000; j++) ; } -+ writel(d | 0x00000008, node->membase+GP); /* Reset */ -+ { int j; for (j = 0; j < 100000; j++) ; } -+ writel(d & 0xfffffff7, node->membase+GP); /* Out of reset */ -+ -+ /* PHY loopback */ -+ while(CMD_BUSY(node)) ; -+ printk ("nicstar%d: Setting PHY Loopback\n",node->index); -+ writel(0x00000022, node->membase + DR0); -+ if (node->max_pcr == IDT_25_PCR) { /* loopback for 77105 */ -+ writel(0x90000202, node->membase + CMD); -+ } -+ else { /* assume 77155 */ -+ writel(0x90000205, node->membase + CMD); -+ } ++const unsigned char llc_oui[] = { ++ 0xaa, /* DSAP: non-ISO */ ++ 0xaa, /* SSAP: non-ISO */ ++ 0x03, /* Ctrl: Unnumbered Information Command PDU */ ++ 0x00, /* OUI: EtherType */ ++ 0x00, ++ 0x00 }; + -+#else + -+ /* PHY reset */ -+ d = readl(node->membase+GP); -+ writel(d & 0xfffffff7, node->membase+GP); /* Out of reset */ -+ { int j; for (j = 0; j < 100000; j++) ; } -+ writel(d | 0x00000008, node->membase+GP); /* Reset */ -+ { int j; for (j = 0; j < 100000; j++) ; } -+ writel(d & 0xfffffff7, node->membase+GP); /* Out of reset */ -+ -+ while (CMD_BUSY(node)) ; -+ writel(0x80000100, node->membase+CMD); /* Sync UTOPIA with SAR clock */ -+ { int j; for (j = 0; j < 100000; j++) ; } -+ -+ /* Normal mode */ -+ while(CMD_BUSY(node)) ; -+ writel(0x00000020, node->membase + DR0); -+ if (node->max_pcr == IDT_25_PCR) { /* 77105 */ -+ writel(0x90000202, node->membase + CMD); -+ } -+ else { /* assume 77155 */ -+ writel(0x90000205, node->membase + CMD); -+ } ++/* ++ * skb_migrate moves the list at FROM to TO, emptying FROM in the process. ++ * This function should live in skbuff.c or skbuff.h. Note that skb_migrate ++ * is not atomic, so turn off interrupts when using it. ++ */ + -+#endif /* PHY_LOOPBACK */ + -+ /* Re-enable memory space and busmastering --- in case the PCI reset -+ * turned us off ... -+ */ -+ if (pcibios_read_config_word(node->pci_bus,node->pci_devfn,PCI_COMMAND,&pci_command)) { -+ printk("nicstar: Can't read PCI_COMMAND from device %d.\n",node->index); -+ return -EIO; -+ } -+ pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_SPECIAL | PCI_COMMAND_MASTER); -+ error = pcibios_write_config_word(node->pci_bus,node->pci_devfn,PCI_COMMAND, -+ pci_command); -+ if (error) { -+ printk("nicstar: Can't enable board memory for device %d.\n",node->index); -+ return -EIO; -+ } -+ -+ /* Set up the recv connection table */ -+ for (i = 0; i < RX_CTABLE_SIZE; i+=4) { -+#if NICSTAR_RCQ -+ write_sram(node, 4, i, 0x00008000, 0x00000000, 0x00000000, 0xffffffff); -+#else -+ write_sram(node, 4, i, 0x00000000, 0x00000000, 0x00000000, 0xffffffff); -+#endif -+ } -+ -+ writel(0x0, node->membase + VPM); ++void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) ++{ ++ struct sk_buff *skb,*prev; + -+ /* Clear VCI map and SCQ shadow */ -+ memset(node->vci_map, 0, sizeof(node->vci_map)); -+ memset(node->tmp_cell, 0, sizeof(node->tmp_cell)); -+ -+ /* Allocate Rx status queue */ -+ /* XXX What about 64-bit pointers? */ -+ node->rx_statq_orig = kmalloc(2*8192, GFP_KERNEL); -+ if (!node->rx_statq_orig) { -+ printk("nicstar%d: Can't allocate Rx status queue.\n",node->index); -+ return -ENOMEM; -+ } -+ node->rx_statq = (nicstar_rsqe *)(((u32)node->rx_statq_orig + (8192 - 1)) & ~(8192 - 1)); ++ for (skb = ((struct sk_buff *) from)->next; ++ skb != (struct sk_buff *) from; skb = skb->next) skb->list = to; ++ prev = from->prev; ++ from->next->prev = (struct sk_buff *) to; ++ prev->next = (struct sk_buff *) to; ++ *to = *from; ++ skb_queue_head_init(from); ++} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/ipcommon.h Thu Jul 3 08:26:06 1997 +@@ -0,0 +1,30 @@ ++/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ + -+ printk("nicstar%d: Rx status queue at 0x%x (0x%x).\n",node->index, (u32)node->rx_statq, (u32)node->rx_statq_orig); ++/* Written 1996,1997 by Werner Almesberger, EPFL LRC */ + -+ for (i = 0; i < RX_STATQ_ENTRIES; i++) { -+ node->rx_statq[i].vpi_vci = 0x0; -+ node->rx_statq[i].buf_handle = 0x0; -+ node->rx_statq[i].crc = 0x0; -+ node->rx_statq[i].status = 0x0; -+ } + -+ node->rx_statq_next = node->rx_statq; -+ node->rx_statq_last = node->rx_statq + (RX_STATQ_ENTRIES - 1); -+ writel((u32)node->rx_statq, node->membase + RSQB); -+ writel((u32)0x0, node->membase + RSQH); -+ -+ /* Allocate Tx status queue */ -+ /* XXX What about 64-bit pointers? */ -+ node->tx_statq_orig = (caddr_t)kmalloc(2*8192, GFP_KERNEL); -+ if (!node->tx_statq_orig) { -+ printk("nicstar%d: Can't allocate Tx status queue.\n",node->index); -+ return -ENOMEM; -+ } -+ node->tx_statq = (nicstar_tsi *)(((u32)node->tx_statq_orig + (8192 - 1)) & ~(8192 - 1)); ++#ifndef NET_ATM_IPCOMMON_H ++#define NET_ATM_IPCOMMON_H + -+ printk("nicstar%d: Tx status queue at 0x%x (0x%x).\n",node->index, (u32)node->tx_statq, (u32)node->tx_statq_orig); + -+ for (i = 0; i < TX_STATQ_ENTRIES; i++) { -+ node->tx_statq[i].timestamp = 0x80000000; -+ } -+ node->tx_statq_next = node->tx_statq; -+ node->tx_statq_last = node->tx_statq + (TX_STATQ_ENTRIES - 1); -+ -+ writel((u32)node->tx_statq, node->membase + TSQB); -+ writel((u32)0x0, node->membase + TSQH); -+ -+ /* Allocate buffer queues */ -+ -+ node->sm_bufs = (caddr_t)kmalloc(SM_BUFSZ * NUM_SM_BUFS, GFP_KERNEL); -+ if (!node->sm_bufs) { -+ printk("nicstar%d: Can't allocate %d %d-byte small buffers!\n", -+ node->index, NUM_SM_BUFS, SM_BUFSZ); -+ return -ENOMEM; -+ } ++#include ++#include ++#include ++#include ++/*#include */ + -+#if 0 -+ /* Old code for handling large buffers */ -+ node->lg_bufs = (caddr_t)kmalloc((SM_BUFSZ + LG_BUFSZ) * NUM_LG_BUFS, GFP_KERNEL); -+ if (!node->lg_bufs) { -+ printk("nicstar%d: Can't allocate %d %d-byte large buffers!\n", -+ node->index, NUM_LG_BUFS, LG_BUFSZ); -+ return -ENOMEM; -+ } -+ p = node->lg_bufs + SM_BUFSZ; -+#endif -+ for (i = 0; i < NUM_LG_BUFS; i++) { -+ node->rx_lg_skb[i] = alloc_skb(SM_BUFSZ + LG_BUFSZ, GFP_KERNEL); -+ skb_reserve(node->rx_lg_skb[i],SM_BUFSZ); -+ } + -+#if NICSTAR_RCQ -+ node->rcq.rcq_head = (u32) rx_lg_skb[0]->data; -+ node->rcq.rcq_base = (u32) rx_lg_skb[0]->data; -+ /* Manual says we should check head vs tail here; but tail reg -+ isn't updated until after we turn on RX path. Moved check to -+ end of init_module... */ -+#endif -+ -+#if NICSTAR_LBUFCNT -+ node->lbuf_cnt = NUM_LG_BUFS - 1; -+#endif -+ for (i = 0; i < NUM_SM_BUFS; i+=2) { -+ push_rxbufs(node, 0, -+ (u32)(node->sm_bufs + (i*SM_BUFSZ) + 4), -+ (u32)(node->sm_bufs + (i*SM_BUFSZ) + 4), -+ (u32)(node->sm_bufs + ((i+1)*SM_BUFSZ) + 4), -+ (u32)(node->sm_bufs + ((i+1)*SM_BUFSZ) + 4)); -+ } ++extern const unsigned char llc_oui[6]; ++extern struct device *clip_devs; + -+ for (i = 0; i < NUM_LG_BUFS; i+=2) { -+ push_rxbufs(node, 1, -+ (u32)(node->rx_lg_skb[i]->data), -+ (u32)(node->rx_lg_skb[i]->data), -+ (u32)(node->rx_lg_skb[i+1]->data), -+ (u32)(node->rx_lg_skb[i+1]->data)); -+ } + -+ skb_queue_head_init(&node->rx_skb_queue); -+ for (i = 0; i < NUM_RX_SKB; i++) { -+ struct sk_buff *skb; -+ skb = alloc_skb( -+ SM_BUFSZ > MAX_SDU_BUFS * sizeof(struct iovec) ? -+ SM_BUFSZ : MAX_SDU_BUFS * sizeof(struct iovec), -+ GFP_KERNEL); -+ if (!skb) { -+ printk("nicstar%d: Can't allocate Rx skb!\n",node->index); -+ return -ENOMEM; -+ } -+ skb_queue_tail(&node->rx_skb_queue,skb); -+ } -+ ++#if 0 /* @@@ more cleanup ahead */ ++struct sk_buff *atm_peek_clip(struct atm_vcc *vcc,unsigned long pdu_size, ++ __u32 (*fetch)(struct atm_vcc *vcc,int i)); ++void ipcom_init(struct device *dev, ++ int (*hard_start_xmit)(struct sk_buff *skb,struct device *dev), ++ unsigned short extra_flags); ++#endif ++void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to); + -+ /* Allocate seg chan queue */ -+ /* XXX What about 64-bit pointers? */ -+ i = create_scq(&(node->scq),SCQ_SIZE); -+ node->scq->id = SCQFULL_MAGIC; -+ if (i != 0) { return i; } -+ -+ printk("nicstar%d: SCQ at 0x%x.\n",node->index,(u32)node->scq->base); -+ -+ write_sram(node, 4, NICSTAR_VBR_SCD0, -+ (u32)node->scq->base, /* SCQ base */ -+ (u32)0x0, /* tail */ -+ (u32)0xffffffff, /* AAL5 CRC */ -+ (u32)0x0); /* rsvd */ -+ node->scq->scd = NICSTAR_VBR_SCD0; -+ -+ /* Install TST */ -+ -+ /* Create host transmit schedule table */ -+ if ((((u32) node->tx_statq - (u32) node->tx_statq_orig) - (4 * TST_SIZE)) < 1) { -+ printk ("Need to move host TST to later %d\n",4*TST_SIZE); -+ node->host_tst = (u32 *) ((u32) node->tx_statq_orig - 8 - (4 * TST_SIZE)); -+ printk ("New host_tst %x\n",(u32)node->host_tst); -+ } -+ else { -+ node->host_tst = (u32 *) node->tx_statq_orig; -+ } -+ -+ node->available_slots = TST_SIZE; ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/proc.c Thu Jul 10 17:59:06 1997 +@@ -0,0 +1,521 @@ ++/* net/atm/proc.c - ATM /proc interface */ + -+ memset((caddr_t) node->host_tst, 0, 4 * TST_SIZE); ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+#ifdef NICSTAR_CBR -+ for (i = NICSTAR_TST_REGION; i < NICSTAR_TST_REGION + TST_SIZE; i += 4) { -+ write_sram(node, 4, i, -+ (u32) TSTE_VBR, /* Tx VBR SCD */ -+ (u32) TSTE_VBR, /* Tx VBR SCD */ -+ (u32) TSTE_VBR, /* Tx VBR SCD */ -+ (u32) TSTE_VBR ); /* Tx VBR SCD */ -+ } + -+ write_sram(node, 1, NICSTAR_TST_REGION + TST_SIZE, -+ (u32)0x60000000 | NICSTAR_TST_REGION, /* Jump to start */ -+ 0x0, 0x0, 0x0); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* for HZ */ ++#include "resources.h" ++#include "signaling.h" /* to get sigd - ugly too */ + -+#else -+ write_sram(node, 2, NICSTAR_TST_REGION + TST_SIZE, -+ (u32)0x40000000, /* Tx VBR SCD */ -+ /* (u32)0x20000000 | NICSTAR_SCD_REGION, *//* Tx SCD */ -+ (u32)0x60000000 | NICSTAR_TST_REGION, /* Jump to start */ -+ 0x0, 0x0); ++#ifdef CONFIG_AREQUIPA ++#include ++void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb); +#endif + -+ writel((u32)(NICSTAR_TST_REGION << 2), node->membase + TSTB); -+ -+#if NICSTAR_RCQ -+ /* Turn on everything */ -+ writel(0x21801c38 | LG_BUFMSK | CFG_VPIVCI | 0x200 | 0x800, node->membase+CFG); -+ /* | 0x800 turns on raw cell interrupts */ -+ /* | 0x200 for raw cell receive */ -+ /* | 0x8000 to receive cells that don't map via RCT (not there/closed) */ -+#else -+ writel(0x21801c38 | LG_BUFMSK | CFG_VPIVCI, node->membase+CFG); /* Turn on everything */ ++#ifdef CONFIG_ATM_CLIP ++#include "ipcommon.h" ++extern void clip_push(struct atm_vcc *vcc,struct sk_buff *skb); +#endif + -+ while(CMD_BUSY(node)); -+#if NICSTAR_RCQ -+ printk("nicstar%d: Checking raw cell queue pointer...\n",node->index); -+ if (node->rcq.rcq_head != readl(node->membase + RAWCT)) { -+ printk("nicstar%d: Raw cell head %x tail %x don't match\n", -+ node->index,(u32)node->rcq.rcq_head, readl(node->membase + RAWCT)); -+ } ++#ifdef CONFIG_ATM_LANE ++#include "lec.h" ++#include "lec_arpc.h" ++extern struct device *dev_lec[MAX_LEC_ITF]; +#endif -+ return 0; -+} + -+static void nicstar_interrupt(int irq, void *dev_id, struct pt_regs *regs) { -+ nicstar_devp node = (nicstar_devp)dev_id; -+ u32 stat, wr_stat; + -+ PRINTK("nicstar: interrupt on %d.\n",irq); -+ -+ wr_stat = 0x0; -+ stat = readl(node->membase + STAT); -+ PRINTK("nicstar%d: Interrupt: STAT 0x%x.\n",node->index, stat); ++/*extern void eni_proc(int i,char *buf); - not yet @@@ */ + -+ if (stat & 0x8000) { -+ wr_stat |= 0x8000; -+ PRINTK("nicstar%d: TSI written to Tx status queue.\n",node->index); -+ process_tx_statq(node); -+ } -+ if (stat & 0x4000) { -+ wr_stat |= 0x4000; -+ printk("nicstar%d: Incomplete CS-PDU transmitted.\n",node->index); -+ } + -+ if (stat & 0x800) { -+ wr_stat |= 0x800; -+ PRINTK("nicstar%d: Timer overflow.\n",node->index); -+ } -+ if (stat & 0x100) { -+ printk("nicstar%d: Small buffer queue full (this is OK).\n",node->index); -+ } -+ if (stat & 0x80) { -+ printk("nicstar%d: Large buffer queue full (this is OK).\n",node->index); -+ } -+ if (stat & 0x40) { -+ printk("nicstar%d: Rx status queue full.\n",node->index); -+ wr_stat |= 0x40; -+ process_rx_statq(node); -+ } -+ if (stat & 0x20) { -+ /* wr_stat |= 0x20; */ -+ writel(0x20, node->membase + STAT); /* XXX mdw ack immediately */ -+ PRINTK("nicstar%d: End of PDU received.\n", node->index); -+ process_rx_statq(node); -+ } -+ if (stat & 0x10) { -+ wr_stat |= 0x10; -+ printk("nicstar%d: Raw cell received.\n",node->index); -+#ifdef NICSTAR_RCQ -+ process_rx_rawcellq(node); ++static int atm_header(ino_t ino,char *buf) ++{ ++ switch (ino) { ++ case PROC_ATM_DEVICES: ++ sprintf(buf,"Itf Type ESI/\"MAC\"addr " ++ "AAL(TX,err,RX,err,drop) ...\n"); ++ break; ++ case PROC_ATM_ARP: ++ sprintf(buf,"IPitf TypeEncp Idle IP address " ++ "ATM address\n"); ++ break; ++ case PROC_ATM_SVC: ++ sprintf(buf,"Itf VPI VCI State Remote\n"); ++ break; ++ case PROC_ATM_PVC: ++ sprintf(buf,"Itf VPI VCI AAL RX(PCR,Class) " ++ "TX(PCR,Class)\n"); ++ break; ++#ifdef CONFIG_ATM_LANE ++ case PROC_ATM_LEC: ++ sprintf(buf,"Itf MAC ATM destination Status Flags VPI/VCI Recv VPI/VCI\n"); ++ break; +#endif -+ } -+ if (stat & 0x8) { -+ printk("nicstar%d: Small buffer queue empty, disabling interrupt.\n",node->index); -+ writel((readl(node->membase + CFG) & ~0x01000000), node->membase + CFG); -+ wr_stat |= 0x8; -+ } -+ if (stat & 0x4) { -+ printk("nicstar%d: Large buffer queue empty, disabling interrupt.\n",node->index); -+ writel((readl(node->membase + CFG) & ~0x01000000), node->membase + CFG); -+ wr_stat |= 0x4; -+ } -+ if (stat & 0x2) { -+ printk("nicstar%d: Rx status queue almost full.\n",node->index); -+ wr_stat |= 0x2; -+ /* XXX Turn off interrupt */ -+ writel((readl(node->membase + CFG) & ~0x00000400), node->membase + CFG); -+ process_rx_statq(node); -+ } -+ -+ if (wr_stat != 0x0) { -+ writel(wr_stat, node->membase + STAT); -+ } -+ -+ return; ++#ifdef CONFIG_AREQUIPA ++ case PROC_ATM_AREQUIPA: ++ sprintf(buf,"Itf VPI VCI State Sock# Inode\n"); ++ break; ++#endif ++ default: ++ return -EINVAL; ++ } ++ return strlen(buf); +} + + -+static void process_tx_statq(nicstar_devp node) { -+ -+ volatile nicstar_tsi *next; -+ nicstar_scq *scq; -+ u32 id; -+ -+ /* Spin until something arrives. If we get a timer-rollover and a -+ * TSI simultaneously this could be dangerous; disabling timer -+ * interrupt will prevent that. -+ */ -+ next = node->tx_statq_next; -+ while (next->timestamp & 0x80000000) ; -+ -+ while (!(node->tx_statq_next->timestamp & 0x80000000)) { -+ PRINTK("nicstar%d: Tx statq entry 0x%x 0x%x\n", -+ node->index, -+ node->tx_statq_next->status, -+ node->tx_statq_next->timestamp); -+ -+ PRINTK ("Processing entry at %x with val %x\n",(u32) node->tx_statq_next, node->tx_statq_next->status); -+ -+#if 0 /* original method */ -+ if ((node->tx_statq_next->status & 0xffff0000) == SCQFULL_MAGIC) { -+ drain_scq(node, node->scq, node->tx_statq_next->status & 0xffff); -+ /* SCQ drained, wake 'er up */ -+ node->scq->full = 0; -+ wake_up_interruptible(&node->scq->scqfull_waitq); -+ } -+#else -+ id = (node->tx_statq_next->status & 0xc0000000) >> 16; -+ switch (id) { -+ case (SCQFULL_MAGIC >> 16): -+ scq = node->scq; -+ break; -+#if NICSTAR_CBR -+ case (CBRSCQFULL_MAGIC_CLOSE >> 16): -+ scq = node->vci_map[(node->tx_statq_next->status & 0x3fff0000)>>16].scq; -+ scq->closing = 1; -+ break; -+ case (CBRSCQFULL_MAGIC >> 16): -+ scq = node->vci_map[(node->tx_statq_next->status & 0x3fff0000)>>16].scq; -+ break; -+#endif -+ default: -+ scq = node->scq; -+ } -+ PRINTK ("Draining SCQ %d at %x\n",id,(u32)scq); -+ drain_scq(node, scq, node->tx_statq_next->status & 0xffff); -+ /* SCQ drained, wake 'er up */ -+ scq->full = 0; -+ wake_up_interruptible(&scq->scqfull_waitq); -+#endif -+ -+ node->tx_statq_next->timestamp |= 0x80000000; -+ -+ if (node->tx_statq_next == node->tx_statq_last) -+ node->tx_statq_next = node->tx_statq; -+ else -+ node->tx_statq_next++; -+ } ++static void add_stats(char *buf,const char *aal, ++ const struct atm_aal_stats *stats) ++{ ++ sprintf(strchr(buf,0),"%s ( %ld %ld %ld %ld %ld )",aal,stats->tx, ++ stats->tx_err,stats->rx,stats->rx_err,stats->rx_drop); ++} + -+ writel((u32)node->tx_statq_next - (u32)node->tx_statq, -+ node->membase + TSQH); + -+ return; -+} ++static void dev_info(const struct atm_dev *dev,char *buf) ++{ ++ int off,i; + -+#if NICSTAR_RCQ -+static void process_rx_rawcellq (nicstar_devp node) { -+ u32 tail; -+ u32 timer; -+ u32 last; -+ int count; -+ -+ tail = readl(node->membase + RAWCT); -+ timer = readl(node->membase + TMR); -+ count = 0; -+ while (node->rcq.rcq_head != tail - RAWCELLSZ) { -+ if (count > 3) { -+ printk ("nicstar OOOPS. Count > 3\n"); -+ return; -+ } -+ /* service head */ -+ PRINTK ("nicstar: dequeueing 0x%x to 0x%x\n",(u32)node->rcq.rcq_head, -+ readl(node->membase + RAWCT)); -+ dequeue_rawcell((u32 *) node->rcq.rcq_head); -+ node->rcq.rcq_head += RAWCELLSZ; -+ last = node->rcq.rcq_base + LG_BUFSZ - RAWCELLSZ; -+ PRINTK ("Last %x tail %x rawct %x\n",(u32)last,(u32)tail,readl(node->membase + RAWCT)); -+ if (node->rcq.rcq_head == (node->rcq.rcq_base + LG_BUFSZ - RAWCELLSZ)) { -+ node->rcq.rcq_head = *((u32 *) node->rcq.rcq_head); -+ free_rx_buf(node, 1, node->rcq.rcq_base); -+ node->rcq.rcq_base = node->rcq.rcq_head; -+ if (node->rcq.rcq_base == tail) return; /* watch out for jumps */ -+ } -+ count++; -+ } -+ /* YYY Might be able to avoid this by polling the cell header; -+ requires initializing the header to a known value. Also -+ assumes that we can find such a known value */ -+ while (((readl(node->membase+TMR)) - timer) < 30); -+ /* service one cell */ -+ dequeue_rawcell((u32 *) node->rcq.rcq_head); -+ node->rcq.rcq_head += RAWCELLSZ; -+ if (node->rcq.rcq_head == (node->rcq.rcq_base + LG_BUFSZ - RAWCELLSZ)) { -+ node->rcq.rcq_head = *((u32 *) node->rcq.rcq_head); -+ free_rx_buf(node, 1, node->rcq.rcq_base); -+ node->rcq.rcq_base = node->rcq.rcq_head; -+ } ++ off = sprintf(buf,"%3d %-8s",dev->number,dev->type); ++ for (i = 0; i < ESI_LEN; i++) ++ off += sprintf(buf+off,"%02x",dev->esi[i]); ++ strcat(buf," "); ++ add_stats(buf,"0",&dev->stats.aal0); ++ strcat(buf," "); ++ add_stats(buf,"5",&dev->stats.aal5); ++ strcat(buf,"\n"); +} + -+static void dequeue_rawcell (u32 *cell) { -+ u32 header; -+ u32 *payload; -+ int i; -+ -+ header = *cell; -+ payload = cell + 4; -+ printk("nicstar: *Raw cell %x arrival hdr=%x pay=%x*\n", -+ (u32)cell,header,(u32)payload); -+ printk("nicstar: Header contents VCI=%d Last=%d\n", -+ header >> 4, (header & 0x2) >> 1); -+ if (header & 0x2) { -+ printk("nicstar: PDU length %d\n", -+ ((payload[10] & 0xff000000) >> 24) + -+ (256 * ((payload[10] & 0x00ff0000) >> 16))); -+ } -+ for (i = 0; i < 12; i++) { -+ printk (" %d 0x%x\n",i,(u32)payload[i]); -+ } -+} -+#endif /* NICSTAR_RCQ */ + -+static void process_rx_statq(nicstar_devp node) { -+ u32 prev; ++#ifdef NOT_YET_CONFIG_ATM_CLIP + -+ /* XXX Problem here: The 77201 can interrupt us (and set EPDU -+ * bits in STAT) before the Rx statq entry arrives in memory. -+ * The interrupt could be raised for multiple incoming PDUs, -+ * and we could miss seeing those entries that are slow to -+ * arrive in memory at the end of this loop. We'll see the PDU -+ * on the next Rx EPDU interrupt, of course. -+ */ -+ while (node->rx_statq_next->status & 0x80000000) { -+ PRINTK("nicstar%d: Rx statq entry 0x%x 0x%x 0x%x 0x%x\n", -+ node->index, -+ node->rx_statq_next->vpi_vci, -+ node->rx_statq_next->buf_handle, -+ node->rx_statq_next->crc, -+ node->rx_statq_next->status); -+ -+ dequeue_rx(node); -+ node->rx_statq_next->status = 0x0; -+ -+ if (node->rx_statq_next == node->rx_statq_last) -+ node->rx_statq_next = node->rx_statq; -+ else -+ node->rx_statq_next++; + -+ } ++static int svc_addr(char *buf,struct sockaddr_atmsvc *addr) ++{ ++ static int code[] = { 1,2,10,6,1,0 }; ++ static int e164[] = { 1,8,4,6,1,0 }; ++ int *fields; ++ int len,i,j,pos; + -+ /* Update the RSQH to point to the last entry actually processed. */ -+ if (node->rx_statq_next == node->rx_statq) { -+ prev = (u32)node->rx_statq_last; -+ } else { -+ prev = (u32)(node->rx_statq_next - 1); -+ } -+ writel((u32)prev - (u32)node->rx_statq, -+ node->membase + RSQH); ++ len = 0; ++ if (*addr->sas_addr.pub) { ++ strcpy(buf,addr->sas_addr.pub); ++ len = strlen(addr->sas_addr.pub); ++ buf += len; ++ if (*addr->sas_addr.pub) { ++ *buf += '+'; ++ len++; ++ } ++ } ++ else if (!*addr->sas_addr.prv) { ++ strcpy(buf,"(none)"); ++ return strlen(buf); ++ } ++ if (*addr->sas_addr.prv) { ++ len += 44; ++ pos = 0; ++ fields = *addr->sas_addr.prv == ATM_AFI_E164 ? e164 : code; ++ for (i = 0; fields[i]; i++) { ++ for (j = fields[i]; j; j--) { ++ sprintf(buf,"%02X",addr->sas_addr.prv[pos++]); ++ buf += 2; ++ } ++ if (fields[i+1]) *buf++ = '.'; ++ } ++ } ++ return len; ++} + -+ PRINTK("RSQ: 0x%x, next 0x%x, diff 0x%x, tail 0x%x\n", -+ (u32)node->rx_statq, -+ (u32)node->rx_statq_next, -+ (u32)node->rx_statq_next - (u32)node->rx_statq, -+ readl(node->membase + RSQT)); + -+ PRINTK("nicstar%d: Status reads 0x%x.\n", node->index, -+ readl(node->membase + STAT)); ++static void atmarp_info(struct device *dev,struct atmarp_entry *entry, ++ char *buf) ++{ ++ unsigned char *ip; ++ int svc,off,ip_len; + -+ return; ++ svc = !entry->vcc || entry->vcc->family == AF_ATMSVC; ++ off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC", ++ entry->encap ? "LLC" : "NULL",(jiffies-entry->last_use)/HZ); ++ ip = (unsigned char *) &entry->ip; ++ ip_len = sprintf(buf+off,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); ++ off += ip_len; ++ while (ip_len++ < 16) buf[off++] = ' '; ++ if (!entry->vcc) strcpy(buf+off,"(incomplete)\n"); ++ else if (!svc) ++ sprintf(buf+off,"%d.%d.%d\n",entry->vcc->dev->number, ++ entry->vcc->vpi,entry->vcc->vci); ++ else { ++ off += svc_addr(buf+off,&entry->vcc->remote); ++ strcpy(buf+off,"\n"); ++ } +} + -+static void push_rxbufs(nicstar_devp node, int lg, -+ u32 handle1, u32 addr1, u32 handle2, u32 addr2) { -+ -+ unsigned long flags; -+ int bc; + -+ -+ if (lg) { -+ bc = (readl(node->membase + STAT) & 0x00ff0000) >> 16; -+ } else { -+ bc = (readl(node->membase + STAT) & 0xff000000) >> 24; -+ } -+ if (bc >= 254) return; -+ -+ save_flags(flags); cli(); -+ while (CMD_BUSY(node)) ; -+ -+ writel(handle1, node->membase + DR0); -+ writel(addr1, node->membase + DR1); -+ writel(handle2, node->membase + DR2); -+ writel(addr2, node->membase + DR3); -+ -+ writel(0x60000000 | (lg ? 0x01 : 0x00), node->membase + CMD); -+ restore_flags(flags); -+ return; -+} -+ -+static void open_rx_connection(nicstar_devp node, -+ int index, -+ u32 status) { -+#if 0 -+ unsigned long flags; +#endif + -+ u32 sram_addr = index * (sizeof(nicstar_rcte)/sizeof(u32)); + -+ write_sram(node, 1, sram_addr, status | 0x80000, -+ 0x0, 0x0, 0x0); ++static void pvc_info(struct atm_vcc *vcc,char *buf) ++{ ++ static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" }; ++ static const char *aal_name[] = { ++ "0", "1", "2", "3/4", /* 0- 3 */ ++ "???", "5", "???", "???" };/* 4- 7 */ ++ int off; ++ ++ off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s", ++ vcc->dev->number,vcc->vpi,vcc->vci, ++ vcc->qos.aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" : ++ aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr, ++ class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr, ++ class_name[vcc->qos.txtp.traffic_class]); ++#ifdef NOT_YET_CONFIG_ATM_CLIP ++ if (vcc->push == atm_push_clip) { ++ struct device *dev; + -+#if 0 -+ /* This is actually unnecessary, I believe, if we add the -+ open connection bit to the SRAM write. Alternately, if -+ we initialize the AAL during init_module, we can just -+ use the open connection command... (SWD) */ -+ save_flags(flags); cli(); -+ while (CMD_BUSY(node)) ; -+ writel(0x20080000 | (sram_addr << 2), node->membase + CMD); -+ restore_flags(flags); ++ dev = (struct device *) vcc->proto_data; ++ off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",dev->name); ++ if (dev->hard_header_len == RFC1483LLC_LEN) ++ off += sprintf(buf+off,"LLC/SNAP"); ++ else if (dev->hard_header_len == 0) ++ off += sprintf(buf+off,"None"); ++ else off += sprintf(buf+off,"Unknown"); ++ } +#endif ++ strcpy(buf+off,"\n"); +} + -+static void close_rx_connection(nicstar_devp node, -+ int index) { -+ unsigned long flags; -+ u32 sram_addr = index * (sizeof(nicstar_rcte)/sizeof(u32)); -+ -+ save_flags(flags); cli(); -+ while (CMD_BUSY(node)) ; -+ writel(0x20000000 | (sram_addr << 2), node->membase + CMD); -+ restore_flags(flags); -+} -+ -+static void push_scq_entry(nicstar_devp node, struct nicstar_scq *scq, -+ nicstar_tbd *entry, -+ int xmit_now) { -+ -+ unsigned long flags; -+ nicstar_tbd magic_bullet = {0xa0000000, scq->id, 0x0, 0x0}; -+ static int delayed_bullet = 0; -+ -+ PRINTK("tail 0x%x next 0x%x\n", -+ (u32) scq->tail, (u32) scq->next); -+ PRINTK("CFG: 0x%x\n",readl(node->membase + CFG)); -+ -+ if (scq->tail == scq->next) { -+ PRINTK ("Going to sleep\n"); -+ /* Sleep until the tail moves */ -+ save_flags(flags); cli(); -+ scq->full = 1; -+ -+ current->timeout = jiffies + SCQFULL_TIMEOUT; -+ interruptible_sleep_on(&scq->scqfull_waitq); -+ restore_flags(flags); -+ -+ if (scq->full) { -+ printk("nicstar%d: SCQ drain timed out.\n",node->index); -+ scq->full = 0; -+ /* XXX Just proceed here, although the SAR's probably hosed ... */ -+ } -+ } -+ -+ *scq->next = *entry; -+ -+ if (scq->next == scq->last) -+ scq->next = scq->base; -+ else -+ scq->next++; -+ -+ if (((scq->next - scq->base) % NUM_SCQ_TRAIL) == NUM_SCQ_TRAIL-1) { -+ delayed_bullet = 1; -+ } + -+ if (xmit_now) { -+ if (delayed_bullet) { -+ delayed_bullet = 0; -+ magic_bullet.buf_addr |= (u32)(scq->next - scq->base); -+ if (scq->tail == scq->next) { -+ PRINTK ("Going to sleep!!\n"); -+ /* Sleep until the tail moves */ -+ save_flags(flags); cli(); -+ scq->full = 1; -+ -+ current->timeout = jiffies + SCQFULL_TIMEOUT; -+ interruptible_sleep_on(&scq->scqfull_waitq); -+ restore_flags(flags); ++static const char *vcc_state(struct atm_vcc *vcc) ++{ ++ if (vcc->flags & ATM_VF_READY) return "CONNECTED"; ++ if (vcc->flags & ATM_VF_RELEASED) return "CLOSING"; ++ if (vcc->flags & ATM_VF_LISTEN) return "LISTEN"; ++ if (vcc->flags & ATM_VF_REGIS) return "INUSE"; ++ if (vcc->flags & ATM_VF_BOUND) return "BOUND"; ++ return "IDLE"; ++} + -+ if (scq->full) { -+ printk("nicstar%d: SCQ drain timed out.\n",node->index); -+ scq->full = 0; -+ /* XXX Just proceed here, although the SAR's probably hosed ... */ -+ } -+ } -+ *scq->next = magic_bullet; -+ if (scq->next == scq->last) -+ scq->next = scq->base; -+ else -+ scq->next++; -+ } -+ write_sram(node, 1, scq->scd, -+ (u32)(scq->next), -+ 0x0, 0x0, 0x0); -+ } + -+ return; -+} ++static void svc_info(struct atm_vcc *vcc,char *buf) ++{ ++ char *here; ++ int i; + -+static int get_ci(nicstar_devp node, -+ struct atm_vcc *vcc, -+ short *vpi, int *vci) { -+ nicstar_vcimap *mapval; -+ -+ PRINTK ("Reserving vci %d\n",(u32) *vci); -+ /* Default, accept VPI 0 and VCI 0-4095. */ -+ if (*vpi == ATM_VPI_UNSPEC || *vci == ATM_VCI_UNSPEC) return -EINVAL; -+ -+ if (*vpi == ATM_VPI_ANY) *vpi = 0; -+ if (*vpi >= NUM_VPI) return -EINVAL; -+ -+ if (*vci == ATM_VCI_ANY) { -+ /* Find lowest VCI */ -+#ifndef ATM_013 -+ for (*vci = (*vpi) * NUM_VCI + ATM_NOT_RSV_VCI; *vci < (*vpi + 1) * NUM_VCI; (*vci)++) { -+ mapval = &(node->vci_map[*vci]); -+ if (vcc->qos.rxtp.traffic_class != ATM_NONE && mapval->rx) continue; -+ if (vcc->qos.txtp.traffic_class != ATM_NONE && mapval->tx) continue; -+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) { -+ mapval->rx = 1; mapval->rx_vcc = vcc; -+ } -+ if (vcc->qos.txtp.traffic_class != ATM_NONE) { -+ mapval->tx = 1; mapval->tx_vcc = vcc; -+ } -+#else -+ if (vcc->qos.rxtp.class != ATM_NONE && mapval->rx) continue; -+ if (vcc->qos.txtp.class != ATM_NONE && mapval->tx) continue; -+ if (vcc->qos.rxtp.class != ATM_NONE) { -+ mapval->rx = 1; mapval->rx_vcc = vcc; -+ } -+ if (vcc->txtp.class != ATM_NONE) { -+ mapval->tx = 1; mapval->tx_vcc = vcc; -+ } -+ break; -+#endif /* ATM_013 */ -+ } -+ if (*vci == NUM_VCI) return -EADDRINUSE; -+ -+ } else { -+ /* Use this particular VCI */ -+ if (*vci >= NUM_VCI) return -EINVAL; -+ mapval = &(node->vci_map[(*vpi << NUM_VCI_BITS) | *vci]); -+#ifndef ATM_013 -+ if (vcc->qos.rxtp.traffic_class != ATM_NONE && mapval->rx) return -EADDRINUSE; -+ if (vcc->qos.txtp.traffic_class != ATM_NONE && mapval->tx) return -EADDRINUSE; -+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) { -+ mapval->rx = 1; mapval->rx_vcc = vcc; -+ } -+ if (vcc->qos.txtp.traffic_class != ATM_NONE) { -+ mapval->tx = 1; mapval->tx_vcc = vcc; -+ } -+#else -+ if (vcc->rxtp.class != ATM_NONE && mapval->rx) return -EADDRINUSE; -+ if (vcc->txtp.class != ATM_NONE && mapval->tx) return -EADDRINUSE; -+ if (vcc->rxtp.class != ATM_NONE) { -+ mapval->rx = 1; mapval->rx_vcc = vcc; -+ } -+ if (vcc->txtp.class != ATM_NONE) { -+ mapval->tx = 1; mapval->tx_vcc = vcc; -+ } ++ if (!vcc->dev) sprintf(buf,"Unassigned "); ++ else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci); ++ here = strchr(buf,0); ++ here += sprintf(here,"%-10s ",vcc == sigd ? "Signaling" : ++#ifdef NOT_YET_CONFIG_ATM_CLIP ++ vcc == atmarpd ? "ATMARPctrl" : +#endif -+ } -+ -+ return 0; ++#ifdef CONFIG_AREQUIPA ++ vcc == aqd ? "Arequipa" : ++#endif ++ vcc_state(vcc)); ++ here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub, ++ *vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : ""); ++ if (*vcc->remote.sas_addr.prv) ++ for (i = 0; i < ATM_ESA_LEN; i++) ++ here += sprintf(here,"%02x", ++ vcc->remote.sas_addr.prv[i]); ++ strcat(here,"\n"); +} + -+static void free_rx_buf(nicstar_devp node, int lg, u32 buf_addr) { -+ static u32 sm_buf = 0x0, lg_buf = 0x0; -+ -+ if (lg) { -+ /* Large buffer */ -+ if (lg_buf == 0x0) { -+ lg_buf = buf_addr; -+ } else { -+ u32 buf; -+ -+#ifdef NICSTAR_LBUFCNT -+ node->lbuf_cnt += 2; -+#endif -+ buf = buf_addr; -+ push_rxbufs(node, 1, lg_buf, lg_buf, buf, buf); -+ lg_buf = 0x0; -+ } -+ } else { -+ /* Small buffer */ -+ if (sm_buf == 0x0) { -+ sm_buf = buf_addr; -+ } else { -+ u32 buf; -+ buf = buf_addr; -+ push_rxbufs(node, 0, sm_buf, sm_buf, buf, buf); -+ sm_buf = 0x0; -+ } -+ } -+ return; -+} + -+static void dequeue_rx(nicstar_devp node) { -+ -+ struct atm_vcc *vcc; -+ struct sk_buff *skb; -+ struct iovec *iov; -+ nicstar_vcimap *mapval; -+ volatile nicstar_rsqe *entry = (volatile nicstar_rsqe *)node->rx_statq_next; -+ unsigned short aal5_len; -+ unsigned short aal0_len; -+ u32 *aal0_ptr; -+ u32 vpi, vci; -+ -+ vpi = (entry->vpi_vci & 0x00ff0000) >> 16; -+ vci = entry->vpi_vci & 0xffff; -+ -+ if ((vpi >= NUM_VPI) || (vci >= NUM_VCI)) { -+ printk("nicstar%d: SDU received for out of range VC %d.%d.\n", -+ node->index, vpi, vci); -+ return; -+ } ++#ifdef CONFIG_AREQUIPA + -+ mapval = &(node->vci_map[(vpi << NUM_VCI_BITS) | vci]); -+ if (!mapval->rx) { -+ printk("nicstar%d: SDU received on inactive VC %d.%d.\n", -+ node->index, vpi, vci); -+ } -+ vcc = mapval->rx_vcc; + -+ if (!(skb = mapval->rx_skb)) { -+ /* Starting new SKB */ -+ skb = mapval->rx_skb = skb_dequeue(&node->rx_skb_queue); -+ if (!skb) { -+ printk("nicstar%d: Out of Rx skb's!\n",node->index); -+ goto drop_message; -+ } -+ } ++static const char *arequipa_state(const struct atm_vcc *vcc) ++{ ++ if (!(vcc->flags & ATM_VF_REGIS) && vcc->family != PF_ATMPVC) ++ return "DOOMED"; ++ if (vcc->upper) return "ATTACHED"; ++ return "DANGLING"; ++} + -+ if (vcc->aal == ATM_AAL0) { -+ iov = &(((struct iovec *)skb->data)[skb->atm.iovcnt]); -+ aal0_ptr = (u32 *)entry->buf_handle; -+ aal0_ptr--; -+ *(aal0_ptr) = /* "reconstruct" cell header */ -+ (entry->vpi_vci << 4) | ((entry->status & 0x4000) >> 14)| -+ ((entry->status & 0x400) >> 10); -+ PRINTK("Reconstructed cell header %x at %x, bufhandle %x\n", -+ *aal0_ptr,(u32)aal0_ptr,entry->buf_handle); -+ iov->iov_base = (void *)(aal0_ptr); -+ aal0_len = ATM_CELL_SIZE - 1; -+ iov->iov_len = aal0_len; -+ skb->len = aal0_len; -+ skb->atm.iovcnt++; -+ vcc->stats->rx++; -+ skb->atm.timestamp = xtime; -+ if ((u32) vcc->push != (u32) atm_push_raw) { -+ skb = (struct sk_buff *) linearize_buffer(node,skb,vcc); -+ } -+ if (skb) { -+ vcc->push(vcc, skb); -+ } -+ mapval->rx_skb = NULL; -+ return; -+ } + -+ iov = &(((struct iovec *)skb->data)[skb->atm.iovcnt]); -+ iov->iov_base = (void *)entry->buf_handle; ++static void arequipa_info(struct atm_vcc *vcc,char *buf) ++{ ++ char *here; ++ ++ if (!vcc->dev) sprintf(buf,"Unassigned "); ++ else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci); ++ here = strchr(buf,0); ++ here += sprintf(here,"%-8s ",arequipa_state(vcc)); ++ if (vcc->upper) ++ here += sprintf(here,"%5d %ld",vcc->upper->num, ++ vcc->upper->socket && SOCK_INODE(vcc->upper->socket) ? ++ SOCK_INODE(vcc->upper->socket)->i_ino : 0); ++ strcat(here,"\n"); ++} + -+ if (entry->status & 0x2000) { -+ /* Last buffer, get AAL5 len */ -+ aal5_len = *(unsigned short *)((unsigned char *)entry->buf_handle + ((entry->status & 0x1ff)*48) - 6); -+ aal5_len = ((aal5_len & 0xff) << 8) | ((aal5_len & 0xff00) >> 8); -+ PRINTK ("Last buffer; AAL5 len is %d\n",aal5_len); -+ -+ iov->iov_len = aal5_len - skb->len; -+ skb->len = aal5_len; -+ skb->atm.iovcnt++; -+#ifdef NICSTAR_LBUFCNT -+ node->lbuf_cnt -= (skb->atm.iovcnt - 1); -+#endif -+ PRINTK("Received %d-buffer message %x\n",skb->atm.iovcnt,skb); -+ vcc->stats->rx++; -+ -+ -+ if ((u32) vcc->push != (u32) atm_push_raw) { -+ skb = (struct sk_buff *) linearize_buffer(node,skb,vcc); -+ PRINTK("rcv %d-buf len %d\n",skb->atm.iovcnt,skb->len); -+ } -+ PRINTK("after is rcv %d-buf len %d\n",skb->atm.iovcnt,skb->len); -+ -+ if (skb) { -+ vcc->push(vcc, skb); -+ } -+ mapval->rx_skb = NULL; -+ } else { -+ iov->iov_len = (entry->status & 0x1ff) * 48; -+ skb->len += iov->iov_len; -+ skb->atm.iovcnt++; -+ } -+ return; + -+drop_message: -+ printk("nicstar%d: drop_message returned in dequeue_rx.\n",node->index); -+ vcc->stats->rx_drop++; -+ -+ if (entry->status & 0x1000) { -+ /* Large buffer */ -+ free_rx_buf(node, 1, entry->buf_handle); -+ } else { -+ /* Small buffer */ -+ free_rx_buf(node, 0, entry->buf_handle); -+ } ++#endif + -+ return; -+} + -+static void nicstar_rx_skb_destructor (struct sk_buff *skb) { -+ if (skb->count > 1) return; -+#if NICSTAR_RC_FLAG -+ nicstar_free_rx_skb((struct atm_vcc *) skb->atm.recycle_buffer,skb); -+#else -+ nicstar_free_rx_skb((struct atm_vcc *) skb->atm.vcc,skb); -+#endif -+} ++#ifdef CONFIG_ATM_LANE + -+static void nicstar_free_rx_skb(struct atm_vcc *vcc, struct sk_buff *skb) { -+ nicstar_devp node = vcc->dev->dev_data; -+ struct iovec *iov; -+ int i; -+ u32 ptr_chk; -+ -+ if (!skb->atm.iovcnt) { -+ for (i = 0; i < NUM_LG_BUFS; i++) { -+ if (node->rx_lg_skb[i]->head == skb->head) break; -+ } -+ if (i < NUM_LG_BUFS) { -+ /* this had better be a large buffer on the rebound (SWD) */ -+ /* restore data pointers */ -+ (node->rx_lg_skb[i])->data = (node->rx_lg_skb[i])->head + SM_BUF_DATALEN; -+ (node->rx_lg_skb[i])->len = 0; -+ (node->rx_lg_skb[i])->tail = (node->rx_lg_skb[i])->data; -+ free_rx_buf(node, 1, (u32)((node->rx_lg_skb[i])->data)); -+ return; -+ } -+ else { -+ /* i > NUM_LG_BUFS ==> small buffer, which has already */ -+ /* been recycled; just requeue this skb after resetting */ -+ /* tail */ -+ return; -+ } -+ } -+ else { /* handle s-g buffer */ -+ iov = (struct iovec *)skb->data; -+ for (i = 0; i < skb->atm.iovcnt; i++) { -+ if (((unsigned char *)iov[i].iov_base >= (unsigned char *)node->sm_bufs) && -+ ((unsigned char *)iov[i].iov_base < (unsigned char *)node->sm_bufs + SM_BUFSZ * NUM_SM_BUFS)) { -+ ptr_chk = (u32)iov[i].iov_base == (u32)node->sm_bufs ? 48 : -+ ((u32)iov[i].iov_base - ((u32)node->sm_bufs + 4)) % SM_BUFSZ; -+ if (ptr_chk) { -+ iov[0].iov_base += 4; -+#ifdef NICSTAR_PARANOID -+ if (ptr_chk != 48) { -+ printk ("nicstar%d: Misaligned buffer pointer (offset %d)!\n", -+ node->index,ptr_chk); -+ } -+ ptr_chk = (u32)iov[i].iov_base == (u32)node->sm_bufs ? 48 : -+ ((u32)iov[i].iov_base - ((u32)node->sm_bufs + 4)) % SM_BUFSZ; -+ if (ptr_chk) { -+ printk("nicstar%d: Misaligned pointer STILL NOT FIXED!!! %x %d\n", -+ node->index,(u32)iov[i].iov_base,ptr_chk); -+ } -+#endif -+ } -+ free_rx_buf(node, 0, (u32)(iov[i].iov_base)); -+ } else { -+ /* Large buffer */ -+ free_rx_buf(node, 1, (u32)(iov[i].iov_base)); -+ } -+ } ++static char* ++lec_arp_get_status_string(unsigned char status) ++{ ++ switch(status) { ++ case ESI_UNKNOWN: ++ return "ESI_UNKNOWN "; ++ case ESI_ARP_PENDING: ++ return "ESI_ARP_PENDING "; ++ case ESI_VC_PENDING: ++ return "ESI_VC_PENDING "; ++ case ESI_FLUSH_PENDING: ++ return "ESI_FLUSH_PENDING "; ++ case ESI_FORWARD_DIRECT: ++ return "ESI_FORWARD_DIRECT"; ++ default: ++ return " "; + } ++} + -+ skb->atm.iovcnt = 0; -+ skb->len = 0; -+ skb_queue_tail(&node->rx_skb_queue, skb); -+ -+ return; -+} -+ -+static void drain_scq(nicstar_devp node, struct nicstar_scq *scq, int index) { -+ nicstar_tbd *last = scq->base + index; -+ int sindex = scq->tail - scq->base; -+ struct sk_buff *skb; -+ struct atm_vcc *vcc; -+ -+ while (scq->tail != last) { -+ if ((skb = scq->scq_shadow[sindex].skb)) { -+ vcc = skb->atm.vcc; -+ if (skb->free == 2) printk("drain_scq: Passed skb 0x%x with free == 2.\n", (u32) skb); -+ if (vcc->pop) { -+ vcc->pop(vcc, skb); -+ } else { -+ dev_kfree_skb(skb, FREE_WRITE); -+ } -+ scq->scq_shadow[sindex].skb = 0; -+ } -+ -+ if (scq->tail == scq->last) { -+ scq->tail = scq->base; sindex = 0; -+ } else { -+ scq->tail++; sindex++; -+ } -+ } ++static void ++lec_info(struct lec_arp_table *entry, char *buf) ++{ ++ int j, offset=0; ++ + ++ for(j=0;jmac_addr[j]); ++ } ++ offset+=sprintf(buf+offset, " "); ++ for(j=0;jatm_addr[j]); ++ } ++ offset+=sprintf(buf+offset, " %s %4.4x", ++ lec_arp_get_status_string(entry->status), ++ entry->flags&0xffff); ++ if (entry->vcc) { ++ offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi, ++ entry->vcc->vci); ++ } else ++ offset+=sprintf(buf+offset, " "); ++ if (entry->recv_vcc) { ++ offset+=sprintf(buf+offset, " %3d %3d", ++ entry->recv_vcc->vpi, entry->recv_vcc->vci); ++ } + -+#ifdef NICSTAR_CBR -+ if (scq->closing) { -+ close_cbr_final(node,node->vci_map[(scq->id >> 16) & 0xfff].tx_vcc); -+ } -+#endif ++ sprintf(buf+offset,"\n"); +} + -+#ifdef NICSTAR_CBR -+static void alloc_tx(nicstar_devp node, struct atm_vcc *vcc) { -+ int i, j; -+ int slots; -+ int spacing; -+ int vci; -+ -+ vci = (vcc->vpi << NUM_VCI_BITS) | vcc->vci; -+ create_scq(&((node->vci_map[vci]).scq),CBRSCQ_SIZE); -+ (node->vci_map[vci].scq)->id = CBRSCQFULL_MAGIC | (vci << 16); -+ PRINTK ("nicstar%d: Allocating CBR SCQ at %x\n",node->index,(u32) ((node->vci_map[vci]).scq)); -+ PRINTK ("nicstar%d: Allocating transmission bandwidth\n",node->index); -+#ifndef ATM_013 -+ printk ("in pcr: %d/%d/%d\n",vcc->qos.txtp.min_pcr, -+ vcc->qos.txtp.max_pcr,node->max_pcr); -+#else -+ printk ("in pcr: %d/%d/%d\n",vcc->txtp.min_pcr, -+ vcc->txtp.max_pcr,node->max_pcr); -+#endif -+ (node->vci_map[vci].scq)->scd = 0; /* initialize SCD pointer */ -+#ifndef ATM_013 -+ slots = (u32) (((float) vcc->qos.txtp.max_pcr / (float) node->max_pcr) * (float) TST_SIZE) + 1; -+#else -+ slots = (u32) (((float) vcc->txtp.max_pcr / (float) node->max_pcr) * (float) TST_SIZE) + 1; +#endif -+ printk ("out: %d slots\n",slots); -+ if (slots > node->available_slots) { -+ printk("Reducing requested BW from %d to %d slots -- full up\n", -+ slots,node->available_slots); -+ slots = node->available_slots; -+ } -+ node->available_slots -= slots; -+ spacing = TST_SIZE / slots; -+ /* sort of randomly pick starting slot */ -+ i = readl(node->membase + TMR) % TST_SIZE; -+ while (slots > 0) { -+ j = i; -+ while (node->host_tst[j]) { -+ j++; -+ if (j >= TST_SIZE) { -+ j -= TST_SIZE; -+ } -+ } -+ if (!((node->vci_map[vci].scq)->scd)) { -+ (node->vci_map[vci].scq)->scd = NICSTAR_SCD_REGION + 12 * j; -+ write_sram(node, 4, NICSTAR_SCD_REGION + 12 * j, -+ (u32) ((nicstar_vcimap *)vcc->dev_data)->scq->base, /* base + head */ -+ 0x0, /* tail */ -+ 0xffffffff, /* aal5 crc */ -+ 0x0); -+ /* should we also init next 8 words to 0? */ -+ PRINTK ("CBR SCQ at j %d sram %x ptr %x\n",j, -+ NICSTAR_SCD_REGION + 12 * j, -+ read_sram(node,NICSTAR_SCD_REGION + 12 * j)); -+ } -+ node->host_tst[j] = (u32) vcc; -+ write_sram(node, 1, NICSTAR_TST_REGION + j, -+ TSTE_CBR | (node->vci_map[vci].scq)->scd, -+ 0x0, 0x0, 0x0); -+ i += spacing; -+ if (i >= TST_SIZE) { -+ i -= TST_SIZE; -+ } -+ slots--; -+ } -+} + -+/* Closes down a CBR connection. */ -+static void close_cbr (nicstar_devp node, struct atm_vcc *vcc) { -+ unsigned long flags; -+ struct nicstar_scq *scq = ((nicstar_vcimap *)vcc->dev_data)->scq; -+ -+ PRINTK("Initial close down of CBR connection %x...",(u32) vcc); -+ /* Push a TSR */ -+ if (scq->tail == scq->next) { -+ /* Sleep until the tail moves */ -+ save_flags(flags); cli(); -+ scq->full = 1; -+ -+ current->timeout = jiffies + SCQFULL_TIMEOUT; -+ interruptible_sleep_on(&scq->scqfull_waitq); -+ restore_flags(flags); -+ -+ if (scq->full) { -+ printk("nicstar%d: SCQ drain timed out.\n",node->index); -+ scq->full = 0; -+ /* XXX Just proceed here, although the SAR's probably hosed ... */ -+ } -+ } + -+ PRINTK("Writing TSR\n"); ++/* ++ * FIXME: it isn't safe to walk the VCC list without turning off interrupts. ++ * What is really needed is some spinlock on the devices. ++ */ + -+ scq->next->status = 0xa0000000; -+ scq->next->buf_addr = CBRSCQFULL_MAGIC_CLOSE | scq->id | (u32)(scq->next - scq->base); -+ scq->next->ctl_len = 0; -+ scq->next->cell_hdr = 0; -+ -+ if (scq->next == scq->last) -+ scq->next = scq->base; -+ else -+ scq->next++; -+ write_sram(node, 1, scq->scd, -+ (u32)(scq->next), -+ 0x0, 0x0, 0x0); -+} -+ -+static void close_cbr_final (nicstar_devp node, struct atm_vcc *vcc) { -+ int i, count; -+ -+ for (i = 0; i < TST_SIZE; i++) { -+ if (node->host_tst[i] == (u32) vcc) { -+ node->host_tst[i] = 0; -+ node->available_slots += 1; -+ write_sram(node,1, NICSTAR_TST_REGION + i, -+ TSTE_VBR, 0x0, 0x0, 0x0); -+ } -+ } -+ count = 0; -+ for (i = 0; i < TST_SIZE; i++) { -+ if (read_sram(node,NICSTAR_TST_REGION + i) != TSTE_VBR) { -+ count ++; -+ } -+ } -+ PRINTK ("non-VBR Count %d avail slots %d\n",count, node->available_slots); -+ /* free up the CBR SCQ */ -+ kfree(((nicstar_vcimap *)vcc->dev_data)->scq->orig); -+ kfree(((nicstar_vcimap *)vcc->dev_data)->scq); -+} -+#endif /* NICSTAR_CBR */ -+ -+/* General function for creating transmission SCQs */ -+static int create_scq (struct nicstar_scq **scq, int size) { -+ (*scq) = kmalloc(sizeof(struct nicstar_scq), GFP_KERNEL); -+ (*scq)->orig = kmalloc(2*size, GFP_KERNEL); -+ if (!(*scq)->orig) { -+ return -ENOMEM; -+ } -+ (*scq)->base = (nicstar_tbd *)(((u32)(*scq)->orig + (size - 1)) & ~(size - 1)); -+ (*scq)->next = (*scq)->base; -+ (*scq)->last = (*scq)->base + ((size / TBD_SIZE) - 1); -+ (*scq)->tail = (*scq)->last; /* XXX mdw scq_next */ -+ (*scq)->full = 0; -+ (*scq)->scqfull_waitq = NULL; -+ (*scq)->closing = 0; -+ memset (((*scq)->scq_shadow), 0, -+ (SCQ_ENTRIES) * (sizeof(struct nicstar_scq_shadow))); -+ return 0; -+} -+ -+static u32 linearize_buffer (struct nicstar_dev *node, struct sk_buff *skb, struct atm_vcc *vcc) { -+ struct iovec *iov = (struct iovec *)skb->data; -+ struct sk_buff *skb_new; -+ -+ if (skb->atm.iovcnt > 2) { /* huge buffer */ -+ int el, cnt; -+ unsigned char *p; -+ -+ /* copy data to new skb (brute force), only for huge SDUs */ -+ skb_new = alloc_skb(skb->len,GFP_ATOMIC); -+ if (!skb_new) { -+ printk("nicstar%d: Can't get skbuff for s-g ip receive of huge buffer (%d bytes)\n",node->index,(u32)skb->len); -+ nicstar_free_rx_skb(vcc, skb); -+ return 0; -+ } -+ p = skb_new->data; -+ el = skb->len; -+ skb_put(skb_new,skb->len); -+ skb_new->free = 1; -+ for (cnt = 0; (cnt < skb->atm.iovcnt) && el; cnt++) { -+ memcpy(p, iov->iov_base, -+ (iov->iov_len > el) ? el : iov->iov_len); -+ p += iov->iov_len; -+ el -= (iov->iov_len > el)?el:iov->iov_len; -+ iov++; -+ } -+ nicstar_free_rx_skb(vcc, skb); -+ return (u32) skb_new; -+ } -+ else if (skb->atm.iovcnt == 2) { -+ /* simply copy small buffer to free space at start of large */ -+ int i; -+ -+ /* which large buffer are we? */ -+ iov++; -+ for (i = 0; i < NUM_LG_BUFS ; i++) { -+ if ((node->rx_lg_skb[i])->data == iov->iov_base) { -+ break; -+ } -+ } -+ if (i >= NUM_LG_BUFS) { -+ /* should probably copy instead */ -+ printk("nicstar%d: Corresponding large buffer not found! dropping packet. i %d vcc %p skb %p data %p\n", -+ node->index, i,vcc,skb,skb->data); -+ nicstar_free_rx_skb(vcc,skb); -+ return 0; -+ } -+ skb_put(node->rx_lg_skb[i],iov->iov_len); -+ iov--; -+ skb_push(node->rx_lg_skb[i],SM_BUF_DATALEN); -+ memcpy((node->rx_lg_skb[i])->data,iov->iov_base,SM_BUF_DATALEN); -+ skb->atm.iovcnt--; -+#ifdef NICSTAR_LBUFCNT -+ PRINTK("2-buffer receive (IP?) len %d old %x new %x node %x cnt %d vcc %x\n",skb->len,skb,node->rx_lg_skb[i],node,node->lbuf_cnt,vcc); -+#endif -+ nicstar_free_rx_skb(vcc,skb); -+ skb_new = skb_clone(node->rx_lg_skb[i], GFP_ATOMIC); -+#ifdef NICSTAR_RC_FLAG -+ skb_new->atm.recycle_buffer = (void *) vcc; ++static int atm_info(ino_t ino,loff_t *pos,char *buf) ++{ ++ struct atm_dev *dev; ++ struct atm_vcc *vcc; ++ int left; ++ ++ switch (ino) { ++ case PROC_ATM_DEVICES: ++ left = *pos-1; ++ for (dev = atm_devs; dev && left; dev = dev->next) ++ left--; ++ if (!dev) return 0; ++ dev_info(dev,buf); ++ break; ++#ifdef NOT_YET_CONFIG_ATM_CLIP ++ case PROC_ATM_ARP: ++ { ++ struct device *dev; ++ struct atmarp_entry *entry; ++ int count; ++ ++ count = *pos; ++ for (dev = clip_devs; dev; ++ dev = PRIV(dev)->next) ++ for (entry = PRIV(dev)->table; entry; ++ entry = entry->next) ++ if (!--count) { ++ atmarp_info(dev,entry, ++ buf); ++ return strlen(buf); ++ } ++ return 0; ++ } ++ return 0; +#endif -+ skb_new->destructor = nicstar_rx_skb_destructor; -+ return (u32) skb_new; -+ } -+ else { -+ caddr_t p = iov->iov_base; /* make a copy of pointer to data */ ++ case PROC_ATM_SVC: ++ left = *pos-1; ++ for (dev = atm_devs; dev; dev = dev->next) ++ for (vcc = dev->vccs; vcc; vcc = vcc->next) ++ if (vcc->family == PF_ATMSVC && ++ !left--) { ++ svc_info(vcc,buf); ++ return strlen(buf); ++ } ++ return 0; ++ case PROC_ATM_PVC: ++ left = *pos-1; ++ for (dev = atm_devs; dev; dev = dev->next) ++ for (vcc = dev->vccs; vcc; vcc = vcc->next) ++ if (vcc->family == PF_ATMPVC && ++ vcc->dev && !left--) { ++ pvc_info(vcc,buf); ++ return strlen(buf); ++ } ++ return 0; ++#ifdef CONFIG_AREQUIPA ++ case PROC_ATM_AREQUIPA: ++ left = *pos-1; ++ for (dev = atm_devs; dev; dev = dev->next) ++ for (vcc = dev->vccs; vcc; vcc = vcc->next) ++ if (vcc->push == atm_push_arequipa && ++ !left--) { ++ arequipa_into(vcc,buf); ++ return strlen(buf); ++ } ++ return 0; ++#endif ++#ifdef CONFIG_ATM_LANE + -+ /* put small buffer contents in skb->data */ -+ memcpy(skb->data,p,skb->len); -+ free_rx_buf(node,0,(u32)p); -+ skb->atm.iovcnt = 0; -+ skb->tail = skb->data + skb->len; -+ skb_new = skb_clone(skb,GFP_ATOMIC); -+ skb_new->destructor = nicstar_rx_skb_destructor; -+#ifdef NICSTAR_RC_FLAG -+ skb_new->atm.recycle_buffer = (void *) vcc; ++ case PROC_ATM_LEC: { ++ struct lec_priv *priv; ++ struct lec_arp_table *entry; ++ int i, count, d, e; ++ ++ count = *pos; ++ for(d=0;dpriv)) { ++ for(i=0;ilec_arp_tables[i]; ++ for(;entry;entry=entry->next) { ++ if (!--count) { ++ e=sprintf(buf,"%s ",dev_lec[d]->name); ++ lec_info(entry,buf+e); ++ return strlen(buf); ++ } ++ } ++ } ++ for(entry=priv->lec_arp_empty_ones; ++ entry; entry=entry->next) { ++ if (!--count) { ++ e=sprintf(buf,"%s ", ++ dev_lec[d]->name); ++ lec_info(entry, buf+e); ++ return strlen(buf); ++ } ++ } ++ for(entry=priv->lec_no_forward; ++ entry; entry=entry->next) { ++ if (!--count) { ++ e=sprintf(buf,"%s ", ++ dev_lec[d]->name); ++ lec_info(entry, buf+e); ++ return strlen(buf); ++ } ++ } ++ } ++ } ++ return 0; ++ } ++ +#endif -+ return (u32) skb_new; -+ } ++ default: ++ return -EINVAL; ++ } ++ return strlen(buf); +} ---- ref/include/linux/pci.h Wed Nov 6 11:12:35 1996 -+++ work/include/linux/pci.h Fri Nov 15 19:58:19 1996 -@@ -241,6 +241,9 @@ - #define PCI_DEVICE_ID_VLSI_82C594 0x0007 - #define PCI_DEVICE_ID_VLSI_82C597 0x0009 - -+#define PCI_VENDOR_ID_IDT 0x111d -+#define PCI_DEVICE_ID_IDT_IDT77201 0x0001 + - #define PCI_VENDOR_ID_ADL 0x1005 - #define PCI_DEVICE_ID_ADL_2301 0x2301 - ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atm.h Tue Mar 11 23:23:29 1997 -@@ -0,0 +1,218 @@ -+/* atm.h - general ATM declarations */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ + -+#ifndef _LINUX_ATM_H -+#define _LINUX_ATM_H ++static long proc_atm_read(struct inode *inode,struct file *file,char *buf, ++ unsigned long count) ++{ ++ unsigned long page; ++ int length,error; + -+/* -+ * BEGIN_xx and END_xx markers are used for automatic generation of -+ * documentation. Do not change them. -+ */ ++ if (count < 0) return -EINVAL; ++ page = get_free_page(GFP_KERNEL); ++ if (!page) return -ENOMEM; ++ if (file->f_pos) ++ length = atm_info(inode->i_ino,&file->f_pos,(char *) page); ++ else length = atm_header(inode->i_ino,(char *) page); ++ if (length > count) length = -EINVAL; ++ if (length >= 0) { ++ error = copy_to_user(buf,(char *) page,length); ++ if (error) length = error; ++ file->f_pos++; ++ } ++ free_page(page); ++ return length; ++} + -+#include -+#include + ++static struct file_operations proc_atm_operations = { ++ NULL, /* lseek */ ++ proc_atm_read, /* read */ ++ NULL, /* write */ ++ NULL, /* readdir */ ++ NULL, /* select */ ++ NULL, /* ioctl */ ++ NULL, /* mmap */ ++ NULL, /* no special open code */ ++ NULL, /* no special release */ ++ NULL /* can't fsync */ ++}; + -+/* general ATM constants */ -+#define ATM_CELL_SIZE 53 /* ATM cell size incl. header */ -+#define ATM_CELL_PAYLOAD 48 /* ATM payload size */ -+#define ATM_AAL0_SDU 52 /* AAL0 SDU size */ -+#define ATM_MAX_AAL34_PDU 65535 /* maximum AAL3/4 PDU payload */ -+#define ATM_AAL5_TRAILER 8 /* AAL5 trailer size */ -+#define ATM_MAX_AAL5_PDU 65535 /* maximum AAL5 PDU payload */ -+#define ATM_MAX_CDV 9999 /* maximum (default) CDV */ -+#define ATM_NOT_RSV_VCI 32 /* first non-reserved VCI value */ ++struct inode_operations proc_atm_inode_operations = { ++ &proc_atm_operations, /* default ATM directory file-ops */ ++ NULL, /* create */ ++ NULL, /* lookup */ ++ NULL, /* link */ ++ NULL, /* unlink */ ++ NULL, /* symlink */ ++ NULL, /* mkdir */ ++ NULL, /* rmdir */ ++ NULL, /* mknod */ ++ NULL, /* rename */ ++ NULL, /* readlink */ ++ NULL, /* follow_link */ ++ NULL, /* readpage */ ++ NULL, /* writepage */ ++ NULL, /* bmap */ ++ NULL, /* truncate */ ++ NULL /* permission */ ++}; + -+#define ATM_MAX_VPI 255 /* maximum VPI at the UNI */ -+#define ATM_MAX_VPI_NNI 4096 /* maximum VPI at the NNI */ -+#define ATM_MAX_VCI 65535 /* maximum VCI */ + -+/* -+ * The following items should be added to sys/socket.h aka linux/socket.h -+ */ ++#define FILE(ino,name,len) &proc_atm, \ ++ (&(struct proc_dir_entry) { ino, len, name, \ ++ S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_atm_inode_operations, NULL }) ++ ++ ++void atm_proc_init(void) ++{ ++ proc_register(FILE(PROC_ATM_DEVICES,"devices",7)); ++ proc_register(FILE(PROC_ATM_ARP,"arp",3)); ++ proc_register(FILE(PROC_ATM_SVC,"svc",3)); ++ proc_register(FILE(PROC_ATM_PVC,"pvc",3)); ++#ifdef CONFIG_ATM_LANE ++ proc_register(FILE(PROC_ATM_LEC,"lec",3)); ++#endif ++#ifdef CONFIG_AREQUIPA ++ proc_register(FILE(PROC_ATM_AREQUIPA,"arequipa",8)); ++#endif ++} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/protocols.h Wed May 14 15:31:31 1997 +@@ -0,0 +1,16 @@ ++/* net/atm/protocols.h - ATM protocol handler entry points */ + -+/* address families */ -+#define AF_ATMPVC 6 /* ATM PVCs */ -+#define AF_ATMSVC 7 /* ATM SVCs */ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+/* "protcol" values for the socket system call */ -+#define ATM_NO_AAL 0 /* AAL not specified */ -+#define ATM_AAL0 13 /* "raw" ATM cells */ -+#define ATM_AAL1 1 /* AAL1 (CBR) */ -+#define ATM_AAL2 2 /* AAL2 (VBR) */ -+#define ATM_AAL34 3 /* AAL3/4 (data) */ -+#define ATM_AAL5 5 /* AAL5 (data) */ -+#define ATM_SAAL 12 /* signaling AAL */ + -+/* -+ * UGLY - there should only be one protocol family (PF_ATM) for both -+ * address families. A quick glance at some kernel internals seems to -+ * suggest to me that doing it the "right" way might involve some -+ * swimming against the stream ... -+ */ ++#ifndef NET_ATM_PROTOCOLS_H ++#define NET_ATM_PROTOCOLS_H + -+/* protocol families */ -+#define PF_ATMPVC AF_ATMPVC -+#define PF_ATMSVC AF_ATMSVC ++void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb); + -+/* layers for getsockopt/setsockopt */ -+#define SOL_ATM 2 -+#define SOL_AAL 3 ++int atm_init_aal0(struct atm_vcc *vcc); /* "raw" AAL0 */ ++int atm_init_aal34(struct atm_vcc *vcc);/* "raw" AAL3/4 transport */ ++int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */ ++int atm_init_atmarp(struct atm_vcc *vcc);/* ATM ARP */ + -+/* -+ * ATM layer (values used for flags must be 2^n, non-flag values should use -+ * the remaining values) -+ */ ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/pvc.c Wed May 14 15:31:31 1997 +@@ -0,0 +1,149 @@ ++/* net/atm/pvc.c - ATM PVC sockets */ + -+#define SO_SETCLP 1 /* set CLP bit value - TODO */ -+#define SO_CIRANGE 3 /* connection identifier range; -+ socket must be bound or connected */ -+#define SO_ATMQOS 5 /* Quality of Service setting */ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+/* AAL layer */ -+#define SO_AALTYPE 0 /* AAL type, get only */ + -+/* socket layer */ -+#define SO_BCTXOPT 16 /* not ATM specific - should go */ -+#define SO_BCRXOPT 17 /* somewhere else */ ++#include ++#include /* struct socket, struct net_proto, ++ struct proto_ops */ ++#include /* ATM stuff */ ++#include /* ATM devices */ ++#include /* Classical IP over ATM */ ++#include /* error codes */ ++#include /* printk */ ++#include ++#ifdef CONFIG_AREQUIPA ++#include ++#endif + ++#include "resources.h" /* devs and vccs */ ++#include "common.h" /* common for PVCs and SVCs */ + -+/* for SO_BCTXOPT and SO_BCRXOPT */ ++#ifndef NULL ++#define NULL 0 ++#endif + -+struct atm_buffconst { -+ unsigned long buf_fac; /* buffer alignment factor */ -+ unsigned long buf_off; /* buffer alignment offset */ -+ unsigned long size_fac; /* buffer size factor */ -+ unsigned long size_off; /* buffer size offset */ -+ unsigned long min_size; /* minimum size */ -+ unsigned long max_size; /* maximum size, 0 = unlimited */ -+}; + ++static int pvc_dup(struct socket *newsock,struct socket *oldsock) ++{ ++ return -EOPNOTSUPP; ++} + -+/* ATM cell header (for AAL0) */ + -+/* BEGIN_CH */ -+#define ATM_HDR_GFC_MASK 0xf0000000 -+#define ATM_HDR_GFC_SHIFT 28 -+#define ATM_HDR_VPI_MASK 0x0ff00000 -+#define ATM_HDR_VPI_SHIFT 20 -+#define ATM_HDR_VCI_MASK 0x000ffff0 -+#define ATM_HDR_VCI_SHIFT 4 -+#define ATM_HDR_PTI_MASK 0x0000000e -+#define ATM_HDR_PTI_SHIFT 1 -+#define ATM_HDR_CLP 0x00000001 -+/* END_CH */ ++static int pvc_shutdown(struct socket *sock,int how) ++{ ++ return -EOPNOTSUPP; ++} + + -+/* PTI codings */ ++static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, ++ int sockaddr_len) ++{ ++ struct sockaddr_atmpvc *addr; ++ struct atm_vcc *vcc; + -+/* BEGIN_PTI */ -+#define ATM_PTI_US0 0 /* user data cell, congestion not exp, SDU-type 0 */ -+#define ATM_PTI_US1 1 /* user data cell, congestion not exp, SDU-type 1 */ -+#define ATM_PTI_UCES0 2 /* user data cell, cong. experienced, SDU-type 0 */ -+#define ATM_PTI_UCES1 3 /* user data cell, cong. experienced, SDU-type 1 */ -+#define ATM_PTI_SEGF5 4 /* segment OAM F5 flow related cell */ -+#define ATM_PTI_E2EF5 5 /* end-to-end OAM F5 flow related cell */ -+#define ATM_PTI_RSV_RM 6 /* reserved for traffic control/resource mgmt */ -+#define ATM_PTI_RSV 7 /* reserved */ -+/* END_PTI */ ++ if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL; ++ addr = (struct sockaddr_atmpvc *) sockaddr; ++ if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; ++ vcc = ATM_SD(sock); ++ if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; ++ if (vcc->flags & ATM_VF_PARTIAL) { ++ if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; ++ if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; ++ } ++ return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi, ++ addr->sap_addr.vci); ++} + + -+/* -+ * The following items should stay in linux/atm.h, which should be linked to -+ * netatm/atm.h -+ */ ++static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, ++ int sockaddr_len,int flags) ++{ ++ return pvc_bind(sock,sockaddr,sockaddr_len); ++} + -+/* Traffic description */ + -+#define ATM_NONE 0 /* no traffic */ -+#define ATM_UBR 1 -+#define ATM_CBR 2 -+#define ATM_VBR 3 -+#define ATM_ABR 4 -+#define ATM_ANYCLASS 5 /* compatible with everything */ ++static int pvc_listen(struct socket *sock,int backlog) ++{ ++ return -EOPNOTSUPP; ++} + -+#define ATM_MAX_PCR -1 /* maximum available PCR */ + -+struct atm_trafprm { -+ unsigned char traffic_class; /* traffic class (ATM_UBR, ...) */ -+ int max_pcr; /* maximum PCR in cells per second */ -+ int min_pcr; /* minimum PCR in cells per second */ -+ int max_cdv; /* maximum CDV in microseconds */ -+ int max_sdu; /* maximum SDU in bytes */ -+}; ++static int pvc_accept(struct socket *sock,struct socket *newsock,int flags) ++{ ++ return -EOPNOTSUPP; ++} + -+struct atm_qos { -+ struct atm_trafprm txtp; /* parameters in TX direction */ -+ struct atm_trafprm rxtp; /* parameters in RX direction */ -+ unsigned char aal; -+}; + -+/* PVC addressing */ ++static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, ++ int *sockaddr_len,int peer) ++{ ++ struct sockaddr_atmpvc *addr; ++ struct atm_vcc *vcc; + -+#define ATM_ITF_ANY -1 /* "magic" PVC address values */ -+#define ATM_VPI_ANY -1 -+#define ATM_VCI_ANY -1 -+#define ATM_VPI_UNSPEC -2 -+#define ATM_VCI_UNSPEC -2 ++#if 0 /* add some sanity checks later ... @@@ */ ++ if (sock->state != SS_CONNECTED) return -EINVAL; ++#endif ++ *sockaddr_len = sizeof(struct sockaddr_atmpvc); ++ addr = (struct sockaddr_atmpvc *) sockaddr; ++ vcc = ATM_SD(sock); ++ addr->sap_family = AF_ATMPVC; ++ addr->sap_addr.itf = vcc->dev->number; ++ addr->sap_addr.vpi = vcc->vpi; ++ addr->sap_addr.vci = vcc->vci; ++ return 0; ++} + + -+struct sockaddr_atmpvc { -+ unsigned short sap_family; /* address family, AF_ATMPVC */ -+ struct { /* PVC address */ -+ short itf; /* ATM interface */ -+ short vpi; /* VPI (only 8 bits at UNI) */ -+ int vci; /* VCI (only 16 bits at UNI) */ -+ } sap_addr; /* PVC address */ ++static struct proto_ops pvc_proto_ops = { ++ PF_ATMPVC, ++ pvc_dup, ++ atm_release, ++ pvc_bind, ++ pvc_connect, ++ NULL, /* no socketpair */ ++ pvc_accept, ++ pvc_getname, ++ atm_poll, ++ atm_ioctl, ++ pvc_listen, ++ pvc_shutdown, ++ atm_setsockopt, ++ atm_getsockopt, ++ NULL, /* no fcntl */ ++ atm_sendmsg, ++ atm_recvmsg +}; + -+/* SVC addressing */ + -+#define ATM_ESA_LEN 20 /* ATM End System Address length */ -+#define ATM_E164_LEN 12 /* maximum E.164 number length */ ++static int pvc_create(struct socket *sock,int protocol) ++{ ++ sock->ops = &pvc_proto_ops; ++ return atm_create(sock,protocol); ++} + -+#define ATM_MAX_BLLI 16 /* maximum number of BLLI elements */ + -+#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 */ -+ -+struct sockaddr_atmsvc { -+ unsigned short sas_family; /* address family, AF_ATMSVC */ -+ struct { /* SVC address */ -+ unsigned char prv[ATM_ESA_LEN];/* private ATM address */ -+ char pub[ATM_E164_LEN+1]; /* public address (E.164) */ -+ /* unused addresses must be bzero'ed */ -+ struct atm_blli *blli; /* local SAP, low-layer information */ -+ struct atm_bhli bhli; /* local SAP, high-layer information */ -+ } sas_addr; /* SVC address */ -+}; ++static struct net_proto_family pvc_family_ops = { ++ PF_ATMPVC, ++ pvc_create, ++ 0, /* no authentication */ ++ 0, /* no encryption */ ++ 0 /* no encrypt_net */ ++}; + + +/* -+ * Some stuff for linux/sockios.h ++ * Initialize the ATM PVC protocol family + */ + -+struct atmif_sioc { -+ int number; -+ int length; -+ void *arg; -+}; -+ -+ -+#define SIOCSIFATMTCP _IO('a',ATMIOC_ITF) /* set ATMTCP mode */ + ++void atmpvc_proto_init(struct net_proto *pro) ++{ ++ if (sock_register(&pvc_family_ops) < 0) { ++ printk(KERN_ERR "ATMPVC: can't register"); ++ return; ++ } ++#ifdef CONFIG_AREQUIPA ++ (void) atm_init_arequipa(); ++#endif ++} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/raw.c Wed May 14 19:04:39 1997 +@@ -0,0 +1,133 @@ ++/* net/atm/raw.c - Raw AAL0 and AAL5 transports */ + -+#ifdef __KERNEL__ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+#include /* struct net_proto */ + ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+void atmpvc_proto_init(struct net_proto *pro); -+void atmsvc_proto_init(struct net_proto *pro); ++#include "common.h" ++#include "protocols.h" ++#include "tunable.h" /* tunable parameters */ + -+#endif /* __KERNEL__ */ + ++#if 0 ++#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) ++#else ++#define DPRINTK(format,args...) +#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atmclip.h Wed Apr 16 16:31:38 1997 -@@ -0,0 +1,37 @@ -+/* atmclip.h - Classical IP over ATM */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef LINUX_ATMCLIP_H -+#define LINUX_ATMCLIP_H -+ -+#include -+#include + + -+#define CLIP_NULENCAP SIOCDEVPRIVATE /* set NULL encapsulation */ -+#define CLIP_LLCENCAP (SIOCDEVPRIVATE+1) /* set LLC/SNAP encap. */ ++/* ++ * SKB == NULL indicates that the link is being closed ++ */ + ++void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb) ++{ ++ if (skb) { ++ DPRINTK("APushR %d += %d\n",vcc->rx_inuse,skb->truesize); ++ atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse); ++ skb_queue_tail(&vcc->recvq,skb); ++ wake_up(&vcc->sleep); ++ } ++} + -+#define RFC1483LLC_LEN 8 /* LLC+OUI+PID = 8 */ -+#define RFC1626_MTU 9180 /* RFC1626 default MTU */ + -+#define CLIP_DEFAULT_IDLETIMER 1200 /* 20 minutes, see RFC1755 */ -+#define CLIP_CHECK_INTERVAL 10 /* check every ten seconds */ ++/* ++ * A return value of NULL means to discard the PDU ++ */ + -+#define SIOCMKCLIP _IO('a',ATMIOC_CLIP) /* create IP interface */ -+#define CLIP_PVC _IO('a',ATMIOC_CLIP+4) /* IP itf becomes CLIP itf */ + -+#ifdef __KERNEL__ ++static struct sk_buff *atm_peek_aal0(struct atm_vcc *vcc,unsigned long pdu_size, ++ __u32 (*fetch)(struct atm_vcc *vcc,int i)) ++{ ++ struct sk_buff *skb; + -+#include -+#include -+#include ++ if (pdu_size+atomic_read(&vcc->rx_inuse)+ATM_PDU_OVHD <= vcc->rx_quota) ++ { ++ skb = alloc_skb(pdu_size,GFP_ATOMIC); ++ if (skb) return skb; ++ } ++ vcc->stats->rx_drop++; ++ return NULL; ++} + + -+int atm_init_clip(struct atm_vcc *vcc); ++/* ++ * atm_peek_aal5 is currently also used for AAL3/4 ++ */ + -+#endif /* __KERNEL__ */ + -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atmdev.h Wed Apr 2 22:05:19 1997 -@@ -0,0 +1,257 @@ -+/* atmdev.h - ATM device driver declarations */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ ++static struct sk_buff *atm_peek_aal5(struct atm_vcc *vcc,unsigned long pdu_size, ++ __u32 (*fetch)(struct atm_vcc *vcc,int i)) ++{ ++ struct sk_buff *skb; + -+#ifndef LINUX_ATMDEV_H -+#define LINUX_ATMDEV_H ++ if (pdu_size+atomic_read(&vcc->rx_inuse)+ATM_PDU_OVHD <= vcc->rx_quota) ++ if (pdu_size < PAGE_SIZE) { ++ skb = alloc_skb((pdu_size+3) & ~3,GFP_ATOMIC); ++ if (skb) return skb; ++ } ++ else { ++ skb = alloc_skb(((pdu_size+3) & ~3)+PAGE_SIZE-1, ++ GFP_ATOMIC); ++ if (skb) { ++ skb_reserve(skb,(unsigned char *) ++ (((unsigned long) skb->data+PAGE_SIZE-1) & ++ ~(PAGE_SIZE-1))-skb->data); ++DPRINTK("PEEK: data at 0x%p\n",skb->data); ++ return skb; ++ } ++ } ++ vcc->stats->rx_drop++; ++ return NULL; ++} + + -+#include -+#include -+#include -+#include ++static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) ++{ ++#ifdef CONFIG_MMU_HACKS ++ if (skb->atm.iovcnt) ++ unlock_user(skb->atm.iovcnt,(struct iovec *) skb->data); ++#endif ++ DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize); ++ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); ++ dev_kfree_skb(skb,FREE_WRITE); ++ wake_up(&vcc->wsleep); ++} + + -+#define MAX_ATM_ITF 10 /* for now, should be lowered */ -+#define MAX_ATM_VCC 128 /* for now, should be dynamic */ ++int atm_init_aal0(struct atm_vcc *vcc) ++{ ++ vcc->push = atm_push_raw; ++ vcc->peek = atm_peek_aal0; ++ vcc->pop = atm_pop_raw; ++ vcc->push_oam = NULL; ++ return 0; ++} + -+#define ESI_LEN 6 + -+#define ATM_OC3_PCR (155520000/270*260/8/53) -+ /* OC3 link rate: 155520000 bps -+ SONET overhead: /270*260 (9 section, 1 path) -+ bits per cell: /8/53 -+ max cell rate: 353207.547 cells/sec */ ++int atm_init_aal34(struct atm_vcc *vcc) ++{ ++ vcc->push = atm_push_raw; ++ vcc->peek = atm_peek_aal5; /* same procedure */ ++ vcc->pop = atm_pop_raw; ++ vcc->push_oam = NULL; ++ return 0; ++} + -+#define ATM_SD(s) ((struct atm_vcc *) ((s)->data)) + ++int atm_init_aal5(struct atm_vcc *vcc) ++{ ++ vcc->push = atm_push_raw; ++ vcc->peek = atm_peek_aal5; ++ vcc->pop = atm_pop_raw; ++ vcc->push_oam = NULL; ++ return 0; ++} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/resources.c Tue Jul 1 11:12:36 1997 +@@ -0,0 +1,151 @@ ++/* net/atm/resources.c - Staticly allocated resources */ + -+struct atm_aal_stats { -+ long tx,tx_err; /* TX okay and errors */ -+ long rx,rx_err; /* RX okay and errors */ -+ long rx_drop; /* RX out of memory */ -+}; ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + -+struct atm_dev_stats { -+ struct atm_aal_stats aal0; -+ struct atm_aal_stats aal34; -+ struct atm_aal_stats aal5; -+}; ++#include ++#include ++#include ++#include /* for barrier */ ++#include /* for get_fs_long and put_fs_long */ + ++#include "resources.h" + -+#define ATM_GETNAMES _IOW('a',ATMIOC_ITF+3,struct atm_iobuf) -+ /* get interface names (numbers) */ -+#define ATM_GETTYPE _IOW('a',ATMIOC_ITF+4,struct atmif_sioc) -+ /* get interface type name */ -+#define ATM_GETESI _IOW('a',ATMIOC_ITF+5,struct atmif_sioc) -+ /* get interface ESI */ -+#define ATM_GETADDR _IOW('a',ATMIOC_ITF+6,struct atmif_sioc) -+ /* get itf's local ATM addr. list */ -+#define ATM_RSTADDR _IOW('a',ATMIOC_ITF+7,struct atmif_sioc) -+ /* reset itf's ATM address list */ -+#define ATM_ADDADDR _IOW('a',ATMIOC_ITF+8,struct atmif_sioc) -+ /* add a local ATM address */ -+#define ATM_DELADDR _IOW('a',ATMIOC_ITF+9,struct atmif_sioc) -+ /* remove a local ATM address */ -+#define ATM_GETCIRANGE _IOW('a',ATMIOC_ITF+10,struct atmif_sioc) -+ /* get connection identifier range */ -+#define ATM_SETCIRANGE _IOW('a',ATMIOC_ITF+11,struct atmif_sioc) -+ /* set connection identifier range */ -+#define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) -+ /* get AAL layer statistics */ -+#define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) -+ /* get AAL layer statistics and zero */ -+#define ATM_SETSC _IOW('a',ATMIOC_SPECIAL+1,int) -+ /* enable or disable single-copy */ + -+/* for ATM_GETTYPE */ -+#define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */ ++#ifndef NULL ++#define NULL 0 ++#endif + + ++struct atm_dev *atm_devs = NULL; ++static struct atm_dev *last_dev = NULL; ++static struct atm_vcc *nodev_vccs = NULL; + -+struct atm_iobuf { -+ int length; -+ void *buffer; -+}; + -+/* for ATM_GETCIRANGE / ATM_SETCIRANGE */ ++static struct atm_dev *alloc_atm_dev(const char *type) ++{ ++ struct atm_dev *dev; + -+#define ATM_CI_MAX -1 /* use maximum range of VPI/VCI */ -+ -+struct atm_cirange { -+ char vpi_bits; /* 1..8, ATM_CI_MAX (-1) for maximum */ -+ char vci_bits; /* 1..16, ATM_CI_MAX (-1) for maximum */ -+}; ++ dev = kmalloc(sizeof(*dev),GFP_KERNEL); ++ if (!dev) return NULL; ++ memset(dev,0,sizeof(*dev)); ++ dev->type = type; ++ dev->prev = last_dev; ++ dev->next = NULL; ++ if (atm_devs) last_dev->next = dev; ++ else atm_devs = dev; ++ last_dev = dev; ++ return dev; ++} + -+/* for ATM_SETSC; actually taken from the ATM_VF number space */ + -+#define ATM_SC_RX 1024 /* enable RX single-copy */ -+#define ATM_SC_TX 2048 /* enable TX single-copy */ ++static void free_atm_dev(struct atm_dev *dev) ++{ ++ if (dev->prev) dev->prev->next = dev->next; ++ else atm_devs = dev->next; ++ if (dev->next) dev->next->prev = dev->prev; ++ else last_dev = dev->prev; ++ kfree(dev); ++} + -+#define ATM_BACKLOG_DEFAULT 32 /* if we get more, we're likely to time out -+ anyway */ + -+#ifdef __KERNEL__ ++struct atm_dev *atm_find_dev(int number) ++{ ++ struct atm_dev *dev; + -+#include /* struct wait_queue */ -+#include /* struct timeval */ -+#include -+#include /* struct sk_buff */ -+#include ++ for (dev = atm_devs; dev; dev = dev->next) ++ if (dev->ops && dev->number == number) return dev; ++ return NULL; ++} + -+#ifdef CONFIG_AREQUIPA -+#include /* for struct sock */ -+#endif + ++struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, ++ unsigned long flags) ++{ ++ struct atm_dev *dev; + -+#define ATM_VF_ADDR 1 /* Address is in use. Set by anybody, cleared -+ by device driver. */ -+#define ATM_VF_READY 2 /* VC is ready to transfer data. Set by device -+ driver, cleared by anybody. */ -+#define ATM_VF_PARTIAL 4 /* resources are bound to PVC (partial PVC -+ setup), controlled by socket layer */ -+#define ATM_VF_BOUND 4 /* local SAP is set, controlled by SVC socket -+ layer */ -+#define ATM_VF_REGIS 8 /* registered with demon, controlled by SVC -+ socket layer */ -+#define ATM_VF_RELEASED 16 /* demon has indicated/requested release, -+ controlled by SVC socket layer */ -+#define ATM_VF_HASQOS 32 /* QOS parameters have been set */ -+#define ATM_VF_LISTEN 64 /* socket is used for listening */ -+#define ATM_VF_META 128 /* SVC socket isn't used for normal data -+ traffic and doesn't depend on signaling -+ to be available */ -+#define ATM_VF_AQREL 256 /* Arequipa VC is being released */ -+#define ATM_VF_AQDANG 512 /* VC is in Arequipa's dangling list */ -+#define ATM_VF_SCRX ATM_SC_RX /* 1024; allow single-copy in the RX dir. */ -+#define ATM_VF_SCTX ATM_SC_TX /* 2048; allow single-copy in the TX dir. */ ++ dev = alloc_atm_dev(type); ++ if (!dev) { ++ printk(KERN_ERR "atm_dev_register: no space for dev %s\n", ++ type); ++ return NULL; ++ } ++ dev->number = 0; ++ while (atm_find_dev(dev->number)) dev->number++; ++ dev->vccs = dev->last = NULL; ++ dev->dev_data = NULL; ++ barrier(); ++ dev->ops = ops; ++ dev->flags = flags; ++ memset((void *) &dev->stats,0,sizeof(struct atm_dev_stats)); ++ return (struct atm_dev *) dev; ++} + -+struct atm_vcc { -+ unsigned short flags; /* VCC flags (ATM_VF_*) */ -+ unsigned char family; /* address family; 0 if unused */ -+ unsigned char aal; /* ATM Adaption Layer */ -+ short vpi; /* VPI and VCI (types must be equal */ -+ /* with sockaddr) */ -+ int vci; -+ unsigned long aal_options; /* AAL layer options */ -+ unsigned long atm_options; /* ATM layer options */ -+ struct atm_dev *dev; /* device back pointer */ -+ struct atm_qos qos; /* QOS */ -+ unsigned long tx_quota,rx_quota; /* buffer quotas */ -+ atomic_t tx_inuse,rx_inuse; /* buffer space in use */ -+ void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); -+ void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ -+ struct sk_buff *(*peek)(struct atm_vcc *vcc,unsigned long pdu_size, -+ __u32 (*fetch)(struct atm_vcc *vcc,int i)); -+ /* super-efficient xfers; note that */ -+ /* PDU_SIZE may be rounded */ -+ struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size); -+ /* TX allocation routine - can be */ -+ /* modified by protocol or by driver.*/ -+ /* NOTE: this interface will change */ -+ int (*push_oam)(struct atm_vcc *vcc,void *cell); -+ void *dev_data; /* per-device data */ -+ void *proto_data; /* per-protocol data */ -+ struct timeval timestamp; /* AAL timestamps */ -+ struct sk_buff_head recvq; /* receive queue */ -+ struct atm_aal_stats *stats; /* pointer to AAL stats group */ -+ struct wait_queue *sleep; /* if socket is busy */ -+ struct wait_queue *wsleep; /* if waiting for write buffer space */ -+ struct atm_vcc *prev,*next; -+ /* SVC part --- may move later */ -+ short itf; /* interface number */ -+ struct sockaddr_atmsvc local; -+ struct sockaddr_atmsvc remote; -+ void (*callback)(struct atm_vcc *vcc); -+ struct sk_buff_head listenq; -+ int backlog_quota; /* number of connection requests we */ -+ /* can still accept */ -+ int reply; -+ void *user_back; /* user backlink - not touched */ -+#ifdef CONFIG_AREQUIPA -+ struct sock *upper; /* our "master" */ -+ struct socket *sock; /* back pointer to our own socket */ -+ struct atm_vcc *aq_next,*aq_prev; /* for consistency checks */ -+ unsigned long generation; /* generation number */ -+#endif -+}; + ++void atm_dev_deregister(struct atm_dev *dev) ++{ ++ free_atm_dev(dev); ++} + -+struct atm_dev_addr { -+ struct sockaddr_atmsvc addr; /* ATM address */ -+ struct atm_dev_addr *next; /* next address */ -+}; + ++void shutdown_atm_dev(struct atm_dev *dev) ++{ ++ if (dev->vccs) { ++ dev->flags |= ATM_DF_CLOSE; ++ return; ++ } ++ if (dev->ops->dev_close) dev->ops->dev_close(dev); ++ atm_dev_deregister(dev); ++} + -+struct atm_dev { -+ const struct atmdev_ops *ops; /* device operations; NULL if unused */ -+ const struct atmphy_ops *phy; /* PHY operations, may be undefined */ -+ /* (NULL) */ -+ const char *type; /* device type name */ -+ int number; /* device index */ -+ struct atm_vcc *vccs; /* VCC table (or NULL) */ -+ struct atm_vcc *last; /* last VCC (or undefined) */ -+ void *dev_data; /* per-device data */ -+ void *phy_data; /* private PHY date */ -+ unsigned long flags; /* device flags, TBD */ -+ struct atm_dev_addr *local; /* local ATM addresses */ -+ unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ -+ struct atm_cirange ci_range; /* VPI/VCI range */ -+ struct atm_dev_stats stats; /* statistics */ -+/* */ int sending; -+}; + ++struct atm_vcc *alloc_atm_vcc(void) ++{ ++ struct atm_vcc *vcc; + -+/* -+ * ioctl, getsockopt, setsockopt, sg_send, and poll are optional and can -+ * be set to NULL. -+ */ ++ vcc = kmalloc(sizeof(*vcc),GFP_KERNEL); ++ if (!vcc) return NULL; ++ memset(vcc,0,sizeof(*vcc)); ++ vcc->prev = NULL; ++ vcc->next = nodev_vccs; ++ nodev_vccs = vcc; ++ return vcc; ++} + -+#define ATM_OF_IMMED 1 /* Attempt immediate delivery */ -+#define ATM_OF_INRATE 2 /* Attempt in-rate delivery */ + -+struct atmdev_ops { /* only send is required */ -+ int (*open)(struct atm_vcc *vcc,short vpi,int vci); -+ void (*close)(struct atm_vcc *vcc); -+ int (*ioctl)(struct atm_dev *dev,unsigned int cmd,unsigned long arg); -+ int (*getsockopt)(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int *optlen); -+ int (*setsockopt)(struct atm_vcc *vcc,int level,int optname, -+ char *optval,int optlen); -+ int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); -+ int (*sg_send)(struct atm_vcc *vcc,unsigned long start, -+ unsigned long size); -+#if 0 /* keep the current hack for now */ -+ int (*send_iovec)(struct atm_vcc *vcc,struct iovec *iov,int size, -+ void (*discard)(struct atm_vcc *vcc,void *user),void *user); -+#endif -+ void (*poll)(struct atm_vcc *vcc,int nonblock); -+ int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags); -+ void (*phy_put)(struct atm_dev *dev,unsigned char value, -+ unsigned long addr); -+ unsigned char (*phy_get)(struct atm_dev *dev,unsigned long addr); -+ void (*feedback)(struct atm_vcc *vcc,struct sk_buff *skb, -+ unsigned long start,unsigned long dest,int len); -+ int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos); -+ void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb); -+ /* @@@ temporary hack */ -+}; ++void free_atm_vcc(struct atm_vcc *vcc) ++{ ++ if (vcc->prev) vcc->prev->next = vcc->next; ++ else if (vcc->dev) vcc->dev->vccs = vcc->next; ++ else nodev_vccs = vcc->next; ++ if (vcc->next) vcc->next->prev = vcc->prev; ++ else if (vcc->dev) vcc->dev->last = vcc->prev; ++ if (vcc->dev && !vcc->dev->vccs && (vcc->dev->flags & ATM_DF_CLOSE)) ++ shutdown_atm_dev(vcc->dev); ++ kfree(vcc); ++} + + -+struct atmphy_ops { -+ int (*start)(struct atm_dev *dev); -+ int (*ioctl)(struct atm_dev *dev,unsigned int cmd,unsigned long arg); -+ void (*interrupt)(struct atm_dev *dev); -+}; ++void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev) ++{ ++ if (vcc->prev) vcc->prev->next = vcc->next; ++ else if (vcc->dev) vcc->dev->vccs = vcc->next; ++ else nodev_vccs = vcc->next; ++ if (vcc->next) vcc->next->prev = vcc->prev; ++ else if (vcc->dev) vcc->dev->last = vcc->prev; ++ if (vcc->dev && !vcc->dev->vccs && (vcc->dev->flags & ATM_DF_CLOSE)) ++ shutdown_atm_dev(vcc->dev); ++ vcc->dev = dev; ++ if (dev) { ++ vcc->next = NULL; ++ vcc->prev = dev->last; ++ if (dev->vccs) dev->last->next = vcc; ++ else dev->vccs = vcc; ++ dev->last = vcc; ++ } ++ else { ++ vcc->next = nodev_vccs; ++ vcc->prev = NULL; ++ nodev_vccs = vcc; ++ } ++} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/resources.h Thu Jul 3 08:25:22 1997 +@@ -0,0 +1,24 @@ ++/* net/atm/resources.h - ATM-related resources */ + ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, -+ unsigned long flags); -+void atm_dev_deregister(struct atm_dev *dev); -+int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci); + -+#endif /* __KERNEL__ */ ++#ifndef NET_ATM_RESOURCES_H ++#define NET_ATM_RESOURCES_H + -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atmsap.h Fri Nov 15 19:06:29 1996 -@@ -0,0 +1,124 @@ -+/* atmsap.h - ATM Service Access Point addressing definitions */ ++#include + -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ + ++extern struct atm_dev *atm_devs; + -+#ifndef _LINUX_ATMSAP_H -+#define _LINUX_ATMSAP_H + -+/* -+ * BEGIN_xx and END_xx markers are used for automatic generation of -+ * documentation. Do not change them. -+ */ ++/* struct atm_dev *alloc_atm_dev(const char *type); */ ++/* void free_atm_dev(struct atm_dev *dev); */ ++struct atm_dev *atm_find_dev(int number); ++void shutdown_atm_dev(struct atm_dev *dev); + ++struct atm_vcc *alloc_atm_vcc(void); ++void free_atm_vcc(struct atm_vcc *vcc); ++void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev); + -+/* -+ * Layer 2 protocol identifiers -+ */ ++#endif +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/signaling.c Thu May 29 21:55:54 1997 +@@ -0,0 +1,215 @@ ++/* net/atm/signaling.c - ATM signaling */ + -+/* BEGIN_L2 */ -+#define ATM_L2_NONE 0 /* L2 not specified */ -+#define ATM_L2_ISO1745 0x01 /* Basic mode ISO 1745 */ -+#define ATM_L2_Q291 0x02 /* ITU-T Q.291 (Rec. I.441) */ -+#define ATM_L2_X25_LL 0x06 /* ITU-T X.25, link layer */ -+#define ATM_L2_X25_ML 0x07 /* ITU-T X.25, multilink */ -+#define ATM_L2_LAPB 0x08 /* Extended LAPB, half-duplex (Rec. T.71) */ -+#define ATM_L2_HDLC_ARM 0x09 /* HDLC ARM (ISO/IEC 4335) */ -+#define ATM_L2_HDLC_NRM 0x0a /* HDLC NRM (ISO/IEC 4335) */ -+#define ATM_L2_HDLC_ABM 0x0b /* HDLC ABM (ISO/IEC 4335) */ -+#define ATM_L2_ISO8802 0x0c /* LAN LLC (ISO/IEC 8802/2) */ -+#define ATM_L2_X75 0x0d /* ITU-T X.75, SLP */ -+#define ATM_L2_Q922 0x0e /* ITU-T Q.922 */ -+#define ATM_L2_USER 0x10 /* user-specified */ -+#define ATM_L2_ISO7776 0x11 /* ISO 7776 DTE-DTE */ -+/* END_L2 */ ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + + -+/* -+ * Layer 3 protocol identifiers -+ */ ++#include /* error codes */ ++#include /* printk, suser */ ++#include ++#include ++#include /* jiffies and HZ */ ++#include /* ATM stuff */ ++#include ++#include ++#include + -+/* BEGIN_L3 */ -+#define ATM_L3_NONE 0 /* L3 not specified */ -+#define ATM_L3_X25 0x06 /* ITU-T X.25, packet layer */ -+#define ATM_L3_ISO8208 0x07 /* ISO/IEC 8208 */ -+#define ATM_L3_X223 0x08 /* ITU-T X.223 | ISO/IEC 8878 */ -+#define ATM_L3_ISO8473 0x09 /* ITU-T X.223 | ISO/IEC 8473 */ -+#define ATM_L3_T70 0x0a /* ITU-T T.70 minimum network layer */ -+#define ATM_L3_TR9577 0x0b /* ISO/IEC TR 9577 */ -+#define ATM_L3_USER 0x10 /* user-specified */ -+/* END_L3 */ ++#include "tunable.h" ++#include "resources.h" ++#include "signaling.h" + + -+/* -+ * High layer identifiers -+ */ ++#undef WAIT_FOR_DEMON /* #define this if system calls on SVC sockets ++ should block until the demon runs. ++ Danger: may cause nasty hangs if the demon ++ crashes. */ + -+/* BEGIN_HL */ -+#define ATM_HL_NONE 0 /* HL not specified */ -+#define ATM_HL_ISO 0x01 /* ISO */ -+#define ATM_HL_USER 0x02 /* user-specific */ -+#if defined(UNI30) || defined(ALLOW_UNI30) -+#define ATM_HL_HLP 0x03 /* high layer profile - UNI 3.0 only */ ++#if 0 ++#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) ++#else ++#define DPRINTK(format,args...) +#endif -+#define ATM_HL_VENDOR 0x04 /* vendor-specific application identifier */ -+/* END_HL */ -+ + -+/* -+ * ITU-T coded mode of operation -+ */ + -+/* BEGIN_IMD */ -+#define ATM_IMD_NONE 0 /* mode not specified */ -+#define ATM_IMD_NORMAL 1 /* normal mode of operation */ -+#define ATM_IMD_EXTENDED 2 /* extended mode of operation */ -+/* END_IMD */ ++struct atm_vcc *sigd = NULL; ++static struct wait_queue *sigd_sleep = NULL; + + -+/* -+ * SAP structures -+ */ ++static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) ++{ ++ struct atmsvc_msg *msg; + -+#define ATM_MAX_HLI 7 /* maximum high-layer information length */ -+ -+ -+struct atm_blli { -+ unsigned char l2_proto; /* layer 2 protocol */ -+ union { -+ struct { -+ unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */ -+ /* absent */ -+ unsigned char window; /* window size (k), 1-127 (0 to omit) */ -+ } itu; /* ITU-T encoding */ -+ unsigned char user; /* user-specified l2 information */ -+ } l2; -+ unsigned char l3_proto; /* layer 3 protocol */ -+ union { -+ struct { -+ unsigned char mode; /* mode of operation (ATM_IMD_xxx), 0 if */ -+ /* absent */ -+ unsigned char def_size; /* default packet size (log2), 4-12 (0 to */ -+ /* omit) */ -+ unsigned char window;/* packet window size, 1-127 (0 to omit) */ -+ } itu; /* ITU-T ecoding */ -+ unsigned char user; /* user specified l3 information */ -+ struct { /* if l3_proto = ATM_L3_TR9577 */ -+ unsigned char ipi; /* initial protocol id */ -+ unsigned char snap[5];/* IEEE 802.1 SNAP identifier */ -+ /* (only if ipi == NLPID_IEEE802_1_SNAP) */ -+ } tr9577; -+ } l3; -+ struct atm_blli *next; /* next BLLI or NULL (undefined when used in */ -+ /* atmsvc_msg) */ -+}; -+ -+ -+struct atm_bhli { -+ unsigned char hl_type; /* high layer information type */ -+ unsigned char hl_length; /* length (only if hl_type == ATM_HL_USER || */ -+ /* hl_type == ATM_HL_ISO) */ -+ unsigned char hl_info[ATM_MAX_HLI];/* high layer information */ -+}; -+ -+#endif ---- ref/include/linux/skbuff.h Thu Oct 31 11:06:31 1996 -+++ work/include/linux/skbuff.h Fri Feb 28 14:29:29 1997 -@@ -112,6 +112,25 @@ - unsigned char *end; /* End pointer */ - void (*destructor)(struct sk_buff *); /* Destruct function */ - __u16 redirport; /* Redirect port */ -+#ifdef CONFIG_ATM -+ struct { -+ int size; /* PDU size (adapter too) */ -+ unsigned long pos; /* adapter data */ -+ struct atm_vcc *vcc; /* ATM VCC */ -+ int iovcnt; /* 0 for "normal" operation */ -+ struct timeval timestamp; /* timestamp or 0,x */ -+#ifdef CONFIG_ATM_NICSTAR -+ void *recycle_buffer; /* set when buffer should be */ -+ /* recycled; points to vcc */ -+#endif -+ int encap; /* non-zero if encapsulated */ -+ /* for ATMARP */ -+#ifdef CONFIG_AREQUIPA -+ int generation; /* generation number */ -+#endif -+ } atm; -+#endif -+ - }; - - #ifdef CONFIG_SKB_LARGE ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/sonet.h Fri Nov 15 19:06:30 1996 -@@ -0,0 +1,52 @@ -+/* sonet.h - SONET/SHD physical layer control */ -+ -+/* Written 1995 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef LINUX_SONET_H -+#define LINUX_SONET_H -+ -+struct sonet_stats { -+ long section_bip; /* section parity errors (B1) */ -+ long line_bip; /* line parity errors (B2) */ -+ long path_bip; /* path parity errors (B3) */ -+ long line_febe; /* line parity errors at remote */ -+ long path_febe; /* path parity errors at remote */ -+ long corr_hcs; /* correctable header errors */ -+ long uncorr_hcs; /* uncorrectable header errors */ -+ long tx_cells; /* cells sent */ -+ long rx_cells; /* cells received */ -+}; -+ -+#define SONET_GETSTAT _IOR('a',ATMIOC_PHYTYP,struct sonet_stats) -+ /* get statistics */ -+#define SONET_GETSTATZ _IOR('a',ATMIOC_PHYTYP+1,struct sonet_stats) -+ /* ... and zero counters */ -+#define SONET_SETDIAG _IOWR('a',ATMIOC_PHYTYP+2,int) -+ /* set error insertion */ -+#define SONET_CLRDIAG _IOWR('a',ATMIOC_PHYTYP+3,int) -+ /* clear error insertion */ -+#define SONET_GETDIAG _IOR('a',ATMIOC_PHYTYP+4,int) -+ /* query error insertion */ -+#define SONET_SETFRAMING _IO('a',ATMIOC_PHYTYP+5) -+ /* set framing mode (SONET/SDH) */ -+#define SONET_GETFRAMING _IOR('a',ATMIOC_PHYTYP+6,int) -+ /* get framing mode */ -+#define SONET_GETFRSENSE _IOR('a',ATMIOC_PHYTYP+7, \ -+ unsigned char[SONET_FRSENSE_SIZE]) /* get framing sense information */ -+ -+#define SONET_INS_SBIP 1 /* section BIP */ -+#define SONET_INS_LBIP 2 /* line BIP */ -+#define SONET_INS_PBIP 4 /* path BIP */ -+#define SONET_INS_FRAME 8 /* out of frame */ -+#define SONET_INS_LOS 16 /* set line to zero */ -+#define SONET_INS_LAIS 32 /* line alarm indication signal */ -+#define SONET_INS_PAIS 64 /* path alarm indication signal */ -+#define SONET_INS_HCS 128 /* insert HCS error */ -+ -+#define SONET_FRAME_SONET 0 /* SONET STS-3 framing */ -+#define SONET_FRAME_SDH 1 /* SDH STM-1 framing */ -+ -+#define SONET_FRSENSE_SIZE 6 /* C1[3],H1[3] (0xff for unknown) */ -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atmsvc.h Tue Mar 11 23:23:43 1997 -@@ -0,0 +1,50 @@ -+/* atmsvc.h - ATM signaling kernel-demon interface definitions */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef _LINUX_ATMSVC_H -+#define _LINUX_ATMSVC_H -+ -+#include -+#include -+ -+ -+#define ATMSIGD_CTRL _IO('a',ATMIOC_SPECIAL) -+ /* become ATM signaling demon control socket */ -+ -+enum atmsvc_msg_type { as_catch_null,as_bind,as_connect,as_accept,as_reject, -+ as_listen,as_okay,as_error,as_indicate,as_close,as_itf_notify }; -+ -+struct atmsvc_msg { -+ enum atmsvc_msg_type type; -+ unsigned long vcc; -+ unsigned long listen_vcc; /* indicate */ -+ int reply; /* for okay and close: */ -+ /* < 0: error before active */ -+ /* (sigd has discarded ctx) */ -+ /* ==0: success */ -+ /* > 0: error when active (still */ -+ /* need to close) */ -+ struct sockaddr_atmpvc pvc; /* indicate, okay (connect) */ -+ struct sockaddr_atmsvc local; /* local SVC address */ -+ struct atm_qos qos; /* QOS parameters */ -+ struct sockaddr_atmsvc svc; /* MUST BE BEFORE "blli", SVC address */ -+ struct atm_blli blli[1]; /* MUST BE LAST */ -+}; -+ -+/* -+ * Message contents: see ftp://lrcftp.epfl.ch/pub/linux/atm/docs/isp-*.tar.gz -+ */ -+ -+/* -+ * Some policy stuff for atmsigd and for net/atm/svc.c. Both have to agree on -+ * what PCR is used to request bandwidth from the device driver. net/atm/svc.c -+ * tries to do better than that, but only if there's no routing decision (i.e. -+ * if signaling only uses one ATM interface). -+ */ -+ -+#define SELECT_TOP_PCR(tp) ((tp).max_pcr && (tp).max_pcr != ATM_MAX_PCR ? \ -+ (tp).max_pcr : (tp).min_pcr ? (tp).min_pcr : ATM_MAX_PCR) -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atmioc.h Fri Nov 15 19:06:30 1996 -@@ -0,0 +1,32 @@ -+/* atmioc.h - ranges for ATM-related ioctl numbers */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef _LINUX_ATMIOC_H -+#define _LINUX_ATMIOC_H -+ -+#include -+ /* everybody including atmioc.h will also need _IO{,R,W,WR} */ -+ -+#define ATMIOC_PHYCOM 0x00 /* PHY device common ioctls, globally unique */ -+#define ATMIOC_PHYCOM_END 0x0f -+#define ATMIOC_PHYTYP 0x10 /* PHY dev type ioctls, unique per PHY type */ -+#define ATMIOC_PHYTYP_END 0x2f -+#define ATMIOC_PHYPRV 0x30 /* PHY dev private ioctls, unique per driver */ -+#define ATMIOC_PHYPRV_END 0x4f -+#define ATMIOC_SARCOM 0x50 /* SAR device common ioctls, globally unique */ -+#define ATMIOC_SARCOM_END 0x50 -+#define ATMIOC_SARPRV 0x60 /* SAR dev private ioctls, unique per driver */ -+#define ATMIOC_SARPRV_END 0x7f -+#define ATMIOC_ITF 0x80 /* Interface ioctls, globally unique */ -+#define ATMIOC_ITF_END 0x8f -+/* 0x90-0xbf: Reserved for future use */ -+#define ATMIOC_AREQUIPA 0xc0 /* Application requested IP over ATM, glob. u. */ -+#define ATMIOC_LANE 0xd0 /* LAN Emulation, globally unique */ -+#define ATMIOC_CLIP 0xe0 /* Classical IP over ATM control, globally u. */ -+#define ATMIOC_CLIP_END 0xef -+#define ATMIOC_SPECIAL 0xf0 /* Special-purpose controls, globally unique */ -+#define ATMIOC_SPECIAL_END 0xff -+ -+#endif ---- ref/net/Makefile Thu May 16 15:35:55 1996 -+++ work/net/Makefile Fri Nov 15 19:06:31 1996 -@@ -7,13 +7,18 @@ - # - # Note 2! The CFLAGS definition is now in the main makefile... - --MOD_SUB_DIRS := ipv4 --ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipx unix appletalk netrom #decnet -+MOD_SUB_DIRS := ipv4 atm -+ALL_SUB_DIRS := 802 atm ax25 bridge core ethernet ipv4 ipx unix appletalk \ -+ netrom #decnet - SUB_DIRS := core ethernet unix - MOD_LIST_NAME := NET_MISC_MODULES - - ifeq ($(CONFIG_NET),y) - SUB_DIRS += 802 -+endif -+ -+ifeq ($(CONFIG_ATM),y) -+SUB_DIRS += atm - endif - - ifeq ($(CONFIG_INET),y) ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/Makefile Fri Nov 15 19:06:31 1996 -@@ -0,0 +1,54 @@ -+# -+# Makefile for the ATM Protocol Families. -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+# Note 2! The CFLAGS definition is now in the main makefile... -+ -+include ../../.config -+ -+CFLAGS += -g -+ -+ifeq ($(CONFIG_ATM),y) -+ -+OBJS = common.o dev.o mmuio.o pvc.o raw.o signaling.o static.o svc.o -+ -+ifeq ($(CONFIG_ATM_ATMARP),y) -+OBJS += atmarp.o -+NEED_IPCOM = ipcommon.o -+endif -+ -+ifeq ($(CONFIG_ATM_CLIP),y) -+OBJS += clip.o -+NEED_IPCOM = ipcommon.o -+endif -+ -+ifeq ($(CONFIG_AREQUIPA),y) -+OBJS += arequipa.o -+NEED_IPCOM = ipcommon.o -+endif -+ -+OBJS += $(NEED_IPCOM) -+ -+ifeq ($(CONFIG_PROC_FS),y) -+OBJS += proc.o -+endif -+ -+ifeq ($(CONFIG_ATM_LANE),y) -+OBJS += lec.o lec_arpc.o -+endif -+ -+atm.o: $(OBJS) -+ $(LD) -r -o atm.o $(OBJS) -+ -+else -+ -+atm.o: -+ $(AR) rcs atm.o -+ -+endif -+ -+ -+include $(TOPDIR)/Rules.make ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/clip.c Thu Feb 6 19:42:00 1997 -@@ -0,0 +1,115 @@ -+/* net/atm/clip.c - Classical IP over ATM */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "protocols.h" -+#include "common.h" -+#include "ipcommon.h" -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+struct clip_priv *old_clip_devs; -+ -+ -+/*static*/ void atm_push_clip(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+ DPRINTK("clip push\n"); -+ if (!skb) { -+ printk(KERN_ALERT "ARGL!\n"); -+ unregister_netdev((struct device *) vcc->proto_data); -+ vcc->proto_data = NULL; -+ return; -+ } -+ skb->dev = vcc->proto_data; -+ ipcom_push(skb); -+} -+ -+ -+static int clip_xmit(struct sk_buff *skb,struct device *dev) -+{ -+ DPRINTK("clip xmit\n"); -+ if (!CLIP(dev)->vcc) return -ENOTCONN; /* @@@ discard skb ? */ -+ ipcom_xmit(dev,CLIP(dev)->vcc,skb); -+ CLIP(dev)->stats.tx_packets++; -+ return 0; -+} -+ -+ -+#if 0 -+static int clip_sg_xmit(struct sk_buff *skb,struct device *dev) -+{ -+/* -+struct iovec *iov; -+int i; -+ -+iov = (struct iovec *) skb->data; -+for (i = 0; i < skb->atm.iovcnt; i++) -+ printk("[%d] 0x%p + %d\n",i,iov[i].iov_base,iov[i].iov_len); -+ -+ printk("clip *DIRECT* xmit (iovcnt: %d)\n",skb->atm.iovcnt); -+*/ -+ CLIP(dev)->vcc->dev->ops->send(CLIP(dev)->vcc,skb); -+ CLIP(dev)->stats.tx_packets++; -+ return 0; -+} -+#endif -+ -+ -+static int clip_init(struct device *dev) -+{ -+ ipcom_init(dev,clip_xmit,0); -+ return 0; -+} -+ -+ -+ -+int atm_init_clip(struct atm_vcc *vcc) -+{ -+ struct device *dev; -+ -+ DPRINTK("atm_init_clip\n"); -+ if (!suser()) return -EPERM; -+ vcc->aal = ATM_AAL5; -+ vcc->push = atm_push_clip; -+ vcc->peek = atm_peek_clip; -+ vcc->pop = atm_pop_clip; -+ vcc->push_oam = NULL; -+ vcc->proto_data = dev = kmalloc(sizeof(struct device)+ -+ sizeof(struct clip_priv),GFP_KERNEL); -+ if (!dev) return -ENOMEM; -+ memset(dev,0,sizeof(struct device)+sizeof(struct clip_priv)); -+ dev->name = CLIP(dev)->name; -+ CLIP(dev)->number = ipcom_pick_number(-1); -+ sprintf(dev->name,"atm%d",CLIP(dev)->number); -+ dev->init = clip_init; -+ CLIP(dev)->vcc = vcc; -+ if (register_netdev(dev)) return -EIO; -+ /* if register_netdev can sleep, we race on ->number */ -+ CLIP(dev)->next = old_clip_devs; -+ old_clip_devs = CLIP(dev); -+ DPRINTK("registered %s,0x%p\n",dev->name,vcc); -+ return CLIP(dev)->number; -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/common.c Tue Apr 22 15:03:58 1997 -@@ -0,0 +1,957 @@ -+/* net/atm/common.c - ATM sockets (common part for PVC and SVC) */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include /* struct socket, struct net_proto, struct -+ proto_ops */ -+#include /* ATM stuff */ -+#include -+#include /* CLIP_*ENCAP */ -+#include /* manifest constants */ -+#include /* for ioctls */ -+#include /* SOL_SOCKET */ -+#include /* error codes */ -+#include /* suser */ -+#include /* verify_area */ -+#include -+#include /* struct timeval */ -+#include -+#include -+#include -+ -+#ifdef CONFIG_AREQUIPA -+#include -+#endif -+ -+#ifdef CONFIG_ATM_LANE -+#include -+#include "lec.h" -+#include "lec_arpc.h" -+#endif -+ -+#include "static.h" /* atm_find_dev */ -+#include "common.h" /* prototypes */ -+#include "protocols.h" /* atm_init_ */ -+#include "tunable.h" /* tunable parameters */ -+#include "atmarp.h" /* for clip_create */ -+#include "signaling.h" /* for WAITING and sigd_attach */ -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) -+{ -+ struct sk_buff *skb; -+ -+ if (vcc->tx_inuse && size+vcc->tx_inuse+ATM_PDU_OVHD > vcc->tx_quota) -+ return NULL; -+ while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); -+ DPRINTK("AlTx %d += %d\n",vcc->tx_inuse,skb->truesize); -+ atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); -+ return skb; -+} -+ -+ -+int atm_create(struct socket *sock,int protocol) -+{ -+ struct atm_vcc *vcc; -+ -+ ATM_SD(sock) = NULL; -+ if (sock->type == SOCK_STREAM) return -EINVAL; -+ if (!(vcc = alloc_atm_vcc())) return -ENOMEM; -+#ifdef CONFIG_AREQUIPA -+ vcc->upper = NULL; -+ vcc->sock = sock; -+#endif -+ vcc->flags = ATM_VF_SCRX | ATM_VF_SCTX; -+ vcc->dev = NULL; -+ vcc->family = sock->ops->family; -+ vcc->alloc_tx = alloc_tx; -+ vcc->callback = NULL; -+ memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); -+ memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); -+ vcc->tx_quota = ATM_TXBQ_DEF; -+ vcc->rx_quota = ATM_RXBQ_DEF; -+ vcc->tx_inuse = vcc->rx_inuse = 0; -+ vcc->aal = protocol; /* temporary @@@ */ -+ vcc->push = NULL; -+ vcc->peek = NULL; -+ vcc->pop = NULL; -+ vcc->push_oam = NULL; -+ vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ -+ vcc->atm_options = vcc->aal_options = 0; -+ vcc->timestamp.tv_sec = vcc->timestamp.tv_usec = 0; -+ vcc->sleep = vcc->wsleep = NULL; -+ skb_queue_head_init(&vcc->recvq); -+ skb_queue_head_init(&vcc->listenq); -+ ATM_SD(sock) = vcc; -+ return 0; -+} -+ -+ -+int atm_release_vcc(struct atm_vcc *vcc,int free_vcc) -+{ -+ struct sk_buff *skb; -+ -+ vcc->flags &= ~ATM_VF_READY; -+ if (vcc->dev) { -+ if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); -+ if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ -+ while ((skb = skb_dequeue(&vcc->recvq))) { -+ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse); -+ if (vcc->dev->ops->free_rx_skb) -+ vcc->dev->ops->free_rx_skb(vcc,skb); -+ else kfree_skb(skb,FREE_READ); -+ } -+ if (vcc->rx_inuse) -+ printk(KERN_WARNING "atm_release_vcc: strange ... " -+ "rx_inuse == %d after closing\n",vcc->rx_inuse); -+ if (vcc->prev) vcc->prev->next = vcc->next; -+ else vcc->dev->vccs = vcc->next; -+ if (vcc->next) vcc->next->prev = vcc->prev; -+ else vcc->dev->last = vcc->prev; -+ } -+ if (free_vcc) free_atm_vcc(vcc); -+ return 0; -+} -+ -+ -+extern void atm_push_clip(struct atm_vcc *vcc,struct sk_buff *skb); -+ -+ -+int atm_release(struct socket *sock,struct socket *peer) -+{ -+ struct atm_vcc *vcc; -+ -+ vcc = ATM_SD(sock); -+ if (!vcc -+#ifdef CONFIG_ATM_CLIP -+ || (vcc->push == atm_push_clip && (vcc->vpi || vcc->vci)) -+#endif -+ ) -+ return 0; /* ugly */ -+ return atm_release_vcc(vcc,1); -+} -+ -+ -+static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) -+{ -+ int max_sdu; -+ -+ if (!tp->traffic_class) return 0; -+ if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->max_pcr) -+ return -EINVAL; -+ switch (aal) { -+ case ATM_AAL0: -+ max_sdu = ATM_CELL_SIZE-1; -+ break; -+ case ATM_AAL34: -+ max_sdu = ATM_MAX_AAL34_PDU; -+ break; -+ default: -+ printk(KERN_WARNING "ATM: AAL problems ... " -+ "(%d)\n",aal); -+ /* fall through */ -+ case ATM_AAL5: -+ max_sdu = ATM_MAX_AAL5_PDU; -+ } -+ if (!tp->max_sdu) tp->max_sdu = max_sdu; -+ else if (tp->max_sdu > max_sdu) return -EINVAL; -+ if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV; -+ return 0; -+} -+ -+ -+static int check_ci(struct atm_vcc *vcc,short vpi,int vci) -+{ -+ struct atm_vcc *walk; -+ -+ for (walk = vcc->dev->vccs; walk; walk = walk->next) -+ if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi && -+ walk->vci == vci && ((walk->qos.txtp.traffic_class != -+ ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) || -+ (walk->qos.rxtp.traffic_class != ATM_NONE && -+ vcc->qos.rxtp.traffic_class != ATM_NONE))) -+ return -EADDRINUSE; -+ /* allow VCCs with same VPI/VCI iff they don't collide on -+ TX/RX (but we may refuse such sharing for other reasons, -+ e.g. if protocol requires to have both channels) */ -+ return 0; -+} -+ -+ -+int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) -+{ -+ static short p = 0; /* poor man's per-device cache */ -+ static int c = 0; -+ short old_p; -+ int old_c; -+ -+ if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) -+ return check_ci(vcc,*vpi,*vci); -+ /* last scan may have left values out of bounds for current device */ -+ if (*vpi != ATM_VPI_ANY) p = *vpi; -+ else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; -+ if (*vci != ATM_VCI_ANY) c = *vci; -+ else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits) -+ c = ATM_NOT_RSV_VCI; -+ old_p = p; -+ old_c = c; -+ do { -+ if (!check_ci(vcc,p,c)) { -+ *vpi = p; -+ *vci = c; -+ return 0; -+ } -+ if (*vci == ATM_VCI_ANY) { -+ c++; -+ if (c >= 1 << vcc->dev->ci_range.vci_bits) -+ c = ATM_NOT_RSV_VCI; -+ } -+ if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) && -+ *vpi == ATM_VPI_ANY) { -+ p++; -+ if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0; -+ } -+ } -+ while (old_p != p || old_c != c); -+ return -EADDRINUSE; -+} -+ -+ -+static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci) -+{ -+ volatile struct atm_dev *dev; /* need volatile for sequence */ -+ int error; -+ -+ if (itf >= MAX_ATM_ITF) return -EINVAL; -+ dev = &atm_dev[itf]; -+ if (!dev->ops) return -ENODEV; -+ if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY && -+ vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC && -+ vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits)) -+ return -EINVAL; -+ if (vci > 0 && vci < ATM_NOT_RSV_VCI && !suser()) return -EPERM; -+ if (vcc->qos.aal) vcc->aal = vcc->qos.aal; /* temporary @@@ */ -+ error = 0; -+ switch (vcc->aal) { -+ case ATM_AAL0: -+ error = atm_init_aal0(vcc); -+ vcc->stats = &((struct atm_dev *) dev)->stats.aal0; -+ break; -+ case ATM_AAL34: -+ error = atm_init_aal34(vcc); -+ vcc->stats = &((struct atm_dev *) dev)->stats.aal34; -+ break; -+ case ATM_NO_AAL: -+ /* ATM_AAL5 is also used in the "0 for default" case */ -+ vcc->aal = ATM_AAL5; -+ /* fall through */ -+ case ATM_AAL5: -+ error = atm_init_aal5(vcc); -+ vcc->stats = &((struct atm_dev *) dev)->stats.aal5; -+ break; -+ default: -+ error = -EPROTOTYPE; -+ } -+ if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->aal); -+ if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->aal); -+ if (error) return error; -+ vcc->dev = (struct atm_dev *) dev; -+ DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->aal); -+ DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class, -+ vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu); -+ DPRINTK(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class, -+ vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu); -+ if (dev->ops->open) { -+ error = dev->ops->open(vcc,vpi,vci); -+ if (error) { -+ vcc->dev = NULL; -+ return error; -+ } -+ } -+ vcc->prev = dev->last; -+ vcc->next = NULL; -+ if (!dev->vccs) dev->vccs = vcc; -+ else dev->last->next = vcc; -+ dev->last = vcc; -+ return 0; -+} -+ -+ -+int atm_connect(struct socket *sock,int itf,short vpi,int vci) -+{ -+ struct atm_vcc *vcc; -+ int error; -+ -+ DPRINTK("atm_connect (vpi %d, vci %d)\n",vpi,vci); -+ if (sock->state == SS_CONNECTED) return -EISCONN; -+ if (sock->state != SS_UNCONNECTED) return -EINVAL; -+ if (!(vpi || vci)) return -EINVAL; -+ vcc = ATM_SD(sock); -+ if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) -+ vcc->flags &= ~ATM_VF_PARTIAL; -+ else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL; -+ printk("atm_connect (TX: cl %d,bw %d-%d,sdu %d; RX: cl %d,bw %d-%d," -+ "sdu %d,AAL %d)\n",vcc->qos.txtp.traffic_class, -+ vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, -+ vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr, -+ vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,vcc->qos.aal ? -+ vcc->qos.aal : vcc->aal); -+ if (!vcc->qos.txtp.traffic_class && !vcc->qos.rxtp.traffic_class) -+ return -EINVAL; -+ if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || -+ vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) -+ return -EINVAL; -+ if (itf != ATM_ITF_ANY) error = atm_do_connect(vcc,itf,vpi,vci); -+ else { -+ int i; -+ -+ error = -ENODEV; -+ for (i = 0; i < MAX_ATM_ITF; i++) -+ if (atm_dev[i].ops) -+ if (!(error = atm_do_connect(vcc,i,vpi,vci))) -+ break; -+ } -+ if (error) return error; -+ if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) -+ vcc->flags |= ATM_VF_PARTIAL; -+ else sock->state = SS_CONNECTED; -+ return 0; -+} -+ -+ -+int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, -+ int nonblock,int flags,int *addr_len) -+{ -+ struct atm_vcc *vcc; -+ struct sk_buff *skb; -+ unsigned long cpu_flags; -+ int eff_len; -+ -+ void *buff; -+ int size; -+ -+ if (sock->state != SS_CONNECTED) return -ENOTCONN; -+ if (flags) return -EOPNOTSUPP; -+ if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ -+ buff = m->msg_iov->iov_base; -+ size = m->msg_iov->iov_len; -+ /* verify_area is done by net/socket.c */ -+ vcc = ATM_SD(sock); -+ if (vcc->dev->ops->poll && (vcc->flags & ATM_VF_READY)) -+ while (1) { -+ vcc->dev->ops->poll(vcc,nonblock); -+ if (current->signal & ~current->blocked) -+ return -ERESTARTSYS; -+ if (skb_peek(&vcc->recvq)) break; -+ if (nonblock) return -EAGAIN; -+ } -+ save_flags(cpu_flags); -+ cli(); -+ while (!(skb = skb_dequeue(&vcc->recvq))) { -+ if (vcc->flags & ATM_VF_RELEASED) return vcc->reply; -+ if (!(vcc->flags & ATM_VF_READY)) return 0; -+ if (nonblock) { -+ restore_flags(cpu_flags); -+ return -EAGAIN; -+ } -+ interruptible_sleep_on(&vcc->sleep); -+ if (current->signal & ~current->blocked) { -+ restore_flags(cpu_flags); -+ return -ERESTARTSYS; -+ } -+ } -+ restore_flags(cpu_flags); -+ vcc->timestamp = skb->atm.timestamp; -+ eff_len = skb->len > size ? size : skb->len; -+ if (vcc->dev->ops->feedback) -+ vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data, -+ (unsigned long) buff,eff_len); -+ DPRINTK("RcvM %d -= %d\n",vcc->rx_inuse,skb->truesize); -+ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse); -+ if (skb->atm.iovcnt) { /* @@@ hack */ -+ /* iovcnt set, use scatter-gather for receive */ -+ int el, cnt; -+ struct iovec *iov = (struct iovec *)skb->data; -+ unsigned char *p = (unsigned char *)buff; -+ -+ el = eff_len; -+ for (cnt = 0; (cnt < skb->atm.iovcnt) && el; cnt++) { -+ memcpy_tofs(p, iov->iov_base, -+ (iov->iov_len > el) ? el : iov->iov_len); -+ p += iov->iov_len; -+ el -= (iov->iov_len > el)?el:iov->iov_len; -+ iov++; -+ } -+ if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb,FREE_READ); -+ else vcc->dev->ops->free_rx_skb(vcc, skb); -+ return eff_len; -+ } -+#ifdef CONFIG_MMU_HACKS -+ if (vcc->flags & ATM_VF_SCRX) -+ mmucp_tofs((unsigned long) buff,eff_len,skb, -+ (unsigned long) skb->data); -+ else -+#endif -+ { -+#ifdef DUMP_PACKETS -+ if (vcc->vci==5 || vcc->vci >32) { -+ char buf[300]; -+ int i; -+ -+ for(i=0;i<99 && i < skb->len;i++) { -+ sprintf(buf+i*3,"%2.2x ", -+ 0xff&skb->data[i]); -+ } -+ printk("recv %d:%s\n",vcc->vci,buf); -+ } -+#endif -+ memcpy_tofs(buff,skb->data,eff_len); -+ if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb,FREE_READ); -+ else vcc->dev->ops->free_rx_skb(vcc, skb); -+ } -+ return eff_len; -+} -+ -+ -+int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, -+ int nonblock,int flags) -+{ -+ struct atm_vcc *vcc; -+ struct sk_buff *skb; -+ int eff,error; -+ -+ const void *buff; -+ int size; -+ -+ if (sock->state != SS_CONNECTED) return -ENOTCONN; -+ if (flags) return -EOPNOTSUPP; -+ if (m->msg_name) return -EISCONN; -+ if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ -+ buff = m->msg_iov->iov_base; -+ size = m->msg_iov->iov_len; -+ vcc = ATM_SD(sock); -+ if (vcc->flags & ATM_VF_RELEASED) return vcc->reply; -+ if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; -+ if (!size) return 0; -+ /* verify_area is done by net/socket.c */ -+#ifdef CONFIG_MMU_HACKS -+ if ((vcc->flags & ATM_VF_SCTX) && vcc->dev->ops->sg_send && -+ vcc->dev->ops->sg_send(vcc,(unsigned long) buff,size)) { -+ int res,max_iov; -+ -+ max_iov = 2+size/PAGE_SIZE; -+ /* -+ * Doesn't use alloc_tx yet - this will change later. @@@ -+ */ -+ while (!(skb = alloc_skb(sizeof(struct iovec)*max_iov, -+ GFP_KERNEL))) { -+ if (nonblock) return -EAGAIN; -+ interruptible_sleep_on(&vcc->wsleep); -+ if (current->signal & ~current->blocked) -+ return -ERESTARTSYS; -+ } -+ skb->free = 1; -+ skb->len = size; -+ res = lock_user((unsigned long) buff,size,max_iov, -+ (struct iovec *) skb->data); -+ if (res < 0) { -+ kfree_skb(skb,FREE_WRITE); -+ if (res != -EAGAIN) return res; -+ } -+ else { -+ DPRINTK("res is %d\n",res); -+ DPRINTK("Asnd %d += %d\n",vcc->tx_inuse,skb->truesize); -+ atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); -+ skb->atm.iovcnt = res; -+ skb_device_lock(skb); -+ error = vcc->dev->ops->send(vcc,skb); -+ /* FIXME: security: may send up to 3 "garbage" bytes */ -+ return error ? error : size; -+ } -+ } -+#endif -+ eff = (size+3) & ~3; /* align to word boundary */ -+ while (!(skb = vcc->alloc_tx(vcc,eff))) { -+ if (nonblock) return -EAGAIN; -+ interruptible_sleep_on(&vcc->wsleep); -+ if (current->signal & ~current->blocked) -+ return -ERESTARTSYS; -+ if (vcc->flags & ATM_VF_RELEASED) return vcc->reply; -+ if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; -+ } -+ skb->free = 1; -+ skb->len = size; -+ skb->atm.iovcnt = 0; -+ memcpy_fromfs(skb->data,buff,size); -+ if (eff != size) memset(skb->data+size,0,eff-size); -+#if 0 /* experimental */ -+ vcc->dev->sending = 1; -+#endif -+ skb_device_lock(skb); -+#ifdef DUMP_PACKETS -+ if (vcc->vci==5 || vcc->vci >32) { -+ char buf[300]; -+ int i; -+ -+ for(i=0;i<99 && i < skb->len;i++) { -+ sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]); -+ } -+ printk("send %d:%s\n",vcc->vci,buf); -+ } -+#endif -+ error = vcc->dev->ops->send(vcc,skb); -+#if 0 /* experimental */ -+ while (vcc->dev->sending) sleep_on(&vcc->sleep); -+#endif -+ return error ? error : size; -+} -+ -+ -+int atm_select(struct socket *sock,int sel_type,select_table *wait) -+{ -+ struct atm_vcc *vcc; -+ -+ vcc = ATM_SD(sock); -+ switch(sel_type) { -+ case SEL_IN: -+ if (vcc->dev && vcc->dev->ops->poll) -+ vcc->dev->ops->poll(ATM_SD(sock),1); -+ if (sock->state == SS_CONNECTING) break; -+ if (!skb_peek(&vcc->recvq) && -+ !skb_peek(&vcc->listenq) && -+ !(vcc->flags & ATM_VF_RELEASED)) break; -+ if (vcc->dev && vcc->dev->ops->poll) return 0; -+ return 1; -+ case SEL_OUT: -+ if (sock->state != SS_CONNECTING) { -+ if (vcc->qos.txtp.traffic_class == ATM_NONE) -+ return 1; -+ if (vcc->qos.txtp.max_sdu+vcc->tx_inuse+ -+ ATM_PDU_OVHD <= vcc->tx_quota) return 1; -+ } -+ select_wait(&vcc->wsleep,wait); -+ return 0; -+ case SEL_EX: -+ if (sock->state != SS_CONNECTING) return 0; -+ if (vcc->reply == WAITING) break; -+ return 1; -+ } -+ select_wait(&vcc->sleep,wait); -+ return 0; -+} -+ -+ -+ -+static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero) -+{ -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ if (arg) -+ memcpy_tofs(arg,&dev->stats,sizeof(struct atm_dev_stats)); -+ if (zero) -+ memset(&dev->stats,0,sizeof(struct atm_dev_stats)); -+ restore_flags(flags); -+ return 0; -+} -+ -+ -+extern int clip_ioctl(void *dev,void *rq,int cmd); /* @@@ lie and cheat ... */ -+ -+ -+#ifdef CONFIG_AREQUIPA -+ -+/* @@@ stolen from net/socket.c - should be in a common header file */ -+ -+ -+struct socket *sockfd_lookup(int fd) -+{ -+ struct file *file; -+ struct inode *inode; -+ -+ if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd])) -+ return NULL; -+ inode = file->f_inode; -+ if (!inode || !inode->i_sock) return NULL; -+ return &inode->u.socket_i; -+} -+ -+#endif -+ -+ -+int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) -+{ -+ struct atm_dev *dev; -+ struct atm_vcc *vcc; -+ unsigned long eff_arg; -+ int rsize,wsize,len; -+ int error; -+ -+ vcc = ATM_SD(sock); -+ rsize = wsize = 0; -+ switch (cmd) { -+ case ATM_GETNAMES: -+ { -+ struct atm_iobuf *buf; -+ -+ error = verify_area(VERIFY_READ,(void *) arg, -+ sizeof(struct atm_iobuf)); -+ if (error) return error; -+ buf = (struct atm_iobuf *) arg; -+ error = verify_area(VERIFY_WRITE, -+ (void *) get_fs_long(&buf->buffer), -+ get_fs_long(&buf->length)); -+ if (error) return error; -+ error = verify_area(VERIFY_WRITE, -+ (void *) &buf->length,sizeof(int)); -+ if (error) return error; -+ return atm_dev_list((void *) get_fs_long(&buf-> -+ buffer),&buf->length); -+ } -+ case SIOCGSTAMP: /* borrowed from IP */ -+ if (!vcc->timestamp.tv_sec) return -ENOENT; -+ vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000; -+ vcc->timestamp.tv_usec %= 1000000; -+ error = verify_area(VERIFY_WRITE,(void *) arg, -+ sizeof(struct timeval)); -+ if (error) return error; -+ memcpy_tofs((void *) arg,&vcc->timestamp, -+ sizeof(struct timeval)); -+ return 0; -+ case ATM_SETSC: -+ if (arg & ~(ATM_VF_SCRX | ATM_VF_SCTX)) return -EINVAL; -+ /* @@@ race condition - should split flags into -+ "volatile" and non-volatile part */ -+ vcc->flags = (vcc->flags & ~(ATM_VF_SCRX | -+ ATM_VF_SCTX)) | arg; -+ return 0; -+ case ATMSIGD_CTRL: -+ if (!suser()) return -EPERM; -+ error = sigd_attach(vcc); -+ if (!error) sock->state = SS_CONNECTED; -+ return error; -+#ifdef CONFIG_ATM_CLIP -+ case CLIP_PVC: -+ if (!suser()) return -EPERM; -+ return atm_init_clip(vcc); -+ case CLIP_NULENCAP: -+ case CLIP_LLCENCAP: -+ if (!suser()) return -EPERM; -+ return clip_ioctl(vcc->proto_data,NULL,cmd); -+ /* rather crude hack ... */ -+#endif -+#ifdef CONFIG_ATM_ATMARP -+ case SIOCMKCLIP: -+ if (!suser()) return -EPERM; -+ return clip_create(arg); -+ case ATMARPD_CTRL: -+ if (!suser()) return -EPERM; -+ error = atm_init_atmarp(vcc); -+ if (!error) sock->state = SS_CONNECTED; -+ return error; -+ case ATMARP_MKIP: -+ if (!suser()) return -EPERM; -+ return atmarp_mkip(vcc,arg); -+ case ATMARP_SETENTRY: -+ if (!suser()) return -EPERM; -+ return atmarp_setentry(vcc,arg); -+ case ATMARP_ENCAP: -+ if (!suser()) return -EPERM; -+ return atmarp_encap(vcc,arg); -+#endif -+#ifdef CONFIG_AREQUIPA -+ case AREQUIPA_PRESET: -+ { -+ struct socket *upper; -+ -+ if (!(upper = sockfd_lookup(arg))) -+ return -ENOTSOCK; -+ if (upper->ops->family != PF_INET) -+ return -EPROTOTYPE; -+ return arequipa_preset(sock, -+ (struct sock *) upper->data); -+ } -+ case AREQUIPA_INCOMING: -+ return arequipa_incoming(sock); -+ case AREQUIPA_CTRL: -+ if (!suser()) return -EPERM; -+ error = arequipad_attach(vcc); -+ if (!error) sock->state = SS_CONNECTED; -+ return error; -+ case AREQUIPA_CLS3RD: -+ if (!suser()) return -EPERM; -+ arequipa_close_vcc((struct atm_vcc *) arg); -+ return 0; -+ case AREQUIPA_SYNCACK: -+ if (!suser()) return -EPERM; -+ wake_up((struct wait_queue **) arg); -+ return 0; -+ case AREQUIPA_WORK: -+ if (!suser()) return -EPERM; -+ arequipa_work(); -+ return 0; -+#endif -+#ifdef CONFIG_ATM_LANE -+ case ATMLEC_CTRL: -+ if (!suser()) return -EPERM; -+ error = lecd_attach(vcc, (int)arg); -+ if (error >=0) sock->state = SS_CONNECTED; -+ return error; -+ case ATMLEC_MCAST: -+ if (!suser()) return -EPERM; -+ return lec_mcast_attach(vcc, (int)arg); -+ case ATMLEC_DATA: -+ if (!suser()) return -EPERM; -+ return lec_vcc_attach(vcc, (void*)arg); -+#endif -+ case ATM_GETTYPE: -+ wsize = -1; /* special - don't check length */ -+ break; -+ case ATM_GETESI: -+ wsize = ESI_LEN; -+ break; -+ case ATM_GETSTATZ: -+ if (!suser()) return -EPERM; -+ /* fall through */ -+ case ATM_GETSTAT: -+ wsize = sizeof(struct atm_dev_stats); -+ break; -+ case ATM_GETCIRANGE: -+ wsize = sizeof(struct atm_cirange); -+ break; -+ case ATM_SETCIRANGE: -+ if (!suser()) return -EPERM; -+ rsize = sizeof(struct atm_cirange); -+ break; -+ case SONET_GETSTATZ: -+ if (!suser()) return -EPERM; -+ /* fall through */ -+ case SONET_GETSTAT: -+ wsize = sizeof(struct sonet_stats); -+ break; -+ case SONET_GETDIAG: -+ wsize = sizeof(int); -+ break; -+ case SONET_SETDIAG: -+ case SONET_CLRDIAG: -+ if (!suser()) return -EPERM; -+ rsize = sizeof(int); -+ break; -+ case SONET_SETFRAMING: -+ rsize = sizeof(int); -+ break; -+ case SONET_GETFRAMING: -+ wsize = sizeof(int); -+ break; -+ case SONET_GETFRSENSE: -+ wsize = SONET_FRSENSE_SIZE; -+ break; -+ default: -+ wsize = -1; /* just in case ... */ -+ } -+ error = verify_area(VERIFY_READ,(void *) arg, -+ sizeof(struct atmif_sioc)); -+ if (error) return error; -+ if (wsize) { -+ error = verify_area(VERIFY_WRITE,(void *) arg, -+ sizeof(struct atmif_sioc)); -+ if (error) return error; -+ } -+ if (!(dev = atm_find_dev(get_fs_long(&((struct atmif_sioc *) arg)-> -+ number)))) return -ENODEV; -+ len = get_fs_long(&((struct atmif_sioc *) arg)->length); -+ eff_arg = get_fs_long(&((struct atmif_sioc *) arg)->arg); -+ if (!eff_arg && (rsize || wsize)) return -EINVAL; -+ if (rsize > 0) { -+ if (len != rsize) return -EINVAL; -+ error = verify_area(VERIFY_READ,(void *) eff_arg,len); -+ if (error) return error; -+ } -+ if (wsize > 0) { -+ if (len != wsize) return -EINVAL; -+ error = verify_area(VERIFY_WRITE,(void *) eff_arg,len); -+ if (error) return error; -+ put_fs_long(wsize,&((struct atmif_sioc *) arg)->length); -+ } -+ switch (cmd) { -+ case ATM_GETTYPE: -+ { -+ int length; -+ -+ length = strlen(dev->type); -+ if (len type, -+ length+1); -+ put_fs_long(length, -+ &((struct atmif_sioc *) arg)->length); -+ return length; -+ } -+ case ATM_GETESI: -+ memcpy_tofs((void *) eff_arg,dev->esi,ESI_LEN); -+ return wsize; -+ case ATM_GETSTATZ: -+ case ATM_GETSTAT: -+ error = fetch_stats(dev,(void *) eff_arg, -+ cmd == ATM_GETSTATZ); -+ return error < 0 ? error : wsize; -+ case ATM_GETCIRANGE: -+ memcpy_tofs((void *) eff_arg,&dev->ci_range, -+ sizeof(struct atm_cirange)); -+ return wsize; -+ default: -+ if (!dev->ops->ioctl) return -EINVAL; -+ error = dev->ops->ioctl(dev,cmd,eff_arg); -+ if (error >= 0) -+ put_fs_long(len, -+ &((struct atmif_sioc *) arg)->length); -+ return error; -+ } -+} -+ -+ -+int atm_setsockopt(struct socket *sock,int level,int optname, -+ char *optval,int optlen) -+{ -+ struct atm_vcc *vcc; -+ -+ vcc = ATM_SD(sock); -+ if (level == SOL_SOCKET) { -+ unsigned long value; -+ -+ switch (optname) { -+ case SO_SNDBUF: -+ if (optlen != sizeof(value)) return -EINVAL; -+ value = get_fs_long(optval); -+ if (!value) value = ATM_TXBQ_DEF; -+ if (value < ATM_TXBQ_MIN) value = ATM_TXBQ_MIN; -+ if (value > ATM_TXBQ_MAX) value = ATM_TXBQ_MAX; -+ vcc->tx_quota = value; -+ return 0; -+ case SO_RCVBUF: -+ if (optlen != sizeof(value)) return -EINVAL; -+ value = get_fs_long(optval); -+ if (!value) value = ATM_RXBQ_DEF; -+ if (value < ATM_RXBQ_MIN) value = ATM_RXBQ_MIN; -+ if (value > ATM_RXBQ_MAX) value = ATM_RXBQ_MAX; -+ vcc->rx_quota = value; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+ } -+ if (level == SOL_ATM) { -+ switch (optname) { -+ case SO_ATMQOS: -+ if (sock->state != SS_UNCONNECTED) -+ return -EBADFD; -+ if (optlen != sizeof(struct atm_qos)) -+ return -EINVAL; -+ memcpy_fromfs(&vcc->qos,optval,optlen); -+#if 0 -+ if ((vcc->qos.txtp.traffic_class == ATM_UBR && -+ (vcc->qos.txtp.min_pcr || -+ vcc->qos.txtp.max_pcr || -+ vcc->qos.rxtp.min_pcr || -+ vcc->qos.rxtp.max_pcr)) || -+ (vcc->qos.rxtp.traffic_class == ATM_UBR && -+ (vcc->qos.rxtp.min_pcr || -+ vcc->qos.rxtp.max_pcr))) -+ printk(KERN_WARNING "Warning: " -+ "semantics of ATM_UBR have changed " -+ "with min/max_pcr != 0\n"); -+#endif -+ vcc->flags |= ATM_VF_HASQOS; -+ return 0; -+ default: -+ break; -+ } -+ } -+ if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL; -+ return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen); -+} -+ -+ -+static int putsockopt(void *data,int len,char *optval,int *optlen) -+{ -+ int error; -+ -+ if (get_fs_long(optlen) < len) return -EINVAL; -+ put_fs_long(len,optlen); -+ error = verify_area(VERIFY_WRITE,optval,len); -+ if (error) return error; -+ memcpy_tofs(optval,data,len); -+ return 0; -+} -+ -+ -+int atm_getsockopt(struct socket *sock,int level,int optname, -+ char *optval,int *optlen) -+{ -+ struct atm_vcc *vcc; -+ int error; -+ -+ error = verify_area(VERIFY_READ,optlen,sizeof(*optlen)); /* paranoia? */ -+ if (error) return error; -+ error = verify_area(VERIFY_WRITE,optlen,sizeof(*optlen)); -+ if (error) return error; -+ vcc = ATM_SD(sock); -+ switch (level) { -+ case SOL_SOCKET: -+ switch (optname) { -+ case SO_SNDBUF: -+ return putsockopt(&vcc->tx_quota, -+ sizeof(unsigned long),optval, -+ optlen); -+ case SO_RCVBUF: -+ return putsockopt(&vcc->rx_quota, -+ sizeof(unsigned long),optval, -+ optlen); -+ case SO_BCTXOPT: -+ case SO_BCRXOPT: -+ level = SOL_AAL; /* cheat */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ /* fall through */ -+ case SOL_AAL: -+ switch (optname) { -+ case SO_AALTYPE: -+ return putsockopt(&vcc->aal, -+ sizeof(unsigned char),optval, -+ optlen); -+ default: -+ break; -+ } -+ break; -+ case SOL_ATM: -+ switch (optname) { -+ case SO_ATMQOS: -+ if (!(vcc->flags & ATM_VF_HASQOS)) -+ return -EINVAL; -+ return putsockopt(&vcc->qos, -+ sizeof(struct atm_qos),optval, -+ optlen); -+ default: -+ break; -+ } -+ /* fall through */ -+ default: -+ break; -+ } -+ if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; -+ return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen); -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/common.h Fri Nov 15 19:06:32 1996 -@@ -0,0 +1,32 @@ -+/* net/atm/common.h - ATM sockets (common part for PVC and SVC) */ -+ -+/* Written 1995 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef NET_ATM_COMMON_H -+#define NET_ATM_COMMON_H -+ -+#include -+ -+int atm_create(struct socket *sock,int protocol); -+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, -+ int nonblock,int flags,int *addr_len); -+int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, -+ int nonblock,int flags); -+int atm_select(struct socket *sock,int sel_type,select_table *wait); -+int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg); -+int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, -+ int optlen); -+int atm_getsockopt(struct socket *sock,int level,int optname,char *optval, -+ int *optlen); -+ -+int atm_release_vcc(struct atm_vcc *vcc,int free_vcc); -+ -+/* SVC */ -+ -+int copy_svc_addr(struct sockaddr_atmsvc *to,struct sockaddr_atmsvc *from); -+void svc_callback(struct atm_vcc *vcc); -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/dev.c Fri Nov 15 19:06:32 1996 -@@ -0,0 +1,38 @@ -+/* net/atm/dev.c - ATM device registeration */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include -+ -+#include "static.h" -+ -+ -+struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, -+ unsigned long flags) -+{ -+ volatile struct atm_dev *dev; /* need volatile to ensure sequence */ -+ -+ dev = alloc_atm_dev(type); -+ if (!dev) { -+ printk(KERN_ERR "atm_dev_register: no space for dev %s\n", -+ type); -+ return NULL; -+ } -+ dev->number = 0; -+ while (atm_find_dev(dev->number)) dev->number++; -+ dev->vccs = dev->last = NULL; -+ dev->dev_data = NULL; -+ dev->ops = ops; -+ dev->flags = flags; -+ memset((void *) &dev->stats,0,sizeof(struct atm_dev_stats)); -+ return (struct atm_dev *) dev; -+} -+ -+ -+void atm_dev_deregister(struct atm_dev *dev) -+{ -+ free_atm_dev(dev); -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/pvc.c Fri Nov 15 19:06:32 1996 -@@ -0,0 +1,175 @@ -+/* net/atm/pvc.c - ATM PVC sockets */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include /* struct socket, struct net_proto, -+ struct proto_ops */ -+#include /* ATM stuff */ -+#include /* ATM devices */ -+#include /* Classical IP over ATM */ -+#include /* error codes */ -+#include /* printk */ -+#include -+#ifdef CONFIG_AREQUIPA -+#include -+#endif -+ -+#include "static.h" /* static data ... */ -+#include "common.h" /* common for PVCs and SVCs */ -+ -+#ifndef NULL -+#define NULL 0 -+#endif -+ -+ -+static int pvc_dup(struct socket *newsock,struct socket *oldsock) -+{ -+ return -EOPNOTSUPP; -+} -+ -+ -+static int pvc_shutdown(struct socket *sock,int how) -+{ -+ return -EOPNOTSUPP; -+} -+ -+ -+static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, -+ int sockaddr_len) -+{ -+ struct sockaddr_atmpvc *addr; -+ struct atm_vcc *vcc; -+ -+ if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL; -+ addr = (struct sockaddr_atmpvc *) sockaddr; -+ if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; -+ vcc = ATM_SD(sock); -+ if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; -+ if (vcc->flags & ATM_VF_PARTIAL) { -+ if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; -+ if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; -+ } -+ return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi, -+ addr->sap_addr.vci); -+} -+ -+ -+static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, -+ int sockaddr_len,int flags) -+{ -+ return pvc_bind(sock,sockaddr,sockaddr_len); -+} -+ -+ -+static int pvc_listen(struct socket *sock,int backlog) -+{ -+ return -EOPNOTSUPP; -+} -+ -+ -+static int pvc_accept(struct socket *sock,struct socket *newsock,int flags) -+{ -+ return -EOPNOTSUPP; -+} -+ -+ -+static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, -+ int *sockaddr_len,int peer) -+{ -+ struct sockaddr_atmpvc *addr; -+ struct atm_vcc *vcc; -+ -+#if 0 /* add some sanity checks later ... @@@ */ -+ if (sock->state != SS_CONNECTED) return -EINVAL; -+#endif -+ *sockaddr_len = sizeof(struct sockaddr_atmpvc); -+ addr = (struct sockaddr_atmpvc *) sockaddr; -+ vcc = ATM_SD(sock); -+ addr->sap_family = AF_ATMPVC; -+ addr->sap_addr.itf = vcc->dev->number; -+ addr->sap_addr.vpi = vcc->vpi; -+ addr->sap_addr.vci = vcc->vci; -+ return 0; -+} -+ -+ -+static int pvc_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) -+{ -+ /* put PVC-specific code here */ -+ return atm_ioctl(sock,cmd,arg); -+} -+ -+ -+static int pvc_setsockopt(struct socket *sock,int level,int optname, -+ char *optval,int optlen) -+{ -+ struct atm_vcc *vcc; -+ int error; -+ -+ error = verify_area(VERIFY_READ,optval,optlen); -+ if (error) return -EINVAL; -+ vcc = ATM_SD(sock); -+ if (level == SOL_ATM && optname == SO_ATMQOS && -+ sock->state == SS_CONNECTED) { -+ struct atm_qos qos; -+ -+ if (optlen != sizeof(struct atm_qos)) return -EINVAL; -+ if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP; -+ memcpy_fromfs(&qos,optval,optlen); -+ return vcc->dev->ops->change_qos(vcc,&qos); -+ } -+ return atm_setsockopt(sock,level,optname,optval,optlen); -+} -+ -+ -+static int pvc_getsockopt(struct socket *sock,int level,int optname, -+ char *optval,int *optlen) -+{ -+ /* put PVC-specific code here */ -+ return atm_getsockopt(sock,level,optname,optval,optlen); -+} -+ -+ -+static struct proto_ops pvc_proto_ops = { -+ PF_ATMPVC, -+ atm_create, -+ pvc_dup, -+ atm_release, -+ pvc_bind, -+ pvc_connect, -+ NULL, /* no socketpair */ -+ pvc_accept, -+ pvc_getname, -+ atm_select, -+ pvc_ioctl, -+ pvc_listen, -+ pvc_shutdown, -+ pvc_setsockopt, -+ pvc_getsockopt, -+ NULL, /* no fcntl */ -+ atm_sendmsg, -+ atm_recvmsg -+}; -+ -+ -+/* -+ * Initialize the ATM PVC protocol family -+ */ -+ -+ -+extern int atmdev_init(void); -+ -+ -+void atmpvc_proto_init(struct net_proto *pro) -+{ -+ atm_static_init(); -+ if (sock_register(pvc_proto_ops.family,&pvc_proto_ops) < 0) { -+ printk(KERN_ERR "ATMPVC: can't register"); -+ return; -+ } -+#ifdef CONFIG_AREQUIPA -+ (void) atm_init_arequipa(); -+#endif -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/static.c Fri Nov 15 19:06:33 1996 -@@ -0,0 +1,114 @@ -+/* net/atm/static.c - Staticly allocated resources */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include -+#include /* for get_fs_long and put_fs_long */ -+ -+#include "static.h" -+ -+ -+#ifndef NULL -+#define NULL 0 -+#endif -+ -+ -+struct atm_dev atm_dev[MAX_ATM_ITF]; -+struct atm_vcc atm_vcc[MAX_ATM_VCC]; -+ -+ -+void atm_static_init(void) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_ATM_ITF; i++) atm_dev[i].ops = NULL; -+ for (i = 0; i < MAX_ATM_VCC; i++) atm_vcc[i].family = 0; -+} -+ -+ -+struct atm_dev *alloc_atm_dev(const char *type) -+{ -+ static int curr_dev = 0; -+ int last_dev; -+ -+ last_dev = curr_dev; -+ do { -+ if (!atm_dev[curr_dev].ops) { -+ memset(&atm_dev[curr_dev],0,sizeof(struct atm_dev)); -+ atm_dev[curr_dev].type = type; -+ return atm_dev+curr_dev; -+ } -+ if (++curr_dev == MAX_ATM_ITF) curr_dev = 0; -+ } -+ while (last_dev != curr_dev); -+ return NULL; -+} -+ -+ -+struct atm_vcc *alloc_atm_vcc(void) -+{ -+ static int curr_vcc = 0; -+ int last_vcc; -+ -+ last_vcc = curr_vcc; -+ do { -+ if (!atm_vcc[curr_vcc].family) return atm_vcc+curr_vcc; -+ if (++curr_vcc == MAX_ATM_VCC) curr_vcc = 0; -+ } -+ while (last_vcc != curr_vcc); -+ return NULL; -+} -+ -+ -+void free_atm_dev(struct atm_dev *dev) -+{ -+ dev->ops = NULL; -+} -+ -+ -+void free_atm_vcc(struct atm_vcc *vcc) -+{ -+ vcc->family = 0; -+} -+ -+ -+struct atm_dev *atm_find_dev(int number) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_ATM_ITF; i++) -+ if (atm_dev[i].ops && atm_dev[i].number == number) -+ return &atm_dev[i]; -+ return NULL; -+} -+ -+ -+int atm_dev_list(int *buffer,int *u_length) -+{ -+ int length,left,i; -+ -+ length = get_fs_long(u_length); -+ left = length/sizeof(int); -+ if (!left) return -EINVAL; -+ for (i = 0; i < MAX_ATM_ITF; i++) -+ if (atm_dev[i].ops) { -+ if (!left) break; -+ put_fs_long(atm_dev[i].number,buffer); -+ buffer++; -+ left--; -+ } -+ put_fs_long(length-(length/sizeof(int)-left)*sizeof(int),u_length); -+ return length/sizeof(int)-left; -+} -+ -+ -+void for_all_vccs(void (*fn)(struct atm_vcc *vcc)) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_ATM_VCC; i++) -+ if (atm_vcc[i].family) fn(atm_vcc+i); -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/static.h Wed Apr 2 22:38:55 1997 -@@ -0,0 +1,29 @@ -+/* net/atm/static.h - Staticly allocated resources */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef NET_ATM_STATIC_H -+#define NET_ATM_STATIC_H -+ -+#include -+ -+ -+/* -+ * This is evil ... -+ */ -+ -+extern struct atm_dev atm_dev[MAX_ATM_ITF]; -+extern struct atm_vcc atm_vcc[MAX_ATM_VCC]; -+ -+ -+void atm_static_init(void); -+struct atm_dev *alloc_atm_dev(const char *type); -+struct atm_vcc *alloc_atm_vcc(void); -+void free_atm_dev(struct atm_dev *dev); -+void free_atm_vcc(struct atm_vcc *vcc); -+struct atm_dev *atm_find_dev(int number); -+int atm_dev_list(int *buffer,int *u_length); -+void for_all_vccs(void (*fn)(struct atm_vcc *vcc)); -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/svc.c Wed Apr 2 22:05:33 1997 -@@ -0,0 +1,604 @@ -+/* net/atm/svc.c - ATM SVC sockets */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include /* struct socket, struct net_proto, -+ struct proto_ops */ -+#include /* error codes */ -+#include /* printk */ -+#include -+#include -+#include /* jiffies and HZ */ -+#include /* O_NONBLOCK */ -+#include /* ATM stuff */ -+#include -+#include -+#include -+ -+#include "static.h" -+#include "common.h" /* common for PVCs and SVCs */ -+#include "signaling.h" -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+/* -+ * Note: since all this is still nicely synchronized with the signaling demon, -+ * there's no need to protect sleep loops with clis. If signaling is -+ * moved into the kernel, that would change. -+ */ -+ -+ -+void svc_callback(struct atm_vcc *vcc) -+{ -+ wake_up(&vcc->sleep); -+} -+ -+ -+static int svc_create(struct socket *sock,int protocol) -+{ -+ int error; -+ -+ error = atm_create(sock,protocol); -+ if (error) return error; -+ ATM_SD(sock)->callback = svc_callback; -+ return 0; -+} -+ -+ -+static int svc_dup(struct socket *newsock,struct socket *oldsock) -+{ -+ return svc_create(newsock,ATM_SD(oldsock)->aal); -+} -+ -+ -+static int svc_shutdown(struct socket *sock,int how) -+{ -+ return -EOPNOTSUPP; -+} -+ -+ -+static void svc_disconnect(struct atm_vcc *vcc) -+{ -+ struct sk_buff *skb; -+ -+ DPRINTK("svc_disconnect\n"); -+ if (vcc->flags & ATM_VF_REGIS) { -+ sigd_enq(vcc,as_close,NULL,NULL,NULL); -+ while (!(vcc->flags & ATM_VF_RELEASED) && sigd) -+ sleep_on(&vcc->sleep); -+ } -+ while ((skb = skb_dequeue(&vcc->listenq))) { -+ vcc->flags &= ~ATM_VF_RELEASED; -+ DPRINTK("LISTEN REL\n"); -+ sigd_enq(NULL,as_reject,vcc,NULL,NULL); /* @@@ should include -+ the reason */ -+ dev_kfree_skb(skb,FREE_WRITE); -+ } -+ vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED); /* may retry later */ -+} -+ -+ -+static int svc_release(struct socket *sock,struct socket *peer) -+{ -+ DPRINTK("svc_release\n"); -+ if (!ATM_SD(sock)) return 0; -+ ATM_SD(sock)->flags &= ~ATM_VF_READY; -+ atm_release_vcc(ATM_SD(sock),0); -+ svc_disconnect(ATM_SD(sock)); -+ /* 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(ATM_SD(sock)); -+ return 0; -+} -+ -+ -+int copy_svc_addr(struct sockaddr_atmsvc *to,struct sockaddr_atmsvc *from) -+{ -+ struct atm_blli *walk,**link,*next; -+ int error,bllis; -+ -+ *to = *from; -+ link = &to->sas_addr.blli; -+ error = bllis = 0; -+ for (walk = from->sas_addr.blli; walk; walk = (struct atm_blli *) -+ get_fs_long((unsigned long) &walk->next)) { -+ if (++bllis > ATM_MAX_BLLI) { -+ error = -E2BIG; -+ break; -+ } -+ *link = kmalloc(sizeof(struct atm_blli),GFP_KERNEL); -+ if (!*link) { -+ error = -ENOMEM; -+ break; -+ } -+ error = verify_area(VERIFY_READ,walk,sizeof(struct atm_blli)); -+ /* kmalloc may swap out user pages */ -+ if (error) break; -+ memcpy_fromfs(*link,walk,sizeof(struct atm_blli)); -+ link = &(*link)->next; -+ } -+ *link = NULL; -+ if (!error) return 0; -+ for (walk = to->sas_addr.blli; walk; walk = next) { -+ next = walk->next; -+ kfree(walk); -+ } -+ return error; -+} -+ -+ -+static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, -+ int sockaddr_len) -+{ -+ struct sockaddr_atmsvc *addr; -+ struct atm_vcc *vcc; -+ int error; -+ -+ if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; -+ if (sock->state == SS_CONNECTED) return -EISCONN; -+ if (sock->state != SS_UNCONNECTED) return -EINVAL; -+ addr = (struct sockaddr_atmsvc *) sockaddr; -+ if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; -+ vcc = ATM_SD(sock); -+ vcc->flags &= ~ATM_VF_BOUND; /* failing rebind will kill old binding */ -+ /* @@@ check memory (de)allocation on rebind */ -+ if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; -+ error = copy_svc_addr(&vcc->local,addr); -+ if (error) return error; -+ vcc->reply = WAITING; -+ sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); -+ while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); -+ vcc->flags &= ~ATM_VF_REGIS; /* doesn't count */ -+ if (!sigd) return -EUNATCH; /* good code ? @@@ */ -+ if (!vcc->reply) vcc->flags |= ATM_VF_BOUND; -+ return vcc->reply; -+} -+ -+ -+static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, -+ int sockaddr_len,int flags) -+{ -+ struct sockaddr_atmsvc *addr; -+ struct atm_vcc *vcc; -+ int error; -+ -+ DPRINTK("svc_connect\n"); -+ if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; -+ if (sock->state == SS_CONNECTED) return -EISCONN; -+ vcc = ATM_SD(sock); -+ if (sock->state == SS_CONNECTING) { -+ if (vcc->reply == WAITING) return -EALREADY; -+ sock->state = SS_UNCONNECTED; -+ if (vcc->reply) return vcc->reply; -+ } -+ else { -+ if (sock->state != SS_UNCONNECTED) return -EINVAL; -+ addr = (struct sockaddr_atmsvc *) sockaddr; -+ if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; -+ if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; -+ if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || -+ vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) -+ return -EINVAL; -+ if (!vcc->qos.txtp.traffic_class && -+ !vcc->qos.rxtp.traffic_class) return -EINVAL; -+ error = copy_svc_addr(&vcc->remote,addr); -+ if (error) return error; -+ vcc->reply = WAITING; -+ sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); -+ if (flags & O_NONBLOCK) { -+ sock->state = SS_CONNECTING; -+ return -EINPROGRESS; -+ } -+ while (vcc->reply == WAITING && sigd) { -+ interruptible_sleep_on(&vcc->sleep); -+ if (current->signal & ~current->blocked) { -+ DPRINTK("*ABORT*\n"); -+ /* -+ * This is tricky: -+ * Kernel -------close------> Demon -+ * Kernel <-----close(0)----- Demon -+ * or -+ * Kernel -------close------> Demon -+ * Kernel <--close(error)---- Demon -+ * or -+ * Kernel -------close------> Demon -+ * Kernel <------okay-------- Demon -+ * Kernel <-----close(0)----- Demon -+ */ -+ vcc->flags &= ~ATM_VF_RELEASED; -+ sigd_enq(vcc,as_close,NULL,NULL,NULL); -+ while (vcc->reply == WAITING && sigd) -+ sleep_on(&vcc->sleep); -+ if (!vcc->reply) -+ while (!(vcc->flags & ATM_VF_RELEASED) -+ && sigd) sleep_on(&vcc->sleep); -+ vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED); -+ /* we're gone now but may connect later */ -+ return -EINTR; -+ } -+ } -+ if (!sigd) return -EUNATCH; -+ if (vcc->reply) return vcc->reply; -+ } -+/* -+ * Not supported yet -+ * -+ * #ifndef CONFIG_SINGLE_SIGITF -+ */ -+ vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp); -+ vcc->qos.txtp.min_pcr = 0; -+/* -+ * #endif -+ */ -+ if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci))) -+ sock->state = SS_CONNECTED; -+ else (void) svc_disconnect(ATM_SD(sock)); -+ return error; -+} -+ -+ -+static int svc_listen(struct socket *sock,int backlog) -+{ -+ struct atm_vcc *vcc; -+ -+ DPRINTK("svc_listen\n"); -+ /* let server handle listen on unbound sockets */ -+ vcc = ATM_SD(sock); -+ vcc->reply = WAITING; -+ sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); -+ while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); -+ if (!sigd) return -EUNATCH; -+ vcc->flags |= ATM_VF_LISTEN; -+ vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; -+ return vcc->reply; -+} -+ -+ -+static int svc_accept(struct socket *sock,struct socket *newsock,int flags) -+{ -+ struct sk_buff *skb; -+ struct atmsvc_msg *msg; -+ struct atm_vcc *old_vcc,*new_vcc; -+ int error; -+ -+ DPRINTK("svc_accept\n"); -+ old_vcc = ATM_SD(sock); -+ new_vcc = ATM_SD(newsock); -+ while (1) { -+ while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) { -+ if (flags & O_NONBLOCK) return 0; /* not -EAGAIN ? */ -+ interruptible_sleep_on(&old_vcc->sleep); -+ if (current->signal & ~current->blocked) -+ return -ERESTARTSYS; -+ } -+ if (!skb) return -EUNATCH; -+ msg = (struct atmsvc_msg *) skb->data; -+ new_vcc->qos = msg->qos; -+ new_vcc->flags |= ATM_VF_HASQOS; -+ new_vcc->remote = msg->svc; -+ /* copy BLLI @@@ */ -+ new_vcc->remote.sas_addr.blli = NULL; -+ error = atm_connect(newsock,msg->pvc.sap_addr.itf, -+ msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); -+ dev_kfree_skb(skb,FREE_WRITE); -+ old_vcc->backlog_quota++; -+ if (error) { -+ sigd_enq(NULL,as_reject,old_vcc,NULL,NULL); -+ /* @@@ should include the reason */ -+ return error == -EAGAIN ? -EBUSY : error; -+ } -+ /* wait should be short, so we ignore the non-blocking flag */ -+ new_vcc->reply = WAITING; -+ sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); -+ while (new_vcc->reply == WAITING && sigd) -+ sleep_on(&new_vcc->sleep); -+ if (!sigd) { -+ atm_release_vcc(new_vcc,1); -+ return -EUNATCH; -+ } -+ if (!new_vcc->reply) break; -+ if (new_vcc->reply != -ERESTARTSYS) { -+ atm_release_vcc(new_vcc,1); -+ return new_vcc->reply; -+ } -+ } -+ newsock->state = SS_CONNECTED; -+ return 0; -+} -+ -+ -+static int svc_getname(struct socket *sock,struct sockaddr *sockaddr, -+ int *sockaddr_len,int peer) -+{ -+ struct sockaddr_atmsvc *addr; -+ -+ /* this will be fun ... we have: public and private -+ address, bhli and possibly a lot of bllis. Now address buffers -+ are static ... argl */ -+ /* The solution: use pointers to link bllis */ -+ /* naturally, we still need some place to put all those nasty -+ little bllis ... */ -+#if 0 -+ /* sigh ... */ -+ if (*sockaddr_len < sizeof(struct sockaddr_atmsvc)) return -EINVAL; -+#endif -+ *sockaddr_len = sizeof(struct sockaddr_atmsvc); -+ addr = (struct sockaddr_atmsvc *) sockaddr; -+ memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, -+ sizeof(struct sockaddr_atmsvc)); -+ addr->sas_addr.blli = NULL; /* @@@ no - copy it */ -+ return 0; -+} -+ -+ -+static int check_addr(struct sockaddr_atmsvc *addr) -+{ -+ int i; -+ -+ if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; -+ if (!*addr->sas_addr.pub) -+ if (!*addr->sas_addr.prv) return -EINVAL; -+ else return 0; -+ for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's \0-terminated */ -+ if (!addr->sas_addr.pub[i]) return 0; -+ return -EINVAL; -+} -+ -+ -+static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b) -+{ -+ if (*a->sas_addr.prv) -+ if (memcmp(a->sas_addr.prv,b->sas_addr.prv,ATM_ESA_LEN)) -+ return 0; -+ if (!*a->sas_addr.pub) return !*b->sas_addr.pub; -+ if (!*b->sas_addr.pub) return 0; -+ return !strcmp(a->sas_addr.pub,b->sas_addr.pub); -+} -+ -+ -+/* -+ * Avoid modification of any list of local interfaces while reading it -+ * (which may involve page faults and therefore rescheduling) -+ */ -+ -+ -+static volatile int local_lock = 0; -+static struct wait_queue *local_wait = NULL; -+ -+ -+static void lock_local(void) -+{ -+ while (local_lock) sleep_on(&local_wait); -+ local_lock = 1; -+} -+ -+ -+static void unlock_local(void) -+{ -+ local_lock = 0; -+ wake_up(&local_wait); -+} -+ -+ -+static void notify_sigd(struct atm_dev *dev) -+{ -+ struct sockaddr_atmpvc pvc; -+ -+ pvc.sap_addr.itf = dev->number; -+ sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL); -+} -+ -+ -+static void reset_addr(struct atm_dev *dev) -+{ -+ struct atm_dev_addr *this; -+ -+ lock_local(); -+ while (dev->local) { -+ this = dev->local; -+ dev->local = this->next; -+ kfree(this); -+ } -+ unlock_local(); -+ notify_sigd(dev); -+} -+ -+ -+static int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) -+{ -+ struct atm_dev_addr **walk; -+ -+ lock_local(); -+ for (walk = &dev->local; *walk; walk = &(*walk)->next) -+ if (identical(&(*walk)->addr,addr)) { -+ unlock_local(); -+ return -EEXIST; -+ } -+ *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL); -+ if (!*walk) { -+ unlock_local(); -+ return -ENOMEM; -+ } -+ (*walk)->addr = *addr; -+ (*walk)->next = NULL; -+ unlock_local(); -+ notify_sigd(dev); -+ return 0; -+} -+ -+ -+static int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) -+{ -+ struct atm_dev_addr **walk,*this; -+ -+ lock_local(); -+ for (walk = &dev->local; *walk; walk = &(*walk)->next) -+ if (identical(&(*walk)->addr,addr)) break; -+ if (!*walk) { -+ unlock_local(); -+ return -ENOENT; -+ } -+ this = *walk; -+ *walk = this->next; -+ kfree(this); -+ unlock_local(); -+ notify_sigd(dev); -+ return 0; -+} -+ -+ -+static int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *buf,int size) -+{ -+ struct atm_dev_addr *walk; -+ int total; -+ -+ lock_local(); -+ total = 0; -+ for (walk = dev->local; walk; walk = walk->next) { -+ total += sizeof(struct sockaddr_atmsvc); -+ if (total > size) { -+ unlock_local(); -+ return -E2BIG; -+ } -+ memcpy_tofs(buf,&walk->addr,sizeof(struct sockaddr_atmsvc)); -+ buf++; -+ } -+ unlock_local(); -+ return total; -+} -+ -+ -+static int svc_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) -+{ -+ struct atm_dev *dev; -+ void *buf; -+ int rsize,wsize,len; -+ int error; -+ -+ rsize = wsize = 0; -+ switch (cmd) { -+ case ATM_ADDADDR: -+ case ATM_DELADDR: -+ rsize = sizeof(struct sockaddr_atmsvc); -+ case ATM_RSTADDR: -+ if (!suser()) return -EPERM; -+ break; -+ case ATM_GETADDR: -+ wsize = -1; -+ break; -+ default: -+ return atm_ioctl(sock,cmd,arg); -+ } -+ error = verify_area(VERIFY_READ,(void *) arg, -+ sizeof(struct atmif_sioc)); -+ if (error) return error; -+ if (wsize) { -+ error = verify_area(VERIFY_WRITE,(void *) arg, -+ sizeof(struct atmif_sioc)); -+ if (error) return error; -+ } -+ if (!(dev = atm_find_dev(get_fs_long(&((struct atmif_sioc *) arg)-> -+ number)))) return -ENODEV; -+ len = get_fs_long(&((struct atmif_sioc *) arg)->length); -+ buf = (void *) get_fs_long(&((struct atmif_sioc *) arg)->arg); -+ if (!buf && (rsize || wsize)) return -EINVAL; -+ if (rsize > 0) { -+ if (len != rsize) return -EINVAL; -+ error = verify_area(VERIFY_READ,buf,len); -+ if (error) return error; -+ } -+ if (wsize > 0) { -+ if (len != wsize) return -EINVAL; -+ error = verify_area(VERIFY_WRITE,buf,len); -+ if (error) return error; -+ put_fs_long(wsize,&((struct atmif_sioc *) arg)->length); -+ } -+ switch (cmd) { -+ case ATM_RSTADDR: -+ reset_addr(dev); -+ return 0; -+ case ATM_ADDADDR: -+ case ATM_DELADDR: -+ { -+ struct sockaddr_atmsvc addr; -+ -+ memcpy_fromfs(&addr,buf,sizeof(addr)); -+ error = check_addr(&addr); -+ if (error) return error; -+ if (cmd == ATM_ADDADDR) -+ return add_addr(dev,&addr); -+ else return del_addr(dev,&addr); -+ } -+ case ATM_GETADDR: -+ error = get_addr(dev,buf,len); -+ if (error < 0) return error; -+ put_fs_long(error, -+ &((struct atmif_sioc *) arg)->length); -+ return error; -+ } -+ return -EINVAL; /* actually, we're in trouble if we end up here ... */ -+} -+ -+ -+static int svc_setsockopt(struct socket *sock,int level,int optname, -+ char *optval,int optlen) -+{ -+ int error; -+ -+ error = verify_area(VERIFY_READ,optval,optlen); -+ if (error) return -EINVAL; -+ /* stuff for SVCs */ -+ return atm_setsockopt(sock,level,optname,optval,optlen); -+} -+ -+ -+static int svc_getsockopt(struct socket *sock,int level,int optname, -+ char *optval,int *optlen) -+{ -+ /* stuff for SVCs */ -+ return atm_getsockopt(sock,level,optname,optval,optlen); -+} -+ -+ -+static struct proto_ops svc_proto_ops = { -+ PF_ATMSVC, -+ svc_create, -+ svc_dup, -+ svc_release, -+ svc_bind, -+ svc_connect, -+ NULL, /* no socketpair */ -+ svc_accept, -+ svc_getname, -+ atm_select, -+ svc_ioctl, -+ svc_listen, -+ svc_shutdown, -+ svc_setsockopt, -+ svc_getsockopt, -+ NULL, /* no fcntl */ -+ atm_sendmsg, -+ atm_recvmsg -+}; -+ -+ -+/* -+ * Initialize the ATM SVC protocol family -+ */ -+ -+void atmsvc_proto_init(struct net_proto *pro) -+{ -+ if (sock_register(svc_proto_ops.family,&svc_proto_ops) < 0) { -+ printk(KERN_ERR "ATMSVC: can't register"); -+ return; -+ } -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/signaling.c Tue Mar 11 20:04:09 1997 -@@ -0,0 +1,217 @@ -+/* net/atm/signaling.c - ATM signaling */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include /* error codes */ -+#include /* printk, suser */ -+#include -+#include -+#include /* jiffies and HZ */ -+#include /* ATM stuff */ -+#include -+#include -+#include -+ -+#include "tunable.h" -+#include "static.h" -+#include "signaling.h" -+ -+ -+#undef WAIT_FOR_DEMON /* #define this if system calls on SVC sockets -+ should block until the demon runs. -+ Danger: may cause nasty hangs if the demon -+ crashes. */ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+struct atm_vcc *sigd = NULL; -+static struct wait_queue *sigd_sleep = NULL; -+ -+ -+static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+ struct atmsvc_msg *msg; -+ -+ msg = (struct atmsvc_msg *) skb->data; -+ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); -+ DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,msg->vcc); -+ vcc = (struct atm_vcc *) msg->vcc; -+ switch (msg->type) { -+ case as_okay: -+ vcc->reply = msg->reply; -+ if (!*vcc->local.sas_addr.prv && -+ !*vcc->local.sas_addr.pub) { -+ vcc->local.sas_family = AF_ATMSVC; -+ memcpy(vcc->local.sas_addr.prv, -+ msg->local.sas_addr.prv,ATM_ESA_LEN); -+ memcpy(vcc->local.sas_addr.pub, -+ msg->local.sas_addr.pub,ATM_E164_LEN+1); -+ } -+ if (vcc->vpi || vcc->vci) break; -+ vcc->itf = msg->pvc.sap_addr.itf; -+ vcc->vpi = msg->pvc.sap_addr.vpi; -+ vcc->vci = msg->pvc.sap_addr.vci; -+ if (vcc->vpi || vcc->vci) vcc->qos = msg->qos; -+ break; -+ case as_error: -+ vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_READY); -+ vcc->reply = msg->reply; -+ break; -+ case as_indicate: -+ vcc = (struct atm_vcc *) msg->listen_vcc; -+ DPRINTK("as_indicate!!!\n"); -+ if (!vcc->backlog_quota) { -+ sigd_enq(0,as_reject,(struct atm_vcc *) -+ msg->listen_vcc,NULL,NULL); -+ return 0; -+ } -+ vcc->backlog_quota--; -+ skb_queue_tail(&vcc->listenq,skb); -+ if (vcc->callback) { -+ DPRINTK("waking vcc->sleep 0x%p\n", -+ &vcc->sleep); -+ vcc->callback(vcc); -+ } -+ return 0; -+ case as_close: -+ vcc->flags |= ATM_VF_RELEASED; -+ vcc->flags &= ~ATM_VF_READY; -+ vcc->reply = msg->reply; -+ break; -+ default: -+ printk(KERN_ALERT "sigd_send: bad message type %d\n", -+ (int) msg->type); -+ return -EINVAL; -+ } -+ if (vcc->callback) vcc->callback(vcc); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return 0; -+} -+ -+ -+void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, -+ const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, -+ const struct sockaddr_atmsvc *svc) -+{ -+ struct sk_buff *skb; -+ struct atmsvc_msg *msg; -+ struct atm_blli *walk; -+ int size,i; -+#ifdef WAIT_FOR_DEMON -+ static unsigned long silence = 0; -+#endif -+ -+ DPRINTK("sigd_enq %d (0x%p)\n",(int) type,vcc); -+ size = sizeof(struct atmsvc_msg)-sizeof(struct atm_blli); -+ if (svc) -+ for (walk = svc->sas_addr.blli; walk; walk = walk->next) -+ size += sizeof(struct atm_blli); -+ while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); -+ skb->free = 1; -+ skb->len = size; -+ msg = (struct atmsvc_msg *) skb->data; -+ msg->type = type; -+ msg->vcc = (unsigned long) vcc; -+ msg->listen_vcc = (unsigned long) listen_vcc; -+ if (vcc) { -+ msg->qos = vcc->qos; -+ if (!msg->qos.aal) msg->qos.aal = vcc->aal; -+ } -+ if (!svc) msg->svc.sas_family = 0; -+ else { -+ msg->svc = *svc; -+ i = 0; -+ for (walk = svc->sas_addr.blli; walk; walk = walk->next) -+ msg->blli[i++] = *walk; -+ } -+ if (vcc) msg->local = vcc->local; -+ if (!pvc) memset(&msg->pvc,0,sizeof(msg->pvc)); -+ else msg->pvc = *pvc; -+ while (!sigd) { -+#ifdef WAIT_FOR_DEMON -+ if (silence < jiffies) { -+ printk(KERN_INFO "atmsvc: waiting for signaling demon " -+ "...\n"); -+ silence = jiffies+30*HZ; -+ } -+ sleep_on(&sigd_sleep); -+#else -+ printk(KERN_WARNING "atmsvc: no signaling demon\n"); -+ kfree_skb(skb,FREE_READ); -+ return; -+#endif -+ } -+ atomic_add(skb->truesize+ATM_PDU_OVHD,&sigd->rx_inuse); -+ skb_queue_tail(&sigd->recvq,skb); -+ wake_up(&sigd->sleep); -+ if (vcc) vcc->flags |= ATM_VF_REGIS; -+} -+ -+ -+static void trigger(struct atm_vcc *vcc) -+{ -+ if (vcc->family == PF_ATMSVC && !(vcc->flags & ATM_VF_META)) { -+ vcc->flags |= ATM_VF_RELEASED; -+ vcc->reply = -EUNATCH; -+ wake_up(&vcc->sleep); -+ } -+} -+ -+ -+static void sigd_close(struct atm_vcc *vcc) -+{ -+ struct sk_buff *skb; -+ -+ DPRINTK("sigd_close\n"); -+ sigd = NULL; -+ if (skb_peek(&vcc->recvq)) -+ printk(KERN_ERR "sigd_close: closing with requests pending\n"); -+ while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb,FREE_READ); -+ for_all_vccs(trigger); -+} -+ -+ -+static struct atmdev_ops sigd_dev_ops = { -+ NULL, /* no open */ -+ sigd_close, /* close */ -+ NULL, /* no ioctl */ -+ NULL, /* no getsockopt */ -+ NULL, /* no setsockopt */ -+ sigd_send, /* send */ -+ NULL, /* no sg_send */ -+ NULL, /* no poll */ -+ NULL, /* no phy_put */ -+ NULL, /* no phy_get */ -+ NULL /* no feedback */ -+}; -+ -+ -+static struct atm_dev sigd_dev = { -+ &sigd_dev_ops, -+ NULL, /* no PHY */ -+ "sig", /* type */ -+ 999, /* dummy device number */ -+ NULL,NULL, /* pretend not to have any VCCs */ -+ NULL,NULL, /* no data */ -+ 0, /* no flags */ -+ NULL, /* no local address */ -+ { 0 } /* no ESI, no statistics */ -+}; -+ -+ -+int sigd_attach(struct atm_vcc *vcc) -+{ -+ if (sigd) return -EADDRINUSE; -+ DPRINTK("sigd_attach\n"); -+ sigd = vcc; -+ vcc->dev = &sigd_dev; -+ vcc->flags |= ATM_VF_READY | ATM_VF_META; -+ wake_up(&sigd_sleep); -+ return 0; -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/signaling.h Wed Apr 2 22:38:55 1997 -@@ -0,0 +1,25 @@ -+/* net/atm/signaling.h - ATM signaling */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef NET_ATM_SIGNALING_H -+#define NET_ATM_SIGNALING_H -+ -+#include -+#include -+#include -+ -+ -+#define WAITING 1 /* for reply: 0: no error, < 0: error, ... */ -+ -+ -+extern struct atm_vcc *sigd; /* needed in svc_release */ -+ -+ -+void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, -+ const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, -+ const struct sockaddr_atmsvc *svc); -+int sigd_attach(struct atm_vcc *vcc); -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/atmarp.c Wed Apr 16 16:31:04 1997 -@@ -0,0 +1,635 @@ -+/* atmarp.c - RFC1577 ATM ARP */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include /* for UINT_MAX */ -+#include -+#include -+#include -+#include -+#include /* for some manifest constants */ -+#include -+#include -+#include -+#include -+#include -+#include /* for net/route.h */ -+#include /* for struct sockaddr_in */ -+#include /* for IFF_UP */ -+#include /* for struct rtable and ip_rt_route */ -+#include /* for HZ */ -+#include /* for htons etc. */ -+#include /* save/restore_flags */ -+ -+ -+#include "common.h" -+#include "tunable.h" -+#include "protocols.h" /* for atm_push_raw */ -+#include "ipcommon.h" -+#include "atmarp.h" -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+/* -+ * Relation between address/subddress and private/public address: -+ * -+ * Caller Called Address Subaddress -+ * ----------- ----------------------- -------------- ---------- -+ * private same private net private - -+ * public-only private via public public (E.164) private -+ * private net public UNI public (NSAP) - -+ * -+ * See also: ATM Forum UNI 3.0 (or 3.1), Annex A -+ */ -+ -+ -+struct device *clip_devs = NULL; -+struct atm_vcc *atmarpd = NULL; -+static struct wait_queue *atmarpd_sleep = NULL; -+static struct timer_list idle_timer = { NULL, NULL, 0L, 0L, NULL }; -+static int start_timer = 1; -+ -+ -+#define WAITING 1 /* see also signaling.h */ -+ -+ -+static int atmarpd_send(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+ struct atmarp_ctrl *ctrl; -+ -+ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); -+ ctrl = (struct atmarp_ctrl *) skb->data; -+ if (ctrl->magic != ATMARP_CTRL_MAGIC) { -+ printk(KERN_ALERT "atmarpd_send: bad magic 0x%x\n", -+ ctrl->magic); -+ return -EPROTO; -+ } -+ if (ctrl->type != act_complete) { -+ printk(KERN_ALERT "atmarpd_send: bad type 0x%x\n",ctrl->type); -+ return -EPROTO; -+ } -+ if (!ctrl->reply) { -+ printk(KERN_ALERT "atmarpd_send: no reply\n"); -+ return -EPROTO; -+ } -+ *ctrl->reply = ctrl->arg; -+ wake_up(&atmarpd_sleep); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return 0; -+} -+ -+ -+static int send_demon(enum atmarp_ctrl_type type,int itf,unsigned long arg, -+ void *data,int length) -+{ -+ struct atmarp_ctrl *ctrl; -+ struct sk_buff *skb; -+ int size,need_reply; -+ volatile int reply; -+ -+ DPRINTK("send_demon(%d)\n",type); -+ if (!atmarpd) return -EUNATCH; -+ size = sizeof(struct atmarp_ctrl)+(data ? length : 0); -+ skb = alloc_skb(size,GFP_ATOMIC); -+ if (!skb) return -ENOMEM; -+ skb->free = 1; -+ skb->len = size; -+ need_reply = type == act_ioctl || type == act_create; -+ ctrl = (struct atmarp_ctrl *) skb->data; -+ ctrl->magic = ATMARP_CTRL_MAGIC; -+ ctrl->type = type; -+ ctrl->reply = need_reply ? &reply : NULL; -+ ctrl->itf_num = itf; -+ ctrl->arg = arg; -+ if (data) memcpy(ctrl->data,data,length); -+ reply = WAITING; -+ atomic_add(skb->truesize+ATM_PDU_OVHD,&atmarpd->rx_inuse); -+ skb_queue_tail(&atmarpd->recvq,skb); -+ wake_up(&atmarpd->sleep); -+ if (!need_reply) return 0; -+ while (reply == WAITING && atmarpd) sleep_on(&atmarpd_sleep); -+ return atmarpd ? reply : -EUNATCH; -+} -+ -+ -+static void remove(struct atmarp_entry *entry) -+{ -+ struct atmarp_entry **walk; -+ -+ for (walk = &PRIV(entry->dev)->table; *walk; walk = &(*walk)->next) -+ if (*walk == entry) { -+ *walk = entry->next; /* atomic */ -+ return; -+ } -+ printk(KERN_CRIT "ATMARP: remove failed (0x%08lx)\n", -+ (unsigned long) entry); -+} -+ -+ -+static inline int time_out_entry(struct atmarp_entry **entry) -+{ -+ struct atmarp_entry *next; -+ -+ DPRINTK("VC TIMED OUT\n"); -+ if ((*entry)->vcc) { -+ (*entry)->vcc->flags |= ATM_VF_RELEASED; -+ (*entry)->vcc->flags &= ~ATM_VF_READY; -+ wake_up(&(*entry)->vcc->sleep); -+ return 0; -+ } -+ if ((*entry)->queued) { -+ dev_kfree_skb((*entry)->queued,FREE_WRITE); -+ DPRINTK("discarding queued skb\n"); -+ } -+ else printk(KERN_CRIT "atmarp: weird - incomplete entry, but " -+ "nothing queued\n"); -+ next = (*entry)->next; -+ kfree(*entry); -+ *entry = next; -+ return 1; -+} -+ -+ -+static void idle_timer_check(unsigned long dummy) -+{ -+ struct device *itf; -+ struct atmarp_entry **entry; -+ unsigned long expire; -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ idle_timer.expires = UINT_MAX; -+ for (itf = clip_devs; itf; itf = PRIV(itf)->next) { -+ entry = &PRIV(itf)->table; -+ while (*entry) { -+ if ((*entry)->idle_timeout) { -+ expire = (*entry)->last_use+(*entry)-> -+ idle_timeout; -+ if (expire < jiffies) { -+ if (time_out_entry(entry)) continue; -+ } -+ else if (expire < idle_timer.expires) -+ idle_timer.expires = expire; -+ } -+ entry = &(*entry)->next; -+ } -+ } -+ if (idle_timer.expires < jiffies+CLIP_CHECK_INTERVAL*HZ) -+ idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ; -+ del_timer(&idle_timer); -+ add_timer(&idle_timer); -+ restore_flags(flags); -+} -+ -+ -+static void atm_push_ip(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+#if 0 -+ DPRINTK("clip push\n"); -+#endif -+ if (!skb) { -+ DPRINTK("removing AE\n"); -+ AE(vcc)->old_push(vcc,NULL); -+ if (AE(vcc)->ip) remove(AE(vcc)); -+ kfree(AE(vcc)); -+ return; -+ } -+ AE(vcc)->last_use = jiffies; -+ skb->dev = AE(vcc)->dev; -+ skb->mac.raw = skb->data; -+ if (!skb->dev->hard_header_len) skb->protocol = htons(ETH_P_IP); -+ else if (skb->len < RFC1483LLC_LEN || memcmp(skb->data,llc_oui, -+ sizeof(llc_oui))) skb->protocol = 0; -+ /* probably wrong encap ... */ -+ else { -+ skb->protocol = ((unsigned short *) skb->data)[3]; -+ skb_pull(skb,RFC1483LLC_LEN); -+ if (vcc && skb->protocol == htons(ETH_P_ARP)) { -+ PRIV(skb->dev)->stats.rx_packets++; -+ atm_push_raw(vcc,skb); -+ return; -+ } -+ } -+ PRIV(skb->dev)->stats.rx_packets++; -+ netif_rx(skb); -+} -+ -+ -+static struct atmarp_entry *new_entry(int timeout) -+{ -+ struct atmarp_entry *entry; -+ -+ entry = kmalloc(sizeof(struct atmarp_entry),GFP_ATOMIC); -+ if (!entry) return NULL; -+ entry->ip = 0; -+ entry->vcc = NULL; -+ entry->encap = 1; -+ entry->dev = clip_devs; -+ entry->old_push = NULL; -+ entry->last_use = jiffies; -+ entry->idle_timeout = timeout*HZ; -+ entry->queued = NULL; -+ entry->next = NULL; -+ return entry; -+} -+ -+ -+static void attach_entry(struct atm_vcc *vcc,struct atmarp_entry *entry) -+{ -+ struct sk_buff_head copy; -+ struct sk_buff *skb; -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ AE(vcc) = entry; -+ entry->old_push = vcc->push; -+ vcc->push = atm_push_ip; -+ entry->vcc = vcc; -+ skb_migrate(&vcc->recvq,©); -+ vcc->rx_inuse = 0; -+ restore_flags(flags); -+ /* re-process everything received between connection setup and MKIP */ -+ while ((skb = skb_dequeue(©))) atm_push_ip(vcc,skb); -+} -+ -+ -+static int clip_hard_header(struct sk_buff *skb,struct device *dev, -+ unsigned short type,void *daddr,void *saddr,unsigned len) -+{ -+ void *here; -+ -+ here = skb_push(skb,dev->hard_header_len); -+ memcpy(here,llc_oui,sizeof(llc_oui)); -+ ((unsigned short *) here)[3] = htons(type); -+ skb->atm.encap = 1; -+ return -RFC1483LLC_LEN; -+} -+ -+ -+static int clip_rebuild_header(void *buff,struct device *dev,unsigned long dst, -+ struct sk_buff *skb) -+{ -+#if 0 -+ void *here; -+ -+ here = skb->data; /*skb_push(skb,dev->hard_header_len);*/ -+ memcpy(here,llc_oui,sizeof(llc_oui)); -+ ((unsigned short *) here)[3] = htons(ETH_P_IP); -+#endif -+ return 0; -+} -+ -+ -+static int clip_xmit(struct sk_buff *skb,struct device *dev) -+{ -+ struct atmarp_entry *entry; -+ -+#if 0 -+ int i; -+ DPRINTK("new clip_xmit (0x%x)\n",skb->raddr); -+/*(int *) 0xffff0000 = 42;*/ -+for (i = 0; i < skb->len; i++) printk("%02X ",skb->data[i]); -+printk("\n"); -+#endif -+ for (entry = PRIV(dev)->table; entry; entry = entry->next) -+ if (entry->ip == skb->raddr) break; -+ if (!entry) { -+ DPRINTK("no entry - queuing\n"); -+ send_demon(act_need,PRIV(dev)->number,skb->raddr,NULL,0); -+ entry = new_entry(ATMARP_RETRY_DELAY); -+ entry->queued = skb; -+ entry->ip = skb->raddr; -+ entry->next = PRIV(dev)->table; -+ PRIV(dev)->table = entry; -+ idle_timer_check(0); -+ /* this new entry may have the soonest timeout, so we need -+ to re-compute the expiration interval. Expired entries -+ may be timed out as a side-effect. */ -+ return 0; -+ } -+ if (!entry->vcc || !(entry->vcc->flags & ATM_VF_READY)) { -+ DPRINTK("not found - discarding\n"); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return 0; -+ /* Should return -EHOSTUNREACH, but then it will retry -+ forever, so we just discard the packet. */ -+ } -+ if (!entry->encap) { -+ if (skb->atm.encap) { -+ skb_pull(skb,RFC1483LLC_LEN); -+ skb->atm.encap = 0; -+ } -+ } -+ else { -+ memcpy((void *) skb->data,llc_oui,sizeof(llc_oui)); -+ ((unsigned short *) skb->data)[3] = htons(ETH_P_IP); -+ } -+ DPRINTK("CX(A) %d += %d\n",entry->vcc->tx_inuse,skb->truesize); -+ atomic_add(skb->truesize,&entry->vcc->tx_inuse); -+ skb->atm.iovcnt = 0; -+ AE(entry->vcc)->last_use = jiffies; -+ entry->vcc->dev->ops->send(entry->vcc,skb); -+ PRIV(dev)->stats.tx_packets++; -+ return 0; -+} -+ -+ -+static struct enet_statistics *atm_clip_get_stats(struct device *dev) -+{ -+ return &PRIV(dev)->stats; -+} -+ -+ -+int atmarp_mkip(struct atm_vcc *vcc,int timeout) -+{ -+ struct atmarp_entry *entry; -+ -+ DPRINTK("MKIP\n"); -+ if (!vcc->push) return -EBADFD; -+ entry = new_entry(timeout); -+ if (!entry) return -ENOMEM; -+ attach_entry(vcc,entry); -+ return 0; -+} -+ -+ -+int atmarp_setentry(struct atm_vcc *vcc,unsigned long ip) -+{ -+ struct atmarp_entry **walk,**next,*succ; -+ struct rtable *route; -+ struct sk_buff *queued; -+ unsigned long flags; -+ -+ DPRINTK("SETENTRY 0x%lx\n",ip); -+ if (vcc->push != atm_push_ip) { -+ printk(KERN_WARNING "atmarp_setentry: VCC has no ARP entry\n"); -+ return -EBADF; -+ } -+ if (!ip) { -+ if (!AE(vcc)->ip) { -+ printk(KERN_ERR "hiding hidden ATMARP entry\n"); -+ return 0; -+ } -+ DPRINTK("setentry: remove\n"); -+ remove(AE(vcc)); -+ AE(vcc)->ip = 0; -+ return 0; -+ } -+ DPRINTK("setentry: route\n"); -+ route = ip_rt_route(ip,1); -+ if (!route) return -EHOSTUNREACH; -+ AE(vcc)->dev = route->rt_dev; -+ if (AE(vcc)->ip) { -+ DPRINTK("setentry: update\n"); -+ DPRINTK("(updating)\n"); -+ AE(vcc)->ip = ip; -+ return 0; -+ } -+ DPRINTK("setentry: add\n"); -+ save_flags(flags); -+ cli(); -+ queued = NULL; -+ for (walk = &PRIV(AE(vcc)->dev)->table; *walk; walk = next) { -+ next = &(*walk)->next; -+ if ((*walk)->ip == ip) { -+ if ((*walk)->vcc) continue; -+ /* more than one VC to dest */ -+ if ((*walk)->queued) { -+ DPRINTK("setentry: flushing\n"); -+ if (queued) -+ printk(KERN_CRIT "atmarp: bad news - " -+ "more than one skb queued\n"); -+ queued = (*walk)->queued; -+ /* -+ * We don't need to reset ->queued to NULL now, -+ * because in all cases, where ->queued is used, -+ * ->vcc is tested first. -+ */ -+ } -+ succ = (*walk)->next; -+ kfree(*walk); -+ *walk = succ; -+ next = walk; -+ } -+ } -+ DPRINTK("(adding)\n"); -+ AE(vcc)->ip = ip; -+ AE(vcc)->next = PRIV(AE(vcc)->dev)->table; -+ PRIV(AE(vcc)->dev)->table = AE(vcc); -+ restore_flags(flags); -+ if (queued) clip_xmit(queued,route->rt_dev); -+ idle_timer_check(0); -+ return 0; -+} -+ -+ -+int atmarp_encap(struct atm_vcc *vcc,int mode) -+{ -+ AE(vcc)->encap = mode; -+ return 0; -+} -+ -+ -+static int atmarp_ioctl(struct device *dev,unsigned int cmd,void *arg) -+{ -+ struct atmarpreq req; -+ __u32 *ip; -+ int error; -+ -+ DPRINTK("atmarp_ioctl\n"); -+ error = verify_area(VERIFY_READ,arg,sizeof(struct atmarpreq)); -+ if (error) return error; -+ memcpy_fromfs(&req,arg,sizeof(struct atmarpreq)); -+ if (req.arp_pa.sa_family != AF_INET) return -EPFNOSUPPORT; -+ ip = &((struct sockaddr_in *) &req.arp_pa)->sin_addr.s_addr; -+ if (!(*ip & ~dev->pa_mask) && !(req.arp_flags & (ATF_ARPSRV | -+ ATF_DEFQOS))) -+ return -EINVAL; -+ switch (cmd) { -+ case SIOCSARP: -+ case SIOCDARP: -+ case SIOCGARP: -+ return send_demon(act_ioctl,PRIV(dev)->number,cmd,&req, -+ sizeof(struct atmarpreq)); -+ /* @@@ get will need special treatment */ -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+ -+static int clip_open(struct device *dev) -+{ -+ DPRINTK("clip_open called\n"); -+ return 0; -+} -+ -+ -+static int clip_stop(struct device *dev) -+{ -+ DPRINTK("clip_stop\n"); -+ /* @@@ just kill it on error ? */ -+ return 0; -+} -+ -+ -+static int clip_init(struct device *dev) -+{ -+ DPRINTK("init %s\n",dev->name); -+ dev->hard_start_xmit = clip_xmit; -+ /* sg_xmit ... */ -+ dev->open = clip_open; -+ dev->stop = clip_stop; -+ ether_setup(dev); -+ dev->tbusy = 0; /* @@@ check */ -+ dev->hard_header = clip_hard_header; -+ dev->do_ioctl = NULL; -+ dev->change_mtu = NULL; -+ dev->ip_arp = atmarp_ioctl; -+ dev->rebuild_header = clip_rebuild_header; -+ dev->get_stats = atm_clip_get_stats; -+ dev->hard_header_len = RFC1483LLC_LEN; -+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); -+ dev->flags |= IFF_NOARP; /* we do our own ARP ... */ -+ dev->mtu = RFC1626_MTU; -+ return send_demon(act_create,PRIV(dev)->number,0,NULL,0); -+} -+ -+ -+int clip_create(int number) /* remove by downing */ -+{ -+ struct device *dev; -+ -+ number = ipcom_pick_number(number); -+ if (number < 0) return number; -+ dev = kmalloc(sizeof(struct device)+sizeof(struct atmarp_priv), -+ GFP_KERNEL); -+ if (!dev) return -ENOMEM; -+ memset(dev,0,sizeof(struct device)+sizeof(struct atmarp_priv)); -+ dev->name = PRIV(dev)->name; -+ sprintf(dev->name,"atm%d",number); -+ dev->init = clip_init; -+ PRIV(dev)->number = number; -+ PRIV(dev)->table = NULL; -+ if (register_netdev(dev)) return -EIO; /* free dev ? */ -+ PRIV(dev)->next = clip_devs; -+ clip_devs = dev; -+ DPRINTK("registered (net:%s)\n",dev->name); -+ return number; -+} -+ -+ -+static int clip_device_event(struct notifier_block *this,unsigned long event, -+ void *dev) -+{ -+ /* ignore non-CLIP devices */ -+ if (((struct device *) dev)->init != clip_init) return NOTIFY_DONE; -+ switch (event) { -+ case NETDEV_UP: -+ (void) send_demon(act_up,PRIV(dev)->number,0,NULL,0); -+ break; -+ case NETDEV_DOWN: -+ DPRINTK("clip_device_event NETDEV_DOWN\n"); -+ (void) send_demon(act_down,PRIV(dev)->number,0,NULL,0); -+ break; -+ case NETDEV_REBOOT: -+ /* ignore */ -+ break; -+ default: -+ printk(KERN_ERR "clip_device_event: unknown event " -+ "%ld\n",event); -+ break; -+ } -+ return NOTIFY_DONE; -+} -+ -+ -+static struct notifier_block clip_dev_notifier = { -+ clip_device_event, -+ NULL, -+ 0 -+}; -+ -+ -+static void atmarpd_close(struct atm_vcc *vcc) -+{ -+ struct sk_buff *skb; -+ -+ DPRINTK("atmarpd_close\n"); -+ atmarpd = NULL; /* assumed to be atomic */ -+ barrier(); -+ unregister_netdevice_notifier(&clip_dev_notifier); -+ wake_up(&atmarpd_sleep); -+ if (skb_peek(&vcc->recvq)) -+ printk(KERN_ERR "atmarpd_close: closing with requests " -+ "pending\n"); -+ while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb,FREE_READ); -+ DPRINTK("(done)\n"); -+} -+ -+ -+static struct atmdev_ops atmarpd_dev_ops = { -+ NULL, /* no open */ -+ atmarpd_close, /* close */ -+ NULL, /* no ioctl */ -+ NULL, /* no getsockopt */ -+ NULL, /* no setsockopt */ -+ atmarpd_send, /* send */ -+ NULL, /* no sg_send */ -+ NULL, /* no poll */ -+ NULL, /* no phy_put */ -+ NULL, /* no phy_get */ -+ NULL /* no feedback */ -+}; -+ -+static struct atm_dev atmarpd_dev = { -+ &atmarpd_dev_ops, -+ NULL, /* no PHY */ -+ "arpd", /* type */ -+ 999, /* dummy device number */ -+ NULL,NULL, /* pretend not to have any VCCs */ -+ NULL,NULL, /* no data */ -+ 0, /* no flags */ -+ NULL, /* no local address */ -+ { 0 } /* no ESI, no statistics */ -+}; -+ -+ -+int atm_init_atmarp(struct atm_vcc *vcc) -+{ -+ struct device *dev; -+ -+ if (atmarpd) return -EADDRINUSE; -+ if (start_timer) { -+ start_timer = 0; -+ idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ; -+ idle_timer.function = idle_timer_check; -+ add_timer(&idle_timer); -+ } -+ atmarpd = vcc; -+ vcc->flags |= ATM_VF_READY | ATM_VF_META; -+ /* allow replies and avoid getting closed if signaling dies */ -+ vcc->dev = &atmarpd_dev; -+ vcc->aal = ATM_AAL5; /* lie */ -+ vcc->push = NULL; -+ vcc->peek = NULL; /* crash */ -+ vcc->pop = NULL; /* crash */ -+ vcc->push_oam = NULL; /* crash */ -+ register_netdevice_notifier(&clip_dev_notifier); -+ for (dev = clip_devs; dev; dev = PRIV(dev)->next) -+ if (dev->flags & IFF_UP) -+ (void) send_demon(act_up,PRIV(dev)->number,0,NULL,0); -+ return 0; -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/atmarp.h Wed Apr 2 22:38:55 1997 -@@ -0,0 +1,53 @@ -+/* net/atm/atmarp.h - RFC1577 ATM ARP */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef NET_ATM_ATMARP_H -+#define NET_ATM_ATMARP_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define PRIV(dev) ((struct atmarp_priv *) ((struct device *) (dev)+1)) -+#define AE(vcc) ((struct atmarp_entry *) (vcc->user_back)) -+ -+ -+struct atmarp_entry { -+ unsigned long ip; /* IP address, 0 if none */ -+ struct atm_vcc *vcc; /* active VCC */ -+ unsigned char encap; /* 0: NULL, 1: LLC/SNAP */ -+ struct device *dev; /* device back pointer */ -+ void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); -+ /* keep old push fn for detaching */ -+ unsigned long last_use; /* last send or receive operation */ -+ unsigned long idle_timeout; /* keep open idle for so many jiffies*/ -+ struct sk_buff *queued; /* queue one skb when resolving */ -+ struct atmarp_entry *next; /* ugly linked list ... */ -+}; -+ -+/* Entry is PVC iff vcc && vcc->family == AF_ATMPVC */ -+ -+ -+struct atmarp_priv { -+ struct atmarp_entry *table; /* ARP table */ -+ char name[8]; /* interface name */ -+ int number; /* for convenience ... */ -+ struct enet_statistics stats; -+ struct device *next; /* next CLIP interface */ -+}; -+ -+ -+extern struct atm_vcc *atmarpd; /* ugly */ -+ -+ -+int clip_create(int number); -+int atmarp_mkip(struct atm_vcc *vcc,int timeout); -+int atmarp_setentry(struct atm_vcc *vcc,unsigned long ip); -+int atmarp_encap(struct atm_vcc *vcc,int mode); -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/ipcommon.h Wed Apr 16 16:40:30 1997 -@@ -0,0 +1,74 @@ -+/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ -+ -+/* Written 1996,1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef NET_ATM_IPCOMMON_H -+#define NET_ATM_IPCOMMON_H -+ -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+extern const unsigned char llc_oui[6]; -+extern struct device *clip_devs; -+ -+ -+#define CLIP(dev) ((struct clip_priv *) ((struct device *) (dev)+1)) -+ -+ -+struct clip_priv { -+ char name[8]; /* interface name */ -+ int number; /* for convenience ... */ -+ struct atm_vcc *vcc; -+ struct enet_statistics stats; -+ struct clip_priv *next; /* next CLIP interface */ -+}; -+ -+ -+extern struct clip_priv *old_clip_devs; -+ -+ -+static inline void ipcom_push(struct sk_buff *skb) -+{ -+ skb->mac.raw = skb->data; -+ if (!skb->dev->hard_header_len) skb->protocol = htons(ETH_P_IP); -+ else if (skb->len < RFC1483LLC_LEN || memcmp(skb->data,llc_oui, -+ sizeof(llc_oui))) skb->protocol = 0; -+ /* probably wrong encap ... */ -+ else { -+ skb->protocol = ((unsigned short *) skb->data)[3]; -+ skb_pull(skb,RFC1483LLC_LEN); -+ } -+ CLIP(skb->dev)->stats.rx_packets++; -+ netif_rx(skb); -+} -+ -+ -+static inline void ipcom_xmit(struct device *dev,struct atm_vcc *vcc, -+ struct sk_buff *skb) -+{ -+ if (dev->hard_header_len) { -+ memcpy(skb->data,llc_oui,sizeof(llc_oui)); -+ ((unsigned short *) skb->data)[3] = htons(ETH_P_IP); /* hack */ -+ } -+ atomic_add(skb->truesize,&vcc->tx_inuse); -+ skb->atm.iovcnt = 0; -+ vcc->dev->ops->send(vcc,skb); -+} -+ -+ -+struct sk_buff *atm_peek_clip(struct atm_vcc *vcc,unsigned long pdu_size, -+ __u32 (*fetch)(struct atm_vcc *vcc,int i)); -+void atm_pop_clip(struct atm_vcc *vcc,struct sk_buff *skb); -+void ipcom_init(struct device *dev, -+ int (*hard_start_xmit)(struct sk_buff *skb,struct device *dev), -+ unsigned short extra_flags); -+int ipcom_pick_number(int number); -+void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to); -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/ipcommon.c Tue Apr 22 15:21:04 1997 -@@ -0,0 +1,234 @@ -+/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */ -+ -+/* Written 1996,1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "ipcommon.h" -+#include "atmarp.h" -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+const unsigned char llc_oui[] = { -+ 0xaa, /* DSAP: non-ISO */ -+ 0xaa, /* SSAP: non-ISO */ -+ 0x03, /* Ctrl: Unnumbered Information Command PDU */ -+ 0x00, /* OUI: EtherType */ -+ 0x00, -+ 0x00 }; -+ -+ -+static int clip_hard_header(struct sk_buff *skb,struct device *dev, -+ unsigned short type,void *daddr,void *saddr,unsigned len) -+{ -+ void *here; -+ -+ if (!dev->hard_header_len) return 0; /* just in case ... */ -+ here = skb_push(skb,dev->hard_header_len); -+ memcpy(here,llc_oui,sizeof(llc_oui)); -+ ((unsigned short *) here)[3] = htons(type); -+ return -RFC1483LLC_LEN; -+} -+ -+ -+static int clip_rebuild_header(void *buff,struct device *dev,unsigned long dst, -+ struct sk_buff *skb) -+{ -+ /* no ARP with this type of IP over ATM */ -+ return 0; -+} -+ -+ -+struct sk_buff *atm_peek_clip(struct atm_vcc *vcc,unsigned long pdu_size, -+ __u32 (*fetch)(struct atm_vcc *vcc,int i)) -+{ -+ struct sk_buff *skb; -+ int header_size; -+ -+ /* TODO: check against buffer quota (should even check against upper -+ layer protocol socket quota) */ -+ header_size = 0; -+ if (fetch && pdu_size > 28) { /* > IP+UDP header */ -+ unsigned long type; -+ -+/* doesn't work yet */ -+type = ntohl(fetch(vcc,2)); -+/*printk("type is 0x%08lx\n",type);*/ -+ type = ntohl(fetch(vcc,2)) & 0xff0000; -+ if (type == IPPROTO_UDP << 8) header_size = 28; /* bytes */ -+ else if (type == IPPROTO_TCP << 8) header_size = 40; /* bytes */ -+ } -+ if (!header_size) skb = alloc_skb((pdu_size+3) & ~3,GFP_ATOMIC); -+ else { -+ skb = alloc_skb(((pdu_size+3) & ~3)+PAGE_SIZE+header_size-1, -+ GFP_ATOMIC); -+ if (skb) { -+ DPRINTK("data before: 0x%p\n",skb->data); -+ skb_reserve(skb,(unsigned char *) (((unsigned long) -+ skb->data+header_size+PAGE_SIZE-1) & -+ ~(PAGE_SIZE-1))-header_size-skb->data); -+ DPRINTK("data after: 0x%p\n",skb->data); -+ } -+ } -+ if (!skb) { -+ CLIP(vcc->proto_data)->stats.rx_dropped++; -+ vcc->stats->rx_drop++; -+ } -+ return skb; -+} -+ -+ -+void atm_pop_clip(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+#if 0 && defined(CONFIG_MMU_HACKS) -+ if (skb->atm.iovcnt) -+ unlock_user(skb->atm.iovcnt-1,(struct iovec *) skb->data+1); -+#endif -+/*printk("popping (r:%d,w:%d)\n",skb->sk->rmem_alloc,skb->sk->wmem_alloc);*/ -+ dev_kfree_skb(skb,FREE_WRITE); -+} -+ -+ -+ -+static struct enet_statistics *atm_clip_get_stats(struct device *dev) -+{ -+ return &CLIP(dev)->stats; -+} -+ -+ -+/*@@@static*/ int clip_ioctl(struct device *dev,struct ifreq *rq,int cmd) -+{ -+ if (!suser()) return -EPERM; -+ switch (cmd) { -+ case CLIP_NULENCAP: -+#if 0 -+ dev->type = ARPHDR_ATMNULL; -+#endif -+ dev->hard_header_len = 0; -+ return 0; -+ case CLIP_LLCENCAP: -+#if 0 -+ dev->type = ARPHDR_ATMLLC; -+#endif -+ dev->hard_header_len = RFC1483LLC_LEN; -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+ -+static int clip_open(struct device *dev) -+{ -+ DPRINTK("clip_open called\n"); -+ return 0; -+} -+ -+ -+static int clip_stop(struct device *dev) -+{ -+ DPRINTK("DOWN! (%s,0x%p)\n",dev->name,CLIP(dev)->vcc); -+ atm_release_vcc(CLIP(dev)->vcc,1); -+ return 0; -+} -+ -+ -+void ipcom_init(struct device *dev, -+ int (*hard_start_xmit)(struct sk_buff *skb,struct device *dev), -+ unsigned short extra_flags) -+{ -+ DPRINTK("ipcom_init\n"); -+ DPRINTK("configuring %s\n",dev->name); -+ dev->hard_start_xmit = hard_start_xmit; -+#if 0 -+#ifdef CONFIG_MMU_HACKS -+ dev->sg_xmit = clip_sg_xmit; -+#else -+ dev->sg_xmit = NULL; -+#endif -+#endif -+ dev->open = clip_open; -+ dev->stop = clip_stop; -+ ether_setup(dev); -+ dev->tbusy = 0; /* @@@ check */ -+ dev->hard_header = clip_hard_header; -+ dev->do_ioctl = clip_ioctl; -+ dev->change_mtu = NULL; -+ dev->rebuild_header = clip_rebuild_header; -+ dev->get_stats = atm_clip_get_stats; -+ dev->hard_header_len = RFC1483LLC_LEN; -+ dev->flags |= IFF_NOARP | IFF_POINTOPOINT | extra_flags; -+#if 0 -+ dev->type = ARPHDR_ATMLLC; -+#endif -+ dev->mtu = RFC1626_MTU; -+ memset(&CLIP(dev)->stats,0,sizeof(struct enet_statistics)); -+ -+} -+ -+ -+int ipcom_pick_number(int number) -+{ -+#ifdef CONFIG_ATM_ATMARP -+ struct device *atmarp; -+#endif -+#ifdef CONFIG_ATM_CLIP -+ struct clip_priv *clip; -+#endif -+ -+ if (number != -1) { -+#ifdef CONFIG_ATM_ATMARP -+ for (atmarp = clip_devs; atmarp; atmarp = PRIV(atmarp)->next) -+ if (PRIV(atmarp)->number == number) return -EEXIST; -+#endif -+ } -+ else { -+ number = 0; -+ -+#ifdef CONFIG_ATM_ATMARP -+ for (atmarp = clip_devs; atmarp; atmarp = PRIV(atmarp)->next) -+ if (PRIV(atmarp)->number >= number) -+ number = PRIV(atmarp)->number+1; -+#endif -+#ifdef CONFIG_ATM_CLIP -+ for (clip = old_clip_devs; clip; clip = clip->next) -+ if (clip->number >= number) number = clip->number+1; -+#endif -+ } -+ return number; -+} -+ -+ -+/* -+ * skb_migrate moves the list at FROM to TO, emptying FROM in the process. -+ * This function should live in skbuff.c or skbuff.h. Note that skb_migrate -+ * is not atomic, so turn off interrupts when using it. -+ */ -+ -+ -+void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) -+{ -+ struct sk_buff *skb,*prev; -+ -+ for (skb = ((struct sk_buff *) from)->next; -+ skb != (struct sk_buff *) from; skb = skb->next) skb->list = to; -+ prev = from->prev; -+ from->next->prev = (struct sk_buff *) to; -+ prev->next = (struct sk_buff *) to; -+ *to = *from; -+ skb_queue_head_init(from); -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/arequipa.c Tue Apr 22 15:43:19 1997 -@@ -0,0 +1,509 @@ -+/* net/atm/arequipa.c - Application requested IP over ATM */ -+ -+/* Written 1996,1997 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* for struct wait_queue */ -+#include /* for sleep_on */ -+#include -+#include -+#include /* cli and such */ -+ -+#include "protocols.h" -+#include "tunable.h" -+#include "signaling.h" /* for indirect closing, see below */ -+#include "common.h" -+#include "ipcommon.h" -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+struct device *arequipa_dev = NULL; -+ /* must use a different null value if skb->dev can ever be NULL */ -+struct atm_vcc *aqd = NULL; -+ -+struct rtable arequipa_rt = { -+ NULL, /* rt_next */ -+ 0L, /* rt_dst */ -+ 0L, /* rt_src */ -+ 0L, /* rt_gateway */ -+ 2, /* rt_refcnt */ -+ 1, /* rt_use */ -+ 0, /* rt_window */ -+ 0L, /* rt_lastuse */ -+ NULL, /* rt_hh */ -+ NULL, /* rt_dev */ -+ RTF_UP, /* rt_flags */ -+ RFC1626_MTU, /* rt_mtu */ -+ 0, /* rt_irtt */ -+ 0 /* rt_tos */ -+}; -+ -+ -+static struct atm_vcc *aq_list = NULL; /* dangling Arequipa VCs */ -+static unsigned long aq_generation = 0; -+static struct sk_buff_head pending; /* pending Arequipa messages */ -+static atomic_t pending_inuse; -+ -+ -+static void arequipa_unuse(struct atm_vcc *vcc) -+{ -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ if (!(vcc->flags & ATM_VF_AQDANG)) { -+ restore_flags(flags); -+ return; -+ } -+ vcc->flags &= ~ATM_VF_AQDANG; -+ if (vcc->aq_prev) vcc->aq_prev->aq_next = vcc->aq_next; -+ else aq_list = vcc->aq_next; -+ if (vcc->aq_next) vcc->aq_next->aq_prev = vcc->aq_prev; -+ restore_flags(flags); -+} -+ -+ -+/* -+ * Closing is tricky. Since we may be in an interrupt when executing -+ * arequipa_close, we can't just go and call close_fp. So what we do it instead -+ * is to ask arequipad nicely to close the VC. arequipad issues an -+ * AREQUIPA_CLS3RD ioctl to close us (via arequipa_close_vcc). Now we're in a -+ * process context and can sleep, etc. Ain't life sweet ? -+ */ -+ -+ -+static void aqd_enq(enum arequipa_msg_type type,void *ptr) -+{ -+ struct sk_buff *skb; -+ -+ if (!aqd) printk(KERN_WARNING "aqd_enq: no Arequipa demon\n"); -+ skb = alloc_skb(sizeof(struct arequipa_msg),GFP_ATOMIC); -+ if (!skb) { -+ printk(KERN_CRIT "aqd_enq: out of memory\n"); -+ return; -+ } -+ skb->free = 1; -+ skb->len = sizeof(struct arequipa_msg); -+ ((struct arequipa_msg *) skb->data)->type = type; -+ ((struct arequipa_msg *) skb->data)->ptr = ptr; -+ if (aqd) { -+ atomic_add(skb->truesize+ATM_PDU_OVHD,&aqd->rx_inuse); -+ skb_queue_tail(&aqd->recvq,skb); -+ wake_up(&aqd->sleep); -+ } -+ else { -+ atomic_add(skb->truesize+ATM_PDU_OVHD,&pending_inuse); -+ skb_queue_tail(&pending,skb); -+ } -+} -+ -+ -+int arequipa_close(struct sock *upper) -+{ -+ struct socket *lower; -+ unsigned long flags; -+ -+ DPRINTK("arequipa_close\n"); -+ if (!(lower = upper->arequipa)) return -ENOTCONN; -+ save_flags(flags); -+ cli(); -+ arequipa_unuse(ATM_SD(lower)); -+ ip_rt_put(upper->ip_route_cache); -+ upper->ip_route_cache = NULL; -+ upper->arequipa = NULL; -+ ATM_SD(lower)->upper = NULL; -+ if (!(ATM_SD(lower)->flags & ATM_VF_AQREL)) -+ aqd_enq(amt_close,ATM_SD(lower)); -+ ATM_SD(lower)->flags |= ATM_VF_AQREL; -+ restore_flags(flags); -+ return 0; -+} -+ -+ -+void arequipa_close_vcc(struct atm_vcc *vcc) -+{ -+ if (!(vcc->flags & ATM_VF_AQREL)) { -+ printk(KERN_CRIT "arequipa_close_vcc: VCC %p doesn't " -+ "have ATM_VF_AQREL set\n",vcc); -+ return; -+ } -+ arequipa_unuse(vcc); -+ close_fp(vcc->sock->file); -+} -+ -+ -+static void arequipa_callback(struct atm_vcc *vcc) -+{ -+ unsigned long flags; -+ -+ DPRINTK("arequipa_callback\n"); -+ svc_callback(vcc); -+ if (!(vcc->flags & ATM_VF_RELEASED)) return; -+ vcc->callback = svc_callback; /* paranoia ... */ -+ save_flags(flags); -+ cli(); -+ arequipa_unuse(vcc); -+ if (vcc->upper) { -+ if (!vcc->upper->arequipa) -+ printk("arequipa_callback: upper pretends not to " -+ "use Arequipa\n"); -+ ip_rt_put(vcc->upper->ip_route_cache); -+ vcc->upper->ip_route_cache = NULL; -+ vcc->upper->arequipa = NULL; -+ } -+ if (vcc->flags & ATM_VF_AQREL) { -+ restore_flags(flags); -+ return; -+ } -+ vcc->flags |= ATM_VF_AQREL; -+ restore_flags(flags); -+ arequipa_close_vcc(vcc); -+ return; -+} -+ -+ -+static int check_aq_vcc(struct socket *lower) -+{ -+ if (lower->ops->family != PF_ATMSVC && lower->ops->family != PF_ATMPVC) -+ return -EPROTOTYPE; -+ if (lower->state != SS_CONNECTED) return -ENOTCONN; -+ if (ATM_SD(lower)->aal != ATM_AAL5) return -EPROTONOSUPPORT; -+ return 0; -+} -+ -+ -+/*static*/ void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+ if (!skb) return; /* it's okay to close Arequipa VCs */ -+ /*DPRINTK("arequipa push(%ld)\n",skb->len);*/ -+ skb->dev = arequipa_dev; -+ skb->atm.generation = vcc->generation; -+ ipcom_push(skb); -+} -+ -+ -+static void make_aq_vcc(struct socket *lower,int incoming) -+{ -+ struct atm_vcc *vcc; -+ struct sk_buff_head copy; -+ struct sk_buff *skb; -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ vcc = ATM_SD(lower); -+ vcc->pop = atm_pop_clip; -+ vcc->callback = arequipa_callback; -+ vcc->push = atm_push_arequipa; -+ vcc->peek = atm_peek_clip; -+ vcc->push_oam = NULL; -+ if (incoming) { -+ vcc->flags |= ATM_VF_AQDANG; -+ vcc->aq_next = aq_list; -+ vcc->aq_prev = NULL; -+ if (aq_list) aq_list->aq_prev = vcc; -+ aq_list = vcc; -+ } -+ vcc->generation = aq_generation++; -+ skb_migrate(&vcc->recvq,©); -+ vcc->rx_inuse = 0; -+ restore_flags(flags); -+ lower->file->f_count++; -+ /* re-process everything received between connection setup and -+ AREQUIPA_INCOMING */ -+ while ((skb = skb_dequeue(©))) atm_push_arequipa(vcc,skb); -+} -+ -+ -+static int arequipa_attach_unchecked(struct socket *lower,struct sock *upper) -+{ -+ unsigned long flags; -+ struct rtable *rt; -+ int error; -+ -+ if (upper->arequipa) { -+ printk(KERN_WARNING "arequipa_attach_unchecked: upper already " -+ "uses Arequipa\n"); -+ return -EISCONN; -+ } -+ error = check_aq_vcc(lower); -+ if (error) return error; -+ save_flags(flags); -+ cli(); -+ if (ATM_SD(lower)->upper) { -+ restore_flags(flags); -+ printk(KERN_WARNING "arequipa_attach_unchecked: lower is " -+ "already attached\n"); -+ return -EISCONN; -+ } -+ DPRINTK("arequipa_attach_unchecked %p (i_count=%d,f_count=%d)\n",upper, -+ lower->inode->i_count,lower->file->f_count); -+ upper->arequipa = lower; -+ ATM_SD(lower)->upper = upper; -+ rt = upper->ip_route_cache; /* revalidate cache */ -+ upper->ip_route_cache = NULL; -+ restore_flags(flags); -+ set_rt_cache(upper,rt); -+ /* -+ * The next statement violates RFC1122, because it may change MSS when -+ * both sides have already exchanged their SYNs. Linux doesn't mind if -+ * this happens, but other systems might. Needs to be fixed. @@@ -+ */ -+ if (ATM_SD(lower)->qos.txtp.max_sdu > RFC1483LLC_LEN) -+ upper->mtu = ATM_SD(lower)->qos.txtp.max_sdu-RFC1483LLC_LEN; -+ return 0; -+} -+ -+ -+int arequipa_attach(struct socket *lower,struct sock *upper, -+ unsigned long generation) -+{ -+ unsigned long flags; -+ struct atm_vcc *walk; -+ -+ save_flags(flags); -+ cli(); -+ for (walk = aq_list; walk; walk = walk->aq_next) -+ if (walk == ATM_SD(lower)) break; -+ restore_flags(flags); -+ if (walk && walk->generation == generation) -+ return arequipa_attach_unchecked(lower,upper); -+ printk(KERN_DEBUG "arequipa_attach: avoided close/attach race\n"); -+ return -ENOTCONN; -+} -+ -+ -+int arequipa_expect(struct sock *upper,int on) -+{ -+ DPRINTK("arequipa_expect %d\n",on); -+ if (!aqd) { -+ printk(KERN_ERR "arequipa_expect: no Arequipa demon\n"); -+ return -EUNATCH; -+ } -+ if (on) { -+ if (upper->aq_route) return 0; -+ upper->aq_route = kmalloc(sizeof(struct rtable),GFP_KERNEL); -+ return upper->aq_route ? 0 : -ENOMEM; -+ } -+ if (!upper->aq_route) return 0; -+ if (upper->arequipa) return -EBUSY; -+ kfree(upper->aq_route); -+ upper->aq_route = NULL; -+ return 0; -+} -+ -+ -+int arequipa_preset(struct socket *lower,struct sock *upper) -+{ -+ unsigned long flags; -+ int error; -+ -+ if (upper->state == TCP_LISTEN) return -EPROTO; -+ if (!aqd) { -+ printk(KERN_ERR "arequipa_preset: no Arequipa demon\n"); -+ return -EUNATCH; -+ } -+ error = arequipa_expect(upper,1); -+ if (error) return error; -+ save_flags(flags); -+ cli(); -+ error = arequipa_attach_unchecked(lower,upper); -+ if (!error) make_aq_vcc(lower,0); -+ restore_flags(flags); -+ return error; -+} -+ -+ -+int arequipa_incoming(struct socket *lower) -+{ -+ int error; -+ -+ if (!suser()) return -EPERM; -+ error = check_aq_vcc(lower); -+ if (error) return error; -+ ATM_SD(lower)->upper = NULL; -+ make_aq_vcc(lower,1); -+ DPRINTK("aq_incoming %d\n",lower->file->f_count); -+ return 0; -+} -+ -+ -+static int arequipa_xmit(struct sk_buff *skb,struct device *dev) -+{ -+ struct atm_vcc *vcc; -+ -+ /*DPRINTK("arequipa xmit\n");*/ -+ if (!skb->sk || !skb->sk->arequipa || -+ !ATM_SD(skb->sk->arequipa)) { -+ printk("arequipa_xmit: discarding orphaned packets\n"); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return 0; -+ } -+ vcc = ATM_SD(skb->sk->arequipa); -+ if (!(vcc->flags & ATM_VF_READY)) { -+ printk("arequipa_xmit: not ready\n"); -+ dev_kfree_skb(skb,FREE_WRITE); -+ return 0; -+ } -+ ipcom_xmit(arequipa_dev,vcc,skb); -+ CLIP(arequipa_dev)->stats.tx_packets++; -+ return 0; -+} -+ -+ -+static int arequipa_init(struct device *dev) -+{ -+ ipcom_init(dev,arequipa_xmit,IFF_UP); -+ dev->pa_addr = 0x01020304; -+ dev->pa_mask = ~0L; -+ dev->pa_alen = 4; -+ return 0; -+} -+ -+ -+int atm_init_arequipa(void) -+{ -+ DPRINTK("atm_init_arequipa\n"); -+ if (!suser()) return -EPERM; -+ arequipa_dev = kmalloc(sizeof(struct device)+sizeof(struct clip_priv), -+ GFP_KERNEL); -+ if (!arequipa_dev) return -ENOMEM; -+ arequipa_rt.rt_dev = arequipa_dev; -+ memset(arequipa_dev,0,sizeof(struct device)+sizeof(struct clip_priv)); -+ arequipa_dev->name = "arequipa"; -+ arequipa_dev->init = arequipa_init; -+ arequipa_rt.rt_dev = arequipa_dev; -+ arequipa_init(arequipa_dev); -+ skb_queue_head_init(&pending); -+ pending_inuse = 0; -+ return 0; -+} -+ -+ -+static void aqd_close(struct atm_vcc *vcc) -+{ -+ unsigned long flags; -+ -+ DPRINTK("aqd_close\n"); -+ save_flags(flags); -+ cli(); -+ aqd = NULL; /* assumed to be atomic */ -+ skb_migrate(&vcc->recvq,&pending); -+ pending_inuse = vcc->rx_inuse; -+ restore_flags(flags); -+ if (skb_peek(&pending)) -+ printk(KERN_CRIT "aqd_close: closing with requests " -+ "pending\n"); -+} -+ -+ -+static struct atmdev_ops aqd_dev_ops = { -+ NULL, /* no open */ -+ aqd_close, /* close */ -+ NULL, /* no ioctl */ -+ NULL, /* no getsockopt */ -+ NULL, /* no setsockopt */ -+ NULL, /* no send */ -+ NULL, /* no sg_send */ -+ NULL, /* no poll */ -+ NULL, /* no phy_put */ -+ NULL, /* no phy_get */ -+ NULL /* no feedback */ -+}; -+ -+ -+static struct atm_dev aqd_dev = { -+ &aqd_dev_ops, -+ NULL, /* no PHY */ -+ "aqd", /* type */ -+ 999, /* dummy device number */ -+ NULL,NULL, /* pretend not to have any VCCs */ -+ NULL,NULL, /* no data */ -+ 0, /* no flags */ -+ NULL, /* no local address */ -+ { 0 } /* no ESI, no statistics */ -+}; -+ -+ -+int arequipad_attach(struct atm_vcc *vcc) -+{ -+ unsigned long flags; -+ -+ if (aqd) return -EADDRINUSE; -+ save_flags(flags); -+ cli(); -+ aqd = vcc; -+ vcc->flags |= ATM_VF_READY | ATM_VF_META; -+ /* allow replies and avoid getting closed if signaling dies */ -+ vcc->dev = &aqd_dev; -+ vcc->aal = ATM_AAL5; /* lie */ -+ vcc->push = NULL; -+ vcc->peek = NULL; /* crash */ -+ vcc->pop = NULL; /* crash */ -+ vcc->push_oam = NULL; /* crash */ -+ if (skb_peek(&pending)) { -+ skb_migrate(&pending,&vcc->recvq); -+ vcc->rx_inuse = pending_inuse; -+ } -+ restore_flags(flags); -+ return 0; -+ -+} -+ -+ -+void arequipa_synchronize(void) -+{ -+ struct wait_queue *wait; -+ -+ init_waitqueue(&wait); -+ aqd_enq(amt_sync,&wait); -+ sleep_on(&wait); -+} -+ -+ -+void arequipa_work(void) -+{ -+ struct sk_buff *skb; -+ struct arequipa_msg *msg; -+ -+ if (!aqd) { -+ printk(KERN_ERR "arequipa_work invoked but arequipad isn't " -+ "connected\n"); -+ return; -+ } -+ while ((skb = skb_dequeue(&aqd->recvq))) { -+ msg = (struct arequipa_msg *) skb->data; -+ switch (msg->type) { -+ case amt_close: -+ arequipa_close_vcc(msg->ptr); -+ break; -+ case amt_sync: -+ wake_up(msg->ptr); -+ break; -+ default: -+ printk(KERN_ERR "unrecognized Arequipa message" -+ " type %d\n",(int) msg->type); -+ } -+ atomic_sub(skb->truesize+ATM_PDU_OVHD,&aqd->rx_inuse); -+ } -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/tunable.h Fri Nov 15 19:06:36 1996 -@@ -0,0 +1,26 @@ -+/* net/atm/tunable.h - Tunable parameters of ATM support */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef NET_ATM_TUNABLE_H -+#define NET_ATM_TUNABLE_H -+ -+#if 0 -+/* this is just a reminder - TTS is a device-specific parameter and shall be -+ used inside device drivers only */ -+#define ATM_TTS 1000 /* worst-case time to service of device -+ drivers, in microseconds */ -+#endif -+ -+#define ATM_RXBQ_DEF ( 64*1024) /* default RX buffer quota, in bytes */ -+#define ATM_TXBQ_DEF ( 64*1024) /* default TX buffer quota, in bytes */ -+#define ATM_RXBQ_MIN ( 1*1024) /* RX buffer minimum, in bytes */ -+#define ATM_TXBQ_MIN ( 1*1024) /* TX buffer minimum, in bytes */ -+#define ATM_RXBQ_MAX (1024*1024) /* RX buffer quota limit, in bytes */ -+#define ATM_TXBQ_MAX (1024*1024) /* TX buffer quota limit, in bytes */ -+ -+#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer -+ quota per PDU */ -+ -+#endif ---- ref/net/ipv4/af_inet.c Fri Oct 18 05:18:54 1996 -+++ work/net/ipv4/af_inet.c Thu Apr 17 16:23:27 1997 -@@ -105,6 +105,14 @@ - #include - #endif - -+#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) -+#include -+int (*atmtcp_attach_hook)(struct socket *sock) = NULL; -+#endif -+#ifdef CONFIG_AREQUIPA -+#include -+#endif -+ - #define min(a,b) ((a)<(b)?(a):(b)) - - extern struct proto packet_prot; -@@ -415,6 +423,10 @@ - - if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0) - { -+#ifdef CONFIG_AREQUIPA -+ if (sk->arequipa) arequipa_close(sk); -+ if (sk->aq_route) kfree_s(sk->aq_route,sizeof(struct rtable)); -+#endif - if(sk->opt) - kfree(sk->opt); - ip_rt_put(sk->ip_route_cache); -@@ -529,6 +541,9 @@ - { - struct sock *sk = (struct sock *) sock->data; - -+#ifdef CONFIG_AREQUIPA -+ if (sk->aq_route && sk->ip_route_cache == sk->aq_route) return -EPROTO; -+#endif - if(inet_autobind(sk)!=0) - return -EAGAIN; - -@@ -662,6 +677,10 @@ - sk_free(sk); - return(-ESOCKTNOSUPPORT); - } -+#ifdef CONFIG_AREQUIPA -+ sk->arequipa = NULL; -+ sk->aq_route = NULL; -+#endif - sk->socket = sock; - #ifdef CONFIG_TCP_NAGLE_OFF - sk->nonagle = 1; -@@ -1340,7 +1359,21 @@ - return((*dlci_ioctl_hook)(cmd, (void *) arg)); - #endif - return -ENOPKG; -- -+#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) -+ case SIOCSIFATMTCP: -+ if (atmtcp_attach_hook) -+ return atmtcp_attach_hook(sock); -+ return -EINVAL; -+#endif -+#ifdef CONFIG_AREQUIPA -+ case AREQUIPA_EXPECT: -+ return arequipa_expect(sk,arg); -+ case AREQUIPA_CLOSE: -+ return arequipa_close(sk); -+ case AREQUIPA_SYNCREQ: -+ arequipa_synchronize(); -+ return 0; -+#endif - default: - if ((cmd >= SIOCDEVPRIVATE) && - (cmd <= (SIOCDEVPRIVATE + 15))) ---- ref/net/protocols.c Sat Mar 30 12:20:34 1996 -+++ work/net/protocols.c Fri Nov 15 19:06:37 1996 -@@ -42,6 +42,10 @@ - #include - extern void rif_init(struct net_proto *); - #endif -+#ifdef CONFIG_ATM -+#include -+#endif -+ - /* - * Protocol Table - */ -@@ -73,6 +77,10 @@ - #endif - #ifdef CONFIG_ATALK - { "DDP", atalk_proto_init }, /* Netatalk Appletalk driver */ -+#endif -+#ifdef CONFIG_ATM -+ { "ATMPVC", atmpvc_proto_init }, -+ { "ATMSVC", atmsvc_proto_init }, - #endif - { NULL, NULL } /* End marker */ - }; ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/mmuio.c Thu Feb 6 19:43:29 1997 -@@ -0,0 +1,454 @@ -+/* net/atm/mmuio.c - MMU-supported high-speed I/O */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+ -+ -+#ifdef CONFIG_MMU_HACKS -+ -+#include -+#include -+ -+ -+#define invalidate flush_tlb_all /* @@@ improve this */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#include /* needed to include net/sock.h */ -+#include -+ -+ -+/* #define MAX_SC_LOCKS 3 */ -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+#ifndef CONFIG_MMU_HACKS_DEBUG -+ -+#define EVENT(s,a,b,c) DPRINTK(s,a,b,c) -+ -+static void event_dump(void) {} -+ -+#else -+ -+/* -+ * Very extensive activity logging. Greatly improves bug detection speed but -+ * costs a few Mbps if enabled. -+ */ -+ -+#define EV 64 -+ -+static const char *ev[EV]; -+ -+static unsigned long ev_a[EV],ev_b[EV],ev_c[EV]; -+static int ec = 0; -+ -+ -+static void EVENT(const char *s,unsigned long a,unsigned long b,unsigned long c) -+{ -+ ev[ec] = s; -+ ev_a[ec] = a; -+ ev_b[ec] = b; -+ ev_c[ec] = c; -+ ec = (ec+1) % EV; -+} -+ -+ -+static void event_dump(void) -+{ -+ int n,i; -+ -+ printk(KERN_NOTICE "----- Event dump follows -----\n"); -+ for (n = 0; n < EV; n++) { -+ i = (ec+n) % EV; -+ printk(KERN_NOTICE); -+ printk(ev[i] ? ev[i] : "(null)",ev_a[i],ev_b[i],ev_c[i]); -+ } -+ printk(KERN_NOTICE "----- Event dump ends here -----\n"); -+} -+ -+ -+#endif /* CONFIG_MMU_HACKS_DEBUG */ -+ -+/* -+ * Helper functions to walk through page tables. If CREATE is set, they add -+ * new entries if needed to reach a given PTE. PTEs are never created. If -+ * CREATE is not set, *PMD and *PTE might become NULL while passing unavailable -+ * memory regions. -+ */ -+ -+ -+static inline int mmu_resolve(unsigned long addr,pgd_t **pgd,pmd_t **pmd, -+ pte_t **pte,int create) -+{ -+ *pgd = pgd_offset(current->mm,addr); -+ *pmd = create ? pmd_alloc(*pgd,addr) : pmd_offset(*pgd,addr); -+ if (!*pmd) { -+ if (create) invalidate(); -+ *pte = NULL; -+ return -ENOMEM; -+ } -+ *pte = create ? pte_alloc(*pmd,addr) : pte_offset(*pmd,addr); -+ if (*pte) return 0; -+ if (create) invalidate(); -+ return -ENOMEM; -+} -+ -+ -+static inline int mmu_step(unsigned long addr,pgd_t **pgd,pmd_t **pmd, -+ pte_t **pte,int create) -+{ -+ if (addr & (PTRS_PER_PTE*PAGE_SIZE-1)) { -+ if (*pte) (*pte)++; -+ } -+ else { -+ if (addr & (PTRS_PER_PMD*PTRS_PER_PTE*PAGE_SIZE-1)) { -+ if (*pmd) (*pmd)++; -+ } -+ else { -+ (*pgd)++; -+ *pmd = create ? pmd_alloc(*pgd,addr) : -+ pmd_offset(*pgd,addr); -+ if (!*pmd) { -+ if (create) invalidate(); -+ *pte = NULL; -+ return -ENOMEM; -+ } -+ } -+ *pte = create ? pte_alloc(*pmd,addr) : pte_offset(*pmd,addr); -+ if (!*pte) { -+ if (create) invalidate(); -+ return -ENOMEM; -+ } -+ } -+ return 0; -+} -+ -+ -+/* -+ * Removes a range of pages belonging to the current process. This helps to -+ * avoid undesirable copying when COW or swapped-out pages are overwritten in -+ * one sweep. -+ */ -+ -+ -+void free_range(unsigned long start,unsigned long size) -+{ -+ pgd_t *pgd; -+ pmd_t *pmd; -+ pte_t *pte; -+ unsigned long end; -+ -+ end = (start+size) & ~(PAGE_SIZE-1); -+ start = (start+PAGE_SIZE-1) & ~(PAGE_SIZE-1); -+ if (start <= end) return; -+ (void) mmu_resolve(start,&pgd,&pmd,&pte,0); -+ while (1) { -+ if (pte && !pte_none(*pte)) { -+ pte_t old_page; -+ -+ old_page = *pte; -+ pte_clear(pte); -+ if (!pte_present(old_page)) -+ swap_free(pte_val(old_page)); -+ else { -+ current->mm->rss--; -+ free_page(pte_page(old_page)); -+ } -+ } -+ if ((start += PAGE_SIZE) >= end) break; -+ (void) mmu_step(start,&pgd,&pmd,&pte,0); -+ } -+ invalidate(); -+} -+ -+ -+/* -+ * Copies data by mapping kernel pages into the current process. If the data is -+ * mis-aligned or if no whole pages can be copied, ordinary memory-to-memory -+ * copies are done. -+ * -+ * TODO: Speed improvement: if copying "almost" a page, don't copy from kernel -+ * to user, but still map the kernel page and copy the user data instead. -+ * This may also reduce the number of bad COW/swap activity. -+ * -+ */ -+ -+ -+struct page_descriptor { -+ struct page_descriptor *next; -+ struct block_header *firstfree; -+ int order; -+ int nfree; -+}; -+ -+ -+/* -+ * Since we always work on "big" buffers (>= one memory page), kmalloc's -+ * page sharing doesn't get in the way. -+ */ -+ -+ -+extern volatile unsigned long net_skbcount; -+ -+ -+static void free_around(struct sk_buff *skb,unsigned long start, -+ unsigned long end) -+{ -+ struct page_descriptor *dsc; -+ unsigned long order,first,last; -+ -+ net_skbcount--; -+ /* FIXME: should also update kmalloc counters @@@ */ -+ dsc = (struct page_descriptor *) ((unsigned long) skb->head & -+ PAGE_MASK); -+ order = dsc->order; -+ order = order < 7 ? 0 : order-7; -+ first = (unsigned long) dsc; -+ last = first+(PAGE_SIZE << order); -+ if (mem_map[MAP_NR(first)].count != 1) { -+ printk(KERN_CRIT "free_around: mem_map[%ld].count is 0x%x\n", -+ MAP_NR(first),mem_map[MAP_NR(first)].count); -+ event_dump(); -+ return; -+ } -+ while (first < last) { -+ mem_map[MAP_NR(first)].count = 1; -+ if (first < start || first >= end) free_page(first); -+ first += PAGE_SIZE; -+ } -+} -+ -+ -+/* fixme: what if reading into shared memory region ? */ -+void mmucp_tofs(unsigned long user,unsigned long size,struct sk_buff *skb, -+ unsigned long kernel) -+{ -+ unsigned long extra; -+ pgd_t *pgd; -+ pmd_t *pmd; -+ pte_t *pte; -+ int error; -+ unsigned long hole_start; -+ -+ if (size > skb->len) size = skb->len; -+ EVENT("mmucp_tofs 0x%lx to 0x%lx+%ld\n",kernel,user,size); -+ if (skb->prev || skb->next || skb->lock || skb->users > 1) { -+ memcpy_tofs((void *) user,(void *) kernel,size); -+ return; -+ } -+ if (((kernel^user) & (PAGE_SIZE-1)) || size < PAGE_SIZE) { -+ EVENT("memcpy(0x%lx,0x%lx,%ld);\n",user,kernel,size); -+ memcpy_tofs((void *) user,(void *) kernel,size); -+ kfree_skb(skb,FREE_READ); -+ return; -+ } -+ if ((extra = -user & (PAGE_SIZE-1))) { -+ if ((size -= extra) < PAGE_SIZE) { -+ EVENT("memcpy(0x%lx,0x%lx,%ld);\n",user,kernel, -+ size+extra); -+ memcpy_tofs((void *) user,(void *) kernel,size+extra); -+ kfree_skb(skb,FREE_READ); -+ return; -+ } -+ EVENT("memcpy(0x%lx,0x%lx,%ld);\n",user,kernel,size); -+ memcpy_tofs((void *) user,(void *) kernel,extra); -+ user += extra; -+ kernel += extra; -+ } -+ if ((error = mmu_resolve(user,&pgd,&pmd,&pte,1)) < 0) { -+ invalidate(); -+ oom(current); -+ return; -+ } -+ hole_start = kernel; -+ while (1) { -+ pte_t old_page; -+ -+ if (mem_map[MAP_NR(pte_page(*pte))].count > 1) { -+ EVENT("memcpy(0x%lx,0x%lx,PAGE_SIZE);\n",user,kernel,0); -+ memcpy_tofs((void *) user,(void *) kernel,PAGE_SIZE); -+ } -+ else { -+ old_page = *pte; -+ pte_clear(pte); -+ if (!pte_none(old_page)) -+ if (!pte_present(old_page)) -+ swap_free(pte_val(old_page)); -+ else { -+ current->mm->rss--; -+ free_page(pte_page(old_page)); -+ } -+ mem_map[MAP_NR(kernel)].count = 1; -+ /* Page is now owned only by user. */ -+ *pte = mk_pte(kernel,PAGE_SHARED); -+ *pte = pte_mkdirty(*pte); -+ EVENT("mapped 0x%lx at 0x%lx\n",kernel,user,0); -+ current->mm->rss++; -+ } -+ user += PAGE_SIZE; -+ kernel += PAGE_SIZE; -+ if ((size -= PAGE_SIZE) < PAGE_SIZE) break; -+ if ((error = mmu_step(user,&pgd,&pmd,&pte,1)) < 0) { -+ kernel -= PAGE_SIZE; /* back off */ -+ size = 0; -+ oom(current); -+ break; -+ } -+ } -+ if (size) { -+ EVENT("memcpy(0x%lx,0x%lx,%ld);\n",user,kernel,size); -+ memcpy_tofs((void *) user,(void *) kernel,size); -+ } -+ invalidate(); -+ /* use skb code for all the administrative overhead */ -+ skb->count++; -+ kfree_skb(skb,FREE_READ); -+ if (skb->count == 1) free_around(skb,hole_start,kernel); -+ else { -+ printk(KERN_CRIT "mmu_tofs: skb->count == %d\n",skb->count); -+ event_dump(); -+ } -+} -+ -+ -+/* -+ * Fault user pages (current process) in physical memory, lock them there, -+ * and set them COW so that they stay around even if the user process tries -+ * to scribble over them. The locked physical page ranges are recorded in the -+ * scatter-gather vector IOV. -+ * -+ * FIXME: Should check user's physical memory size limit. -+ */ -+ -+ -+int lock_user(unsigned long start,unsigned long size,int iov_max, -+ struct iovec *iov) -+{ -+ struct vm_area_struct *vma; -+ unsigned long end,last,from,page; -+ pgd_t *pgd; -+ pmd_t *pmd; -+ pte_t *pte; -+ int iovcnt,error; -+ -+ EVENT("lock_user: %ld@0x%lx\n",size,start,0); -+ end = start+size; -+ if (start >= end) return 0; -+ for (vma = find_vma(current,start); vma; vma = vma->vm_next) -+ if (vma->vm_flags & (VM_SHARED | VM_SHM)) return -EAGAIN; -+ else if (vma->vm_end >= end) break; -+ iovcnt = 0; -+ if ((error = mmu_resolve(start,&pgd,&pmd,&pte,1)) < 0) return error; -+ last = from = 0; -+ while (1) { -+ mem_map_t *map; -+ -+ EVENT("<0x%p|0x%p|0x%p>\n",pgd,pmd,pte); -+ EVENT("0x%lx,0x%lx,%d\n",start,end,iovcnt); -+ if (pte_none(*pte) || !pte_present(*pte)) { -+ struct vm_area_struct *vma; -+ -+ EVENT("handling missing page\n",0,0,0); -+ if (!(vma = find_vma(current,start))) { -+ printk(KERN_CRIT "lock_user: VMA (0x%lx) not " -+ "found",start); -+ event_dump(); -+ return -EINVAL; -+ } -+ do_no_page(current,vma,start,vma->vm_flags & VM_WRITE); -+ } -+ page = pte_page(*pte); -+ EVENT("got page 0x%lx\n",page,0,0); -+ if (!page) { -+ printk(KERN_ERR "lock_user: Gnorf, no page\n"); -+ event_dump(); -+ return -EINVAL; -+ } -+ map = mem_map+MAP_NR(page); -+ if (PageReserved(map)) { -+ printk(KERN_ERR "lock_user: reserved\n"); -+ event_dump(); -+ return -EINVAL; -+ } -+ atomic_inc(&map->count); -+ *pte = pte_wrprotect(*pte); -+ if (!last) { -+ from = page+(start & (PAGE_SIZE-1)); -+ start &= ~(PAGE_SIZE-1); -+ } -+ else if (page != last+PAGE_SIZE) { -+ if (iovcnt >= iov_max) return -ENOSPC; -+ iov->iov_base = (caddr_t) from; -+ iov->iov_len = last+PAGE_SIZE-from; -+ EVENT("putting ... last=0x%lx,from=0x%lx\n", -+ last,from,0); -+ iovcnt++; -+ iov++; -+ from = page; -+ } -+ last = page; -+ if ((start += PAGE_SIZE) >= end) break; -+ if ((error = mmu_step(start,&pgd,&pmd,&pte,1)) < 0) -+ return error; -+ } -+ invalidate(); -+ if (iovcnt >= iov_max) return -ENOSPC; -+ iov->iov_base = (caddr_t) from; -+ iov->iov_len = last+(end & (PAGE_SIZE-1))-from; -+ if (start == end) iov->iov_len += PAGE_SIZE; -+/* -+for (i = 0; i <= iovcnt; i++) -+ printk("iov[%d].iov_base = 0x%p\niov[%d].iov_len = 0x%lx\n", -+i,iov[i-iovcnt].iov_base,i,iov[i-iovcnt].iov_len); -+*/ -+ return iovcnt+1; -+} -+ -+ -+/* -+ * Release user pages locked with lock_user. wrprotect isn't cleared, so we'll -+ * get a few extra protection faults (COW handling doesn't copy pages that are -+ * not shared), but that shouldn't do any harm. -+ */ -+ -+ -+void unlock_user(int iovcnt,struct iovec *iov) -+{ -+ unsigned long walk,end; -+ -+ while (iovcnt--) { -+ end = (unsigned long) iov->iov_base+iov->iov_len; -+ for (walk = (unsigned long) iov->iov_base & ~(PAGE_SIZE-1); -+ walk < end; walk += PAGE_SIZE) { -+ mem_map_t *map; -+ -+ map = mem_map+MAP_NR(walk); -+ free_page(walk); -+ } -+ iov++; -+ } -+} -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/mmuio.h Fri Feb 28 14:51:54 1997 -@@ -0,0 +1,25 @@ -+/* mmuio.h - MMU-supported high-speed I/O */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef _LINUX_MMUIO_H -+#define _LINUX_MMUIO_H -+ -+#include -+ -+#ifdef CONFIG_MMU_HACKS -+ -+#include -+#include -+ -+void free_range(unsigned long start,unsigned long size); -+void mmucp_tofs(unsigned long user,unsigned long size,struct sk_buff *skb, -+ unsigned long kernel); -+int lock_user(unsigned long start,unsigned long size,int iov_max, -+ struct iovec *iov); -+void unlock_user(int iovcnt,struct iovec *iov); -+ -+#endif -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/raw.c Fri Apr 4 19:32:52 1997 -@@ -0,0 +1,139 @@ -+/* net/atm/raw.c - Raw AAL0 and AAL5 transports */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "protocols.h" -+#include "tunable.h" /* tunable parameters */ -+ -+ -+#if 0 -+#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -+#else -+#define DPRINTK(format,args...) -+#endif -+ -+ -+/* -+ * SKB == NULL indicates that the link is being closed -+ */ -+ -+void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+ if (skb) { -+ DPRINTK("APushR %d += %d\n",vcc->rx_inuse,skb->truesize); -+ atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse); -+ skb_queue_tail(&vcc->recvq,skb); -+ wake_up(&vcc->sleep); -+ } -+} -+ -+ -+/* -+ * A return value of NULL means to discard the PDU -+ */ -+ -+ -+static struct sk_buff *atm_peek_aal0(struct atm_vcc *vcc,unsigned long pdu_size, -+ __u32 (*fetch)(struct atm_vcc *vcc,int i)) -+{ -+ struct sk_buff *skb; -+ -+ if (pdu_size+vcc->rx_inuse+ATM_PDU_OVHD <= vcc->rx_quota) { -+ skb = alloc_skb(pdu_size,GFP_ATOMIC); -+ if (skb) return skb; -+ } -+ vcc->stats->rx_drop++; -+ return NULL; -+} -+ -+ -+/* -+ * atm_peek_aal5 is currently also used for AAL3/4 -+ */ -+ -+ -+static struct sk_buff *atm_peek_aal5(struct atm_vcc *vcc,unsigned long pdu_size, -+ __u32 (*fetch)(struct atm_vcc *vcc,int i)) -+{ -+ struct sk_buff *skb; -+ -+ if (pdu_size+vcc->rx_inuse+ATM_PDU_OVHD <= vcc->rx_quota) -+ if (pdu_size < PAGE_SIZE) { -+ skb = alloc_skb((pdu_size+3) & ~3,GFP_ATOMIC); -+ if (skb) return skb; -+ } -+ else { -+ skb = alloc_skb(((pdu_size+3) & ~3)+PAGE_SIZE-1, -+ GFP_ATOMIC); -+ if (skb) { -+ skb_reserve(skb,(unsigned char *) -+ (((unsigned long) skb->data+PAGE_SIZE-1) & -+ ~(PAGE_SIZE-1))-skb->data); -+DPRINTK("PEEK: data at 0x%p\n",skb->data); -+ return skb; -+ } -+ } -+ vcc->stats->rx_drop++; -+ return NULL; -+} -+ -+ -+static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) -+{ -+#ifdef CONFIG_MMU_HACKS -+ if (skb->atm.iovcnt) -+ unlock_user(skb->atm.iovcnt,(struct iovec *) skb->data); -+#endif -+ DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize); -+ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); -+ dev_kfree_skb(skb,FREE_WRITE); -+#if 0 /* experimental */ -+if (vcc->dev->sending != 1) printk("sending == %d !!!\n",vcc->dev->sending); -+ vcc->dev->sending--; -+#endif -+ wake_up(&vcc->wsleep); -+} -+ -+ -+int atm_init_aal0(struct atm_vcc *vcc) -+{ -+ vcc->aal = ATM_AAL0; -+ vcc->push = atm_push_raw; -+ vcc->peek = atm_peek_aal0; -+ vcc->pop = atm_pop_raw; -+ vcc->push_oam = NULL; -+ return 0; -+} -+ -+ -+int atm_init_aal34(struct atm_vcc *vcc) -+{ -+ vcc->aal = ATM_AAL34; -+ vcc->push = atm_push_raw; -+ vcc->peek = atm_peek_aal5; /* same procedure */ -+ vcc->pop = atm_pop_raw; -+ vcc->push_oam = NULL; -+ return 0; -+} -+ -+ -+int atm_init_aal5(struct atm_vcc *vcc) -+{ -+ vcc->aal = ATM_AAL5; -+ vcc->push = atm_push_raw; -+ vcc->peek = atm_peek_aal5; -+ vcc->pop = atm_pop_raw; -+ vcc->push_oam = NULL; -+ return 0; -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/protocols.h Fri Nov 15 19:06:39 1996 -@@ -0,0 +1,17 @@ -+/* net/atm/protocols.h - ATM protocol handler entry points */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef NET_ATM_PROTOCOLS_H -+#define NET_ATM_PROTOCOLS_H -+ -+void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb); -+ -+int atm_init_aal0(struct atm_vcc *vcc); /* "raw" AAL0 */ -+int atm_init_aal34(struct atm_vcc *vcc);/* "raw" AAL3/4 transport */ -+int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */ -+int atm_init_clip(struct atm_vcc *vcc); /* Classical IP over ATM (RFC1577) */ -+int atm_init_atmarp(struct atm_vcc *vcc);/* ATM ARP */ -+ -+#endif ---- ref/include/linux/netdevice.h Thu Oct 31 11:06:31 1996 -+++ work/include/linux/netdevice.h Fri Feb 28 14:29:29 1997 -@@ -187,6 +187,8 @@ - int (*set_mac_address)(struct device *dev, void *addr); - #define HAVE_PRIVATE_IOCTL - int (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd); -+ int (*ip_arp)(struct device *dev,unsigned int cmd, -+ void *arg); - #define HAVE_SET_CONFIG - int (*set_config)(struct device *dev, struct ifmap *map); - #define HAVE_HEADER_CACHE -@@ -287,6 +289,8 @@ - /* These functions live elsewhere (drivers/net/net_init.c, but related) */ - - extern void ether_setup(struct device *dev); -+extern int ether_arp(struct device *dev,unsigned int cmd, -+ void *arg); - extern void tr_setup(struct device *dev); - extern void fddi_setup(struct device *dev); - extern int ether_config(struct device *dev, struct ifmap *map); ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atmarp.h Wed Mar 19 20:44:11 1997 -@@ -0,0 +1,99 @@ -+/* atmarp.h - ATM ARP protocol and kernel-demon interface definitions */ -+ -+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef _LINUX_ATMARP_H -+#define _LINUX_ATMARP_H -+ -+#include -+#include -+#include -+ -+ -+/* RFC 1577 ATM ARP header */ -+ -+struct atmarphdr { -+ unsigned short ar_hrd; /* Hardware type */ -+ unsigned short ar_pro; /* Protocol type */ -+ unsigned char ar_shtl;/* Type & length of source ATM number (q) */ -+ unsigned char ar_sstl;/* Type & length of source ATM subaddress (r) */ -+ unsigned short ar_op; /* Operation code (request, reply, or NAK) */ -+ unsigned char ar_spln;/* Length of source protocol address (s) */ -+ unsigned char ar_thtl;/* Type & length of target ATM number (x) */ -+ unsigned char ar_tstl;/* Type & length of target ATM subaddress (y) */ -+ unsigned char ar_tpln;/* Length of target protocol address (z) */ -+ /* ar_sha, at_ssa, ar_spa, ar_tha, ar_tsa, ar_tpa */ -+ unsigned char data[1]; -+}; -+ -+#define TL_LEN 0x3f /* ATMARP Type/Length field structure */ -+#define TL_E164 0x40 -+ -+ -+#define ATF_NULL 0x040 /* use NULL encapsulation */ -+#define ATF_ARPSRV 0x080 /* entry describes ARP server */ -+#define ATF_DEFQOS 0x100 /* entry defines default QOS */ -+ -+ -+#define MAX_ATMARP_SIZE (sizeof(struct atmarphdr)-1+2*(ATM_E164_LEN+ \ -+ ATM_ESA_LEN+4)) -+ -+#define ATMARP_RETRY_DELAY 30 /* request next resolution or forget -+ NAK after 30 sec - should go into -+ atmclip.h */ -+ -+/* These really ought to go into include/linux/if_arp.h */ -+ -+/* ARP protocol HARDWARE identifiers. */ -+#define ARPHRD_ATM 19 /* ATM Forum */ -+ -+/* ARP protocol opcodes. */ -+#define ARPOP_InREQUEST 8 /* InARP request */ -+#define ARPOP_InREPLY 9 /* InARP reply */ -+#define ARPOP_NAK 10 /* (ATM)ARP NAK */ -+ -+ -+#define ATMARPD_CTRL _IO('a',ATMIOC_CLIP+1) /* become atmarpd ctrl sock */ -+#define ATMARP_MKIP _IO('a',ATMIOC_CLIP+2) /* attach socket to IP */ -+#define ATMARP_SETENTRY _IO('a',ATMIOC_CLIP+3) /* fill or hide ARP entry */ -+#define ATMARP_ENCAP _IO('a',ATMIOC_CLIP+5) /* change encapsulation */ -+ -+/* ATMARP ioctl request. */ -+struct atmarpreq { -+ struct sockaddr arp_pa; /* protocol address */ -+ struct sockaddr_atmsvc arp_ha; /* PVC or SVC address */ -+ struct atm_qos arp_qos; /* requested QOS */ -+ int arp_flags; /* flags */ -+}; -+ -+ -+struct atmarp_arpsioc { -+ struct sockaddr pa; /* protocol address */ -+ int aa_len; /* size of ATM address */ -+ struct sockaddr_atmsvc aa; /* SVC address */ -+}; -+ -+ -+#define ATMARP_CTRL_MAGIC 0xac /* put this into the magic byte */ -+ -+enum atmarp_ctrl_type { -+ act_invalid, /* catch uninitialized structures */ -+ act_need, /* need address resolution */ -+ act_create, /* interface has been created */ -+ act_up, /* interface is coming up */ -+ act_down, /* interface is going down */ -+ act_ioctl, /* ioctl follows */ -+ act_complete /* demon indicates completion */ -+}; -+ -+struct atmarp_ctrl { -+ unsigned char magic; /* constant */ -+ enum atmarp_ctrl_type type; /* message type */ -+ volatile int *reply; /* reply address, NULL is asynch */ -+ int itf_num;/* interface number (if present) */ -+ unsigned long arg; /* argument, e.g. IP address */ -+ unsigned char data[1];/*optional data */ -+}; -+ -+#endif ---- ref/net/ipv4/udp.c Sun Oct 6 15:42:09 1996 -+++ work/net/ipv4/udp.c Fri Nov 15 19:06:40 1996 -@@ -109,6 +109,11 @@ - #include - #include - -+#ifdef CONFIG_AREQUIPA -+#include -+#include -+#endif -+ - /* - * Snmp MIB for the UDP layer - */ -@@ -616,7 +621,7 @@ - sk->dummy_th.dest = usin->sin_port; - sk->state = TCP_ESTABLISHED; - udp_cache_zap(); -- sk->ip_route_cache = rt; -+ set_rt_cache(sk,rt); - return(0); - } - -@@ -655,6 +660,13 @@ - - static inline void udp_deliver(struct sock *sk, struct sk_buff *skb) - { -+#ifdef CONFIG_AREQUIPA -+ if (skb->dev == arequipa_dev && !sk->arequipa && sk->aq_route) { -+ if (!sk->ip_route_cache) printk("WNG: no route\n"); -+ (void) arequipa_attach(skb->atm.vcc->sock,sk, -+ skb->atm.generation); -+ } -+#endif - skb->sk = sk; - - if (sk->users) { ---- ref/net/ipv4/tcp.c Wed Nov 6 13:39:47 1996 -+++ work/net/ipv4/tcp.c Fri Nov 15 19:06:41 1996 -@@ -1948,6 +1948,9 @@ - int atype; - struct tcphdr *t1; - struct rtable *rt; -+#ifdef CONFIG_SCALED_WINDOWS -+ unsigned long window; -+#endif - - if (sk->state != TCP_CLOSE) - return(-EISCONN); -@@ -2003,6 +2006,11 @@ - * Put in the IP header and routing stuff. - */ - -+#ifdef CONFIG_AREQUIPA -+ ip_rt_put(sk->ip_route_cache); -+ set_rt_cache(sk,ip_rt_route(sk->daddr,sk->localroute)); -+#endif -+ - tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, - IPPROTO_TCP, sk->opt, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl,&sk->ip_route_cache); - if (tmp < 0) -@@ -2014,6 +2022,11 @@ - if ((rt = sk->ip_route_cache) != NULL && !sk->saddr) - sk->saddr = rt->rt_src; - sk->rcv_saddr = sk->saddr; -+#ifdef CONFIG_SCALED_WINDOWS -+ sk->snd_wscale = 0; -+ sk->rcv_wscale = 0; -+ sk->wscaling = 0; -+#endif - - /* - * Set up our outgoing TCP sequence number -@@ -2062,14 +2075,35 @@ - * Put in the TCP options to say MTU. - */ - -- ptr = skb_put(buff,4); -- ptr[0] = 2; -- ptr[1] = 4; -+#ifdef CONFIG_SCALED_WINDOWS -+ window = sk->rcvbuf; -+ sk->rcv_wscale = 0; -+ while (window > MAX_WINDOW) { -+ window >>= 1; -+ sk->rcv_wscale++; -+ } -+ t1->doff += 1; /* 4 bytes for window scaling option and NOP */ -+ ptr = skb_put(buff,TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW); -+#else -+ ptr = skb_put(buff,TCPOLEN_MSS); -+#endif -+ ptr[0] = TCPOPT_MSS; -+ ptr[1] = TCPOLEN_MSS; - ptr[2] = (sk->mtu) >> 8; - ptr[3] = (sk->mtu) & 0xff; -- buff->csum = csum_partial(ptr, 4, 0); -+#ifdef CONFIG_SCALED_WINDOWS -+ ptr[4] = TCPOPT_NOP; -+ ptr[5] = TCPOPT_WINDOW; -+ ptr[6] = TCPOLEN_WINDOW; -+ ptr[7] = sk->rcv_wscale; -+ buff->csum = csum_partial(ptr,TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW,0); -+ tcp_send_check(t1, sk->saddr, sk->daddr, -+ sizeof(struct tcphdr)+TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW,buff); -+#else -+ buff->csum = csum_partial(ptr, TCPOLEN_MSS, 0); - tcp_send_check(t1, sk->saddr, sk->daddr, -- sizeof(struct tcphdr) + 4, buff); -+ sizeof(struct tcphdr) + TCPOLEN_MSS, buff); -+#endif - - /* - * This must go first otherwise a really quick response will get reset. ---- ref/net/ipv4/ip_forward.c Wed Oct 30 02:42:42 1996 -+++ work/net/ipv4/ip_forward.c Fri Nov 15 19:06:42 1996 -@@ -39,6 +39,9 @@ - #include - #include - #include -+#ifdef CONFIG_AREQUIPA -+#include -+#endif - - #ifdef CONFIG_IP_FORWARD - #ifdef CONFIG_IP_MROUTE -@@ -150,7 +153,11 @@ - iph->check = checksum; - } - -+#ifndef CONFIG_AREQUIPA - if (iph->ttl <= 0) -+#else -+ if (iph->ttl <= 0 || dev == arequipa_dev) -+#endif - { - /* Tell the sender its packet died... */ - icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev); ---- ref/include/linux/proc_fs.h Wed Oct 30 03:53:15 1996 -+++ work/include/linux/proc_fs.h Fri Feb 28 14:29:29 1997 -@@ -34,6 +34,7 @@ - PROC_KSYMS, - PROC_DMA, - PROC_IOPORTS, -+ PROC_ATM, - #ifdef __SMP_PROF__ - PROC_SMP_PROF, - #endif -@@ -151,6 +152,16 @@ - #define PROC_DYNAMIC_FIRST 4096 - #define PROC_NDYNAMIC 4096 - -+enum atm_directory_inos { -+ PROC_ATM_DEVICES = 384, -+ PROC_ATM_ARP, -+ PROC_ATM_LEC, -+ PROC_ATM_SVC, -+ PROC_ATM_PVC, -+ PROC_ATM_AREQUIPA, -+ PROC_ATM_LAST -+}; -+ - #define PROC_SUPER_MAGIC 0x9fa0 - - /* -@@ -190,6 +201,7 @@ - extern struct proc_dir_entry proc_root; - extern struct proc_dir_entry proc_net; - extern struct proc_dir_entry proc_scsi; -+extern struct proc_dir_entry proc_atm; - extern struct proc_dir_entry proc_sys; - extern struct proc_dir_entry proc_pid; - extern struct proc_dir_entry proc_pid_fd; -@@ -278,5 +290,6 @@ - extern struct inode_operations proc_kmsg_inode_operations; - extern struct inode_operations proc_link_inode_operations; - extern struct inode_operations proc_fd_inode_operations; -+extern struct inode_operations proc_atm_inode_operations; - - #endif ---- ref/fs/proc/root.c Tue Apr 30 12:09:45 1996 -+++ work/fs/proc/root.c Fri Nov 15 19:06:42 1996 -@@ -15,6 +15,10 @@ - #include - #include - -+ -+extern void atm_proc_init(void); -+ -+ - /* - * Offset of the first process in the /proc root directory.. - */ -@@ -148,6 +152,16 @@ - NULL, NULL /* parent, subdir */ - }; - -+struct proc_dir_entry proc_atm = { -+ PROC_ATM, 3, "atm", -+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, -+ 0, &proc_dir_inode_operations, -+ NULL, NULL, -+ NULL, -+ &proc_root, NULL -+}; -+ -+ - int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) - { - dp->next = dir->subdir; -@@ -296,6 +310,11 @@ - proc_register(&proc_root, &proc_net); - proc_register(&proc_root, &proc_scsi); - proc_register(&proc_root, &proc_sys_root); -+ -+#ifdef CONFIG_ATM -+ proc_register(&proc_root, &proc_atm); -+ atm_proc_init(); -+#endif - - #ifdef CONFIG_DEBUG_MALLOC - proc_register(&proc_root, &(struct proc_dir_entry) { ---- ref/fs/proc/inode.c Thu Apr 25 15:32:45 1996 -+++ work/fs/proc/inode.c Fri Nov 15 19:06:43 1996 -@@ -4,6 +4,7 @@ - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -+#include - #include - #include - #include -@@ -161,6 +162,14 @@ - return; - } - -+#ifdef CONFIG_ATM -+ if (ino >= PROC_ATM_DEVICES && ino < PROC_ATM_LAST) { -+ inode->i_mode = S_IFREG | S_IRUGO; -+ inode->i_op = &proc_atm_inode_operations; -+ return; -+ } -+#endif -+ - if (!pid) { - switch (ino) { - case PROC_KMSG: -@@ -175,6 +184,13 @@ - inode->i_nlink = 2; - inode->i_op = &proc_scsi_inode_operations; - break; -+#ifdef CONFIG_ATM -+ case PROC_ATM: -+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; -+ inode->i_nlink = 2; -+ inode->i_op = &proc_atm_inode_operations; -+ break; -+#endif - case PROC_KCORE: - inode->i_mode = S_IFREG | S_IRUSR; - inode->i_op = &proc_kcore_inode_operations; ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/proc.c Wed Mar 19 21:01:30 1997 -@@ -0,0 +1,503 @@ -+/* net/atm/proc.c - ATM /proc interface */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* to get aqd */ -+#include /* for HZ */ -+ -+#include "static.h" /* ugly */ -+#include "signaling.h" /* to get sigd - ugly too */ -+#include "ipcommon.h" -+#include "atmarp.h" -+ -+#ifdef CONFIG_ATM_LANE -+#include "lec.h" -+#include "lec_arpc.h" -+extern struct device *dev_lec[MAX_LEC_ITF]; -+#endif -+ -+#ifdef CONFIG_AREQUIPA -+void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb); -+#endif -+ -+/*extern void eni_proc(int i,char *buf); - not yet @@@ */ -+extern void atm_push_clip(struct atm_vcc *vcc,struct sk_buff *skb); -+ -+ -+static int atm_header(ino_t ino,char *buf) -+{ -+ switch (ino) { -+ case PROC_ATM_DEVICES: -+ sprintf(buf,"Itf Type ESI/\"MAC\"addr " -+ "AAL(TX,err,RX,err,drop) ...\n"); -+ break; -+ case PROC_ATM_ARP: -+ sprintf(buf,"IPitf TypeEncp Idle IP address " -+ "ATM address\n"); -+ break; -+ case PROC_ATM_SVC: -+ sprintf(buf,"Itf VPI VCI State Remote\n"); -+ break; -+ case PROC_ATM_PVC: -+ sprintf(buf,"Itf VPI VCI AAL RX(PCR,Class) " -+ "TX(PCR,Class)\n"); -+ break; -+#ifdef CONFIG_ATM_LANE -+ case PROC_ATM_LEC: -+ sprintf(buf,"Itf MAC ATM destination Status Flags VPI/VCI Recv VPI/VCI\n"); -+ break; -+#endif -+#ifdef CONFIG_AREQUIPA -+ case PROC_ATM_AREQUIPA: -+ sprintf(buf,"Itf VPI VCI State Sock# Inode\n"); -+ break; -+#endif -+ default: -+ return -EINVAL; -+ } -+ return strlen(buf); -+} -+ -+ -+static void add_stats(char *buf,const char *aal, -+ const struct atm_aal_stats *stats) -+{ -+ sprintf(strchr(buf,0),"%s ( %ld %ld %ld %ld %ld )",aal,stats->tx, -+ stats->tx_err,stats->rx,stats->rx_err,stats->rx_drop); -+} -+ -+ -+static void dev_info(const struct atm_dev *dev,char *buf) -+{ -+ int off,i; -+ -+ off = sprintf(buf,"%3d %-8s",dev->number,dev->type); -+ for (i = 0; i < ESI_LEN; i++) -+ off += sprintf(buf+off,"%02x",dev->esi[i]); -+ strcat(buf," "); -+ add_stats(buf,"0",&dev->stats.aal0); -+ strcat(buf," "); -+ add_stats(buf,"5",&dev->stats.aal5); -+ strcat(buf,"\n"); -+} -+ -+ -+#ifdef CONFIG_ATM_ATMARP -+ -+ -+static int svc_addr(char *buf,struct sockaddr_atmsvc *addr) -+{ -+ static int code[] = { 1,2,10,6,1,0 }; -+ static int e164[] = { 1,8,4,6,1,0 }; -+ int *fields; -+ int len,i,j,pos; -+ -+ len = 0; -+ if (*addr->sas_addr.pub) { -+ strcpy(buf,addr->sas_addr.pub); -+ len = strlen(addr->sas_addr.pub); -+ buf += len; -+ if (*addr->sas_addr.pub) { -+ *buf += '+'; -+ len++; -+ } -+ } -+ else if (!*addr->sas_addr.prv) { -+ strcpy(buf,"(none)"); -+ return strlen(buf); -+ } -+ if (*addr->sas_addr.prv) { -+ len += 44; -+ pos = 0; -+ fields = *addr->sas_addr.prv == ATM_AFI_E164 ? e164 : code; -+ for (i = 0; fields[i]; i++) { -+ for (j = fields[i]; j; j--) { -+ sprintf(buf,"%02X",addr->sas_addr.prv[pos++]); -+ buf += 2; -+ } -+ if (fields[i+1]) *buf++ = '.'; -+ } -+ } -+ return len; -+} -+ -+ -+static void atmarp_info(struct device *dev,struct atmarp_entry *entry, -+ char *buf) -+{ -+ unsigned char *ip; -+ int svc,off,ip_len; -+ -+ svc = !entry->vcc || entry->vcc->family == AF_ATMSVC; -+ off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC", -+ entry->encap ? "LLC" : "NULL",(jiffies-entry->last_use)/HZ); -+ ip = (unsigned char *) &entry->ip; -+ ip_len = sprintf(buf+off,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); -+ off += ip_len; -+ while (ip_len++ < 16) buf[off++] = ' '; -+ if (!entry->vcc) strcpy(buf+off,"(incomplete)\n"); -+ else if (!svc) -+ sprintf(buf+off,"%d.%d.%d\n",entry->vcc->dev->number, -+ entry->vcc->vpi,entry->vcc->vci); -+ else { -+ off += svc_addr(buf+off,&entry->vcc->remote); -+ strcpy(buf+off,"\n"); -+ } -+} -+ -+ -+#endif -+ -+ -+static void pvc_info(struct atm_vcc *vcc,char *buf) -+{ -+ static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" }; -+ static const char *aal_name[] = { -+ "0", "1", "2", "3/4", /* 0- 3 */ -+ "???", "5", "???", "???" };/* 4- 7 */ -+ int off; -+ -+ off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s", -+ vcc->dev->number,vcc->vpi,vcc->vci, -+ vcc->aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" : -+ aal_name[vcc->aal],vcc->qos.rxtp.min_pcr, -+ class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr, -+ class_name[vcc->qos.txtp.traffic_class]); -+#ifdef CONFIG_ATM_CLIP -+ if (vcc->push == atm_push_clip) { -+ struct device *dev; -+ -+ dev = (struct device *) vcc->proto_data; -+ off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",dev->name); -+ if (dev->hard_header_len == RFC1483LLC_LEN) -+ off += sprintf(buf+off,"LLC/SNAP"); -+ else if (dev->hard_header_len == 0) -+ off += sprintf(buf+off,"None"); -+ else off += sprintf(buf+off,"Unknown"); -+ } -+#endif -+ strcpy(buf+off,"\n"); -+} -+ -+ -+static const char *vcc_state(struct atm_vcc *vcc) -+{ -+ if (vcc->flags & ATM_VF_READY) return "CONNECTED"; -+ if (vcc->flags & ATM_VF_RELEASED) return "CLOSING"; -+ if (vcc->flags & ATM_VF_LISTEN) return "LISTEN"; -+ if (vcc->flags & ATM_VF_REGIS) return "INUSE"; -+ if (vcc->flags & ATM_VF_BOUND) return "BOUND"; -+ return "IDLE"; -+} -+ -+ -+static void svc_info(struct atm_vcc *vcc,char *buf) -+{ -+ char *here; -+ int i; -+ -+ if (!vcc->dev) sprintf(buf,"Unassigned "); -+ else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci); -+ here = strchr(buf,0); -+ here += sprintf(here,"%-10s ",vcc == sigd ? "Signaling" : -+#ifdef CONFIG_ATM_ATMARP -+ vcc == atmarpd ? "ATMARPctrl" : -+#endif -+#ifdef CONFIG_AREQUIPA -+ vcc == aqd ? "Arequipa" : -+#endif -+ vcc_state(vcc)); -+ here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub, -+ *vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : ""); -+ if (*vcc->remote.sas_addr.prv) -+ for (i = 0; i < ATM_ESA_LEN; i++) -+ here += sprintf(here,"%02x", -+ vcc->remote.sas_addr.prv[i]); -+ strcat(here,"\n"); -+} -+ -+ -+#ifdef CONFIG_AREQUIPA -+ -+ -+static const char *arequipa_state(const struct atm_vcc *vcc) -+{ -+ if (!(vcc->flags & ATM_VF_REGIS) && vcc->family != PF_ATMPVC) -+ return "DOOMED"; -+ if (vcc->upper) return "ATTACHED"; -+ return "DANGLING"; -+} -+ -+ -+static void arequipa_info(struct atm_vcc *vcc,char *buf) -+{ -+ char *here; -+ -+ if (!vcc->dev) sprintf(buf,"Unassigned "); -+ else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci); -+ here = strchr(buf,0); -+ here += sprintf(here,"%-8s ",arequipa_state(vcc)); -+ if (vcc->upper) -+ here += sprintf(here,"%5d %ld",vcc->upper->num, -+ vcc->upper->socket && SOCK_INODE(vcc->upper->socket) ? -+ SOCK_INODE(vcc->upper->socket)->i_ino : 0); -+ strcat(here,"\n"); -+} -+ -+ -+#endif -+ -+ -+#ifdef CONFIG_ATM_LANE -+ -+static char* -+lec_arp_get_status_string(unsigned char status) -+{ -+ switch(status) { -+ case ESI_UNKNOWN: -+ return "ESI_UNKNOWN "; -+ case ESI_ARP_PENDING: -+ return "ESI_ARP_PENDING "; -+ case ESI_VC_PENDING: -+ return "ESI_VC_PENDING "; -+ case ESI_FLUSH_PENDING: -+ return "ESI_FLUSH_PENDING "; -+ case ESI_FORWARD_DIRECT: -+ return "ESI_FORWARD_DIRECT"; -+ default: -+ return " "; -+ } -+} -+ -+static void -+lec_info(struct lec_arp_table *entry, char *buf) -+{ -+ int j, offset=0; -+ -+ -+ for(j=0;jmac_addr[j]); -+ } -+ offset+=sprintf(buf+offset, " "); -+ for(j=0;jatm_addr[j]); -+ } -+ offset+=sprintf(buf+offset, " %s %4.4x", -+ lec_arp_get_status_string(entry->status), -+ entry->flags&0xffff); -+ if (entry->vcc) { -+ offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi, -+ entry->vcc->vci); -+ } else -+ offset+=sprintf(buf+offset, " "); -+ if (entry->recv_vcc) { -+ offset+=sprintf(buf+offset, " %3d %3d", -+ entry->recv_vcc->vpi, entry->recv_vcc->vci); -+ } -+ -+ sprintf(buf+offset,"\n"); -+} -+ -+#endif -+ -+ -+static int atm_info(ino_t ino,loff_t *pos,char *buf) -+{ -+ switch (ino) { -+ case PROC_ATM_DEVICES: -+ while (*pos <= MAX_ATM_ITF) -+ if (atm_dev[*pos-1].ops) break; -+ else (*pos)++; -+ if (*pos > MAX_ATM_ITF) return 0; -+ dev_info(atm_dev+*pos-1,buf); -+ break; -+#ifdef CONFIG_ATM_ATMARP -+ case PROC_ATM_ARP: -+ { -+ struct device *dev; -+ struct atmarp_entry *entry; -+ int count; -+ -+ count = *pos; -+ for (dev = clip_devs; dev; -+ dev = PRIV(dev)->next) -+ for (entry = PRIV(dev)->table; entry; -+ entry = entry->next) -+ if (!--count) { -+ atmarp_info(dev,entry, -+ buf); -+ return strlen(buf); -+ } -+ return 0; -+ } -+ return 0; -+#endif -+ case PROC_ATM_SVC: -+ while (*pos <= MAX_ATM_VCC) -+ if (atm_vcc[*pos-1].family == PF_ATMSVC) break; -+ else (*pos)++; -+ if (*pos > MAX_ATM_VCC) return 0; -+ svc_info(atm_vcc+*pos-1,buf); -+ break; -+ case PROC_ATM_PVC: -+ while (*pos <= MAX_ATM_VCC) -+ if (atm_vcc[*pos-1].family == PF_ATMPVC && -+ atm_vcc[*pos-1].dev) break; -+ else (*pos)++; -+ if (*pos > MAX_ATM_VCC) return 0; -+ pvc_info(atm_vcc+*pos-1,buf); -+ break; -+#ifdef CONFIG_AREQUIPA -+ case PROC_ATM_AREQUIPA: -+ while (*pos <= MAX_ATM_VCC) -+ if ((atm_vcc[*pos-1].family == PF_ATMPVC || -+ atm_vcc[*pos-1].family == PF_ATMSVC) && -+ atm_vcc[*pos-1].push == atm_push_arequipa) -+ break; -+ else (*pos)++; -+ if (*pos > MAX_ATM_VCC) return 0; -+ arequipa_info(atm_vcc+*pos-1,buf); -+ break; -+#endif -+#ifdef CONFIG_ATM_LANE -+ -+ case PROC_ATM_LEC: { -+ struct lec_priv *priv; -+ struct lec_arp_table *entry; -+ int i, count, d, e; -+ -+ count = *pos; -+ for(d=0;dpriv)) { -+ for(i=0;ilec_arp_tables[i]; -+ for(;entry;entry=entry->next) { -+ if (!--count) { -+ e=sprintf(buf,"%s ",dev_lec[d]->name); -+ lec_info(entry,buf+e); -+ return strlen(buf); -+ } -+ } -+ } -+ for(entry=priv->lec_arp_empty_ones; -+ entry; entry=entry->next) { -+ if (!--count) { -+ e=sprintf(buf,"%s ", -+ dev_lec[d]->name); -+ lec_info(entry, buf+e); -+ return strlen(buf); -+ } -+ } -+ for(entry=priv->lec_no_forward; -+ entry; entry=entry->next) { -+ if (!--count) { -+ e=sprintf(buf,"%s ", -+ dev_lec[d]->name); -+ lec_info(entry, buf+e); -+ return strlen(buf); -+ } -+ } -+ } -+ } -+ return 0; -+ } -+ -+#endif -+ default: -+ return -EINVAL; -+ } -+ return strlen(buf); -+} -+ -+ -+static int proc_atm_read(struct inode *inode,struct file *file,char *buf, -+ int count) -+{ -+ unsigned long page; -+ int length; -+ -+ if (count < 0) return -EINVAL; -+ page = get_free_page(GFP_KERNEL); -+ if (!page) return -ENOMEM; -+ if (file->f_pos) -+ length = atm_info(inode->i_ino,&file->f_pos,(char *) page); -+ else length = atm_header(inode->i_ino,(char *) page); -+ if (length > count) length = -EINVAL; -+ if (length >= 0) { -+ memcpy_tofs(buf,(char *) page,length); -+ file->f_pos++; -+ } -+ free_page(page); -+ return length; -+} -+ -+ -+static struct file_operations proc_atm_operations = { -+ NULL, /* lseek */ -+ proc_atm_read, /* read */ -+ NULL, /* write */ -+ NULL, /* readdir */ -+ NULL, /* select */ -+ NULL, /* ioctl */ -+ NULL, /* mmap */ -+ NULL, /* no special open code */ -+ NULL, /* no special release */ -+ NULL /* can't fsync */ -+}; -+ -+struct inode_operations proc_atm_inode_operations = { -+ &proc_atm_operations, /* default ATM directory file-ops */ -+ NULL, /* create */ -+ NULL, /* lookup */ -+ NULL, /* link */ -+ NULL, /* unlink */ -+ NULL, /* symlink */ -+ NULL, /* mkdir */ -+ NULL, /* rmdir */ -+ NULL, /* mknod */ -+ NULL, /* rename */ -+ NULL, /* readlink */ -+ NULL, /* follow_link */ -+ NULL, /* readpage */ -+ NULL, /* writepage */ -+ NULL, /* bmap */ -+ NULL, /* truncate */ -+ NULL /* permission */ -+}; -+ -+ -+#define FILE(ino,name,len) &proc_atm, \ -+ (&(struct proc_dir_entry) { ino, len, name, \ -+ S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_atm_inode_operations, NULL }) -+ -+ -+void atm_proc_init(void) -+{ -+ proc_register(FILE(PROC_ATM_DEVICES,"devices",7)); -+ proc_register(FILE(PROC_ATM_ARP,"arp",3)); -+ proc_register(FILE(PROC_ATM_SVC,"svc",3)); -+ proc_register(FILE(PROC_ATM_PVC,"pvc",3)); -+#ifdef CONFIG_ATM_LANE -+ proc_register(FILE(PROC_ATM_LEC,"lec",3)); -+#endif -+#ifdef CONFIG_AREQUIPA -+ proc_register(FILE(PROC_ATM_AREQUIPA,"arequipa",8)); -+#endif -+} ---- ref/drivers/char/console.c Thu Nov 7 10:25:21 1996 -+++ work/drivers/char/console.c Fri Nov 15 19:06:44 1996 -@@ -1982,6 +1982,43 @@ - } - } - -+ -+static unsigned long tty_base = 0; -+ -+ -+static void put_scon(char ch) -+{ -+ unsigned long flags; -+ -+ while (1) { -+ while (!(inb_p(tty_base+5) & 0x20)); -+ save_flags(flags); -+ cli(); -+ if (inb_p(tty_base+5) & 0x20) break; -+ restore_flags(flags); -+ } -+ outb_p(ch,tty_base); -+ restore_flags(flags); -+} -+ -+ -+static void print_scon(const char *str) -+{ -+ if (!tty_base) return; -+ while (*str) { -+ if (*str == '\n') put_scon('\r'); -+ put_scon(*str++); -+ } -+} -+ -+ -+void serial_console_setup(char *str,int *ints) -+{ -+ if (ints[0] != 1 || ints[1] < 0 || ints[1] > 3) return; -+ tty_base = ((unsigned short *) 0x400)[ints[1]]; -+} -+ -+ - /* - * unsigned long con_init(unsigned long); - * -@@ -2100,6 +2137,11 @@ - display_desc, video_num_columns, video_num_lines, - MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", - MAX_NR_CONSOLES); -+ -+ if (tty_base) { -+ register_console(print_scon); -+ return kmem_start; -+ } - - /* - * can't register TGA yet, because PCI bus probe has *not* taken ---- ref/init/main.c Wed Oct 30 02:42:41 1996 -+++ work/init/main.c Fri Nov 15 19:06:45 1996 -@@ -36,6 +36,9 @@ - #ifdef CONFIG_ROOT_NFS - #include - #endif -+#ifdef CONFIG_BIGPHYS_AREA -+#include -+#endif - - #include - -@@ -174,6 +177,8 @@ - #endif - - -+void serial_console_setup(char *str,int *ints); -+ - #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) - extern void ipc_init(void); - #endif -@@ -415,6 +420,10 @@ - #ifdef CONFIG_BAYCOM - { "baycom=", baycom_setup }, - #endif -+#ifdef CONFIG_BIGPHYS_AREA -+ { "bigphysarea=", bigphysarea_setup }, -+#endif -+ { "scon=", serial_console_setup }, - { 0, 0 } - }; - -@@ -806,6 +815,9 @@ - memory_start = console_init(memory_start,memory_end); - #ifdef CONFIG_PCI - memory_start = pci_init(memory_start,memory_end); -+#endif -+#ifdef CONFIG_BIGPHYS_AREA -+ memory_start = bigphysarea_init(memory_start,memory_end); - #endif - memory_start = kmalloc_init(memory_start,memory_end); - sti(); ---- ref/drivers/block/genhd.c Wed Aug 21 08:18:07 1996 -+++ work/drivers/block/genhd.c Fri Nov 15 19:06:46 1996 -@@ -53,6 +53,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. -@@ -743,6 +744,9 @@ - #endif - #ifdef CONFIG_INET - net_dev_init(); -+#endif -+#ifdef CONFIG_ATM -+ (void) atmdev_init(); - #endif - console_map_init(); - ---- ref/drivers/net/net_init.c Wed Nov 6 13:39:42 1996 -+++ work/drivers/net/net_init.c Fri Nov 15 19:06:46 1996 -@@ -199,6 +199,7 @@ - dev->set_mac_address = eth_mac_addr; - dev->header_cache_bind = eth_header_cache_bind; - dev->header_cache_update= eth_header_cache_update; -+ dev->ip_arp = ether_arp; - - dev->type = ARPHRD_ETHER; - dev->hard_header_len = ETH_HLEN; ---- ref/drivers/net/eql.c Sun Sep 22 20:17:08 1996 -+++ work/drivers/net/eql.c Fri Nov 15 19:06:47 1996 -@@ -248,6 +248,7 @@ - dev->open = eql_open; - dev->stop = eql_close; - dev->do_ioctl = eql_ioctl; -+ dev->ip_arp = ether_arp; - dev->hard_start_xmit = eql_slave_xmit; - dev->get_stats = eql_get_stats; - ---- ref/drivers/net/pi2.c Fri Mar 1 06:50:45 1996 -+++ work/drivers/net/pi2.c Fri Nov 15 19:06:48 1996 -@@ -1414,6 +1414,7 @@ - dev->open = pi_open; - dev->stop = pi_close; - dev->do_ioctl = pi_ioctl; -+ dev->ip_arp = ether_arp; - dev->hard_start_xmit = pi_send_packet; - dev->get_stats = pi_get_stats; - ---- ref/drivers/net/ppp.c Tue Oct 8 19:21:03 1996 -+++ work/drivers/net/ppp.c Fri Nov 15 19:06:50 1996 -@@ -398,6 +398,7 @@ - dev->stop = ppp_dev_close; - dev->get_stats = ppp_dev_stats; - dev->do_ioctl = ppp_dev_ioctl; -+ dev->ip_arp = NULL; - dev->addr_len = 0; - dev->tx_queue_len = 10; - dev->type = ARPHRD_PPP; ---- ref/net/ipv4/arp.c Wed Oct 30 02:42:42 1996 -+++ work/net/ipv4/arp.c Fri Nov 15 19:06:51 1996 -@@ -2201,7 +2201,7 @@ - * Handle an ARP layer I/O control request. - */ - --int arp_ioctl(unsigned int cmd, void *arg) -+static int do_arp_ioctl(unsigned int cmd, void *arg) - { - int err; - struct arpreq r; -@@ -2212,12 +2212,7 @@ - { - case SIOCDARP: - case SIOCSARP: -- if (!suser()) -- return -EPERM; - case SIOCGARP: -- err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); -- if (err) -- return err; - memcpy_fromfs(&r, arg, sizeof(struct arpreq)); - break; - case OLD_SIOCDARP: -@@ -2406,6 +2401,47 @@ - - - -+int ether_arp(struct device *dev,unsigned int cmd,void *arg) -+{ -+ return do_arp_ioctl(cmd,arg); -+} -+ -+ -+int arp_ioctl(unsigned int cmd,void *arg) -+{ -+ struct arpreq req; -+ struct rtable *route; -+ int error; -+ -+ switch (cmd) { -+ case SIOCSARP: -+ case SIOCDARP: -+ if (!suser()) return -EPERM; -+ /* fall through */ -+ case SIOCGARP: -+ error = verify_area(VERIFY_READ,arg,sizeof(req)); -+ if (error) return error; -+ memcpy_fromfs(&req,arg,sizeof(req)); -+ if (req.arp_pa.sa_family != AF_INET) -+ return -EPFNOSUPPORT; ++ msg = (struct atmsvc_msg *) skb->data; ++ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); ++ DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,msg->vcc); ++ vcc = (struct atm_vcc *) msg->vcc; ++ switch (msg->type) { ++ case as_okay: ++ vcc->reply = msg->reply; ++ if (!*vcc->local.sas_addr.prv && ++ !*vcc->local.sas_addr.pub) { ++ vcc->local.sas_family = AF_ATMSVC; ++ memcpy(vcc->local.sas_addr.prv, ++ msg->local.sas_addr.prv,ATM_ESA_LEN); ++ memcpy(vcc->local.sas_addr.pub, ++ msg->local.sas_addr.pub,ATM_E164_LEN+1); ++ } ++ if (vcc->vpi || vcc->vci) break; ++ vcc->itf = msg->pvc.sap_addr.itf; ++ vcc->vpi = msg->pvc.sap_addr.vpi; ++ vcc->vci = msg->pvc.sap_addr.vci; ++ if (vcc->vpi || vcc->vci) vcc->qos = msg->qos; ++ break; ++ case as_error: ++ vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_READY); ++ vcc->reply = msg->reply; ++ break; ++ case as_indicate: ++ vcc = (struct atm_vcc *) msg->listen_vcc; ++ DPRINTK("as_indicate!!!\n"); ++ if (!vcc->backlog_quota) { ++ sigd_enq(0,as_reject,(struct atm_vcc *) ++ msg->listen_vcc,NULL,NULL); ++ return 0; ++ } ++ vcc->backlog_quota--; ++ skb_queue_tail(&vcc->listenq,skb); ++ if (vcc->callback) { ++ DPRINTK("waking vcc->sleep 0x%p\n", ++ &vcc->sleep); ++ vcc->callback(vcc); ++ } ++ return 0; ++ case as_close: ++ vcc->flags |= ATM_VF_RELEASED; ++ vcc->flags &= ~ATM_VF_READY; ++ vcc->reply = msg->reply; + break; + default: -+ /* Here's the deal: unknown ioctls are passed, but -+ their request structure _must_ begin with a struct -+ sockaddr. */ -+ error = verify_area(VERIFY_READ,arg, -+ sizeof(struct sockaddr)); -+ if (error) return error; -+ memcpy_fromfs(&req.arp_pa,arg,sizeof(struct sockaddr)); ++ printk(KERN_ALERT "sigd_send: bad message type %d\n", ++ (int) msg->type); ++ return -EINVAL; + } -+ route = ip_rt_route(((struct sockaddr_in *) &req.arp_pa)->sin_addr. -+ s_addr,1); -+ if (!route) return -EHOSTUNREACH; -+ if (!route->rt_dev->ip_arp) return -EINVAL; -+ return route->rt_dev->ip_arp(route->rt_dev,cmd,arg); -+} -+ -+ - /* - * Called once on startup. - */ ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atmlec.h Wed Mar 19 20:44:11 1997 -@@ -0,0 +1,64 @@ -+/* -+ * -+ * ATM Lan Emulation Daemon vs. driver interface -+ * -+ * carnil@cs.tut.fi -+ * -+ */ -+ -+#ifndef _ATMLEC_H_ -+#define _ATMLEC_H_ -+ -+#include -+#include -+#include -+/* ATM lec daemon control socket */ -+#define ATMLEC_CTRL _IO('a',ATMIOC_LANE) -+#define ATMLEC_DATA _IO('a',ATMIOC_LANE+1) -+#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2) -+ -+/* Maximum number of LEC interfaces (tweakable) */ -+#define MAX_LEC_ITF 4 -+ -+typedef enum { -+ l_set_mac_addr, l_del_mac_addr, -+ l_svc_setup, -+ l_addr_delete, l_topology_change, -+ l_flush_complete, l_arp_update, -+ l_config, l_flush_tran_id, -+ l_set_lecid, l_arp_xmt -+} atmlec_msg_type; -+ -+#define ATMLEC_MSG_TYPE_MAX l_arp_xmt -+ -+struct atmlec_config_msg { -+ unsigned int maximum_unknown_frame_count; -+ unsigned long max_unknown_frame_time; -+ unsigned short max_retry_count; -+ unsigned long aging_time; -+ unsigned long forward_delay_time; -+ unsigned long arp_response_time; -+ unsigned long flush_timeout; -+ unsigned long path_switching_delay; -+}; -+ -+struct atmlec_msg { -+ atmlec_msg_type type; -+ union { -+ struct { -+ unsigned char mac_addr[ETH_ALEN]; -+ unsigned char atm_addr[ATM_ESA_LEN]; -+ unsigned long flag;/* Topology_change flag, -+ remoteflag, permanent flag, -+ lecid, transaction id */ -+ } normal; -+ struct atmlec_config_msg config; -+ } content; -+}; -+ -+struct atmlec_ioc { -+ int dev_num; -+ unsigned char atm_addr[ATM_ESA_LEN]; -+ unsigned char receive; /* 1= receive vcc, 0 = send_vcc */ -+}; -+#endif /* _ATMLEC_H_ */ ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/lec.c Wed Dec 4 13:13:39 1996 -@@ -0,0 +1,646 @@ -+/* -+ * lec.c: Lan Emulation driver -+ * Marko Kiiskila carnil@cs.tut.fi -+ * -+ */ -+ -+#include -+ -+/* We are ethernet device */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* And atm device */ -+#include -+#include -+ -+#include "lec.h" -+#include "lec_arpc.h" -+#include "tunable.h" -+ -+ -+#define DPRINTK(format,args...) -+/* -+#define DPRINTK printk -+*/ -+#define DUMP_PACKETS 0 /* 0 = None, -+ * 1 = 30 first bytes -+ * 2 = Whole packet -+ */ -+ -+static int lec_open(struct device *dev); -+static int lec_send_packet(struct sk_buff *skb, struct device *dev); -+static int lec_close(struct device *dev); -+static struct enet_statistics *lec_get_stats(struct device *dev); -+static int lec_init(struct device *dev); -+ -+/* will be lec0, lec1, lec2 etc. */ -+static char myname[] = "lecx"; -+ -+/* Device structures */ -+struct device *dev_lec[MAX_LEC_ITF] = -+{NULL, NULL, NULL, NULL}; -+ -+/* -+ * Open/initialize the netdevice. This is called (in the current kernel) -+ * sometime after booting when the 'ifconfig' program is run. -+ * -+ * This routine should set everything up anew at each open, even -+ * registers that "should" only need to be set once at boot, so that -+ * there is non-reboot way to recover if something goes wrong. -+ */ -+ -+static int -+lec_open(struct device *dev) -+{ -+ struct lec_priv *priv = (struct lec_priv *)dev->priv; -+ -+ dev->tbusy = 0; -+ dev->start = 1; -+ dev->interrupt = 1; -+ memset(&priv->stats,0,sizeof(struct enet_statistics)); -+ -+ return 0; -+} -+ -+static int -+lec_send_packet(struct sk_buff *skb, struct device *dev) -+{ -+ struct lec_priv *priv = (struct lec_priv *)dev->priv; -+ struct lecdatahdr_8023 *lec_h; -+ struct atm_vcc *send_vcc; -+ unsigned char *nb; -+#if DUMP_PACKETS > 0 -+ char buf[300]; -+ int i=0; -+#endif /* DUMP_PACKETS >0 */ -+ -+ DPRINTK("Lec_send_packet called\n"); -+ if (!priv->lecd) { -+ printk("%s:No lecd attached\n",dev->name); -+ priv->stats.tx_errors++; -+ return -EUNATCH; -+ } -+ if (dev->tbusy) { -+ /* -+ * If we get here, some higher level has decided we are broken. -+ * There should really be a "kick me" function call instead. -+ */ -+ printk(KERN_WARNING "%s: transmit timed out.\n", dev->name); -+ dev->tbusy=0; -+ } -+ /* -+ * If some higher layer thinks we've missed an tx-done interrupt -+ * we are passed NULL. Caution: dev_tint() handles the cli()/sti() -+ * itself. -+ */ -+ if (skb == NULL) { -+ dev_tint(dev); -+ return 0; -+ } -+ /* -+ * Block a timer-based transmit from overlapping. This could better be -+ * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. -+ */ -+ -+ if (set_bit(0, (void*)&dev->tbusy) != 0) { -+ printk(KERN_WARNING "%s: Transmitter access conflict.\n", -+ dev->name); -+ } else { -+ DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n", -+ (long)skb->head, (long)skb->data, (long)skb->tail, -+ (long)skb->end); -+ -+ /* 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); -+#if DUMP_PACKETS >= 2 -+ for(i=0;ilen && i <99;i++) { -+ sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]); -+ } -+#elif DUMP_PACKETS >= 1 -+ for(i=0;ilen && i < 30;i++) { -+ sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]); -+ } -+#endif /* DUMP_PACKETS >= 1 */ -+ if (i==skb->len) -+ printk("%s\n",buf); -+ else -+ printk("%s...\n",buf); -+#endif /* DUMP_PACKETS > 0 */ -+ /* Send to right vcc */ -+ send_vcc = lec_arp_resolve(priv, lec_h->h_dest); -+ DPRINTK("%s:send_vcc:%p vcc_flags:%x\n", dev->name, -+ send_vcc, send_vcc?send_vcc->flags:0); -+ if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) { -+ priv->stats.tx_errors++; -+ DPRINTK("%s:lec_send_packet: handing back...\n", -+ dev->name); -+ dev->tbusy=1; -+ return 1; -+ } else { -+#if DUMP_PACKETS > 0 -+ printk("%s:sending to vpi:%d vci:%d\n", dev->name, -+ send_vcc->vpi, send_vcc->vci); -+#endif /* DUMP_PACKETS > 0 */ -+ /* Minimum ethernet-frame size */ -+ if (skb->len <62) { -+ if (skb->truesize < 62) { -+ printk("%s:data packet %ld / %d\n", -+ dev->name, -+ skb->len,skb->truesize); -+ nb=(unsigned char*)kmalloc(64, -+ GFP_ATOMIC); -+ memcpy(nb,skb->data,skb->len); -+ kfree(skb->head); -+ skb->head = skb->data = nb; -+ skb->tail = nb+62; -+ skb->end = nb+64; -+ skb->len=62; -+ skb->truesize = 64; -+ } else { -+ skb->len = 62; -+ } -+ } -+ atomic_add(skb->truesize, &send_vcc->tx_inuse); -+ skb->atm.iovcnt = 0; -+ send_vcc->dev->ops->send(send_vcc, skb); -+ priv->stats.tx_packets++; -+ } -+ } -+ /* Should we wait for card's device driver to notify us? */ -+ dev->tbusy=0; -+ -+ return 0; ++ if (vcc->callback) vcc->callback(vcc); ++ dev_kfree_skb(skb,FREE_WRITE); ++ return 0; +} + -+/* The inverse routine to net_open(). */ -+static int -+lec_close(struct device *dev) -+{ -+ dev->tbusy = 1; -+ dev->start = 0; -+ return 0; -+} + -+/* -+ * Get the current statistics. -+ * This may be called with the card open or closed. -+ */ -+static struct enet_statistics * -+lec_get_stats(struct device *dev) ++void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, ++ const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, ++ const struct sockaddr_atmsvc *svc) +{ -+ struct lec_priv *priv = (struct lec_priv *)dev->priv; -+ -+ 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; -+} ++ struct sk_buff *skb; ++ struct atmsvc_msg *msg; ++ struct atm_blli *walk; ++ int size,i; ++#ifdef WAIT_FOR_DEMON ++ static unsigned long silence = 0; ++#endif + -+int -+lec_rebuild_header(void *buff, struct device *dev, unsigned long dst, -+ struct sk_buff *skb) -+{ -+ struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023*)buff; -+ -+ /* -+ * Only ARP/IP is currently supported -+ */ -+ if (hdr->h_type != htons(ETH_P_IP)) { -+ 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; -+ } -+ /* -+ * Try and get ARP to resolve the header. -+ */ -+#ifdef CONFIG_INET -+ return arp_find(hdr->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; ++ DPRINTK("sigd_enq %d (0x%p)\n",(int) type,vcc); ++ size = sizeof(struct atmsvc_msg)-sizeof(struct atm_blli); ++ if (svc) ++ for (walk = svc->sas_addr.blli; walk; walk = walk->next) ++ size += sizeof(struct atm_blli); ++ while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); ++ skb_put(skb,size); ++ msg = (struct atmsvc_msg *) skb->data; ++ msg->type = type; ++ msg->vcc = (unsigned long) vcc; ++ msg->listen_vcc = (unsigned long) listen_vcc; ++ if (vcc) msg->qos = vcc->qos; ++ if (!svc) msg->svc.sas_family = 0; ++ else { ++ msg->svc = *svc; ++ i = 0; ++ for (walk = svc->sas_addr.blli; walk; walk = walk->next) ++ msg->blli[i++] = *walk; ++ } ++ if (vcc) msg->local = vcc->local; ++ if (!pvc) memset(&msg->pvc,0,sizeof(msg->pvc)); ++ else msg->pvc = *pvc; ++ while (!sigd) { ++#ifdef WAIT_FOR_DEMON ++ if (silence < jiffies) { ++ printk(KERN_INFO "atmsvc: waiting for signaling demon " ++ "...\n"); ++ silence = jiffies+30*HZ; ++ } ++ sleep_on(&sigd_sleep); +#else -+ return 0; ++ printk(KERN_WARNING "atmsvc: no signaling demon\n"); ++ kfree_skb(skb,FREE_READ); ++ return; +#endif ++ } ++ atomic_add(skb->truesize+ATM_PDU_OVHD,&sigd->rx_inuse); ++ skb_queue_tail(&sigd->recvq,skb); ++ wake_up(&sigd->sleep); ++ if (vcc) vcc->flags |= ATM_VF_REGIS; +} + -+/* -+ * Upper level calls this function to bind hardware header cache entry. -+ * If the call is successful, then corresponding Address Resolution Protocol -+ * (maybe, not ARP) takes responsibility for updating cache content. -+ */ -+void -+lec_header_cache_bind(struct hh_cache ** hhp, struct device *dev, -+ unsigned short htype, __u32 daddr) ++ ++static void sigd_close(struct atm_vcc *vcc) +{ -+ struct hh_cache *hh; -+ -+ if (htype != ETH_P_IP) { -+ printk("eth_header_cache_bind: %04x cache is not implemented\n", -+ htype); -+ return; -+ } -+ if (arp_bind_cache(hhp, dev, htype, daddr)) -+ return; -+ if ((hh=*hhp) != NULL) { -+ memcpy(hh->hh_data+8, dev->dev_addr, ETH_ALEN); -+ hh->hh_data[14] = htype>>8; -+ hh->hh_data[15] = htype&0xFF; -+ } -+} ++ struct sk_buff *skb; ++ struct atm_dev *dev; ++ struct atm_vcc *walk; + -+/* -+ * 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) -+{ -+ if (hh->hh_type != ETH_P_IP) { -+ printk("lec_header_cache_update: %04x cache is not implemented\n", -+ hh->hh_type); -+ return; -+ } -+ memcpy(hh->hh_data+2, haddr, ETH_ALEN); -+ hh->hh_uptodate = 1; ++ DPRINTK("sigd_close\n"); ++ sigd = NULL; ++ if (skb_peek(&vcc->recvq)) ++ printk(KERN_ERR "sigd_close: closing with requests pending\n"); ++ while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb,FREE_READ); ++ for (dev = atm_devs; dev; dev = dev->next) ++ for (walk = dev->vccs; walk; walk = walk->next) ++ if (walk->family == PF_ATMSVC && ++ !(walk->flags & ATM_VF_META)) { ++ walk->flags |= ATM_VF_RELEASED; ++ walk->reply = -EUNATCH; ++ wake_up(&walk->sleep); ++ } +} + -+static int -+lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) -+{ -+ struct device *dev = (struct device*)vcc->proto_data; -+ struct lec_priv *priv = (struct lec_priv*)dev->priv; -+ struct atmlec_msg *mesg; -+ int i; -+ -+ atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse); -+ mesg = (struct atmlec_msg *)skb->data; -+ DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type); -+ switch(mesg->type) { -+ case l_set_mac_addr: -+ for (i=0;i<6;i++) { -+ dev->dev_addr[i] = mesg->content.normal.mac_addr[i]; -+ } -+ break; -+ case l_del_mac_addr: -+ for(i=0;i<6;i++) { -+ dev->dev_addr[i] = 0; -+ } -+ break; -+ case l_addr_delete: -+ lec_addr_delete(priv, mesg->content.normal.atm_addr, -+ mesg->content.normal.flag); -+ break; -+ case l_topology_change: -+ priv->topology_change = mesg->content.normal.flag; -+ break; -+ case l_flush_complete: -+ lec_flush_complete(priv, mesg->content.normal.flag); -+ break; -+ case l_arp_update: -+ lec_arp_update(priv, mesg->content.normal.mac_addr, -+ mesg->content.normal.atm_addr, -+ mesg->content.normal.flag); -+ break; -+ case l_config: -+ priv->maximum_unknown_frame_count = -+ mesg->content.config.maximum_unknown_frame_count; -+ priv->max_unknown_frame_time = -+ (mesg->content.config.max_unknown_frame_time*HZ); -+ priv->max_retry_count = -+ mesg->content.config.max_retry_count; -+ priv->aging_time = (mesg->content.config.aging_time*HZ); -+ priv->forward_delay_time = -+ (mesg->content.config.forward_delay_time*HZ); -+ priv->arp_response_time = -+ (mesg->content.config.arp_response_time*HZ); -+ priv->flush_timeout = (mesg->content.config.flush_timeout*HZ); -+ priv->path_switching_delay = -+ (mesg->content.config.path_switching_delay*HZ); -+ break; -+ case l_flush_tran_id: -+ lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr, -+ mesg->content.normal.flag); -+ break; -+ case l_set_lecid: -+ priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag); -+ break; -+ default: -+ printk("%s: Unknown message type %d\n", dev->name, mesg->type); -+ dev_kfree_skb(skb, FREE_WRITE); -+ return -EINVAL; -+ } -+ dev_kfree_skb(skb, FREE_WRITE); -+ return 0; -+} + -+static void -+lec_atm_close(struct atm_vcc *vcc) -+{ -+ struct sk_buff *skb; -+ struct device *dev = (struct device *)vcc->proto_data; -+ struct lec_priv *priv = (struct lec_priv *)dev->priv; -+ -+ priv->lecd = NULL; -+ /* Do something needful? */ -+ -+ dev->tbusy = 1; -+ dev->start = 0; -+ -+ lec_arp_destroy(priv); -+ -+ if (skb_peek(&vcc->recvq)) -+ printk("%s lec_atm_close: closing with messages pending\n", -+ dev->name); -+ while ((skb = skb_dequeue(&vcc->recvq))) -+ dev_kfree_skb(skb,FREE_READ); -+ -+ printk("%s: Shut down!\n", dev->name); -+} -+ -+static struct atmdev_ops lecdev_ops = { -+ NULL, /*open*/ -+ lec_atm_close, /*close*/ -+ NULL, /*ioctl*/ -+ NULL, /*getsockopt */ -+ NULL, /*setsockopt */ -+ lec_atm_send, /*send */ -+ NULL, /*sg_send */ -+ NULL, /*poll */ -+ NULL, /*phy_put*/ -+ NULL, /*phy_get*/ -+ NULL /*feedback*/ ++static struct atmdev_ops sigd_dev_ops = { ++ NULL, /* no dev_close */ ++ NULL, /* no open */ ++ sigd_close, /* close */ ++ NULL, /* no ioctl */ ++ NULL, /* no getsockopt */ ++ NULL, /* no setsockopt */ ++ sigd_send, /* send */ ++ NULL, /* no sg_send */ ++ NULL, /* no send_oam */ ++ NULL, /* no phy_put */ ++ NULL, /* no phy_get */ ++ NULL, /* no feedback */ ++ NULL, /* no change_qos */ ++ NULL /* no free_rx_skb */ +}; + -+static struct atm_dev lecatm_dev = { -+ &lecdev_ops, -+ NULL, /*PHY*/ -+ "lec", /*type*/ -+ 999, /*dummy device number*/ -+ NULL,NULL, /*no VCCs*/ -+ NULL,NULL, /*no data*/ -+ 0, /*no flags*/ -+ NULL, /* no local address*/ -+ { 0 } /*no ESI, no statistics */ -+}; + -+int -+send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, -+ unsigned char *mac_addr, unsigned char *atm_addr) -+{ -+ struct sk_buff *skb; -+ struct atmlec_msg *mesg; ++static struct atm_dev sigd_dev = { ++ &sigd_dev_ops, ++ NULL, /* no PHY */ ++ "sig", /* type */ ++ 999, /* dummy device number */ ++ NULL,NULL, /* pretend not to have any VCCs */ ++ NULL,NULL, /* no data */ ++ 0, /* no flags */ ++ NULL, /* no local address */ ++ { 0 } /* no ESI, no statistics */ ++}; + -+ if (!priv || !priv->lecd) { -+ return -1; -+ } -+ skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); -+ if (!skb) -+ return -1; -+ skb->free = 1; -+ skb->len = sizeof(struct atmlec_msg); -+ mesg = (struct atmlec_msg *)skb->data; -+ mesg->type = type; -+ if (mac_addr) -+ memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN); -+ if (atm_addr) -+ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); -+ -+ atomic_add(skb->truesize+ATM_PDU_OVHD, &priv->lecd->rx_inuse); -+ skb_queue_tail(&priv->lecd->recvq, skb); -+ wake_up(&priv->lecd->sleep); -+ return 0; -+} -+ -+static int -+lec_init(struct device *dev) -+{ -+ dev->priv = kmalloc(sizeof(struct lec_priv), GFP_KERNEL); -+ if (!dev->priv) -+ return -ENOMEM; -+ -+ memset(dev->priv,0,sizeof(struct lec_priv)); -+ -+ ether_setup(dev); -+ dev->open = lec_open; -+ dev->stop = lec_close; -+ dev->hard_start_xmit = lec_send_packet; -+ dev->hard_header_len = LEC_HEADER_LEN; -+ -+ dev->hard_header = lec_hard_header; -+ dev->rebuild_header = lec_rebuild_header; -+ dev->header_cache_bind = lec_header_cache_bind; -+ dev->header_cache_update= lec_header_cache_update; -+ -+ dev->get_stats = lec_get_stats; -+ dev->set_multicast_list = NULL; -+ dev->do_ioctl = NULL; -+ printk("%s: Initialized!\n",dev->name); -+ return 0; -+} -+ -+static unsigned char lec_ctrl_magic[] = { -+ 0xff, -+ 0x00, -+ 0x01, -+ 0x01 }; -+ -+void -+lec_push(struct atm_vcc *vcc, struct sk_buff *skb) -+{ -+ 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]; -+ -+ printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name, -+ vcc->vpi, vcc->vci); -+#endif -+ if (!skb) { -+ DPRINTK("%s: null skb\n",dev->name); -+ lec_vcc_close(priv, vcc); -+ return; -+ } -+#if DUMP_PACKETS > 0 -+ printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name, -+ skb->len, priv->lecid); -+#if DUMP_PACKETS >= 2 -+ for(i=0;ilen && i <99;i++) { -+ sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]); -+ } -+#elif DUMP_PACKETS >= 1 -+ for(i=0;ilen && i < 30;i++) { -+ sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]); -+ } -+#endif /* DUMP_PACKETS >= 1 */ -+ if (i==skb->len) -+ printk("%s\n",buf); -+ else -+ printk("%s...\n",buf); -+#endif /* DUMP_PACKETS > 0 */ -+ if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/ -+ DPRINTK("%s: To daemon\n",dev->name); -+ atomic_add(skb->truesize+ATM_PDU_OVHD, &vcc->rx_inuse); -+ skb_queue_tail(&vcc->recvq, skb); -+ wake_up(&vcc->sleep); -+ } else { /* Data frame, queue to protocol handlers */ -+ hdr = (struct lecdatahdr_8023 *)skb->data; -+ if (hdr->le_header == htons(priv->lecid) || -+ !priv->lecd) { -+ /* Probably looping back, or if lecd is missing, -+ lecd has gone down */ -+ DPRINTK("Ignoring loopback frame...\n"); -+ dev_kfree_skb(skb, FREE_READ); -+ return; -+ } -+ if (priv->lec_arp_empty_ones) { /* FILTER DATA!!!! */ -+ 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); -+ netif_rx(skb); -+ priv->stats.rx_packets++; -+ } -+} + -+int -+lec_vcc_attach(struct atm_vcc *vcc, void *arg) ++int sigd_attach(struct atm_vcc *vcc) +{ -+ struct atmlec_ioc ioc_data; -+ -+ /* Lecd must be up in this case */ -+ memcpy_fromfs(&ioc_data, arg, sizeof(struct atmlec_ioc)); -+ if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF || -+ !dev_lec[ioc_data.dev_num]) -+ return -EINVAL; -+ lec_vcc_added(dev_lec[ioc_data.dev_num]->priv, -+ &ioc_data, vcc, vcc->push); -+ vcc->push = lec_push; -+ vcc->proto_data = dev_lec[ioc_data.dev_num]; -+ return 0; -+} -+ -+int -+lec_mcast_attach(struct atm_vcc *vcc, int arg) -+{ -+ if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) -+ return -EINVAL; -+ vcc->proto_data = dev_lec[arg]; -+ return (lec_mcast_make((struct lec_priv*)dev_lec[arg]->priv, vcc)); -+} -+ -+/* Initialize device. */ -+int -+lecd_attach(struct atm_vcc *vcc, int arg) -+{ -+ int i, result; -+ struct lec_priv *priv; -+ -+ if (arg<0) -+ i = 0; -+ else -+ i = arg; -+ if (arg >= MAX_LEC_ITF) -+ return -EINVAL; -+ if (!dev_lec[i]) { -+ dev_lec[i] = (struct device*)kmalloc(sizeof(struct device)+ -+ sizeof(myname)+1, -+ GFP_KERNEL); -+ if (!dev_lec[i]) -+ return -ENOMEM; -+ memset(dev_lec[i],0, sizeof(struct device)+sizeof(myname)+1); -+ dev_lec[i]->name = (char*)(dev_lec[i]+1); -+ sprintf(dev_lec[i]->name, "lec%d",i); -+ dev_lec[i]->init = lec_init; -+ if ((result = register_netdev(dev_lec[i])) !=0) -+ return result; -+ priv = (struct lec_priv *)dev_lec[i]->priv; -+ } else { -+ priv = (struct lec_priv *)dev_lec[i]->priv; -+ if (priv->lecd) -+ return -EADDRINUSE; -+ } -+ lec_arp_init(priv); -+ priv->lecd = vcc; -+ vcc->dev = &lecatm_dev; -+ -+ vcc->proto_data = dev_lec[i]; -+ vcc->flags |= ATM_VF_READY | ATM_VF_META; -+ -+ /* Set default values to these variables */ -+ priv->maximum_unknown_frame_count = 1; -+ priv->max_unknown_frame_time = (1*HZ); -+ priv->vcc_timeout_period = (1200*HZ); -+ priv->max_retry_count = 1; -+ priv->aging_time = (300*HZ); -+ priv->forward_delay_time = (15*HZ); -+ priv->topology_change = 0; -+ priv->arp_response_time = (1*HZ); -+ priv->flush_timeout = (4*HZ); -+ priv->path_switching_delay = (6*HZ); -+ -+ return i; ++ if (sigd) return -EADDRINUSE; ++ DPRINTK("sigd_attach\n"); ++ sigd = vcc; ++ vcc->dev = &sigd_dev; ++ vcc->flags |= ATM_VF_READY | ATM_VF_META; ++ wake_up(&sigd_sleep); ++ return 0; +} --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/lec.h Wed Apr 2 22:38:55 1997 -@@ -0,0 +1,107 @@ -+/* -+ * -+ * Lan Emulation client header file -+ * -+ * Marko Kiiskila carnil@cs.tut.fi -+ * -+ */ ++++ work/net/atm/signaling.h Thu Jul 3 08:25:18 1997 +@@ -0,0 +1,25 @@ ++/* net/atm/signaling.h - ATM signaling */ ++ ++/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ ++ + -+#ifndef _LEC_H_ -+#define _LEC_H_ ++#ifndef NET_ATM_SIGNALING_H ++#define NET_ATM_SIGNALING_H + ++#include +#include -+#include -+#include -+ -+#define LEC_HEADER_LEN 16 ++#include + -+struct lecdatahdr_8023 { -+ unsigned short le_header; -+ unsigned char h_dest[ETH_ALEN]; -+ unsigned char h_source[ETH_ALEN]; -+ unsigned short h_type; -+}; + -+struct lecdatahdr_8025 { -+ unsigned short le_header; -+ unsigned char ac_pad; -+ unsigned char fc; -+ unsigned char h_dst[ETH_ALEN]; -+ unsigned char h_source[ETH_ALEN]; -+}; ++#define WAITING 1 /* for reply: 0: no error, < 0: error, ... */ + -+/* -+ * ATM LAN Emulation supports both LLC & Dix Ethernet EtherType -+ * frames. -+ * 1. Dix Ethernet EtherType frames encoded by placing EtherType -+ * field in h_type field. Data follows immediatelly after header. -+ * 2. LLC Data frames whose total length, including LLC field and data, -+ * but not padding required to meet the minimum data frame length, -+ * is less than 1536(0x0600) MUST be encoded by placing that length -+ * in the the h_type field. The LLC field follows header immediatelly. -+ * 3. LLC data frames longer than this maximum MUST be encoded by placing -+ * the value 0 in the h_type field. -+ * -+ */ + -+/* Hash table size */ -+#define LEC_ARP_TABLE_SIZE 16 ++extern struct atm_vcc *sigd; /* needed in svc_release */ + -+struct lec_priv { -+ struct enet_statistics stats; -+ unsigned short lecid; /* Lecid of this client */ -+ struct lec_arp_table *lec_arp_empty_ones; -+ /* Used for storing VCC's that don't have a MAC address attached yet */ -+ struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE]; -+ /* Actual LE ARP table */ -+ struct lec_arp_table *lec_no_forward; -+ /* Used for storing VCC's (and forward packets from) which are to -+ 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. */ -+ atomic_t lec_arp_lock_var; -+ struct atm_vcc *mcast_vcc; -+ struct atm_vcc *lecd; -+ struct timer_list lec_arp_timer; -+ /* C10 */ -+ unsigned int maximum_unknown_frame_count; -+/* Within the period of time defined by this variable, the client will send -+ no more than C10 frames to BUS for a given unicast destination. (C11) */ -+ unsigned long max_unknown_frame_time; -+/* If no traffic has been sent in this vcc for this period of time, -+ vcc will be torn down (C12)*/ -+ unsigned long vcc_timeout_period; -+/* An LE Client MUST not retry an LE_ARP_REQUEST for a -+ given frame's LAN Destination more than maximum retry count times, -+ after the first LEC_ARP_REQUEST (C13)*/ -+ unsigned short max_retry_count; -+/* Max time the client will maintain an entry in its arp cache in -+ absence of a verification of that relationship (C17)*/ -+ unsigned long aging_time; -+/* Max time the client will maintain an entry in cache when -+ topology change flag is true (C18) */ -+ unsigned long forward_delay_time; -+/* Topology change flag (C19)*/ -+ int topology_change; -+/* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE -+ cycle to take (C20)*/ -+ unsigned long arp_response_time; -+/* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the -+ LE_FLUSH_REQUEST has been sent before taking recover action. (C21)*/ -+ unsigned long flush_timeout; -+/* The time since sending a frame to the bus after which the -+ LE Client may assume that the frame has been either discarded or -+ delivered to the recipient (C22) */ -+ unsigned long path_switching_delay; -+}; + -+int lecd_attach(struct atm_vcc *vcc, int arg); -+int lec_vcc_attach(struct atm_vcc *vcc, void *arg); -+int lec_mcast_attach(struct atm_vcc *vcc, int arg); -+int make_lec(struct atm_vcc *vcc); -+int send_to_lecd(struct lec_priv *priv, -+ atmlec_msg_type type, unsigned char *mac_addr, -+ unsigned char *atm_addr); -+void lec_push(struct atm_vcc *vcc, struct sk_buff *skb); -+#endif _LEC_H_ ++void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, ++ const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, ++ const struct sockaddr_atmsvc *svc); ++int sigd_attach(struct atm_vcc *vcc); + ++#endif --- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/lec_arpc.c Thu Nov 28 22:02:05 1996 -@@ -0,0 +1,1044 @@ -+#include -+#include -+#include -+#include -+#include -+#include ++++ work/net/atm/svc.c Sat May 17 00:40:32 1997 +@@ -0,0 +1,387 @@ ++/* net/atm/svc.c - ATM SVC sockets */ + -+#include ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+#include "lec.h" -+#include "lec_arpc.h" + ++#include ++#include /* struct socket, struct net_proto, ++ struct proto_ops */ ++#include /* error codes */ ++#include /* printk */ ++#include ++#include ++#include /* jiffies and HZ */ ++#include /* O_NONBLOCK */ ++#include /* ATM stuff */ ++#include ++#include ++#include ++#include ++ ++#include "resources.h" ++#include "common.h" /* common for PVCs and SVCs */ ++#include "signaling.h" + -+#define DPRINTK(format,args...) -+/* -+#define DPRINTK printk -+*/ -+#define DEBUG_ARP_TABLE 0 -+ -+#define LEC_ARP_REFRESH_INTERVAL (3*HZ) -+ -+static void lec_arp_check_expire(unsigned long data); -+static __inline__ void lec_arp_expire_arp(unsigned long data); -+void dump_arp_table(struct lec_priv *priv); + -+/* -+ * Arp table funcs -+ */ ++#if 0 ++#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) ++#else ++#define DPRINTK(format,args...) ++#endif + -+#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1)) + -+static __inline__ void -+lec_arp_lock(struct lec_priv *priv) -+{ -+ atomic_inc(&priv->lec_arp_lock_var); -+} ++static int svc_create(struct socket *sock,int protocol); + -+static __inline__ void -+lec_arp_unlock(struct lec_priv *priv) -+{ -+ atomic_dec(&priv->lec_arp_lock_var); -+} + +/* -+ * Initialization of arp-cache ++ * Note: since all this is still nicely synchronized with the signaling demon, ++ * there's no need to protect sleep loops with clis. If signaling is ++ * moved into the kernel, that would change. + */ -+void -+lec_arp_init(struct lec_priv *priv) -+{ -+ unsigned short i; + -+ for (i=0;ilec_arp_tables[i] = NULL; -+ } -+ init_timer(&priv->lec_arp_timer); -+ priv->lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL; -+ priv->lec_arp_timer.data = (unsigned long)priv; -+ priv->lec_arp_timer.function = lec_arp_check_expire; -+ add_timer(&priv->lec_arp_timer); -+} + -+void -+lec_arp_clear_vccs(struct lec_arp_table *entry) ++void svc_callback(struct atm_vcc *vcc) +{ -+ if (entry->vcc) { -+ entry->vcc->push = entry->old_push; -+ entry->vcc->flags |= ATM_VF_RELEASED; -+ entry->vcc->flags &= ~ATM_VF_READY; -+ entry->vcc = NULL; -+ } -+ if (entry->recv_vcc) { -+ entry->recv_vcc->push = entry->old_recv_push; -+ entry->recv_vcc->flags |= ATM_VF_RELEASED; -+ entry->recv_vcc->flags &= ~ATM_VF_READY; -+ entry->recv_vcc = NULL; -+ } -+} -+ -+/* -+ * Insert entry to lec_arp_table -+ */ -+static __inline__ void -+lec_arp_put(struct lec_arp_table **lec_arp_tables, -+ struct lec_arp_table *to_put) -+{ -+ unsigned short place; -+ unsigned long flags; -+ -+ save_flags(flags); -+ cli(); -+ -+ place = HASH(to_put->mac_addr[ETH_ALEN-1]); -+ to_put->next = lec_arp_tables[place]; -+ lec_arp_tables[place] = to_put; -+ -+ restore_flags(flags); -+ DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", -+ 0xff&to_put->mac_addr[0], 0xff&to_put->mac_addr[1], -+ 0xff&to_put->mac_addr[2], 0xff&to_put->mac_addr[3], -+ 0xff&to_put->mac_addr[4], 0xff&to_put->mac_addr[5]); ++ wake_up(&vcc->sleep); +} + -+/* -+ * Remove entry from lec_arp_table -+ */ -+static __inline__ int -+lec_arp_remove(struct lec_arp_table **lec_arp_tables, -+ struct lec_arp_table *to_remove) -+{ -+ unsigned short place; -+ struct lec_arp_table *tmp; -+ unsigned long flags; -+ int remove_vcc=1; -+ -+ save_flags(flags); -+ cli(); -+ -+ if (!to_remove) { -+ restore_flags(flags); -+ return -1; -+ } -+ place = HASH(to_remove->mac_addr[ETH_ALEN-1]); -+ tmp = lec_arp_tables[place]; -+ if (tmp == to_remove) { -+ lec_arp_tables[place] = tmp->next; -+ } else { -+ while(tmp && tmp->next != to_remove) { -+ tmp = tmp->next; -+ } -+ if (!tmp) {/* Entry was not found */ -+ restore_flags(flags); -+ return -1; -+ } -+ } -+ tmp->next = to_remove->next; -+ del_timer(&to_remove->timer); -+ -+ /* If this is the only MAC connected to this VCC, also tear down -+ the VCC */ -+ if (to_remove->status >= ESI_FLUSH_PENDING) { -+ /* -+ * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT -+ */ -+ for(place=0;placenext){ -+ if (memcmp(tmp->atm_addr, to_remove->atm_addr, -+ ATM_ESA_LEN)==0) { -+ remove_vcc=0; -+ break; -+ } -+ } -+ } -+ if (remove_vcc) -+ lec_arp_clear_vccs(to_remove); -+ } -+ restore_flags(flags); -+ DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", -+ 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1], -+ 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3], -+ 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]); -+ -+ return 0; -+} + -+#if DEBUG_ARP_TABLE -+static char* -+get_status_string(unsigned char st) ++static int svc_dup(struct socket *newsock,struct socket *oldsock) +{ -+ switch(st) { -+ case ESI_UNKNOWN: -+ return "ESI_UNKNOWN"; -+ case ESI_ARP_PENDING: -+ return "ESI_ARP_PENDING"; -+ case ESI_VC_PENDING: -+ return "ESI_VC_PENDING"; -+ case ESI_FLUSH_PENDING: -+ return "ESI_FLUSH_PENDING"; -+ case ESI_FORWARD_DIRECT: -+ return "ESI_FORWARD_DIRECT"; -+ default: -+ return ""; -+ } ++ return svc_create(newsock,0); +} -+#endif -+ -+void -+dump_arp_table(struct lec_priv *priv) -+{ -+#if DEBUG_ARP_TABLE -+ int i,j, offset; -+ struct lec_arp_table *rulla; -+ char buf[1024]; -+ struct lec_arp_table **lec_arp_tables = -+ (struct lec_arp_table **)priv->lec_arp_tables; -+ struct lec_arp_table *lec_arp_empty_ones = -+ (struct lec_arp_table *)priv->lec_arp_empty_ones; -+ struct lec_arp_table *lec_no_forward = -+ (struct lec_arp_table *)priv->lec_no_forward; -+ -+ printk("Dump %p:\n",priv); -+ for (i=0;imac_addr[j]&0xff); -+ } -+ offset +=sprintf(buf+offset,"Atm:"); -+ for(j=0;jatm_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,"->%p\n",rulla->next); -+ rulla = rulla->next; -+ } -+ printk("%s",buf); -+ } -+ rulla = lec_no_forward; -+ if (rulla) -+ printk("No forward\n"); -+ while(rulla) { -+ offset=0; -+ offset += sprintf(buf+offset,"Mac:"); -+ for(j=0;jmac_addr[j]&0xff); -+ } -+ offset +=sprintf(buf+offset,"Atm:"); -+ for(j=0;jatm_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); -+ } -+ rulla = lec_arp_empty_ones; -+ if (rulla) -+ printk("Empty ones\n"); -+ while(rulla) { -+ offset=0; -+ offset += sprintf(buf+offset,"Mac:"); -+ for(j=0;jmac_addr[j]&0xff); -+ } -+ offset +=sprintf(buf+offset,"Atm:"); -+ for(j=0;jatm_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 -+} + -+/* -+ * Destruction of arp-cache -+ */ -+void -+lec_arp_destroy(struct lec_priv *priv) ++static int svc_shutdown(struct socket *sock,int how) +{ -+ struct lec_arp_table *entry, *next; -+ unsigned long flags; -+ int i; -+ -+ save_flags(flags); -+ cli(); -+ -+ del_timer(&priv->lec_arp_timer); -+ -+ /* -+ * Remove all entries -+ */ -+ for (i=0;ilec_arp_tables[i];entry != NULL; entry=next) { -+ next = entry->next; -+ lec_arp_remove(priv->lec_arp_tables, entry); -+ kfree(entry); -+ } -+ } -+ entry = priv->lec_arp_empty_ones; -+ while(entry) { -+ next = entry->next; -+ del_timer(&entry->timer); -+ lec_arp_clear_vccs(entry); -+ kfree(entry); -+ entry = next; -+ } -+ priv->lec_arp_empty_ones = NULL; -+ entry = priv->lec_no_forward; -+ while(entry) { -+ next = entry->next; -+ del_timer(&entry->timer); -+ lec_arp_clear_vccs(entry); -+ kfree(entry); -+ entry = next; -+ } -+ priv->lec_no_forward = NULL; -+ priv->mcast_vcc = NULL; -+ memset(priv->lec_arp_tables, 0, -+ sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE); -+ restore_flags(flags); ++ return -EOPNOTSUPP; +} + + -+/* -+ * Find entry by mac_address -+ */ -+static __inline__ struct lec_arp_table* -+lec_arp_find(struct lec_priv *priv, -+ unsigned char *mac_addr) -+{ -+ unsigned short place; -+ struct lec_arp_table *to_return; -+ -+ DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", -+ mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff, -+ mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff); -+ lec_arp_lock(priv); -+ place = HASH(mac_addr[ETH_ALEN-1]); -+ -+ to_return = priv->lec_arp_tables[place]; -+ while(to_return) { -+ if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) { -+ lec_arp_unlock(priv); -+ return to_return; -+ } -+ to_return = to_return->next; -+ } -+ lec_arp_unlock(priv); -+ return NULL; -+} -+ -+static struct lec_arp_table* -+make_entry(struct lec_priv *priv, unsigned char *mac_addr) ++static void svc_disconnect(struct atm_vcc *vcc) +{ -+ struct lec_arp_table *to_return; ++ struct sk_buff *skb; + -+ to_return=(struct lec_arp_table *)kmalloc(sizeof(struct lec_arp_table), -+ GFP_ATOMIC); -+ if (!to_return) { -+ printk("LEC: Arp entry kmalloc failed\n"); -+ return NULL; -+ } -+ memset(to_return,0,sizeof(struct lec_arp_table)); -+ memcpy(to_return->mac_addr, mac_addr, ETH_ALEN); -+ init_timer(&to_return->timer); -+ to_return->timer.function = lec_arp_expire_arp; -+ to_return->timer.data = (unsigned long)to_return; -+ to_return->last_used = jiffies; -+ to_return->priv = priv; -+ return to_return; ++ DPRINTK("svc_disconnect\n"); ++ if (vcc->flags & ATM_VF_REGIS) { ++ sigd_enq(vcc,as_close,NULL,NULL,NULL); ++ while (!(vcc->flags & ATM_VF_RELEASED) && sigd) ++ sleep_on(&vcc->sleep); ++ } ++ while ((skb = skb_dequeue(&vcc->listenq))) { ++ vcc->flags &= ~ATM_VF_RELEASED; ++ DPRINTK("LISTEN REL\n"); ++ sigd_enq(NULL,as_reject,vcc,NULL,NULL); /* @@@ should include ++ the reason */ ++ dev_kfree_skb(skb,FREE_WRITE); ++ } ++ vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED); /* may retry later */ +} + -+/* -+ * -+ * Arp sent timer expired -+ * -+ */ -+static void -+lec_arp_expire_arp(unsigned long data) ++ ++static int svc_release(struct socket *sock,struct socket *peer) +{ -+ struct lec_arp_table *entry; ++ DPRINTK("svc_release\n"); ++ if (!ATM_SD(sock)) return 0; ++ ATM_SD(sock)->flags &= ~ATM_VF_READY; ++ atm_release_vcc(ATM_SD(sock),0); ++ svc_disconnect(ATM_SD(sock)); ++ /* 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(ATM_SD(sock)); ++ return 0; ++} + -+ entry = (struct lec_arp_table *)data; + -+ del_timer(&entry->timer); ++int copy_svc_addr(struct sockaddr_atmsvc *to,struct sockaddr_atmsvc *from) ++{ ++ struct atm_blli *walk,**link,*next; ++ int error,bllis; + -+ DPRINTK("lec_arp_expire_arp\n"); -+ if (entry->status == ESI_ARP_PENDING) { -+ if (entry->no_tries <= entry->priv->max_retry_count) { -+ send_to_lecd(entry->priv, l_arp_xmt, -+ entry->mac_addr, NULL); -+ entry->no_tries++; -+ } -+ entry->timer.expires = jiffies + (1*HZ); -+ add_timer(&entry->timer); -+ } ++ *to = *from; ++ link = &to->sas_addr.blli; ++ error = bllis = 0; ++ for (walk = from->sas_addr.blli; walk; walk = next) { ++ if (++bllis > ATM_MAX_BLLI) { ++ error = -E2BIG; ++ break; ++ } ++ *link = kmalloc(sizeof(struct atm_blli),GFP_KERNEL); ++ if (!*link) { ++ error = -ENOMEM; ++ break; ++ } ++ error = copy_from_user(*link,walk,sizeof(struct atm_blli)); ++ if (error) break; ++ link = &(*link)->next; ++ error = get_user(next,&walk->next); ++ if (error) break; ++ } ++ *link = NULL; ++ if (!error) return 0; ++ for (walk = to->sas_addr.blli; walk; walk = next) { ++ next = walk->next; ++ kfree(walk); ++ } ++ return error; +} + -+/* -+ * -+ * Unknown/unused vcc expire, remove associated entry -+ * -+ */ -+static void -+lec_arp_expire_vcc(unsigned long data) -+{ -+ struct lec_arp_table *to_remove = (struct lec_arp_table*)data; -+ struct lec_priv *priv = (struct lec_priv *)to_remove->priv; -+ struct lec_arp_table *entry = NULL; -+ -+ del_timer(&to_remove->timer); -+ -+ DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n", -+ to_remove, priv, -+ to_remove->vcc?to_remove->recv_vcc->vpi:0, -+ to_remove->vcc?to_remove->recv_vcc->vci:0); -+ DPRINTK("eo:%p nf:%p\n",priv->lec_arp_empty_ones,priv->lec_no_forward); -+ if (to_remove == priv->lec_arp_empty_ones) -+ priv->lec_arp_empty_ones = to_remove->next; -+ else { -+ entry = priv->lec_arp_empty_ones; -+ while (entry && entry->next != to_remove) -+ entry = entry->next; -+ if (entry) -+ entry->next = to_remove->next; -+ } -+ if (!entry) -+ if (to_remove == priv->lec_no_forward) { -+ priv->lec_no_forward = to_remove->next; -+ } else { -+ entry = priv->lec_no_forward; -+ while (entry && entry->next != to_remove) -+ entry = entry->next; -+ if (entry) -+ entry->next = to_remove->next; -+ } -+ lec_arp_clear_vccs(to_remove); -+ kfree(to_remove); -+} + -+/* -+ * Expire entries. -+ * 1. Re-set timer -+ * 2. For each entry, delete entries that have aged past the age limit. -+ * 3. For each entry, depending on the status of the entry, perform -+ * the following maintenance. -+ * a. If status is ESI_VC_PENDING or ESI_ARP_PENDING then if the -+ * tick_count is above the max_unknown_frame_time, clear -+ * the tick_count to zero and clear the packets_flooded counter -+ * to zero. This supports the packet rate limit per address -+ * while flooding unknowns. -+ * b. If the status is ESI_FLUSH_PENDING and the tick_count is greater -+ * than or equal to the path_switching_delay, change the status -+ * to ESI_FORWARD_DIRECT. This causes the flush period to end -+ * regardless of the progress of the flush protocol. -+ */ -+static void -+lec_arp_check_expire(unsigned long data) -+{ -+ struct lec_priv *priv = (struct lec_priv *)data; -+ struct lec_arp_table **lec_arp_tables = -+ (struct lec_arp_table **)priv->lec_arp_tables; -+ struct lec_arp_table *entry, *next; -+ unsigned long now; -+ unsigned long time_to_check; -+ int i; -+ -+ del_timer(&priv->lec_arp_timer); -+ -+ DPRINTK("lec_arp_check_expire %p,%d\n",priv,priv->lec_arp_lock_var); -+ DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones, -+ priv->lec_no_forward); -+ if (!priv->lec_arp_lock_var) { -+ lec_arp_lock(priv); -+ now = jiffies; -+ for(i=0;iflags) & LEC_REMOTE_FLAG && -+ priv->topology_change) -+ time_to_check=priv->forward_delay_time; -+ else -+ time_to_check = priv->aging_time; -+ -+ DPRINTK("About to expire: %lx - %lx > %lx\n", -+ now,entry->last_used, time_to_check); -+ if((now-entry->last_used > time_to_check) && -+ !(entry->flags & LEC_PERMANENT_FLAG)) { -+ /* Remove entry */ -+ DPRINTK("LEC:Entry timed out\n"); -+ next = entry->next; -+ lec_arp_remove(lec_arp_tables, entry); -+ kfree(entry); -+ entry = next; -+ } else { -+ /* Something else */ -+ if ((entry->status == ESI_VC_PENDING || -+ entry->status == ESI_ARP_PENDING) -+ && -+ now-entry->timestamp >= -+ priv->max_unknown_frame_time) { -+ entry->timestamp = jiffies; -+ entry->packets_flooded = 0; -+ } -+ if (entry->status == ESI_FLUSH_PENDING -+ && -+ now-entry->timestamp >= -+ priv->path_switching_delay) { -+ entry->last_used = jiffies; -+ entry->status = -+ ESI_FORWARD_DIRECT; -+ } -+ entry = entry->next; -+ } -+ } -+ } -+ lec_arp_unlock(priv); -+ } -+ priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL; -+ add_timer(&priv->lec_arp_timer); -+} -+/* -+ * Try to find vcc where mac_address is attached. -+ * -+ */ -+struct atm_vcc* -+lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find) ++static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, ++ int sockaddr_len) +{ -+ struct lec_arp_table *entry; ++ struct sockaddr_atmsvc *addr; ++ struct atm_vcc *vcc; ++ int error; + -+ if (mac_to_find[0]&0x01) { -+ return priv->mcast_vcc; -+ } -+ entry = lec_arp_find(priv, mac_to_find); -+ -+ if (entry) { -+ if (entry->status == ESI_FORWARD_DIRECT) { -+ /* Connection Ok */ -+ entry->last_used = jiffies; -+ 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 -+ BUS. */ -+ if (entry->status != ESI_FLUSH_PENDING && -+ entry->packets_floodedmaximum_unknown_frame_count) { -+ entry->packets_flooded++; -+ DPRINTK("LEC_ARP: Flooding..\n"); -+ return priv->mcast_vcc; -+ } -+ return NULL; -+ } else { -+ /* No matching entry was found */ -+ entry = make_entry(priv, mac_to_find); -+ DPRINTK("LEC_ARP: Making entry\n"); -+ if (!entry) { -+ 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; -+ entry->no_tries = 1; -+ entry->last_used = entry->timestamp = jiffies; -+ send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL); -+ entry->timer.expires = jiffies + (1*HZ); -+ entry->timer.function = lec_arp_expire_arp; -+ add_timer(&entry->timer); -+ return priv->mcast_vcc; -+ } ++ if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; ++ if (sock->state == SS_CONNECTED) return -EISCONN; ++ if (sock->state != SS_UNCONNECTED) return -EINVAL; ++ addr = (struct sockaddr_atmsvc *) sockaddr; ++ if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; ++ vcc = ATM_SD(sock); ++ vcc->flags &= ~ATM_VF_BOUND; /* failing rebind will kill old binding */ ++ /* @@@ check memory (de)allocation on rebind */ ++ if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; ++ error = copy_svc_addr(&vcc->local,addr); ++ if (error) return error; ++ vcc->reply = WAITING; ++ sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); ++ while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); ++ vcc->flags &= ~ATM_VF_REGIS; /* doesn't count */ ++ if (!sigd) return -EUNATCH; /* good code ? @@@ */ ++ if (!vcc->reply) vcc->flags |= ATM_VF_BOUND; ++ return vcc->reply; +} + -+int -+lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, -+ unsigned long permanent) -+{ -+ struct lec_arp_table *entry, *next; -+ int i; -+ -+ lec_arp_lock(priv); -+ DPRINTK("lec_addr_delete\n"); -+ for(i=0;ilec_arp_tables[i];entry != NULL; entry=next) { -+ next = entry->next; -+ if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) -+ && (permanent || -+ !(entry->flags & LEC_PERMANENT_FLAG))) { -+ lec_arp_remove(priv->lec_arp_tables, entry); -+ kfree(entry); -+ } -+ lec_arp_unlock(priv); -+ return 0; -+ } -+ } -+ lec_arp_unlock(priv); -+ return -1; -+} + -+/* -+ * Notifies: Response to arp_request (atm_addr != NULL) -+ */ -+void -+lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, -+ unsigned char *atm_addr, unsigned long remoteflag) -+{ -+ struct lec_arp_table *entry, *tmp; -+ int i; -+ -+ DPRINTK("LEC:lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", -+ mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3], -+ mac_addr[4],mac_addr[5]); -+ lec_arp_lock(priv); -+ if (priv->lec_arp_empty_ones) { -+ entry = priv->lec_arp_empty_ones; -+ if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) { -+ priv->lec_arp_empty_ones = entry->next; -+ } else { -+ while(entry->next && memcmp(entry->next->atm_addr, -+ atm_addr, ATM_ESA_LEN)) -+ entry = entry->next; -+ if (entry->next) { -+ tmp = entry; -+ entry = entry->next; -+ tmp->next = entry->next; -+ } else -+ entry = NULL; -+ -+ } -+ if (entry) { -+ del_timer(&entry->timer); -+ tmp = lec_arp_find(priv, mac_addr); -+ if (tmp) { -+ del_timer(&tmp->timer); -+ tmp->status = ESI_FORWARD_DIRECT; -+ memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN); -+ tmp->vcc = entry->vcc; -+ tmp->old_push = entry->old_push; -+ tmp->last_used = jiffies; -+ kfree(entry); -+ entry=tmp; -+ } else { -+ entry->status = ESI_FORWARD_DIRECT; -+ memcpy(entry->mac_addr, mac_addr, ETH_ALEN); -+ entry->last_used = jiffies; -+ lec_arp_put(priv->lec_arp_tables, entry); -+ } -+ if (remoteflag) -+ entry->flags|=LEC_REMOTE_FLAG; -+ else -+ entry->flags&=~LEC_REMOTE_FLAG; -+ lec_arp_unlock(priv); -+ DPRINTK("After update\n"); -+ dump_arp_table(priv); -+ return; -+ } -+ } -+ entry = lec_arp_find(priv, mac_addr); -+ if (!entry) { -+ entry = make_entry(priv, mac_addr); -+ entry->status = ESI_UNKNOWN; -+ lec_arp_put(priv->lec_arp_tables, entry); -+ /* Temporary, changes before end of function */ -+ } -+ memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); -+ del_timer(&entry->timer); -+ for(i=0;ilec_arp_tables[i];tmp;tmp=tmp->next) { -+ if (entry != tmp && -+ !memcmp(tmp->atm_addr, atm_addr, -+ ATM_ESA_LEN)) { -+ /* Vcc to this host exists */ -+ if (tmp->status > ESI_VC_PENDING) { -+ /* -+ * ESI_FLUSH_PENDING, -+ * ESI_FORWARD_DIRECT -+ */ -+ entry->vcc = tmp->vcc; -+ entry->old_push=tmp->old_push; -+ } -+ entry->status=tmp->status; -+ break; -+ } -+ } -+ } -+ if (remoteflag) -+ entry->flags|=LEC_REMOTE_FLAG; -+ else -+ entry->flags&=~LEC_REMOTE_FLAG; -+ 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); -+ } -+ DPRINTK("After update2\n"); -+ dump_arp_table(priv); -+ lec_arp_unlock(priv); -+} ++static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, ++ int sockaddr_len,int flags) ++{ ++ struct sockaddr_atmsvc *addr; ++ struct atm_vcc *vcc; ++ int error; + ++ DPRINTK("svc_connect\n"); ++ if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; ++ if (sock->state == SS_CONNECTED) return -EISCONN; ++ vcc = ATM_SD(sock); ++ if (sock->state == SS_CONNECTING) { ++ if (vcc->reply == WAITING) return -EALREADY; ++ sock->state = SS_UNCONNECTED; ++ if (vcc->reply) return vcc->reply; ++ } ++ else { ++ if (sock->state != SS_UNCONNECTED) return -EINVAL; ++ addr = (struct sockaddr_atmsvc *) sockaddr; ++ if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; ++ if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; ++ if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || ++ vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) ++ return -EINVAL; ++ if (!vcc->qos.txtp.traffic_class && ++ !vcc->qos.rxtp.traffic_class) return -EINVAL; ++ error = copy_svc_addr(&vcc->remote,addr); ++ if (error) return error; ++ vcc->reply = WAITING; ++ sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); ++ if (flags & O_NONBLOCK) { ++ sock->state = SS_CONNECTING; ++ return -EINPROGRESS; ++ } ++ while (vcc->reply == WAITING && sigd) { ++ interruptible_sleep_on(&vcc->sleep); ++ if (current->signal & ~current->blocked) { ++ DPRINTK("*ABORT*\n"); ++ /* ++ * This is tricky: ++ * Kernel -------close------> Demon ++ * Kernel <-----close(0)----- Demon ++ * or ++ * Kernel -------close------> Demon ++ * Kernel <--close(error)---- Demon ++ * or ++ * Kernel -------close------> Demon ++ * Kernel <------okay-------- Demon ++ * Kernel <-----close(0)----- Demon ++ */ ++ vcc->flags &= ~ATM_VF_RELEASED; ++ sigd_enq(vcc,as_close,NULL,NULL,NULL); ++ while (vcc->reply == WAITING && sigd) ++ sleep_on(&vcc->sleep); ++ if (!vcc->reply) ++ while (!(vcc->flags & ATM_VF_RELEASED) ++ && sigd) sleep_on(&vcc->sleep); ++ vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED); ++ /* we're gone now but may connect later */ ++ return -EINTR; ++ } ++ } ++ if (!sigd) return -EUNATCH; ++ if (vcc->reply) return vcc->reply; ++ } +/* -+ * Notifies: Vcc setup ready ++ * Not supported yet ++ * ++ * #ifndef CONFIG_SINGLE_SIGITF + */ -+void -+lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, -+ struct atm_vcc *vcc, -+ void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb)) -+{ -+ struct lec_arp_table *entry; -+ int i, found_entry=0; -+ unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,0xff}; -+ -+ lec_arp_lock(priv); -+ if (ioc_data->receive == 2) { -+ /* Vcc for BUS distribute */ -+ DPRINTK("LEC_ARP: Attaching mcast distribute\n"); -+ entry = lec_arp_find(priv, bus_mac); -+ if (!entry) { -+ printk("LEC_ARP: Multicast entry not found!\n"); -+ lec_arp_unlock(priv); -+ return; -+ } -+ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); -+ entry->recv_vcc = vcc; -+ entry->old_recv_push = old_push; -+ lec_arp_unlock(priv); -+ return; -+ } else if (ioc_data->receive == 1) { -+ /* Vcc which we don't want to make default vcc, attach it -+ anyway. */ -+ DPRINTK("LEC_ARP:Attaching data direct, not 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[18],ioc_data->atm_addr[19]); -+ entry = make_entry(priv, bus_mac); -+ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); -+ memset(entry->mac_addr, 0, ETH_ALEN); -+ entry->recv_vcc = vcc; -+ entry->old_recv_push = old_push; -+ entry->status = ESI_UNKNOWN; -+ entry->timer.expires = jiffies + priv->vcc_timeout_period; -+ entry->timer.function = lec_arp_expire_vcc; -+ add_timer(&entry->timer); -+ entry->next = priv->lec_no_forward; -+ priv->lec_no_forward = entry; -+ lec_arp_unlock(priv); -+ dump_arp_table(priv); -+ 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[18],ioc_data->atm_addr[19]); -+ for (i=0;ilec_arp_tables[i];entry;entry=entry->next) { -+ if (memcmp(ioc_data->atm_addr, entry->atm_addr, -+ ATM_ESA_LEN)==0) { -+ DPRINTK("LEC_ARP: Attaching data direct\n"); -+ DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n", -+ entry->vcc?entry->vcc->vci:0, -+ entry->recv_vcc?entry->recv_vcc->vci:0); -+ found_entry=1; -+ del_timer(&entry->timer); -+ if (vcc) { -+ lec_arp_clear_vccs(entry); -+ } -+ entry->vcc = vcc; -+ entry->old_push = old_push; -+ if (entry->status == ESI_VC_PENDING) { -+ if(priv->maximum_unknown_frame_count -+ ==0) -+ entry->status = -+ ESI_FORWARD_DIRECT; -+ else { -+ entry->timestamp = jiffies; -+ entry->status = -+ ESI_FLUSH_PENDING; -+#if 0 -+ send_to_lecd(priv,l_flush_xmt, -+ NULL, -+ entry->atm_addr); -+#endif -+ } -+ } else { -+ /* They were forming a connection -+ to us, and we to them. Our -+ ATM address is numerically lower -+ than theirs, so we make connection -+ we formed into default VCC (8.1.11). -+ Connection they made gets torn -+ down. This might confuse some -+ clients. Can be changed if -+ someone reports trouble... */ -+ ; -+ } -+ } -+ } -+ } -+ if (found_entry) { -+ lec_arp_unlock(priv); -+ DPRINTK("After vcc was added\n"); -+ dump_arp_table(priv); -+ return; -+ } -+ /* Not found, snatch address from first data packet that arrives from -+ this vcc */ -+ entry = make_entry(priv, bus_mac); -+ entry->vcc = vcc; -+ entry->old_push = old_push; -+ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); -+ memset(entry->mac_addr, 0, ETH_ALEN); -+ entry->status = ESI_UNKNOWN; -+ entry->next = priv->lec_arp_empty_ones; -+ priv->lec_arp_empty_ones = entry; -+ entry->timer.expires = jiffies + priv->vcc_timeout_period; -+ entry->timer.function = lec_arp_expire_vcc; -+ add_timer(&entry->timer); -+ lec_arp_unlock(priv); -+ DPRINTK("After vcc was added\n"); -+ dump_arp_table(priv); -+} -+ -+void -+lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) -+{ -+ struct lec_arp_table *entry; -+ int i; -+ -+ DPRINTK("LEC:lec_flush_complete %lx\n",tran_id); -+ for (i=0;ilec_arp_tables[i];entry;entry=entry->next) { -+ if (entry->flush_tran_id == tran_id && -+ entry->status == ESI_FLUSH_PENDING) { -+ entry->status = ESI_FORWARD_DIRECT; -+ DPRINTK("LEC_ARP: Flushed\n"); -+ } -+ } -+ } -+ dump_arp_table(priv); -+} -+ -+void -+lec_set_flush_tran_id(struct lec_priv *priv, -+ unsigned char *atm_addr, unsigned long tran_id) -+{ -+ struct lec_arp_table *entry; -+ int i; -+ -+ for (i=0;ilec_arp_tables[i];entry;entry=entry->next) -+ if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) { -+ entry->flush_tran_id = tran_id; -+ DPRINTK("Set flush transaction id to %lx for %p\n",tran_id,entry); -+ } -+} -+ -+int -+lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc) -+{ -+ unsigned char mac_addr[] = { -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -+ struct lec_arp_table *to_add; -+ -+ lec_arp_lock(priv); -+ to_add = make_entry(priv, mac_addr); -+ if (!to_add) -+ return -ENOMEM; -+ to_add->status = ESI_FORWARD_DIRECT; -+ to_add->flags |= LEC_PERMANENT_FLAG; -+ to_add->vcc = vcc; -+ to_add->old_push = vcc->push; -+ vcc->push = lec_push; -+ priv->mcast_vcc = vcc; -+ lec_arp_put(priv->lec_arp_tables, to_add); -+ lec_arp_unlock(priv); -+ return 0; -+} -+ -+void -+lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) -+{ -+ struct lec_arp_table *entry, *next; -+ int i; -+ -+ DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci); -+ dump_arp_table(priv); -+ lec_arp_lock(priv); -+ for(i=0;ilec_arp_tables[i];entry; entry=next) { -+ next = entry->next; -+ if (vcc == entry->vcc) { -+ lec_arp_remove(priv->lec_arp_tables,entry); -+ kfree(entry); -+ 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; -+ } -+ } -+ } -+ entry=priv->lec_arp_empty_ones; -+ while(entry && entry->vcc==vcc) { -+ lec_arp_clear_vccs(entry); -+ priv->lec_arp_empty_ones=entry->next; -+ del_timer(&entry->timer); -+ kfree(entry); -+ entry=priv->lec_arp_empty_ones; -+ } -+ for(;entry!=NULL;entry=next) { -+ next=entry->next; -+ if (vcc == next->vcc) { -+ lec_arp_clear_vccs(next); -+ entry->next = next->next; -+ del_timer(&next->timer); -+ kfree(next); -+ } -+ } -+ entry=priv->lec_no_forward; -+ while(entry && entry->recv_vcc==vcc) { -+ lec_arp_clear_vccs(entry); -+ priv->lec_no_forward=entry->next; -+ del_timer(&entry->timer); -+ kfree(entry); -+ entry=priv->lec_no_forward; -+ } -+ for(;entry!=NULL;entry=next) { -+ next=entry->next; -+ if (vcc == next->recv_vcc) { -+ lec_arp_clear_vccs(next); -+ entry->next = next->next; -+ del_timer(&next->timer); -+ kfree(next); -+ } -+ } -+ lec_arp_unlock(priv); -+ dump_arp_table(priv); -+} -+ -+void -+lec_arp_check_empties(struct lec_priv *priv, -+ struct atm_vcc *vcc, struct sk_buff *skb) -+{ -+ struct lec_arp_table *entry, *prev; -+ struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data; -+ unsigned long flags; -+ -+ lec_arp_lock(priv); -+ entry = priv->lec_arp_empty_ones; -+ if (vcc == entry->vcc) { -+ save_flags(flags); -+ cli(); -+ del_timer(&entry->timer); -+ memcpy(entry->mac_addr, hdr->h_source, ETH_ALEN); -+ entry->status = ESI_FORWARD_DIRECT; -+ entry->last_used = jiffies; -+ priv->lec_arp_empty_ones = entry->next; -+ restore_flags(flags); -+ /* We might have got an entry */ -+ if ((prev=lec_arp_find(priv,hdr->h_source))) { -+ lec_arp_remove(priv->lec_arp_tables, prev); -+ kfree(prev); -+ } -+ lec_arp_put(priv->lec_arp_tables, entry); -+ lec_arp_unlock(priv); -+ return; -+ } -+ prev = entry; -+ entry = entry->next; -+ while (entry && entry->vcc != vcc) { -+ prev= entry; -+ entry = entry->next; -+ } -+ if (!entry) { -+ DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n"); -+ lec_arp_unlock(priv); -+ return; -+ } -+ save_flags(flags); -+ cli(); -+ del_timer(&entry->timer); -+ memcpy(entry->mac_addr, hdr->h_source, ETH_ALEN); -+ entry->status = ESI_FORWARD_DIRECT; -+ entry->last_used = jiffies; -+ prev->next = entry->next; -+ restore_flags(flags); -+ if ((prev = lec_arp_find(priv, hdr->h_source))) { -+ lec_arp_remove(priv->lec_arp_tables,prev); -+ kfree(prev); -+ } -+ lec_arp_put(priv->lec_arp_tables,entry); -+ lec_arp_unlock(priv); -+} -+ ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/net/atm/lec_arpc.h Wed Apr 2 22:38:55 1997 -@@ -0,0 +1,101 @@ ++ vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp); ++ vcc->qos.txtp.min_pcr = 0; +/* -+ * Lec arp cache -+ * Marko Kiiskila carnil@cs.tut.fi -+ * ++ * #endif + */ -+#ifndef _LEC_ARP_H -+#define _LEC_ARP_H -+#include -+#include -+#include -+#include -+ -+struct lec_arp_table { -+ struct lec_arp_table *next; /* Linked entry list */ -+ unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */ -+ unsigned char mac_addr[ETH_ALEN]; /* Mac address */ -+ struct atm_vcc *vcc; /* Vcc this entry is attached */ -+ struct atm_vcc *recv_vcc; /* Vcc we receive data from */ -+ void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); -+ /* Push that leads to daemon */ -+ void (*old_recv_push)(struct atm_vcc *vcc, struct sk_buff *skb); -+ /* Push that leads to daemon */ -+ void (*old_close)(struct atm_vcc *vcc); -+ /* We want to see when this -+ * vcc gets closed */ -+ unsigned long last_used; /* For expiry */ -+ unsigned long timestamp; /* Used for various timestamping -+ * things: -+ * 1. FLUSH started -+ * (status=ESI_FLUSH_PENDING) -+ * 2. Counting to -+ * max_unknown_frame_time -+ * (status=ESI_ARP_PENDING|| -+ * status=ESI_VC_PENDING) -+ */ -+ unsigned char no_tries; /* No of times arp retry has been -+ tried */ -+ unsigned char status; /* Status of this entry */ -+ unsigned short flags; /* Flags for this entry */ -+ unsigned short packets_flooded; /* Data packets flooded */ -+ unsigned long flush_tran_id; /* Transaction id in flush protocol */ -+ struct timer_list timer; /* Arping timer */ -+ struct lec_priv *priv; /* Pointer back */ -+}; ++ if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci))) ++ sock->state = SS_CONNECTED; ++ else (void) svc_disconnect(ATM_SD(sock)); ++ return error; ++} + -+/* Status fields */ -+#define ESI_UNKNOWN 0 /* -+ * Next packet sent to this mac address -+ * causes ARP-request to be sent -+ */ -+#define ESI_ARP_PENDING 1 /* -+ * There is no ATM address associated with this -+ * 48-bit address. The LE-ARP protocol is in -+ * progress. -+ */ -+#define ESI_VC_PENDING 2 /* -+ * There is a valid ATM address associated with -+ * this 48-bit address but there is no VC set -+ * up to that ATM address. The signaling -+ * protocol is in process. -+ */ -+#define ESI_FLUSH_PENDING 4 /* -+ * The LEC has been notified of the FLUSH_START -+ * status and it is assumed that the flush -+ * protocol is in process. -+ */ -+#define ESI_FORWARD_DIRECT 5 /* -+ * Either the Path Switching Delay (C22) has -+ * elapsed or the LEC has notified the Mapping -+ * that the flush protocol has completed. In -+ * either case, it is safe to forward packets -+ * to this address via the data direct VC. -+ */ -+ -+/* Flag values */ -+#define LEC_REMOTE_FLAG 0x0001 -+#define LEC_PERMANENT_FLAG 0x0002 -+ -+/* Protos */ -+void lec_arp_init(struct lec_priv *priv); -+int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc); -+void lec_arp_destroy(struct lec_priv *priv); -+void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc); -+ -+struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, -+ unsigned char *mac_to_addr); -+void lec_vcc_added(struct lec_priv *dev, -+ struct atmlec_ioc *ioc_data, struct atm_vcc *vcc, -+ void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb)); -+void lec_arp_check_empties(struct lec_priv *priv, -+ struct atm_vcc *vcc, struct sk_buff *skb); -+int lec_addr_delete(struct lec_priv *priv, -+ unsigned char *mac_addr, unsigned long permanent); -+void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id); -+void lec_arp_update(struct lec_priv *priv, -+ unsigned char *mac_addr, unsigned char *atm_addr, -+ unsigned long remoteflag); -+void lec_set_flush_tran_id(struct lec_priv *priv, -+ unsigned char *mac_addr, unsigned long tran_id); -+ -+#endif ---- ref/include/net/route.h Wed Oct 30 03:58:23 1996 -+++ work/include/net/route.h Fri Feb 28 14:47:56 1997 -@@ -26,6 +26,7 @@ - #define _ROUTE_H - - #include -+#include - - /* - * 0 - no debugging messages -@@ -158,11 +159,17 @@ - #endif - #endif - + - extern __inline__ struct rtable * ip_check_route(struct rtable ** rp, - __u32 daddr, int local) - { - struct rtable * rt = *rp; - -+#ifdef CONFIG_AREQUIPA -+ extern struct device *arequipa_dev; ++static int svc_listen(struct socket *sock,int backlog) ++{ ++ struct atm_vcc *vcc; + -+ if (rt && rt->rt_dev == arequipa_dev) return rt; -+#endif - if (!rt || rt->rt_dst != daddr || !(rt->rt_flags&RTF_UP) - || ((local==1)^((rt->rt_flags&RTF_LOCAL) != 0))) - { -@@ -172,6 +179,35 @@ - } - return rt; - } ++ DPRINTK("svc_listen\n"); ++ /* let server handle listen on unbound sockets */ ++ vcc = ATM_SD(sock); ++ vcc->reply = WAITING; ++ sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); ++ while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); ++ if (!sigd) return -EUNATCH; ++ vcc->flags |= ATM_VF_LISTEN; ++ vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; ++ return vcc->reply; ++} + + -+extern __inline__ void set_rt_cache(struct sock *sk,struct rtable *rt) ++static int svc_accept(struct socket *sock,struct socket *newsock,int flags) +{ -+#ifndef CONFIG_AREQUIPA -+ sk->ip_route_cache = rt; -+#else -+ extern struct rtable arequipa_rt; ++ struct sk_buff *skb; ++ struct atmsvc_msg *msg; ++ struct atm_vcc *old_vcc,*new_vcc; ++ int error; + -+ if (!sk->arequipa) { -+ sk->ip_route_cache = rt; -+ return; -+ } -+ if (!sk->aq_route) { -+ printk(KERN_CRIT "set_rt_cache: !sk->aq_route\n"); -+ sk->ip_route_cache = rt; -+ return; ++ DPRINTK("svc_accept\n"); ++ old_vcc = ATM_SD(sock); ++ new_vcc = ATM_SD(newsock); ++ while (1) { ++ while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) { ++ if (flags & O_NONBLOCK) return 0; /* not -EAGAIN ? */ ++ interruptible_sleep_on(&old_vcc->sleep); ++ if (current->signal & ~current->blocked) ++ return -ERESTARTSYS; ++ } ++ if (!skb) return -EUNATCH; ++ msg = (struct atmsvc_msg *) skb->data; ++ new_vcc->qos = msg->qos; ++ new_vcc->flags |= ATM_VF_HASQOS; ++ new_vcc->remote = msg->svc; ++ /* copy BLLI @@@ */ ++ new_vcc->remote.sas_addr.blli = NULL; ++ error = atm_connect(newsock,msg->pvc.sap_addr.itf, ++ msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); ++ dev_kfree_skb(skb,FREE_WRITE); ++ old_vcc->backlog_quota++; ++ if (error) { ++ sigd_enq(NULL,as_reject,old_vcc,NULL,NULL); ++ /* @@@ should include the reason */ ++ return error == -EAGAIN ? -EBUSY : error; ++ } ++ /* wait should be short, so we ignore the non-blocking flag */ ++ new_vcc->reply = WAITING; ++ sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); ++ while (new_vcc->reply == WAITING && sigd) ++ sleep_on(&new_vcc->sleep); ++ if (!sigd) { ++ atm_release_vcc(new_vcc,1); ++ return -EUNATCH; ++ } ++ if (!new_vcc->reply) break; ++ if (new_vcc->reply != -ERESTARTSYS) { ++ atm_release_vcc(new_vcc,1); ++ return new_vcc->reply; ++ } + } -+#if 0 /* only needed if preloading the route cache for Arequipa */ -+ if (sk->ip_route_cache) ip_rt_put(sk->ip_route_cache); -+#endif -+ sk->ip_route_cache = NULL; -+ if (!rt) return; -+ *sk->aq_route = arequipa_rt; -+ sk->ip_route_cache = sk->aq_route; -+ sk->aq_route->rt_src = rt->rt_src; -+ ip_rt_put(rt); -+#endif ++ newsock->state = SS_CONNECTED; ++ return 0; +} - - - #endif /* _ROUTE_H */ ---- ref/include/net/sock.h Thu Nov 7 10:35:28 1996 -+++ work/include/net/sock.h Fri Feb 28 14:29:29 1997 -@@ -190,6 +190,9 @@ - zapped, /* In ax25 & ipx means not linked */ - broadcast, - nonagle, -+#ifdef CONFIG_SCALED_WINDOWS -+ wscaling, -+#endif - bsdism; - unsigned long lingertime; - int proc; -@@ -211,7 +214,13 @@ - __u32 saddr; /* Sending source */ - __u32 rcv_saddr; /* Bound address */ - unsigned short max_unacked; -+#ifdef CONFIG_SCALED_WINDOWS -+ __u32 window; -+ unsigned char rcv_wscale; /* our window scale */ -+ unsigned char snd_wscale; /* their window scale */ -+#else - unsigned short window; -+#endif - __u32 lastwin_seq; /* sequence number when we last updated the window we offer */ - __u32 high_seq; /* sequence number when we did current fast retransmit */ - volatile unsigned long ato; /* ack timeout */ -@@ -224,7 +233,11 @@ - unsigned short mtu; /* mss negotiated in the syn's */ - volatile unsigned short mss; /* current eff. mss - can change */ - volatile unsigned short user_mss; /* mss requested by user in ioctl */ -+#ifdef CONFIG_SCALED_WINDOWS -+ volatile __u32 max_window; -+#else - volatile unsigned short max_window; -+#endif - unsigned long window_clamp; - unsigned int ssthresh; - unsigned short num; -@@ -302,7 +315,13 @@ - int ip_mc_loop; /* Loopback */ - char ip_mc_name[MAX_ADDR_LEN];/* Multicast device name */ - struct ip_mc_socklist *ip_mc_list; /* Group array */ --#endif -+#endif -+#ifdef CONFIG_AREQUIPA -+ struct socket *arequipa; /* dedicated link layer socket, -+ NULL if not connected */ -+ struct rtable *aq_route; /* buffer for fake route, NULL -+ if neither preset nor expect */ -+#endif - - /* - * This part is used for the timeout functions (timer.c). ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/arequipa.h Tue Apr 22 15:04:18 1997 -@@ -0,0 +1,60 @@ -+/* arequipa.h - Arequipa interface definitions */ -+ -+/* Written 1996,1997 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ -+ + -+#ifndef _LINUX_AREQUIPA_H -+#define _LINUX_AREQUIPA_H + -+#include ++static int svc_getname(struct socket *sock,struct sockaddr *sockaddr, ++ int *sockaddr_len,int peer) ++{ ++ struct sockaddr_atmsvc *addr; + ++ /* this will be fun ... we have: public and private ++ address, bhli and possibly a lot of bllis. Now address buffers ++ are static ... argl */ ++ /* The solution: use pointers to link bllis */ ++ /* naturally, we still need some place to put all those nasty ++ little bllis ... */ ++#if 0 ++ /* sigh ... */ ++ if (*sockaddr_len < sizeof(struct sockaddr_atmsvc)) return -EINVAL; ++#endif ++ *sockaddr_len = sizeof(struct sockaddr_atmsvc); ++ addr = (struct sockaddr_atmsvc *) sockaddr; ++ memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, ++ sizeof(struct sockaddr_atmsvc)); ++ addr->sas_addr.blli = NULL; /* @@@ no - copy it */ ++ return 0; ++} + -+enum arequipa_msg_type { amt_invalid,amt_close,amt_sync }; + -+struct arequipa_msg { -+ enum arequipa_msg_type type; -+ void *ptr; ++static struct proto_ops svc_proto_ops = { ++ PF_ATMSVC, ++ svc_dup, ++ svc_release, ++ svc_bind, ++ svc_connect, ++ NULL, /* no socketpair */ ++ svc_accept, ++ svc_getname, ++ atm_poll, ++ atm_ioctl, ++ svc_listen, ++ svc_shutdown, ++ atm_setsockopt, ++ atm_getsockopt, ++ NULL, /* no fcntl */ ++ atm_sendmsg, ++ atm_recvmsg +}; + + -+#define AREQUIPA_PRESET _IO('a',ATMIOC_AREQUIPA) -+#define AREQUIPA_INCOMING _IO('a',ATMIOC_AREQUIPA+1) -+#define AREQUIPA_EXPECT _IO('a',ATMIOC_AREQUIPA+2) -+#define AREQUIPA_CLOSE _IO('a',ATMIOC_AREQUIPA+3) -+#define AREQUIPA_CTRL _IO('a',ATMIOC_AREQUIPA+4) -+#define AREQUIPA_CLS3RD _IO('a',ATMIOC_AREQUIPA+5) -+#define AREQUIPA_SYNCREQ _IO('a',ATMIOC_AREQUIPA+6) -+#define AREQUIPA_SYNCACK _IO('a',ATMIOC_AREQUIPA+7) -+#define AREQUIPA_WORK _IO('a',ATMIOC_AREQUIPA+8) -+ -+ -+#ifdef __KERNEL__ ++static int svc_create(struct socket *sock,int protocol) ++{ ++ int error; + -+#include -+#include -+#include -+#include ++ sock->ops = &svc_proto_ops; ++ error = atm_create(sock,protocol); ++ if (error) return error; ++ ATM_SD(sock)->callback = svc_callback; ++ return 0; ++} + + -+extern struct atm_vcc *aqd; /* for net/atm/proc.c */ -+/* extern struct rtable arequipa_rt; - not needed */ -+extern struct device *arequipa_dev; ++static struct net_proto_family svc_family_ops = { ++ PF_ATMSVC, ++ svc_create, ++ 0, /* no authentication */ ++ 0, /* no encryption */ ++ 0 /* no encrypt_net */ ++}; + -+int atm_init_arequipa(void); -+int arequipa_attach(struct socket *lower,struct sock *upper, -+ unsigned long generation); + -+int arequipa_preset(struct socket *lower,struct sock *upper); -+int arequipa_expect(struct sock *upper,int on); -+int arequipa_incoming(struct socket *lower); -+int arequipa_close(struct sock *upper); -+void arequipa_synchronize(void); -+void arequipa_work(void); ++/* ++ * Initialize the ATM SVC protocol family ++ */ + -+int arequipad_attach(struct atm_vcc *vcc); -+void arequipa_close_vcc(struct atm_vcc *vcc); ++void atmsvc_proto_init(struct net_proto *pro) ++{ ++ if (sock_register(&svc_family_ops) < 0) { ++ printk(KERN_ERR "ATMSVC: can't register"); ++ return; ++ } ++} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/tunable.h Wed May 14 15:31:34 1997 +@@ -0,0 +1,26 @@ ++/* net/atm/tunable.h - Tunable parameters of ATM support */ + ++/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ + -+#endif /* __KERNEL__ */ + -+#endif ---- ref/net/ipv4/tcp_input.c Wed Oct 30 03:13:01 1996 -+++ work/net/ipv4/tcp_input.c Thu Apr 3 13:07:44 1997 -@@ -36,6 +36,11 @@ - #include - #include - -+#ifdef CONFIG_AREQUIPA -+#include -+#include -+#endif ++#ifndef NET_ATM_TUNABLE_H ++#define NET_ATM_TUNABLE_H + - /* - * Policy code extracted so it's now separate - */ -@@ -316,13 +321,22 @@ - switch(opcode) - { - case TCPOPT_MSS: -- if(opsize==4 && th->syn) -- { -+ if(opsize==TCPOLEN_MSS && -+ th->syn) { - sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr)); - mss_seen = 1; - } - break; -- /* Add other options here as people feel the urge to implement stuff like large windows */ -+#ifdef CONFIG_SCALED_WINDOWS -+ case TCPOPT_WINDOW: -+ if (opsize==TCPOLEN_WINDOW && th->syn) { -+ sk->snd_wscale=min(ptr[0], -+ MAX_WIN_SCALE); -+ sk->wscaling=1; -+ } -+ break; -+#endif -+ /* Add other options here */ - } - ptr+=opsize-2; - length-=opsize; -@@ -428,7 +442,24 @@ - return; - } - } -- -+#ifdef CONFIG_AREQUIPA -+ newsk->arequipa = NULL; -+ if (sk->aq_route) { -+ newsk->aq_route = kmalloc(sizeof(struct rtable),GFP_ATOMIC); -+ if (newsk->aq_route) { -+ if (dev == arequipa_dev) -+ (void) arequipa_attach(skb->atm.vcc->sock, -+ newsk,skb->atm.generation); -+ } -+ else { -+ if (sk->opt) kfree(sk->opt); -+ kfree_s(newsk,sizeof(*sk)); -+ tcp_statistics.TcpAttemptFails++; -+ kfree_skb(skb,FREE_READ); -+ return; -+ } -+ } -+#endif - skb->when = jiffies; /* For timeout */ - skb_queue_head_init(&newsk->write_queue); - skb_queue_head_init(&newsk->receive_queue); -@@ -440,6 +471,11 @@ - newsk->rto = TCP_TIMEOUT_INIT; - newsk->mdev = TCP_TIMEOUT_INIT; - newsk->max_window = 0; -+#ifdef CONFIG_SCALED_WINDOWS -+ newsk->snd_wscale = 0; -+ newsk->rcv_wscale = 0; -+ newsk->wscaling = 0; -+#endif - /* - * See draft-stevens-tcpca-spec-01 for discussion of the - * initialization of these values. -@@ -532,7 +568,7 @@ - */ - - rt = ip_rt_route(newsk->opt && newsk->opt->srr ? newsk->opt->faddr : saddr, 0); -- newsk->ip_route_cache = rt; -+ set_rt_cache(newsk,rt); - - if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) - newsk->window_clamp = rt->rt_window; -@@ -542,7 +578,9 @@ - if (sk->user_mss) - newsk->mtu = sk->user_mss; - else if (rt) -- newsk->mtu = rt->rt_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr); -+ newsk->mtu = newsk->ip_route_cache->rt_mtu - -+ sizeof(struct iphdr) - sizeof(struct tcphdr); -+ /* changed for Arequipa's MSS hack */ - else - newsk->mtu = 576 - sizeof(struct iphdr) - sizeof(struct tcphdr); - -@@ -686,6 +724,9 @@ - * Have we discovered a larger window - */ - window_seq = ntohs(th->window); -+#ifdef CONFIG_SCALED_WINDOWS -+ if (sk->wscaling && sk->snd_wscale) window_seq <<= sk->snd_wscale; ++#if 0 ++/* this is just a reminder - TTS is a device-specific parameter and shall be ++ used inside device drivers only */ ++#define ATM_TTS 1000 /* worst-case time to service of device ++ drivers, in microseconds */ +#endif - if (window_seq > sk->max_window) - { - sk->max_window = window_seq; -@@ -1174,6 +1215,10 @@ - sk->rtt = 0; - sk->rto = TCP_TIMEOUT_INIT; - sk->mdev = TCP_TIMEOUT_INIT; + -+#ifdef CONFIG_SCALED_WINDOWS -+ if (!sk->wscaling) sk->rcv_wscale = 0; -+#endif - } - - /* -@@ -1801,6 +1846,13 @@ - skb->saddr = daddr; - skb->daddr = saddr; - -+#ifdef CONFIG_AREQUIPA -+ if (dev == arequipa_dev && !sk->arequipa && sk->aq_route && -+ sk->state == TCP_ESTABLISHED) -+ (void) arequipa_attach(skb->atm.vcc->sock,sk, -+ skb->atm.generation); -+#endif ++#define ATM_RXBQ_DEF ( 64*1024) /* default RX buffer quota, in bytes */ ++#define ATM_TXBQ_DEF ( 64*1024) /* default TX buffer quota, in bytes */ ++#define ATM_RXBQ_MIN ( 1*1024) /* RX buffer minimum, in bytes */ ++#define ATM_TXBQ_MIN ( 1*1024) /* TX buffer minimum, in bytes */ ++#define ATM_RXBQ_MAX (1024*1024) /* RX buffer quota limit, in bytes */ ++#define ATM_TXBQ_MAX (1024*1024) /* TX buffer quota limit, in bytes */ + - /* - * We may need to add it to the backlog here. - */ -@@ -1961,6 +2013,12 @@ - return 0; - } - -+ /* -+ * Need to do option processing early to get -+ * window scale right. -+ */ -+ tcp_options(sk,th); ++#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer ++ quota per PDU */ + - /* process the ACK, get the SYN packet out - * of the send queue, do other initial - * processing stuff. [We know it's good, and -@@ -1978,7 +2036,6 @@ - sk->fin_seq = skb->seq; - tcp_send_ack(sk); - tcp_set_state(sk, TCP_ESTABLISHED); -- tcp_options(sk,th); - sk->dummy_th.dest=th->source; - sk->copied_seq = sk->acked_seq; - if(!sk->dead) ---- ref/net/ipv4/Config.in Fri Jul 19 07:24:05 1996 -+++ work/net/ipv4/Config.in Fri Nov 15 19:06:56 1996 -@@ -42,3 +42,4 @@ - #bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF - bool 'IP: Drop source routed frames' CONFIG_IP_NOSR - bool 'IP: Allow large windows (not recommended if <16Mb of memory)' CONFIG_SKB_LARGE -+bool 'IP: Window scale option' CONFIG_SCALED_WINDOWS ---- ref/net/core/skbuff.c Thu Jun 6 08:45:39 1996 -+++ work/net/core/skbuff.c Wed Jan 29 18:47:11 1997 -@@ -702,6 +702,12 @@ - skb->end=bptr+len; - skb->len=0; - skb->destructor=NULL; ++#endif +--- ref/net/core/skbuff.c Thu Jul 10 14:29:18 1997 ++++ work/net/core/skbuff.c Wed May 14 16:21:52 1997 +@@ -187,6 +187,12 @@ + skb->end = bptr + len; + skb->len = 0; + skb->inclone = 0; +#ifdef CONFIG_ATM + skb->atm.iovcnt = 0; +#ifdef CONFIG_ATM_NICSTAR @@ -19725,430 +8122,23 @@ return skb; } -@@ -762,6 +768,12 @@ - n->tries = 0; - n->lock = 0; - n->users = 0; +@@ -256,6 +262,9 @@ + atomic_set(&n->users, 1); + n->inclone = inbuff; + n->destructor = NULL; +#ifdef CONFIG_ATM_NICSTAR -+ if (n->atm.recycle_buffer) { -+ n->atm.recycle_buffer = NULL; -+ n->destructor = NULL; -+ } ++ n->atm.recycle_buffer = NULL; +#endif return n; } -@@ -820,6 +832,12 @@ - n->users=0; - n->pkt_type=skb->pkt_type; +@@ -310,6 +319,9 @@ n->stamp=skb->stamp; + n->destructor = NULL; + n->security=skb->security; +#ifdef CONFIG_ATM_NICSTAR -+ if (n->atm.recycle_buffer) { -+ n->atm.recycle_buffer = NULL; -+ n->destructor = NULL; -+ } ++ n->atm.recycle_buffer = NULL; +#endif - - IS_SKB(n); return n; ---- ref/include/net/tcp.h Wed Oct 30 03:58:24 1996 -+++ work/include/net/tcp.h Fri Feb 28 14:50:32 1997 -@@ -23,16 +23,26 @@ - - /* - * 40 is maximal IP options size -- * 4 is TCP option size (MSS) -+ * 4 is TCP option size (MSS only) -+ * 8 is TCP option size (MSS + NOP + WINDOW) - */ -+#ifdef CONFIG_SCALED_WINDOWS -+#define MAX_SYN_SIZE (sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + 8 + MAX_HEADER + 15) -+#else - #define MAX_SYN_SIZE (sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + 4 + MAX_HEADER + 15) -+#endif - #define MAX_FIN_SIZE (sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + MAX_HEADER + 15) - #define MAX_ACK_SIZE (sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + MAX_HEADER + 15) - #define MAX_RESET_SIZE (sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + MAX_HEADER + 15) - --#define MAX_WINDOW 32767 /* Never offer a window over 32767 without using -- window scaling (not yet supported). Some poor -- stacks do signed 16bit maths! */ -+#ifdef CONFIG_SCALED_WINDOWS -+#define MAX_WINDOW 65535 -+#define MAX_WIN_SCALE 14 -+#else -+#define MAX_WINDOW 32767 /* Never offer a window over 32767 -+ without using window scaling. Some -+ poor stacks do signed 16bit maths! */ -+#endif - #define MIN_WINDOW 2048 - #define MAX_ACK_BACKLOG 2 - #define MAX_DUP_ACKS 2 -@@ -82,12 +92,16 @@ - #define TCPOPT_NOP 1 /* Padding */ - #define TCPOPT_EOL 0 /* End of options */ - #define TCPOPT_MSS 2 /* Segment size negotiating */ --/* -- * We don't use these yet, but they are for PAWS and big windows -- */ - #define TCPOPT_WINDOW 3 /* Window scaling */ - #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ - -+/* -+ * TCP option lengths -+ */ -+#define TCPOLEN_NOP 1 -+#define TCPOLEN_MSS 4 -+#define TCPOLEN_WINDOW 3 -+#define TCPOLEN_TIMESTAMP 10 - - /* - * The next routines deal with comparing 32 bit unsigned ints -@@ -207,7 +221,11 @@ - sk->lastwin_seq = sk->acked_seq; - oldwin = window; - } -+#ifdef CONFIG_SCALED_WINDOWS -+ return oldwin >> sk->rcv_wscale; -+#else - return oldwin; -+#endif } - /* ---- ref/net/core/sock.c Wed Oct 30 02:42:42 1996 -+++ work/net/core/sock.c Fri Nov 15 19:06:56 1996 -@@ -172,22 +172,32 @@ - sk->broadcast=valbool; - return 0; - case SO_SNDBUF: -+#ifdef CONFIG_SCALED_WINDOWS -+ if(val > (MAX_WINDOW << MAX_WIN_SCALE)) -+ val = MAX_WINDOW << MAX_WIN_SCALE; -+#else - if(val > SK_WMEM_MAX*2) - val = SK_WMEM_MAX*2; -- if(val < 256) -- val = 256; - if(val > 65535) - val = 65535; -+#endif -+ if(val < 256) -+ val = 256; - sk->sndbuf = val; - return 0; - - case SO_RCVBUF: -+#ifdef CONFIG_SCALED_WINDOWS -+ if(val > (MAX_WINDOW << MAX_WIN_SCALE)) -+ val = MAX_WINDOW << MAX_WIN_SCALE; -+#else - if(val > SK_RMEM_MAX*2) - val = SK_RMEM_MAX*2; -- if(val < 256) -- val = 256; - if(val > 65535) - val = 65535; -+#endif -+ if(val < 256) -+ val = 256; - sk->rcvbuf = val; - return(0); - ---- ref/net/ipv4/tcp_output.c Mon Sep 2 14:18:26 1996 -+++ work/net/ipv4/tcp_output.c Fri Nov 15 19:06:57 1996 -@@ -69,7 +69,22 @@ - minwin = sk->mtu; - maxwin = sk->window_clamp; - if (!maxwin) -+#ifdef CONFIG_SCALED_WINDOWS -+ { -+ maxwin = sk->rcvbuf; -+ if (!sk->wscaling && maxwin > MAX_WINDOW) { -+ maxwin = MAX_WINDOW; -+ } else if (sk->state == TCP_SYN_RECV && sk->wscaling) { -+ sk->rcv_wscale = 0; -+ while (maxwin > MAX_WINDOW) { -+ maxwin >>= 1; -+ sk->rcv_wscale++; -+ } -+ } -+ } -+#else - maxwin = MAX_WINDOW; -+#endif - if (minwin > maxwin/2) - minwin = maxwin/2; - -@@ -845,6 +860,33 @@ - t1->rst = 0; - t1->psh = 0; - t1->ack_seq = htonl(newsk->acked_seq); -+#ifdef CONFIG_SCALED_WINDOWS -+ if (newsk->wscaling) { -+ t1->doff = 7; -+ ptr = skb_put(buff,TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW); -+ ptr[0] = TCPOPT_MSS; -+ ptr[1] = TCPOLEN_MSS; -+ ptr[2] = ((newsk->mtu) >> 8) & 0xff; -+ ptr[3] = (newsk->mtu) & 0xff; -+ ptr[4] = TCPOPT_NOP; -+ ptr[5] = TCPOPT_WINDOW; -+ ptr[6] = TCPOLEN_WINDOW; -+ ptr[7] = newsk->rcv_wscale; -+ buff->csum = csum_partial(ptr, TCPOLEN_MSS+TCPOLEN_NOP+ -+ TCPOLEN_WINDOW, 0); -+ tcp_send_check(t1, newsk->saddr, newsk->daddr, sizeof(*t1)+ -+ TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW, buff); -+ } else { -+ t1->doff = 6; -+ ptr = skb_put(buff,TCPOLEN_MSS); -+ ptr[0] = TCPOPT_MSS; -+ ptr[1] = TCPOLEN_MSS; -+ ptr[2] = ((newsk->mtu) >> 8) & 0xff; -+ ptr[3] =(newsk->mtu) & 0xff; -+ buff->csum = csum_partial(ptr, TCPOLEN_MSS, 0); -+ tcp_send_check(t1, newsk->saddr, newsk->daddr, sizeof(*t1)+TCPOLEN_MSS, buff); -+ } -+#else - t1->doff = sizeof(*t1)/4+1; - ptr = skb_put(buff,4); - ptr[0] = 2; -@@ -853,6 +895,7 @@ - ptr[3] =(newsk->mtu) & 0xff; - buff->csum = csum_partial(ptr, 4, 0); - tcp_send_check(t1, newsk->saddr, newsk->daddr, sizeof(*t1)+4, buff); -+#endif - newsk->prot->queue_xmit(newsk, ndev, buff, 0); - tcp_reset_xmit_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT); - skb->sk = newsk; ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/bigphysarea.h Fri Nov 15 19:06:57 1996 -@@ -0,0 +1,25 @@ -+/* linux/mm/bigphysarea.h, M. Welsh (mdw@cs.cornell.edu) -+ * Copyright (c) 1996 by Matt Welsh. -+ * -+ * This is a set of routines which allow you to reserve a large (?) -+ * amount of physical memory at boot-time, which can be allocated/deallocated -+ * by drivers. This memory is intended to be used for devices such as -+ * video framegrabbers which need a lot of physical RAM (above the amount -+ * allocated by kmalloc). This is by no means efficient or recommended; -+ * to be used only in extreme circumstances. -+ * -+ */ -+ -+#ifndef __LINUX_BIGPHYSAREA_H -+#define __LINUX_BIGPHYSAREA_H -+ -+#include -+ -+extern caddr_t bigphysarea; -+ -+extern void bigphysarea_setup(char *str, int *ints); -+extern unsigned long bigphysarea_init(unsigned long mem_start, unsigned long mem_end); -+extern caddr_t bigphysarea_alloc(int size); -+extern void bigphysarea_free(caddr_t addr, int size); -+ -+#endif __LINUX_BIGPHYSAREA_H ---- ref/mm/Makefile Fri Mar 22 11:56:56 1996 -+++ work/mm/Makefile Fri Nov 15 19:06:57 1996 -@@ -12,4 +12,8 @@ - kmalloc.o vmalloc.o \ - swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o - -+ifeq ($(CONFIG_BIGPHYS_AREA),y) -+ O_OBJS += bigphysarea.o -+endif -+ - include $(TOPDIR)/Rules.make ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/mm/bigphysarea.c Fri Nov 15 19:06:58 1996 -@@ -0,0 +1,113 @@ -+/* linux/mm/bigphysarea.c, M. Welsh (mdw@cs.cornell.edu) -+ * Copyright (c) 1996 by Matt Welsh. -+ * -+ * This is a set of routines which allow you to reserve a large (?) -+ * amount of physical memory at boot-time, which can be allocated/deallocated -+ * by drivers. This memory is intended to be used for devices such as -+ * video framegrabbers which need a lot of physical RAM (above the amount -+ * allocated by kmalloc). This is by no means efficient or recommended; -+ * to be used only in extreme circumstances. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int bigphysarea_pages = 0; -+static unsigned char *bigphysarea_map; -+caddr_t bigphysarea; -+ -+#define BIGPHYS_FREE 0 -+#define BIGPHYS_INUSE 1 -+ -+void bigphysarea_setup(char *str, int *ints) { -+ if (ints[0] != 1) { -+ printk("bigphysarea_setup: Usage: bigphysarea=\n"); -+ } else { -+ bigphysarea_pages = ints[1]; -+ } -+} -+ -+unsigned long bigphysarea_init(unsigned long mem_start, unsigned long mem_end) { -+ int ncp, i; -+ -+ if (bigphysarea_pages == 0) return mem_start; -+ -+ ncp = (bigphysarea_pages / PAGE_SIZE) + 1; -+ bigphysarea_map = (caddr_t)((mem_start + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1)); -+ bigphysarea = bigphysarea_map + (ncp * PAGE_SIZE); -+ -+ printk("bigphysarea: Allocated %d pages at 0x%lx.\n", -+ bigphysarea_pages, (unsigned long)bigphysarea); -+ -+ for (i = 0; i < bigphysarea_pages; i++) { -+ bigphysarea_map[i] = BIGPHYS_FREE; -+ } -+ -+ return (unsigned long)(bigphysarea + (bigphysarea_pages * PAGE_SIZE)); -+} -+ -+caddr_t bigphysarea_alloc(int size) { -+ int i, j, n; -+ -+ n = (size / PAGE_SIZE) + 1; -+ -+ i = 0; -+ -+try_again: -+ /* Get the first unallocated page */ -+ for (; i < bigphysarea_pages; i++) { -+ if (bigphysarea_map[i] == BIGPHYS_FREE) break; -+ } -+ if (i == bigphysarea_pages) return NULL; -+ -+ /* Check out the region */ -+ for (j = i; (j < bigphysarea_pages) && (j < (i + n)); j++) { -+ if (bigphysarea_map[i] != BIGPHYS_FREE) break; -+ } -+ -+ if (j == (i + n)) { -+ /* Got it */ -+ for (j = i; (j < (i + n)); j++) { -+ bigphysarea_map[j] = BIGPHYS_INUSE; -+ } -+ return bigphysarea + (i * PAGE_SIZE); -+ } -+ -+ /* Try again ... */ -+ i = j; -+ goto try_again; -+ -+} -+ -+void bigphysarea_free(caddr_t addr, int size) { -+ int i, j; -+ int n = (size / PAGE_SIZE) + 1; -+ -+ i = (((unsigned int)addr - (unsigned int)bigphysarea)/PAGE_SIZE); -+ for (j = 0; j < n; j++) { -+ if (bigphysarea_map[i+j] != BIGPHYS_INUSE) return; -+ bigphysarea_map[i+j] = BIGPHYS_FREE; -+ } -+} ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atm_eni.h Fri Apr 4 19:58:15 1997 -@@ -0,0 +1,15 @@ -+/* atm_eni.h - Driver-specific declarations of the ENI driver (for use by -+ driver-specific utilities) */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef LINUX_ATM_ENI_H -+#define LINUX_ATM_ENI_H -+ -+#include -+ -+#define ENI_MEMDUMP _IOW('a',ATMIOC_SARPRV,struct atmif_sioc) -+ /* printk memory map */ -+ -+#endif ---- /dev/null Mon Jul 18 01:46:18 1994 -+++ work/include/linux/atm_zatm.h Fri Apr 4 19:56:22 1997 -@@ -0,0 +1,54 @@ -+/* atm_zatm.h - Driver-specific declarations of the ZATM driver (for use by -+ driver-specific utilities) */ -+ -+/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ -+ -+ -+#ifndef LINUX_ATM_ZATM_H -+#define LINUX_ATM_ZATM_H -+ -+/* -+ * Note: non-kernel programs including this file must also include -+ * sys/types.h for struct timeval -+ */ -+ -+#include -+ -+#define ZATM_GETPOOL _IOW('a',ATMIOC_SARPRV+1,struct atmif_sioc) -+ /* get pool statistics */ -+#define ZATM_GETPOOLZ _IOW('a',ATMIOC_SARPRV+2,struct atmif_sioc) -+ /* get statistics and zero */ -+#define ZATM_SETPOOL _IOW('a',ATMIOC_SARPRV+3,struct atmif_sioc) -+ /* set pool parameters */ -+#define ZATM_GETTHIST _IOW('a',ATMIOC_SARPRV+4,struct atmif_sioc) -+ /* get a history of timer -+ differences */ -+ -+struct zatm_pool_info { -+ int ref_count; /* free buffer pool usage counters */ -+ int low_water,high_water; /* refill parameters */ -+ int rqa_count,rqu_count; /* queue condition counters */ -+ int offset,next_off; /* alignment optimizations: offset */ -+ int next_cnt,next_thres; /* repetition counter and threshold */ -+}; -+ -+struct zatm_pool_req { -+ int pool_num; /* pool number */ -+ struct zatm_pool_info info; /* actual information */ -+}; -+ -+struct zatm_thist { -+ struct timeval real; /* real (wall-clock) time */ -+ struct timeval expected; /* expected real time */ -+}; -+ -+ -+#define ZATM_OAM_POOL 0 /* free buffer pool for OAM cells */ -+#define ZATM_AAL0_POOL 1 /* free buffer pool for AAL0 cells */ -+#define ZATM_AAL5_POOL_BASE 2 /* first AAL5 free buffer pool */ -+#define ZATM_LAST_POOL ZATM_AAL5_POOL_BASE+10 /* max. 64 kB */ -+ -+#define ZATM_TIMER_HISTORY_SIZE 16 /* number of timer adjustments to -+ record; must be 2^n */ -+ -+#endif diff -ur --new-file old/atm/ilmid/COPYRIGHT new/atm/ilmid/COPYRIGHT --- old/atm/ilmid/COPYRIGHT Fri Dec 1 06:02:42 1995 +++ new/atm/ilmid/COPYRIGHT Tue Apr 22 04:23:25 1997 @@ -1,8 +1,6 @@ -Copyright (c) 1995 Telecommunications & Information -Sciences Laboratory, The University of Kansas -All Rights Reserved. - +Copyright (c) 1995-97 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 @@ -13,17 +11,8 @@ acknowledged in any publications resulting from using the software. -TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" -CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR +I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" +CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - -Telecommunications & Information Science Lab -2291, Irving Hill Road Lawrence, KS 66046 -(913)-864-7757 -http://www.tisl.ukans.edu - -The development of this software was generously -supported by research grants from Sprint corporation, -and we would like to express our thanks. diff -ur --new-file old/atm/ilmid/Makefile new/atm/ilmid/Makefile --- old/atm/ilmid/Makefile Fri Jan 31 22:04:17 1997 +++ new/atm/ilmid/Makefile Tue Apr 22 04:10:19 1997 @@ -1,7 +1,7 @@ LIBS = -L../lib -latmd -latm -Lasn1 -lasn1 INCLUDES = -I../lib -Iasn1 SRCS = rfc1157_snmp.c rfc1155_smi.c util.c io.c message.c \ - netprefix.c mib.c ilmid.c + atmf_uni.c mib.c sysgroup.c ilmid.c OBJS = $(SRCS:%.c=%.o) BOOTPGMS=ilmid diff -ur --new-file old/atm/ilmid/atmf_uni.c new/atm/ilmid/atmf_uni.c --- old/atm/ilmid/atmf_uni.c Thu Jan 1 01:00:00 1970 +++ new/atm/ilmid/atmf_uni.c Tue Apr 22 04:18:53 1997 @@ -0,0 +1,182 @@ +/* + * atmf_uni.h - ATM Forum UNI MIB + * + * Written by Scott W. Shumate + * + * Copyright (c) 1995-97 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. + * + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + */ + +#include "atmf_uni.h" +#include "atmd.h" +#include "util.h" + +#define COMPONENT "NETPREFIX" +#define NETPREFIX_LEN 12 +#define NETPREFIX_STRINGLEN '\15' +#define INDEX_LEN 15 +#define LOCALUNI '\0' +#define VALID 1 +#define INVALID 0 + +AsnOid atmfPortIndex = {13, "\53\06\01\04\01\202\141\02\01\01\01\01\00"}; +AsnOid atmfMyIpNmAddress = {11, "\53\06\01\04\01\202\141\02\01\02\00"}; +AsnOid atmfNetPrefixStatus = {NETPREFIX_LEN, "\53\06\01\04\01\202\141\02\07\01\01\03"}; + +AsnInt atmfPortIndexValue = 0; +AsnOid atmfMyIpNmAddressValue = {4 , "\0\0\0\0"}; + +static AsnOid atmNetPrefix = {0, NULL}; + +typedef struct NetPrefixNode +{ + AsnOid *name; + struct NetPrefixNode *prev; + struct NetPrefixNode *next; +} NetPrefixNode; + +AsnOid *accessNetPrefix(void) +{ + if(atmNetPrefix.octs == NULL) + return NULL; + + return(&atmNetPrefix); +} + +void deleteNetPrefix(void) +{ + NetPrefixNode *prefix, *nextPrefix; + + for(prefix = (NetPrefixNode *) MIBdelete(&atmfNetPrefixStatus); + prefix != NULL; + prefix = nextPrefix) + { + nextPrefix = prefix->next; + free(prefix->name->octs); + free(prefix->name); + free(prefix); + } + + if(atmNetPrefix.octs != NULL) + { + free(atmNetPrefix.octs); + atmNetPrefix.octs = NULL; + } +} + +AsnInt getNetPrefix(VarBind *varbind, Variable *var) +{ + int cmp; + NetPrefixNode *prefix; + AsnOid *varBindName; + + varBindName = &varbind->name; + if(AsnOidSize(varBindName) != NETPREFIX_LEN + INDEX_LEN || + varbind->name.octs[NETPREFIX_LEN] != LOCALUNI || + varbind->name.octs[NETPREFIX_LEN + 1] != NETPREFIX_STRINGLEN) + return NOSUCHNAME; + + for(prefix = (NetPrefixNode *) var->value, cmp = -1; + prefix != NULL && (cmp = AsnOidCompare(varBindName, prefix->name)) == -1; + prefix = prefix->next); + + if(cmp != 0) + return NOSUCHNAME; + + varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); + varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; + varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); + varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; + varbind->value->a.simple->a.number = VALID; + return NOERROR; +} + + +AsnInt getnextNetPrefix(VarBind *varbind, Variable *var) +{ + NetPrefixNode *prefix; + AsnOid *varBindName; + + varBindName = &varbind->name; + for(prefix = (NetPrefixNode *) var->value; + prefix != NULL && AsnOidCompare(prefix->name, varBindName) != AsnOidGreater; + prefix = prefix->next); + + if(prefix == NULL) + return NOSUCHNAME; + + varbind->name.octs = Asn1Alloc(prefix->name->octetLen); + AsnOidCopy(varBindName, prefix->name); + + varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); + varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; + varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); + varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; + varbind->value->a.simple->a.number = VALID; + + return NOERROR; +} + +AsnInt setNetPrefix(VarBind *varbind, Variable *var) +{ + int cmp; + NetPrefixNode *prefix, *newPrefix; + AsnOid *varBindName; + + varBindName = &varbind->name; + if(varbind->value->choiceId != OBJECTSYNTAX_SIMPLE || + varbind->value->a.simple->choiceId != SIMPLESYNTAX_NUMBER || + (varbind->value->a.simple->a.number != VALID && + varbind->value->a.simple->a.number != INVALID)) + return BADVALUE; + + if(AsnOidSize(varBindName) != NETPREFIX_LEN + INDEX_LEN || + varBindName->octs[NETPREFIX_LEN] != LOCALUNI || + varBindName->octs[NETPREFIX_LEN + 1] != NETPREFIX_STRINGLEN) + return NOSUCHNAME; + + for(prefix = (NetPrefixNode *) var->value, cmp = -1; + prefix != NULL && (cmp = AsnOidCompare(varBindName, prefix->name)) == -1; + prefix = prefix->next); + + if(varbind->value->a.simple->a.number == VALID && cmp != 0) + { + newPrefix = alloc_t(NetPrefixNode); + newPrefix->name = alloc_t(AsnOid); + newPrefix->name->octs = alloc(varBindName->octetLen); + AsnOidCopy(newPrefix->name, varBindName); + Q_INSERT_BEFORE((NetPrefixNode *) var->value, newPrefix, prefix); + if(atmNetPrefix.octs == NULL) + { + atmNetPrefix.octetLen = varBindName->octetLen - NETPREFIX_LEN - 2; + atmNetPrefix.octs = alloc(atmNetPrefix.octetLen); + memcpy(atmNetPrefix.octs, &varBindName->octs[NETPREFIX_LEN + 2], atmNetPrefix.octetLen); + } + } + else if (varbind->value->a.simple->a.number == INVALID && cmp == 0) + { + Q_REMOVE((NetPrefixNode *) var->value, prefix); + } + + return NOERROR; +} + + + + + + diff -ur --new-file old/atm/ilmid/atmf_uni.h new/atm/ilmid/atmf_uni.h --- old/atm/ilmid/atmf_uni.h Thu Jan 1 01:00:00 1970 +++ new/atm/ilmid/atmf_uni.h Tue Apr 22 04:18:58 1997 @@ -0,0 +1,45 @@ +/* + * atmf_uni.h - ATM Forum UNI MIB + * + * Written by Scott W. Shumate + * + * Copyright (c) 1995-97 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. + * + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + */ + +#ifndef ATMF_UNI_H +#define ATMF_UNI_H + +#include "asn_incl.h" +#include "rfc1155_smi.h" +#include "rfc1157_snmp.h" +#include "mib.h" + +AsnOid atmfPortIndex; +AsnOid atmfMyIpNmAddress; +AsnOid atmfNetPrefixStatus; + +AsnInt atmfPortIndexValue; +AsnOid atmfMyIpNmAddressValue; + +AsnOid *accessNetPrefix(void); +void deleteNetPrefix(void); +AsnInt getNetPrefix(VarBind *varbind, Variable *var); +AsnInt getnextNetPrefix(VarBind *varbind, Variable *var); +AsnInt setNetPrefix(VarBind *varbind, Variable *var); + +#endif diff -ur --new-file old/atm/ilmid/ilmid.c new/atm/ilmid/ilmid.c --- old/atm/ilmid/ilmid.c Mon Feb 3 20:15:45 1997 +++ new/atm/ilmid/ilmid.c Mon May 19 21:24:55 1997 @@ -1,11 +1,9 @@ /* - * ilmid.c - Ilmi agent daemon + * ilmi.c - ILMI demon * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,19 +15,10 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ /* Change Log: @@ -51,7 +40,8 @@ #include "io.h" #include "atmd.h" #include "mib.h" -#include "netprefix.h" +#include "atmf_uni.h" +#include "sysgroup.h" #define RESPONSE_TIMEOUT 2 #define POLL_PERIOD 15 @@ -79,8 +69,9 @@ AsnOid *set_oid, *netprefix_oid, *esi_oid; VarBind *varbind; struct timeval timeout; - IlmiState state, new_state; + IlmiState state, new_state; + resetUpTime(); poll_message = create_poll_message(); set_message = create_set_message(); set_oid = &((VarBind *) FIRST_LIST_ELMT(set_message->data->a.set_request->variable_bindings))->name; @@ -101,6 +92,7 @@ case RESTART: deleteNetPrefix(); diag(COMPONENT, DIAG_INFO, "sending cold-start"); + coldstart_message->data->a.trap->time_stamp = accessUpTime(); send_message(fd, coldstart_message); no_response = 0; @@ -168,7 +160,7 @@ case RESTART: case VERIFY: if(in_message->data->a.get_response->error_status == NOERROR && - AsnOidMember(&varbind->name, &atmAddressStatus)) + AsnOidCompare(&atmAddressStatus, &varbind->name) == AsnOidRoot) new_state = RESTART; else new_state = NET_PREFIX; @@ -177,7 +169,7 @@ case ADDRESS: if(in_message->data->a.get_response->error_status == NOERROR) { - diag(COMPONENT, DIAG_WARN, "ATM address registered"); + diag(COMPONENT, DIAG_INFO, "ATM address registered"); update_nsap(itf, netprefix_oid, esi_oid); no_response = 0; new_state = POLL; @@ -188,7 +180,7 @@ case POLL: if(in_message->data->a.get_response->error_status == NOERROR && - AsnOidEqual(&varbind->name, set_oid)) + AsnOidCompare(&varbind->name, set_oid) == AsnOidEqual) { no_response = 0; new_state = IDLE; @@ -309,7 +301,7 @@ if(argc != optind) usage(argv[0]); - diag(COMPONENT, DIAG_WARN, "Linux ATM ILMI, version %s", VERSION); + diag(COMPONENT, DIAG_INFO, "Linux ATM ILMI, version %s", VERSION); if(bg) { diff -ur --new-file old/atm/ilmid/io.c new/atm/ilmid/io.c --- old/atm/ilmid/io.c Tue Mar 11 11:54:52 1997 +++ new/atm/ilmid/io.c Mon May 19 21:27:06 1997 @@ -3,9 +3,7 @@ * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,19 +15,10 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * I ALLOW 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. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #include @@ -128,7 +117,7 @@ n = 0; if (req.length && atm_equal(&addr, &ouraddr[0], ATM_ESA_LEN, 0)) { - diag(COMPONENT, DIAG_WARN, "Primary ATM Address did not change"); + diag(COMPONENT, DIAG_INFO, "Primary ATM Address did not change"); n = 1; } @@ -149,7 +138,7 @@ atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) &addr, A2T_PRETTY); - diag(COMPONENT, DIAG_WARN, "Primary ATM Address %s added local", buffer); + diag(COMPONENT, DIAG_INFO, "Primary ATM Address %s added local", buffer); for (n = 0; n < m/sizeof(addr); n++) { @@ -164,7 +153,7 @@ if (ioctl(fd, ATM_ADDADDR, &req) < 0) diag(COMPONENT, DIAG_ERROR, "ioctl ATM_ADDADDR: %s", strerror(errno)); else - diag(COMPONENT, DIAG_WARN, "Extra ATM Address %s added local", buffer); + diag(COMPONENT, DIAG_INFO, "Extra ATM Address %s added local", buffer); } } diff -ur --new-file old/atm/ilmid/io.h new/atm/ilmid/io.h --- old/atm/ilmid/io.h Fri Jan 31 20:44:41 1997 +++ new/atm/ilmid/io.h Tue Apr 22 04:18:58 1997 @@ -3,9 +3,7 @@ * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,19 +15,10 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * I ALLOW 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. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #ifndef IO_H diff -ur --new-file old/atm/ilmid/message.c new/atm/ilmid/message.c --- old/atm/ilmid/message.c Mon Feb 3 20:14:34 1997 +++ new/atm/ilmid/message.c Tue Apr 22 04:18:53 1997 @@ -3,9 +3,9 @@ * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Written by Scott W. Shumate + * + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,23 +17,14 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #include "message.h" -#include "netprefix.h" +#include "atmf_uni.h" #include "util.h" int no_var_bindings = 0; diff -ur --new-file old/atm/ilmid/message.h new/atm/ilmid/message.h --- old/atm/ilmid/message.h Mon Feb 3 20:10:13 1997 +++ new/atm/ilmid/message.h Tue Apr 22 04:18:58 1997 @@ -3,9 +3,7 @@ * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,19 +15,10 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #ifndef MESSAGE_H diff -ur --new-file old/atm/ilmid/mib.c new/atm/ilmid/mib.c --- old/atm/ilmid/mib.c Thu Nov 30 23:19:54 1995 +++ new/atm/ilmid/mib.c Mon May 5 05:48:52 1997 @@ -1,11 +1,9 @@ /* - * mib.c - Ilmi management information base (MIB) + * mib.c - MIB Primitives * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,23 +15,15 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #include "mib.h" -#include "netprefix.h" +#include "sysgroup.h" +#include "atmf_uni.h" #include "util.h" #include "atmd.h" @@ -41,11 +31,16 @@ static Variable variables[] = { - { &atmNetPrefixStatus, - getNetPrefix, - getnextNetPrefix, - setNetPrefix, - NULL }, + { &sysDescr, getString, NULL, NULL, &sysDescrValue }, + { &sysObjectID, getOid, NULL, NULL, &sysObjectIDValue }, + { &sysUpTime, getUpTime, NULL, NULL, NULL }, + { &sysContact, getString, NULL, NULL, &sysContactValue }, + { &sysName, getString, NULL, NULL, &sysNameValue }, + { &sysLocation, getString, NULL, NULL, &sysLocationValue }, + { &sysServices, getInteger, NULL, NULL, &sysServicesValue }, + { &atmfPortIndex, getInteger, NULL, NULL, &atmfPortIndexValue }, + { &atmfMyIpNmAddress, getOid, NULL, NULL, &atmfMyIpNmAddressValue }, + { &atmfNetPrefixStatus, getNetPrefix, getnextNetPrefix, setNetPrefix, NULL }, { NULL } }; @@ -53,52 +48,85 @@ { VarBind *varbind; Variable *var; - int cmp; - + AsnOidResult result; + *index = 1; FOR_EACH_LIST_ELMT(varbind, list) + { + /* Find the first MIB object not lexigraphically less than the * + * requested OID */ + var = variables; + while(var->name != NULL) { - for(var = variables, cmp = -1; - var->name != NULL && (cmp = AsnOidCompare(&varbind->name, var->name)) == -1; - var++); - - if(cmp == 0) - *status = var->get(varbind, var); - else - *status = NOSUCHNAME; - - if(*status != NOERROR) - return; - - (*index)++; + result = AsnOidCompare(var->name, &varbind->name); + if(result != AsnOidLess) + break; + var++; } - *index = 0; - return; -} + /* Call get if the requested OID is equal to a simple MIB object */ + /* OR if the requested OID is a leaf of a complex MIB object */ + if((result == AsnOidEqual && var->getnext == NULL) || + (result == AsnOidRoot && var->getnext != NULL)) + *status = var->get(varbind, var); + /* else the object was not found */ + else + *status = NOSUCHNAME; + + /* Check if the get failed */ + if(*status != NOERROR) + return; + + (*index)++; + } + *index = 0; + return; +} + void MIBgetnext(VarBindList *list, PDUInt *status, AsnInt *index) { VarBind *varbind; Variable *var; + AsnOidResult result; *index = 1; FOR_EACH_LIST_ELMT(varbind, list) + { + /* Find the first complex MIB object not lexigraphically less than * + * or simple MIB object greater than the requested OID */ + var = variables; + while(var->name != NULL) { - for(var = variables; - var->name != NULL && AsnOidNext(&varbind->name, var->name); - var++); - - for(*status = NOSUCHNAME; - var->name != NULL && *status == NOSUCHNAME; - var++) + result = AsnOidCompare(var->name, &varbind->name); + if(var->getnext == NULL) + { + if(result == AsnOidGreater) + break; + } else if(result != AsnOidLess) + break; + var++; + } + + /* Find the next valid MIB object */ + for(*status = NOSUCHNAME; + var->name != NULL && *status == NOSUCHNAME; + var++) + if(var->getnext == NULL) + { + varbind->name.octs = Asn1Alloc(var->name->octetLen); + AsnOidCopy(&varbind->name, var->name); + *status = var->get(varbind, var); + } + else *status = var->getnext(varbind, var); - if(*status != NOERROR) - return; + /* Check if no valid MIB object found */ + if(*status != NOERROR) + return; - (*index)++; - } + (*index)++; + } *index = 0; return; } @@ -107,40 +135,64 @@ { VarBind *varbind; Variable *var; - int cmp; + AsnOidResult result; *index = 1; FOR_EACH_LIST_ELMT(varbind, list) + { + /* Find the first MIB object not lexigraphically less than the * + * requested OID */ + var = variables; + while(var->name != NULL) { - for(var = variables, cmp = -1; - var->name != NULL && (cmp = AsnOidCompare(&varbind->name, var->name)) == -1; - var++); + result = AsnOidCompare(var->name, &varbind->name); + if(result != AsnOidLess) + break; + var++; + } - if(cmp == 0) - *status = var->set(varbind, var); + /* Call set if the requested variable is equal to a simple MIB object */ + if((result == AsnOidEqual && var->getnext == NULL) || + /* OR if the request variable is a leaf of a complex MIB object */ + (result == AsnOidRoot && var->getnext != NULL)) + /* Return read only if no set function exists */ + if(var->set == NULL) + *status = READONLY; else - *status = NOSUCHNAME; - - if(*status != NOERROR) - return; + *status = var->set(varbind, var); + else + /* else the MIB object was not found */ + *status = NOSUCHNAME; + + /* Check if the set failed */ + if(*status != NOERROR) + return; - (*index)++; - } - *index = 0; - return; + (*index)++; + } + *index = 0; + return; } void *MIBdelete(AsnOid *oid) { Variable *var; void *value; - int cmp; + AsnOidResult result; - for(var = variables, cmp = -1; - var->name != NULL && (cmp = AsnOidCompare(oid, var->name)) == -1; - var++); + /* Find the first MIB object not lexigraphically less than the * + * requested variable */ + var = variables; + while(var->name != NULL) + { + result = AsnOidCompare(var->name, oid); + if(result != AsnOidLess) + break; + var++; + } - if(cmp != 0) + /* Return NULL if the MIB object is not found */ + if(result != AsnOidEqual) return NULL; value = var->value; @@ -148,4 +200,38 @@ return value; } + +AsnInt getString(VarBind *varbind, Variable *var) +{ + varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); + varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; + varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); + varbind->value->a.simple->choiceId = SIMPLESYNTAX_STRING; + varbind->value->a.simple->a.string = (AsnOcts*) var->value; + return NOERROR; +} + +AsnInt getOid(VarBind *varbind, Variable *var) +{ + varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); + varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; + varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); + varbind->value->a.simple->choiceId = SIMPLESYNTAX_OBJECT; + varbind->value->a.simple->a.object = (AsnOid*) var->value; + return NOERROR; +} + +AsnInt getInteger(VarBind *varbind, Variable *var) +{ + varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); + varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; + varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); + varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; + varbind->value->a.simple->a.number = *((AsnInt *) var->value); + return NOERROR; +} + + + + diff -ur --new-file old/atm/ilmid/mib.h new/atm/ilmid/mib.h --- old/atm/ilmid/mib.h Fri Jan 31 20:47:21 1997 +++ new/atm/ilmid/mib.h Tue Apr 22 04:18:58 1997 @@ -1,11 +1,9 @@ /* - * mib.h - Ilmi management information base (MIB) + * mib.h - MIB Primitives * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,19 +15,10 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #ifndef MIB_H @@ -52,5 +41,9 @@ void MIBgetnext(VarBindList *list, PDUInt *status, AsnInt *index); void MIBset(VarBindList *list, PDUInt *status, AsnInt *index); void *MIBdelete(AsnOid *oid); + +AsnInt getString(VarBind *varbind, Variable *var); +AsnInt getOid(VarBind *varbind, Variable *var); +AsnInt getInteger(VarBind *varbind, Variable *var); #endif diff -ur --new-file old/atm/ilmid/netprefix.c new/atm/ilmid/netprefix.c --- old/atm/ilmid/netprefix.c Fri Dec 1 03:41:59 1995 +++ new/atm/ilmid/netprefix.c Thu Jan 1 01:00:00 1970 @@ -1,188 +0,0 @@ -/* - * netprefix.c - Access routines to the NetPrefix ILMI MIB variable - * - * Written by Scott W. Shumate - * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * 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. - * - * TISL 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. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. - */ - -#include "netprefix.h" -#include "atmd.h" -#include "util.h" - -#define COMPONENT "NETPREFIX" -#define NETPREFIX_LEN 12 -#define NETPREFIX_STRINGLEN '\15' -#define INDEX_LEN 15 -#define LOCALUNI '\0' -#define VALID 1 -#define INVALID 0 - -AsnOid atmNetPrefixStatus = {NETPREFIX_LEN, "\53\06\01\04\01\202\141\02\07\01\01\03"}; - -static AsnOid atmNetPrefix = {0, NULL}; - -typedef struct NetPrefixNode -{ - AsnOid *name; - struct NetPrefixNode *prev; - struct NetPrefixNode *next; -} NetPrefixNode; - -AsnOid *accessNetPrefix(void) -{ - if(atmNetPrefix.octs == NULL) - return NULL; - - return(&atmNetPrefix); -} - -void deleteNetPrefix(void) -{ - NetPrefixNode *prefix, *nextPrefix; - - for(prefix = (NetPrefixNode *) MIBdelete(&atmNetPrefixStatus); - prefix != NULL; - prefix = nextPrefix) - { - nextPrefix = prefix->next; - free(prefix->name->octs); - free(prefix->name); - free(prefix); - } - - if(atmNetPrefix.octs != NULL) - { - free(atmNetPrefix.octs); - atmNetPrefix.octs = NULL; - } -} - -AsnInt getNetPrefix(VarBind *varbind, Variable *var) -{ - int cmp; - NetPrefixNode *prefix; - AsnOid *varBindName; - - varBindName = &varbind->name; - if(AsnOidSize(varBindName) != NETPREFIX_LEN + INDEX_LEN || - varbind->name.octs[NETPREFIX_LEN] != LOCALUNI || - varbind->name.octs[NETPREFIX_LEN + 1] != NETPREFIX_STRINGLEN) - return NOSUCHNAME; - - for(prefix = (NetPrefixNode *) var->value, cmp = -1; - prefix != NULL && (cmp = AsnOidCompare(varBindName, prefix->name)) == -1; - prefix = prefix->next); - - if(cmp != 0) - return NOSUCHNAME; - - varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); - varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; - varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); - varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; - varbind->value->a.simple->a.number = VALID; - return NOERROR; -} - - -AsnInt getnextNetPrefix(VarBind *varbind, Variable *var) -{ - NetPrefixNode *prefix; - AsnOid *varBindName; - - varBindName = &varbind->name; - for(prefix = (NetPrefixNode *) var->value; - prefix != NULL && AsnOidGreater(varBindName, prefix->name); - prefix = prefix->next); - - if(prefix == NULL) - return NOSUCHNAME; - - varbind->name.octs = Asn1Alloc(prefix->name->octetLen); - AsnOidCopy(varBindName, prefix->name); - - varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); - varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; - varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); - varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; - varbind->value->a.simple->a.number = VALID; - - return NOERROR; -} - -AsnInt setNetPrefix(VarBind *varbind, Variable *var) -{ - int cmp; - NetPrefixNode *prefix, *newPrefix; - AsnOid *varBindName; - - varBindName = &varbind->name; - if(varbind->value->choiceId != OBJECTSYNTAX_SIMPLE || - varbind->value->a.simple->choiceId != SIMPLESYNTAX_NUMBER || - (varbind->value->a.simple->a.number != VALID && - varbind->value->a.simple->a.number != INVALID)) - return BADVALUE; - - if(AsnOidSize(varBindName) != NETPREFIX_LEN + INDEX_LEN || - varBindName->octs[NETPREFIX_LEN] != LOCALUNI || - varBindName->octs[NETPREFIX_LEN + 1] != NETPREFIX_STRINGLEN) - return NOSUCHNAME; - - for(prefix = (NetPrefixNode *) var->value, cmp = -1; - prefix != NULL && (cmp = AsnOidCompare(varBindName, prefix->name)) == -1; - prefix = prefix->next); - - if(varbind->value->a.simple->a.number == VALID && cmp != 0) - { - newPrefix = alloc_t(NetPrefixNode); - newPrefix->name = alloc_t(AsnOid); - newPrefix->name->octs = alloc(varBindName->octetLen); - AsnOidCopy(newPrefix->name, varBindName); - Q_INSERT_BEFORE((NetPrefixNode *) var->value, newPrefix, prefix); - if(atmNetPrefix.octs == NULL) - { - atmNetPrefix.octetLen = varBindName->octetLen - NETPREFIX_LEN - 2; - atmNetPrefix.octs = alloc(atmNetPrefix.octetLen); - memcpy(atmNetPrefix.octs, &varBindName->octs[NETPREFIX_LEN + 2], atmNetPrefix.octetLen); - } - } - else if (varbind->value->a.simple->a.number == INVALID && cmp == 0) - { - Q_REMOVE((NetPrefixNode *) var->value, prefix); - } - - return NOERROR; -} - - - - - - diff -ur --new-file old/atm/ilmid/netprefix.h new/atm/ilmid/netprefix.h --- old/atm/ilmid/netprefix.h Fri Jan 31 20:46:50 1997 +++ new/atm/ilmid/netprefix.h Thu Jan 1 01:00:00 1970 @@ -1,51 +0,0 @@ -/* - * netprefix.h - Access routines to the NetPrefix MIB variable - * - * Written by Scott W. Shumate - * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * 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. - * - * TISL 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. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. - */ - -#ifndef ACCESS_H -#define ACCESS_H - -#include "asn_incl.h" -#include "rfc1155_smi.h" -#include "rfc1157_snmp.h" -#include "mib.h" - -AsnOid atmNetPrefixStatus; - -AsnOid *accessNetPrefix(void); -void deleteNetPrefix(void); -AsnInt getNetPrefix(VarBind *varbind, Variable *var); -AsnInt getnextNetPrefix(VarBind *varbind, Variable *var); -AsnInt setNetPrefix(VarBind *varbind, Variable *var); - -#endif diff -ur --new-file old/atm/ilmid/sysgroup.c new/atm/ilmid/sysgroup.c --- old/atm/ilmid/sysgroup.c Thu Jan 1 01:00:00 1970 +++ new/atm/ilmid/sysgroup.c Tue Apr 22 04:18:53 1997 @@ -0,0 +1,69 @@ +/* + * sysgroup.c - MIB-II system group + * + * Written by Scott W. Shumate + * + * Copyright (c) 1995-97 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. + * + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + */ + +#include +#include "sysgroup.h" +#include "string.h" + +AsnOid sysDescr = {8, "\53\06\01\02\01\01\01\00"}; +AsnOid sysObjectID = {8, "\53\06\01\02\01\01\02\00"}; +AsnOid sysUpTime = {8, "\53\06\01\02\01\01\03\00"}; +AsnOid sysContact = {8, "\53\06\01\02\01\01\04\00"}; +AsnOid sysName = {8, "\53\06\01\02\01\01\05\00"}; +AsnOid sysLocation = {8, "\53\06\01\02\01\01\06\00"}; +AsnOid sysServices = {8, "\53\06\01\02\01\01\07\00"}; + +AsnOcts sysDescrValue = {25, "ATM on Linux Version 0.30"}; +AsnOid sysObjectIDValue = {8, "\53\06\01\04\01\03\01\01"}; +AsnOcts sysContactValue = {14, "root@localhost"}; +AsnOcts sysNameValue = {23, "localhost.my.domain.com"}; +AsnOcts sysLocationValue = {36, "Connected to an ATM switch somewhere"}; +AsnInt sysServicesValue = 4; + +static time_t up_time; + + +void resetUpTime(void) +{ + up_time = time(0); +} + +TimeTicks accessUpTime(void) +{ + /* Return time in hundreds of seconds */ + return (TimeTicks) ((time(0) - up_time) * 100); +} + +AsnInt getUpTime(VarBind *varbind, Variable *var) +{ + varbind->value = Asn1Alloc(sizeof(struct ObjectSyntax)); + varbind->value->choiceId = OBJECTSYNTAX_SIMPLE; + varbind->value->a.simple = Asn1Alloc(sizeof(struct SimpleSyntax)); + varbind->value->a.simple->choiceId = SIMPLESYNTAX_NUMBER; + varbind->value->a.simple->a.number = (AsnInt) accessUpTime(); + return NOERROR; +} + + + + diff -ur --new-file old/atm/ilmid/sysgroup.h new/atm/ilmid/sysgroup.h --- old/atm/ilmid/sysgroup.h Thu Jan 1 01:00:00 1970 +++ new/atm/ilmid/sysgroup.h Tue Apr 22 04:18:58 1997 @@ -0,0 +1,54 @@ +/* + * sysgroup.h - MIB-II system group + * + * Written by Scott W. Shumate + * + * Copyright (c) 1995-97 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. + * + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS + * SOFTWARE. + */ + +#ifndef SYSGROUP_H +#define SYSGROUP_H + +#include "asn_incl.h" +#include "rfc1155_smi.h" +#include "rfc1157_snmp.h" +#include "mib.h" + +AsnOid sysDescr; +AsnOid sysObjectID; +AsnOid sysUpTime; +AsnOid sysContact; +AsnOid sysName; +AsnOid sysLocation; +AsnOid sysServices; + +AsnOcts sysDescrValue; +AsnOid sysObjectIDValue; +AsnOcts sysContactValue; +AsnOcts sysNameValue; +AsnOcts sysLocationValue; +AsnInt sysServicesValue; + +AsnInt getString(VarBind *varbind, Variable *var); +AsnInt getOid(VarBind *varbind, Variable *var); +void resetUpTime(void); +TimeTicks accessUpTime(void); +AsnInt getUpTime(VarBind *varbind, Variable *var); +AsnInt getInteger(VarBind *varbind, Variable *var); + +#endif diff -ur --new-file old/atm/ilmid/util.c new/atm/ilmid/util.c --- old/atm/ilmid/util.c Thu Nov 30 23:17:49 1995 +++ new/atm/ilmid/util.c Mon May 5 05:48:52 1997 @@ -3,9 +3,7 @@ * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,23 +15,46 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #include "util.h" #include "atmd.h" + +AsnOidResult AsnOidCompare(AsnOid *o1, AsnOid *o2) +{ + int result; + + if(o1->octetLen > o2->octetLen) + { + result = memcmp(o1->octs, o2->octs, o2->octetLen); + if(result == -1) + return AsnOidLess; + else + return AsnOidGreater; + } else if(o1->octetLen < o2->octetLen) + { + result = memcmp(o1->octs, o2->octs, o1->octetLen); + if(result == 1) + return AsnOidGreater; + else if(result == 0) + return AsnOidRoot; + else + return AsnOidLess; + } else + { + result = memcmp(o1->octs, o2->octs, o1->octetLen); + if(result == -1) + return AsnOidLess; + else if(result == 0) + return AsnOidEqual; + else + return AsnOidGreater; + } +} int AsnOidSize(AsnOid *oid) { diff -ur --new-file old/atm/ilmid/util.h new/atm/ilmid/util.h --- old/atm/ilmid/util.h Fri Jan 31 20:44:07 1997 +++ new/atm/ilmid/util.h Mon May 5 05:48:52 1997 @@ -3,9 +3,7 @@ * * Written by Scott W. Shumate * - * Copyright (c) 1995 Telecommunications & Information - * Sciences Laboratory, The University of Kansas - * All Rights Reserved. + * Copyright (c) 1995-97 All Rights Reserved. * * Permission to use, copy, modify and distribute this * software and its documentation is hereby granted, @@ -17,19 +15,10 @@ * acknowledged in any publications resulting from using * the software. * - * TISL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION AND DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * I ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION AND DISCLAIM ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS * SOFTWARE. - * - * Telecommunications & Information Science Lab - * 2291, Irving Hill Road Lawrence, KS 66046 - * (913)-864-7757 - * http://www.tisl.ukans.edu - * - * The development of this software was generously - * supported by research grants from Sprint corporation, - * and we would like to express our thanks. */ #ifndef UTIL_H @@ -40,32 +29,19 @@ #include "rfc1157_snmp.h" #include "atmd.h" -#define AsnOidCompare(o1, o2) ((o1)->octetLen < (o2)->octetLen ? \ - (memcmp((o1)->octs, (o2)->octs, (o1)->octetLen) > 0 ? 1 : -1) : \ - (memcmp((o1)->octs, (o2)->octs, (o2)->octetLen))) - -#define AsnOidGreater(o1, o2) ((o1)->octetLen < (o2)->octetLen ? \ - memcmp((o1)->octs, (o2)->octs, (o1)->octetLen) > 0 : \ - memcmp((o1)->octs, (o2)->octs, (o2)->octetLen) >= 0) - -#define AsnOidLess(o1, o2) ((o1)->octetLen < (o2)->octetLen ? \ - memcmp((o1)->octs, (o2)->octs, (o1)->octetLen) <= 0 : \ - memcmp((o1)->octs, (o2)->octs, (o2)->octetLen) < 0) - -#define AsnOidEqual(o1,o2) ((o1)->octetLen == (o2)->octetLen ? \ - memcmp((o1)->octs, (o2)->octs, (o1)->octetLen) == 0 : 0) - -#define AsnOidNext(o1, o2) ((o1)->octetLen < (o2)->octetLen ? \ - memcmp((o1)->octs, (o2)->octs, (o1)->octetLen) < 0 : \ - memcmp((o1)->octs, (o2)->octs, (o2)->octetLen) < 0) - -#define AsnOidMember(o1,o2) ((o1)->octetLen < (o2)->octetLen ? \ - 0 : memcmp((o1)->octs, (o2)->octs, (o2)->octetLen) == 0) - #define AsnOidCopy(o1, o2) ({memcpy((o1)->octs, (o2)->octs, (o1)->octetLen = (o2)->octetLen);}) #define AsnOidAppend(o1, o2) ({memcpy(&(o1)->octs[(o1)->octetLen], (o2)->octs, (o2)->octetLen); \ (o1)->octetLen += (o2)->octetLen;}) + +typedef enum _AsnOidResult { + AsnOidLess, + AsnOidRoot, + AsnOidEqual, + AsnOidGreater +} AsnOidResult; + +AsnOidResult AsnOidCompare(AsnOid *o1, AsnOid *o2); int AsnOidSize(AsnOid *oid); diff -ur --new-file old/atm/ip/atmarp.c new/atm/ip/atmarp.c --- old/atm/ip/atmarp.c Tue Mar 11 12:08:13 1997 +++ new/atm/ip/atmarp.c Thu Jul 3 08:58:12 1997 @@ -194,6 +194,7 @@ perror("socket"); return 1; } + *req.arp_dev = 0; if (ioctl(s,op,&req) < 0) { perror("ioctl SIOCxARP"); return 1; diff -ur --new-file old/atm/maint/Makefile new/atm/maint/Makefile --- old/atm/maint/Makefile Tue Apr 22 23:35:33 1997 +++ new/atm/maint/Makefile Thu Jul 10 19:07:16 1997 @@ -1,9 +1,14 @@ +INCLUDES=-I../qgen -I../saal BOOTPGMS=atmaddr SYSPGMS=atmtcp zntune -USRPGMS=atmdiag atmdump sonetdiag +USRPGMS=atmdiag atmdump sonetdiag #saaldump MAN8=atmaddr.8 atmdiag.8 atmdump.8 atmtcp.8 include ../Rules.make atmdiag.o: atmdiag.c $(CC) -c $(CFLAGS_NOOPT) atmdiag.c + +saaldump: saaldump.o + $(CC) $(LDFLAGS) -o saaldump saaldump.o ../qgen/qd.dump.o \ + -L../saal -lsaal -L../lib -latm diff -ur --new-file old/atm/maint/atmtcp.8 new/atm/maint/atmtcp.8 --- old/atm/maint/atmtcp.8 Mon Aug 14 09:41:50 1995 +++ new/atm/maint/atmtcp.8 Thu May 29 09:09:48 1997 @@ -1,13 +1,15 @@ -.TH ATMTCP 8 "Aug 4, 1995" "Linux" "Maintenance Commands" +.TH ATMTCP 8 "May 29, 1997" "Linux" "Maintenance Commands" .SH NAME atmtcp \- set up ATM over TCP connections .SH SYNOPSIS .ad l .B atmtcp +.RB [ -b ] .B \-l .RB [ \fIlclport\fB ] .br .B atmtcp +.RB [ -b ] .B \-c .I host .RB [ \fIrmtport\fB ] @@ -23,6 +25,8 @@ .B atmtcp on a different port than the default port (8401). .SH OPTIONS +.IP \fB\-b\fP +Run in background (i.e. in a forked child process) after initializing. .IP \fB\-l\fP listen for an incoming connection. Only one connection is accepted. .IP \fB\-c\ \fIhost\fP @@ -30,14 +34,12 @@ .SH RESTRICTIONS Only AAL PDUs are exchanged, no segmentation or reassembly is performed. That implies that using different AALs (e.g. AAL5 and AAL0) on either side -will reveal limitations of this emulation. Classical IP can't be used over +will reveal limitations of this emulation. .B atmtcp -connections. +continues to run during the the whole lifetime of the connection. Forcibly +terminating .B atmtcp -doesn't detach from the TCP socket it creates, so it has to run during -the whole lifetime of the connection. Forcibly terminating -.B atmtcp -may crash the system. +will force all VCs to be closed and the virtual ATM device to be removed. .SH AUTHOR Werner Almesberger, EPFL LRC .SH "SEE ALSO" diff -ur --new-file old/atm/maint/atmtcp.c new/atm/maint/atmtcp.c --- old/atm/maint/atmtcp.c Mon Oct 16 10:29:25 1995 +++ new/atm/maint/atmtcp.c Tue Jul 1 13:50:54 1997 @@ -1,6 +1,6 @@ /* atmtcp.c - control ATM on TCP emulation */ -/* Written 1995 by Werner Almesberger, EPFL-LRC */ +/* Written 1995,1997 by Werner Almesberger, EPFL-LRC */ #include @@ -10,23 +10,100 @@ #include #include #include +#include #include #include + #include +#include + + +#define PORT 8402 /* old ATMTCP used 8401, but now the header is in + network byte order, so we're incompatible in most + cases */ + +#define MAX_PACKET ATM_MAX_AAL5_PDU+sizeof(struct atmtcp_hdr) -#define PORT 8401 +static int s_tcp,s_krn; + + +/* + * This is a pretty poor implementation because we need to read twice for each + * PDU. But then, atmtcp isn't exactly designed for throughput ... + */ + + +static void from_tcp(void) +{ + static char buf[MAX_PACKET]; + static int bytes = 0; + int ret,size; + + size = sizeof(struct atmtcp_hdr)-bytes; + if (size <= 0) size += ntohl(((struct atmtcp_hdr *) buf)->length); + ret = read(s_tcp,buf+bytes,size); + if (ret < 0) { + perror("read from TCP"); + exit(1); + } + if (!ret) exit(0); /* EOF */ + bytes += ret; + if (bytes < sizeof(struct atmtcp_hdr)) return; + if (ntohl(((struct atmtcp_hdr *) buf)->length) > ATM_MAX_AAL5_PDU) { + fprintf(stderr,"giant PDU (length = %ld) received\n", + ntohl(((struct atmtcp_hdr *) buf)->length)); + exit(1); + } + if (bytes < sizeof(struct atmtcp_hdr)+ + ntohl(((struct atmtcp_hdr *) buf)->length)) return; + size = write(s_krn,buf,bytes); + if (size < 0) perror("write to kernel"); + else if (size != bytes) { + fprintf(stderr,"bad write (%d != %d)\n",size,bytes); + exit(1); + } + bytes = 0; +} + + +static void to_tcp(void) +{ + char buf[MAX_PACKET]; + int ret,wrote; + + ret = read(s_krn,buf,MAX_PACKET); + if (ret < 0) { + perror("read from kernel"); + exit(1); + } + if (!ret) exit(0); /* we don't use that yet */ + if (ret < sizeof(struct atmtcp_hdr)) { + fprintf(stderr,"kernel message too small (%d)\n",ret); + exit(1); + } + if (ret != sizeof(struct atmtcp_hdr)+ + ntohl(((struct atmtcp_hdr *) buf)->length)) { + fprintf(stderr,"invalid kernel message\n"); + exit(1); + } + wrote = write(s_tcp,buf,ret); + if (wrote < 0) { + perror("write to TCP"); + exit(1); + } + if (!wrote) exit(0); /* EOF */ + if (wrote != ret) { + fprintf(stderr,"bad write (%d != %d)\n",wrote,ret); + exit(1); + } +} static void usage(const char *name) { -#if 0 - fprintf(stderr,"%s -l {} [ ]\n",name); - fprintf(stderr,"%s -c [ ]\n",name); -#else - fprintf(stderr,"%s -l [ ]\n",name); - fprintf(stderr,"%s -c [ ]\n",name); -#endif + fprintf(stderr,"%s [ -b ] -l [ ]\n",name); + fprintf(stderr,"%s [ -b ] -c [ ]\n",name); exit(1); } @@ -35,7 +112,7 @@ { struct sockaddr_in addr; int listen_mode,port,itf; - int s,s2; + int s2; if (argc < 2) usage(argv[0]); listen_mode = !strcmp(argv[1],"-l"); @@ -47,30 +124,42 @@ if (argc > 4 || strcmp(argv[1],"-c")) usage(argv[0]); port = argc == 4 ? atoi(argv[3]) : -1; } - if ((s = socket(PF_INET,SOCK_STREAM,0)) < 0) { + if ((s_tcp = socket(PF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); return 1; } if (!port) usage(argv[0]); addr.sin_family = AF_INET; addr.sin_port = htons(port == -1 ? PORT : port); + /* + * Create atmtcp interface before setting up the TCP connection in order + * to make assignment of interface numbers a bit more predictable. + */ + if ((s_krn = socket(PF_ATMSVC,SOCK_DGRAM,0)) < 0) { + perror("socket"); + return 1; + } + if ((itf = ioctl(s_krn,SIOCSIFATMTCP,0)) < 0) { + perror("ioctl SIOCSIFATMTCP"); + return 1; + } if (listen_mode) { addr.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { + if (bind(s_tcp,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); return 1; } printf("Listening on port %d ...\n",ntohs(addr.sin_port)); - if (listen(s,5) < 0) { + if (listen(s_tcp,5) < 0) { perror("listen"); return 1; } - if ((s2 = accept(s,NULL,NULL)) < 0) { + if ((s2 = accept(s_tcp,NULL,NULL)) < 0) { perror("accept"); return 1; } - (void) close(s); - s = s2; + (void) close(s_tcp); + s_tcp = s2; } else { struct hostent *h; @@ -83,16 +172,27 @@ herror(argv[2]); return 1; } - if (connect(s,(struct sockaddr *) &addr,sizeof(addr)) < 0) { + if (connect(s_tcp,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("connect"); return 1; } } - if ((itf = ioctl(s,SIOCSIFATMTCP,NULL)) < 0) { - perror("ioctl SIOCSIFATMTCP"); - return 1; - } printf("Connected, interface %d\n",itf); - (void) pause(); + while (1) { + fd_set set; + int ret; + + FD_ZERO(&set); + FD_SET(s_tcp,&set); + FD_SET(s_krn,&set); + ret = select(s_tcp > s_krn ? s_tcp+1 : s_krn+1,&set,NULL,NULL,0); + if (ret < 0) { + if (errno != EINTR) perror("select"); + } + else { + if (FD_ISSET(s_tcp,&set)) from_tcp(); + if (FD_ISSET(s_krn,&set)) to_tcp(); + } + } return 0; } diff -ur --new-file old/atm/mkdist new/atm/mkdist --- old/atm/mkdist Fri Apr 4 21:10:17 1997 +++ new/atm/mkdist Thu Jul 10 18:49:33 1997 @@ -1,7 +1,7 @@ #!/bin/sh [ -r ./VERSION ] || exit 1 VERSION=`cat ./VERSION` -SRCDIR=$HOME/k/2025 +SRCDIR=$HOME/k/2137 ARCHDIR=$HOME/l/arch ( cd $SRCDIR @@ -27,7 +27,7 @@ atm/sigd/mkmess.pl atm/sigd/atmsigd.8 atm/sigd/atmsigd.conf.4 \ atm/saal/Makefile atm/saal/saal.h atm/saal/saal.c atm/saal/sscf.h \ atm/saal/sscf.c atm/saal/sscop.h atm/saal/sscop.c atm/saal/queue.h \ - atm/saal/queue.c \ + atm/saal/queue.c atm/saal/pdu.h atm/saal/pdu.c \ atm/qgen/TODO atm/qgen/Makefile atm/qgen/mknl.pl atm/qgen/common.h \ atm/qgen/common.c atm/qgen/file.h atm/qgen/file.c atm/qgen/first.c \ atm/qgen/second.c atm/qgen/third.c atm/qgen/op.h atm/qgen/qgen.h \ @@ -42,7 +42,8 @@ atm/ilmid/rfc1157_snmp.c atm/ilmid/rfc1157_snmp.h \ atm/ilmid/mib.h atm/ilmid/mib.c atm/ilmid/util.h atm/ilmid/util.c \ atm/ilmid/message.h atm/ilmid/message.c atm/ilmid/ilmid.c \ - atm/ilmid/netprefix.h atm/ilmid/netprefix.c atm/ilmid/io.h atm/ilmid/io.c \ + atm/ilmid/sysgroup.h atm/ilmid/sysgroup.c atm/ilmid/io.h atm/ilmid/io.c \ + atm/ilmid/atmf_uni.c atm/ilmid/atmf_uni.h \ atm/ilmid/asn1/README atm/ilmid/asn1/Makefile \ atm/ilmid/asn1/asn_bits.h atm/ilmid/asn1/asn_bits.c \ atm/ilmid/asn1/asn_config.h atm/ilmid/asn1/asn_incl.h \ diff -ur --new-file old/atm/qgen/qlib.c new/atm/qgen/qlib.c --- old/atm/qgen/qlib.c Wed Jan 15 13:41:24 1997 +++ new/atm/qgen/qlib.c Fri Jul 4 10:52:17 1997 @@ -495,7 +495,11 @@ PREFIX(report)(Q_ERROR,q_err_msg[type],value); PREFIX(report)(Q_ERROR,"[ PC=%d SP=%d RP=%d, pos=%d end=%d ]",*pc-parse, *sp,*rp,*pos-buf,*end-buf); - error = alloc_t(Q_ERR_DSC); + error = malloc(sizeof(Q_ERR_DSC)); + if (!error) { + perror("out of memory"); + exit(0); + } error->type = type; for (last = &dsc->errors; *last; last = &(*last)->next); *last = error; diff -ur --new-file old/atm/qgen/uni3x new/atm/qgen/uni3x --- old/atm/qgen/uni3x Fri Jan 17 19:57:00 1997 +++ new/atm/qgen/uni3x Mon Jun 30 12:14:48 1997 @@ -252,7 +252,7 @@ _plan "atm_np" <4@1,more> = case { ATM_NP_E164 { _type "atm_ton" <3@5> = ATM_TON_INTRNTNL - cdpn_e164 <-40> # @@@ fix this + cdpn_e164 <-96> } ATM_NP_NSAP { # ATM Endsystem Address _type "atm_ton" <3@5> = ATM_TON_UNKNOWN @@ -281,7 +281,7 @@ def ie_cgpn = { # @@@ extend language to allow same trick as for cdpn ITU_STD_HDR { cgpn_plan "atm_np" <4@1,more> - cgpn_type "atm_ton" <2@6,more> + cgpn_type "atm_ton" <3@5,more> _ext <1@8> = case { 0 { _ext <1@8,more> = 1 diff -ur --new-file old/atm/qgen/uni40 new/atm/qgen/uni40 --- old/atm/qgen/uni40 Wed Jan 29 12:20:36 1997 +++ new/atm/qgen/uni40 Mon Jun 30 12:15:10 1997 @@ -245,7 +245,7 @@ _plan "atm_np" <4@1,more> = case { ATM_NP_E164 { _type "atm_ton" <3@5> = ATM_TON_INTRNTNL - cdpn_e164 <-40> # @@@ fix this + cdpn_e164 <-96> } ATM_NP_NSAP { # ATM Endsystem Address _type "atm_ton" <3@5> = ATM_TON_UNKNOWN @@ -274,7 +274,7 @@ def ie_cgpn = { # @@@ extend language to allow same trick as for cdpn ITU_STD_HDR { cgpn_plan "atm_np" <4@1,more> - cgpn_type "atm_ton" <2@6,more> + cgpn_type "atm_ton" <3@5,more> _ext <1@8> = case { 0 { _ext <1@8,more> = 1 diff -ur --new-file old/atm/saal/Makefile new/atm/saal/Makefile --- old/atm/saal/Makefile Tue Sep 17 15:30:33 1996 +++ new/atm/saal/Makefile Thu Jul 3 15:38:24 1997 @@ -1,5 +1,5 @@ LIBS= -OBJS=saal.o sscf.o sscop.o queue.o +OBJS=pdu.o saal.o sscf.o sscop.o queue.o all: libsaal.a diff -ur --new-file old/atm/saal/pdu.c new/atm/saal/pdu.c --- old/atm/saal/pdu.c Thu Jan 1 01:00:00 1970 +++ new/atm/saal/pdu.c Thu Jul 3 15:41:21 1997 @@ -0,0 +1,264 @@ +/* pdu.c - SSCOP (Q.2110) PDU reader */ + +/* Written 1995-1997 by Werner Almesberger, EPFL-LRC */ + + +#include /* for ntohl */ + +#include "pdu.h" + + +#ifndef NULL +#define NULL 0 +#endif + + +void (*pdu_maa)(void *arg,char code,int count) = NULL; +void (*pdu_diag)(int severity,const char *fmt,...) = NULL; + + +void print_pdu(const char *label,unsigned char type,void *data, + const int *length,const int *s,const int *ps,const int *r,const int *mr, + const int *sq) +{ + int len; + int *list; + + switch (type) { + case SSCOP_SD: + pdu_diag(SP_DEBUG,"%s SD(S=%d,len=%d)",label,*s,*length); + break; + case SSCOP_POLL: + pdu_diag(SP_DEBUG,"%s POLL(PS=%d,S=%d)",label,*ps,*s); + break; + case SSCOP_STAT: + if (*length & 3) { + pdu_diag(SP_WARN,"%s STAT PDU has wrong size (%d)",label, + *length); + break; + } + len = *length/4; + pdu_diag(SP_DEBUG,"%s STAT(PS=%d,MR=%d,R=%d,items=%d:",label,*ps, + *mr,*r,len); + list = (int *) data; + while (len > 1) { + pdu_diag(SP_DEBUG,"%s %d..%d",label,ntohl(list[0]), + ntohl(list[1])); + list += 2; + len -= 2; + } + if (!len) + pdu_diag(SP_DEBUG,"%s )",label); + else pdu_diag(SP_DEBUG,"%s %d)",label,ntohl(*list)); + break; + case SSCOP_USTAT: + if (*length != 8) { + pdu_diag(SP_WARN,"%s USTAT PDU has wrong size (%d)",label, + *length); + break; + } + list = (int *) data; + pdu_diag(SP_DEBUG,"%s USTAT(MR=%d,R=%d,%d..%d)",label,*mr,*r, + ntohl(list[0]),ntohl(list[1])); + break; + case SSCOP_UD: + pdu_diag(SP_DEBUG,"%s UD(len=%d)",label,*length); + break; + case SSCOP_MD: + pdu_diag(SP_DEBUG,"%s MD(len=%d)",label,*length); + break; + case SSCOP_BGN: + pdu_diag(SP_DEBUG,"%s BGN(SQ=%d,MR=%d,len=%d)",label,*sq,*mr, + *length); + break; + case SSCOP_BGAK: + pdu_diag(SP_DEBUG,"%s BGAK(MR=%d,len=%d)",label,*mr,*length); + break; + case SSCOP_BGREJ: + pdu_diag(SP_DEBUG,"%s BGREJ(len=%d)",label,*length); + break; + case SSCOP_END: + pdu_diag(SP_DEBUG,"%s END(S=%d,len=%d)",label,*s,*length); + break; + case SSCOP_ENDAK: + pdu_diag(SP_DEBUG,"%s ENDAK()",label); + break; + case SSCOP_RS: + pdu_diag(SP_DEBUG,"%s RS(SQ=%d,MR=%d,len=%d)",label,*sq,*mr, + *length); + break; + case SSCOP_RSAK: + pdu_diag(SP_DEBUG,"%s RSAK(MR=%d)",label,*mr); + break; + case SSCOP_ER: + pdu_diag(SP_DEBUG,"%s ER(MR=%d)",label,*mr); + break; + case SSCOP_ERAK: + pdu_diag(SP_DEBUG,"%s ERAK(MR=%d)",label,*mr); + break; + default: + pdu_diag(SP_ERROR,"%s unknown PDU type %d\n",label,type); + } +} + + +int decompose_pdu(void *maa_arg,void *msg,int size,unsigned char *type, + int *length,int *s,int *ps,int *r,int *mr,int *sq) +{ + unsigned long *last; + unsigned char pad; + int n; + +/* + * *length is undefined if PDU has no variable-length data part + */ + + if (size < 4 || (size & 3)) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"invalid message length (%d)", + size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + last = (unsigned long *) ((char *) msg+size-4); + *type = SSCOP_TYPE(*last); + pad = SSCOP_PAD(*last); + n = SSCOP_N(*last); + *length = size-4-pad; + switch (*type) { + case SSCOP_SD: + *s = n; + break; + case SSCOP_POLL: + if (size != 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "POLL PDU has bad length (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *s = n; + *ps = SSCOP_N(*(unsigned long *) msg); + break; + case SSCOP_STAT: + if (size < 12) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "STAT PDU too short (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + if (*length & 3) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "STAT PDU has bad length (%d)",length); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *r = n; + *mr = SSCOP_N(last[-1]); + *ps = SSCOP_N(last[-2]); + *length -= 8; + break; + case SSCOP_USTAT: + if (size != 16) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "USTAT PDU has bad length (%d)",size); + if (pdu_maa) pdu_maa(pdu_maa,'U',0); + return -1; + } + *r = n; + *mr = SSCOP_N(last[-1]); + *length -= 4; + break; + case SSCOP_UD: + case SSCOP_MD: + break; + case SSCOP_BGN: + if (size < 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"BGN PDU too short (%d)", + size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *mr = n; + *sq = SSCOP_N(last[-1]) & 0xff; + *length -= 4; + break; + case SSCOP_BGAK: + if (size < 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "BGAK PDU too short (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *mr = n; + *length -= 4; + break; + case SSCOP_BGREJ: + if (size < 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "BGREJ PDU too short (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *length -= 4; + break; + case SSCOP_END: + if (size < 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"END PDU too short (%d)", + size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *s = !!(ntohl(*last) & SSCOP_S_BIT); + *length -= 4; + break; + case SSCOP_ENDAK: + if (size != 8) { + pdu_diag(SP_DEBUG,"ENDAK PDU has bad length (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + if (size < 4) return -1; /* make it work with Fore */ + } + break; + case SSCOP_RS: + if (size < 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN,"RS PDU too short (%d)", + size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *mr = n; + *sq = SSCOP_N(last[-1]) & 0xff; + *length -= 4; + break; + case SSCOP_RSAK: + if (size != 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "RSAK PDU has bad length (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *mr = n; + break; + case SSCOP_ER: + if (size != 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "ER PDU has bad length (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *mr = n; + *sq = SSCOP_N(last[-1]) & 0xff; + break; + case SSCOP_ERAK: + if (size != 8) { + pdu_diag(pdu_maa ? SP_DEBUG : SP_WARN, + "ERAK PDU has bad length (%d)",size); + if (pdu_maa) pdu_maa(maa_arg,'U',0); + return -1; + } + *mr = n; + break; + default: + pdu_diag(SP_ERROR,"unknown PDU type %d (0x%x)",*type,*type); + return -1; + } + return 0; +} diff -ur --new-file old/atm/saal/pdu.h new/atm/saal/pdu.h --- old/atm/saal/pdu.h Thu Jan 1 01:00:00 1970 +++ new/atm/saal/pdu.h Fri Jul 4 10:06:14 1997 @@ -0,0 +1,70 @@ +/* pdu.h - SSCOP (Q.2110) PDU reader */ + +/* Written 1995-1997 by Werner Almesberger, EPFL-LRC */ + + +#ifndef PDU_H +#define PDU_H + +/* SSCOP PDU types, Q.2110 section 7.1 */ + +#define SSCOP_BGN 1 /* Request Initialization */ +#define SSCOP_BGAK 2 /* Request Acknowledgement */ +#define SSCOP_BGREJ 7 /* Connection Reject */ +#define SSCOP_END 3 /* Disconnect Command */ +#define SSCOP_ENDAK 4 /* Disconnect Acknowledgement */ +#define SSCOP_RS 5 /* Resynchronization Command */ +#define SSCOP_RSAK 6 /* Resynchronization Acknowledgement */ +#define SSCOP_ER 9 /* Recovery Command */ +#define SSCOP_ERAK 15 /* Recovery Acknowledgement */ +#define SSCOP_SD 8 /* Sequence Connection-mode Data */ +#define SSCOP_POLL 10 /* Transmitter State Information with request ... */ +#define SSCOP_STAT 11 /* Solicited Receiver State Information */ +#define SSCOP_USTAT 12 /* Unsolicited Receiver State Information */ +#define SSCOP_UD 13 /* Unnumbered User Data */ +#define SSCOP_MD 14 /* Unnumbered Management Data */ + + +/* Trailer format macros */ + +#define SSCOP_TRAIL(type,pad,n) (htonl((n) | ((type) << 24) | ((pad) << 30))) +#define SSCOP_S_BIT 0x10000000 +#define SSCOP_TYPE(last) ((ntohl(last) >> 24) & 15) +#define SSCOP_PAD(last) (ntohl(last) >> 30) +#define SSCOP_N(last) (ntohl(last) & 0xffffff) +#define SSCOP_S(last) (ntohl(last) & SSCOP_S_BIT) + + +/* Helper macros for PDU construction and decomposition */ + +#define PDU_VARS \ + unsigned char type; \ + int length; \ + int s,ps,r,mr,sq +#define DECOMPOSE_PDU(maa_arg,msg,size) decompose_pdu(maa_arg,msg,size,&type, \ + &length,&s,&ps,&r,&mr,&sq) +#define PRINT_PDU(label,data) print_pdu(label,type,data,&length,&s,&ps,&r, \ + &mr,&sq) + + +/* + * Severity codes for pdu_diag. Surprisingly, they happen to have the same + * numerical values as their corresponding diag counterparts. + */ + +#define SP_DEBUG 3 +#define SP_WARN 1 +#define SP_ERROR 0 + + +extern void (*pdu_maa)(void *arg,char code,int count); +extern void (*pdu_diag)(int severity,const char *fmt,...); + + +void print_pdu(const char *label,unsigned char type,void *data, + const int *length,const int *s,const int *ps,const int *r,const int *mr, + const int *sq); +int decompose_pdu(void *maa_arg,void *msg,int size,unsigned char *type, + int *length,int *s,int *ps,int *r,int *mr,int *sq); + +#endif diff -ur --new-file old/atm/saal/sscop.c new/atm/saal/sscop.c --- old/atm/saal/sscop.c Mon Apr 7 16:03:36 1997 +++ new/atm/saal/sscop.c Thu Jul 3 15:43:44 1997 @@ -7,13 +7,15 @@ #include #endif #include +#include #include -#include /* for htonl, ntohl */ +#include /* for htonl */ #include "atmd.h" #include "sscop.h" #include "queue.h" +#include "pdu.h" /* @@ -79,35 +81,6 @@ #define TIMER_IDLE 30000000 /* 30 sec (>> keepalive) */ -/* SSCOP PDU types, 7.1 */ - -#define SSCOP_BGN 1 /* Request Initialization */ -#define SSCOP_BGAK 2 /* Request Acknowledgement */ -#define SSCOP_BGREJ 7 /* Connection Reject */ -#define SSCOP_END 3 /* Disconnect Command */ -#define SSCOP_ENDAK 4 /* Disconnect Acknowledgement */ -#define SSCOP_RS 5 /* Resynchronization Command */ -#define SSCOP_RSAK 6 /* Resynchronization Acknowledgement */ -#define SSCOP_ER 9 /* Recovery Command */ -#define SSCOP_ERAK 15 /* Recovery Acknowledgement */ -#define SSCOP_SD 8 /* Sequence Connection-mode Data */ -#define SSCOP_POLL 10 /* Transmitter State Information with request ... */ -#define SSCOP_STAT 11 /* Solicited Receiver State Information */ -#define SSCOP_USTAT 12 /* Unsolicited Receiver State Information */ -#define SSCOP_UD 13 /* Unnumbered User Data */ -#define SSCOP_MD 14 /* Unnumbered Management Data */ - - -/* Trailer format macros */ - -#define SSCOP_TRAIL(type,pad,n) (htonl((n) | ((type) << 24) | ((pad) << 30))) -#define SSCOP_S_BIT 0x10000000 -#define SSCOP_TYPE(last) ((ntohl(last) >> 24) & 15) -#define SSCOP_PAD(last) (ntohl(last) >> 30) -#define SSCOP_N(last) (ntohl(last) & 0xffffff) -#define SSCOP_S(last) (ntohl(last) & SSCOP_S_BIT) - - /* Some helper macros */ #define START_TIMER(t) ({ STOP_TIMER(dsc->timer_##t); \ @@ -121,18 +94,6 @@ #define NORM_TX(v) NORMALIZE((v),dsc->vt_a) -/* Helper macros for PDU construction and decomposition */ - -#define PDU_VARS \ - unsigned char type; \ - int length; \ - int s,ps,r,mr,sq -#define DECOMPOSE_PDU(dsc,msg,size) decompose_pdu(dsc,msg,size,&type, \ - &length,&s,&ps,&r,&mr,&sq) -#define PRINT_PDU(dsc,label,data) print_pdu(dsc,label,type,data,&length, \ - &s,&ps,&r,&mr,&sq) - - static const char *pdu_name[] = { "???","BGN","BGAK","END","ENDAK","RS","RSAK", "BGREJ","SD","ER","POLL","STAT","USTAT","UD","MD","ERAK" }; @@ -141,8 +102,24 @@ "InRecPend","DataTransReady" }; -static void maa_error(SSCOP_DSC *dsc,char code,int count) +static void do_diag(int severity,const char *fmt,...) { + va_list ap; + + va_start(ap,fmt); + vdiag(COMPONENT,severity,fmt,ap); + va_end(ap); +} + + +static void maa_error(void *arg,char code,int count) +{ + /* + * arg is void * because it's also used in pdu.c, which doesn't know about + * SSCOP_DSC + */ + SSCOP_DSC *dsc = arg; + static const char *const msgs[] = { "A:SD PDU","B:BGN PDU","C:BGAK PDU","D:BGREJ PDU","E:END PDU", "F:ENDAK PDU","G:POLL PDU","H:STAT PDU","I:USTAT PDU","J:RS", @@ -166,94 +143,6 @@ } -static void print_pdu(SSCOP_DSC *dsc,const char *label,unsigned char type, - void *data,const int *length,const int *s,const int *ps,const int *r, - const int *mr,const int *sq) -{ - int len; - int *list; - - switch (type) { - case SSCOP_SD: - diag(COMPONENT,DIAG_DEBUG,"%s SD(S=%d,len=%d)",label,*s,*length); - break; - case SSCOP_POLL: - diag(COMPONENT,DIAG_DEBUG,"%s POLL(PS=%d,S=%d)",label,*ps,*s); - break; - case SSCOP_STAT: - if (*length & 3) { - diag(COMPONENT,DIAG_WARN,"%s STAT PDU has wrong size (%d)", - label,*length); - break; - } - len = *length/4; - diag(COMPONENT,DIAG_DEBUG,"%s STAT(PS=%d,MR=%d,R=%d,items=%d:", - label,*ps,*mr,*r,len); - list = (int *) data; - while (len > 1) { - diag(COMPONENT,DIAG_DEBUG,"%s %d..%d",label,ntohl(list[0]), - ntohl(list[1])); - list += 2; - len -= 2; - } - if (!len) - diag(COMPONENT,DIAG_DEBUG,"%s )",label); - else diag(COMPONENT,DIAG_DEBUG,"%s %d)",label, - ntohl(*list)); - break; - case SSCOP_USTAT: - if (*length != 8) { - diag(COMPONENT,DIAG_WARN,"%s USTAT PDU has wrong size (%d)", - label,*length); - break; - } - list = (int *) data; - diag(COMPONENT,DIAG_DEBUG,"%s USTAT(MR=%d,R=%d,%d..%d)",label,*mr, - *r,ntohl(list[0]), - ntohl(list[1])); - break; - case SSCOP_UD: - diag(COMPONENT,DIAG_DEBUG,"%s UD(len=%d)",label,*length); - break; - case SSCOP_MD: - diag(COMPONENT,DIAG_DEBUG,"%s MD(len=%d)",label,*length); - break; - case SSCOP_BGN: - diag(COMPONENT,DIAG_DEBUG,"%s BGN(SQ=%d,MR=%d,len=%d)",label,*sq, - *mr,*length); - break; - case SSCOP_BGAK: - diag(COMPONENT,DIAG_DEBUG,"%s BGAK(MR=%d,len=%d)",label,*mr, - *length); - break; - case SSCOP_BGREJ: - diag(COMPONENT,DIAG_DEBUG,"%s BGREJ(len=%d)",label,*length); - break; - case SSCOP_END: - diag(COMPONENT,DIAG_DEBUG,"%s END(S=%d,len=%d)",label,*s,*length); - break; - case SSCOP_ENDAK: - diag(COMPONENT,DIAG_DEBUG,"%s ENDAK()",label); - break; - case SSCOP_RS: - diag(COMPONENT,DIAG_DEBUG,"%s RS(SQ=%d,MR=%d,len=%d)",label,*sq, - *mr,*length); - break; - case SSCOP_RSAK: - diag(COMPONENT,DIAG_DEBUG,"%s RSAK(MR=%d)",label,*mr); - break; - case SSCOP_ER: - diag(COMPONENT,DIAG_DEBUG,"%s ER(MR=%d)",label,*mr); - break; - case SSCOP_ERAK: - diag(COMPONENT,DIAG_DEBUG,"%s ERAK(MR=%d)",label,*mr); - break; - default: - diag(COMPONENT,DIAG_ERROR,"%s unknown PDU type %d\n",label,type); - } -} - - static int sdu_length(BUFFER *buf) { return buf->length-4-SSCOP_PAD(*(unsigned long *) ((char *) buf->data+ @@ -261,159 +150,6 @@ } -static int decompose_pdu(SSCOP_DSC *dsc,void *msg,int size, - unsigned char *type,int *length,int *s,int *ps,int *r,int *mr,int *sq) -{ - unsigned long *last; - unsigned char pad; - int n; - -/* - * *length is undefined if PDU has no variable-length data part - */ - - if (size < 4 || (size & 3)) { - diag(COMPONENT,DIAG_DEBUG,"invalid message length (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - last = (unsigned long *) ((char *) msg+size-4); - *type = SSCOP_TYPE(*last); - pad = SSCOP_PAD(*last); - n = SSCOP_N(*last); - *length = size-4-pad; - switch (*type) { - case SSCOP_SD: - *s = n; - break; - case SSCOP_POLL: - if (size != 8) { - diag(COMPONENT,DIAG_DEBUG,"POLL PDU has bad length (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *s = n; - *ps = SSCOP_N(*(unsigned long *) msg); - break; - case SSCOP_STAT: - if (size < 12) { - diag(COMPONENT,DIAG_DEBUG,"STAT PDU too short (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - if (*length & 3) { - diag(COMPONENT,DIAG_DEBUG,"STAT PDU has bad length (%d)", - length); - maa_error(dsc,'U',0); - return -1; - } - *r = n; - *mr = SSCOP_N(last[-1]); - *ps = SSCOP_N(last[-2]); - *length -= 8; - break; - case SSCOP_USTAT: - if (size != 16) { - diag(COMPONENT,DIAG_DEBUG,"USTAT PDU has bad length (%d)", - size); - maa_error(dsc,'U',0); - return -1; - } - *r = n; - *mr = SSCOP_N(last[-1]); - *length -= 4; - break; - case SSCOP_UD: - case SSCOP_MD: - break; - case SSCOP_BGN: - if (size < 8) { - diag(COMPONENT,DIAG_DEBUG,"BGN PDU too short (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *mr = n; - *sq = SSCOP_N(last[-1]) & 0xff; - *length -= 4; - break; - case SSCOP_BGAK: - if (size < 8) { - diag(COMPONENT,DIAG_DEBUG,"BGAK PDU too short (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *mr = n; - *length -= 4; - break; - case SSCOP_BGREJ: - if (size < 8) { - diag(COMPONENT,DIAG_DEBUG,"BGREJ PDU too short (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *length -= 4; - break; - case SSCOP_END: - if (size < 8) { - diag(COMPONENT,DIAG_DEBUG,"END PDU too short (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *s = !!(ntohl(*last) & SSCOP_S_BIT); - *length -= 4; - break; - case SSCOP_ENDAK: - if (size != 8) { - diag(COMPONENT,DIAG_DEBUG,"ENDAK PDU has bad length (%d)", - size); - maa_error(dsc,'U',0); - if (size < 4) return -1; /* make it work with Fore */ - } - break; - case SSCOP_RS: - if (size < 8) { - diag(COMPONENT,DIAG_DEBUG,"RS PDU too short (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *mr = n; - *sq = SSCOP_N(last[-1]) & 0xff; - *length -= 4; - break; - case SSCOP_RSAK: - if (size != 8) { - diag(COMPONENT,DIAG_DEBUG,"RSAK PDU has bad length (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *mr = n; - break; - case SSCOP_ER: - if (size != 8) { - diag(COMPONENT,DIAG_DEBUG,"ER PDU has bad length (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *mr = n; - *sq = SSCOP_N(last[-1]) & 0xff; - break; - case SSCOP_ERAK: - if (size != 8) { - diag(COMPONENT,DIAG_DEBUG,"ERAK PDU has bad length (%d)",size); - maa_error(dsc,'U',0); - return -1; - } - *mr = n; - break; - default: - diag(COMPONENT,DIAG_DEBUG,"unknown PDU type %d (0x%x)",*type, - *type); - return -1; - } - return 0; -} - - static BUFFER *build_pdu(SSCOP_DSC *dsc,unsigned char type,void *data, int num) { @@ -505,7 +241,7 @@ if (DECOMPOSE_PDU(dsc,buf->data,buf->length)) diag(COMPONENT,DIAG_FATAL,"composed garbage"); - PRINT_PDU(dsc,"SEND",buf->data); + PRINT_PDU("SEND",buf->data); } if (dsc->ops->cpcs_send) dsc->ops->cpcs_send(dsc->user,buf->data,buf->length); @@ -1180,7 +916,7 @@ dump_pdu(msg,size); if (DECOMPOSE_PDU(dsc,msg,size)) return 1; - PRINT_PDU(dsc,"RECV",msg); + PRINT_PDU("RECV",msg); switch (type) { case SSCOP_UD: if (dsc->ops->unitdata) dsc->ops->unitdata(dsc->user,msg,length); @@ -1955,6 +1691,13 @@ void start_sscop(SSCOP_DSC *dsc,SSCOP_USER_OPS *ops,void *user_data) { + static int initialize = 1; + + if (initialize) { + pdu_maa = maa_error; + pdu_diag = do_diag; + initialize = 0; + } dsc->ops = ops; dsc->user = user_data; dsc->vt_sq = dsc->vr_sq = 0; /* 20.5 */ diff -ur --new-file old/atm/saal/sscop.h new/atm/saal/sscop.h --- old/atm/saal/sscop.h Thu Sep 26 18:14:28 1996 +++ new/atm/saal/sscop.h Thu Jul 3 13:32:08 1997 @@ -1,6 +1,6 @@ /* sscop.h - SSCOP (Q.2110) user interface */ -/* Written 1995,1996 by Werner Almesberger, EPFL-LRC */ +/* Written 1995-1997 by Werner Almesberger, EPFL-LRC */ #ifndef SSCOP_H diff -ur --new-file old/atm/sigd/kernel.c new/atm/sigd/kernel.c --- old/atm/sigd/kernel.c Thu Apr 17 17:58:07 1997 +++ new/atm/sigd/kernel.c Mon Jun 30 13:26:18 1997 @@ -58,18 +58,26 @@ q_assign(&dsc,QF_qos_fw,0); /* QOS 0 */ q_assign(&dsc,QF_qos_bw,0); local = NULL; - if (sock->local && *sock->local->sas_addr.prv) local = sock->local; - else if (local_addr[0].state == ls_same && *local_addr[0].addr.sas_addr.prv) + if (sock->local && (*sock->local->sas_addr.prv || + *sock->local->sas_addr.pub)) local = sock->local; + else if (local_addr[0].state == ls_same && + (*local_addr[0].addr.sas_addr.prv || + *local_addr[0].addr.sas_addr.pub)) local = &local_addr[0].addr; - /* @@@ handle E.164 too */ if (!local) { if (!error) error = -EADDRNOTAVAIL; } - else { - q_assign(&dsc,QF_cgpn_plan,ATM_NP_NSAP); - q_assign(&dsc,QF_cgpn_type,ATM_TON_UNKNOWN); - q_write(&dsc,QF_cgpn,(void *) local->sas_addr.prv,ATM_ESA_LEN); - } + else if (*sock->local->sas_addr.pub) { + q_assign(&dsc,QF_cgpn_plan,ATM_NP_E164); + q_assign(&dsc,QF_cgpn_type,ATM_TON_INTRNTNL); + q_write(&dsc,QF_cgpn,(void *) local->sas_addr.pub, + strlen(local->sas_addr.pub)); + } + else { + q_assign(&dsc,QF_cgpn_plan,ATM_NP_NSAP); + q_assign(&dsc,QF_cgpn_type,ATM_TON_UNKNOWN); + q_write(&dsc,QF_cgpn,(void *) local->sas_addr.prv,ATM_ESA_LEN); + } if (net) { int vci; @@ -154,6 +162,9 @@ for (walk = local_addr; walk->state != ls_unused; walk++) if (walk->state == ls_same && atm_equal(&walk->addr, &msg->svc,(ATM_ESA_LEN-1)*8,AXE_WILDCARD)) break; + if(*msg->svc.sas_addr.pub) + diag(COMPONENT,DIAG_DEBUG,"binding to E.164 address " + "%s\n",msg->svc.sas_addr.pub); if (walk->state == ls_unused) SEND_ERROR(msg->vcc,-EADDRNOTAVAIL); else send_kernel(msg->vcc,0,as_okay,0,NULL,NULL,NULL,NULL); diff -ur --new-file old/atm/sigd/q2931.c new/atm/sigd/q2931.c --- old/atm/sigd/q2931.c Wed Mar 26 18:16:56 1997 +++ new/atm/sigd/q2931.c Mon Jun 30 12:46:50 1997 @@ -67,9 +67,20 @@ SOCKET *sock,*this,**walk; struct sockaddr_atmsvc *sap,*new_sap; struct atm_qos qos,new_qos; - unsigned char buf[ATM_ESA_LEN]; - int len,i; + unsigned char buf[ATM_ESA_LEN]; /* max(ATM_ESA_LEN,ATM_E164_LEN) */ + int addr_loc,len,i; + switch (q_fetch(&in_dsc,QF_cgpn_plan)) { + case ATM_NP_E164: + addr_loc = QF_cdpn_e164; + break; + case ATM_NP_NSAP: + addr_loc = QF_cdpn_esa; + break; + default: + send_release_complete(call_ref,ATM_CV_UNALLOC); + return; + } sap = sap_decode(&in_dsc,&qos); new_sap = NULL; sock = lookup_sap(sap,&qos,&new_sap,&new_qos); @@ -103,7 +114,7 @@ this->qos = new_qos; /* if (sock->local) *this->local->sas_addr = sock->local->sas_addr; ??? */ diag(COMPONENT,DIAG_DEBUG,"AAL type %ld",q_fetch(&in_dsc,QF_aal_type)); - len = q_read(&in_dsc,QF_cdpn_esa,(void *) &buf,sizeof(buf)); + len = q_read(&in_dsc,addr_loc,(void *) &buf,sizeof(buf)); if (debug) { printf("Addr len %d:",len); for (i = 0; i < (len < 30 ? len : 30); i++) printf(" %02X",buf[i]); @@ -123,14 +134,30 @@ memset(this->remote,0,sizeof(struct sockaddr_atmsvc)); if (q_present(&in_dsc,QF_cgpn)) { /* should handle E.164 too */ char buffer[MAX_ATM_ADDR_LEN+1]; + int plan; - this->remote->sas_family = AF_ATMSVC; - i = q_read(&in_dsc,QF_cgpn,(void *) this->remote->sas_addr.prv, - ATM_ESA_LEN); - /*printf("addr_len = %d\n",i);*/ - if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *) this->remote, - pretty) < 0) strcpy(buffer,""); - diag(COMPONENT,DIAG_DEBUG,"Incoming call from %s",buffer); + plan = q_fetch(&in_dsc,QF_cgpn_plan); + switch (plan) { + case ATM_NP_NSAP: + i = q_read(&in_dsc,QF_cgpn,(void *) this->remote->sas_addr.prv, + ATM_ESA_LEN); + break; + case ATM_NP_E164: + i = q_read(&in_dsc,QF_cgpn,(void *) this->remote->sas_addr.pub, + ATM_E164_LEN); + break; + default: + diag(COMPONENT,DIAG_WARN,"Ignoring cgpn with unrecognized " + "numbering plan 0x%x\n",plan); + i = 0; + } + if (i) { + this->remote->sas_family = AF_ATMSVC; + if (atm2text(buffer,MAX_ATM_ADDR_LEN+1, + (struct sockaddr *) this->remote,pretty) < 0) + strcpy(buffer,""); + diag(COMPONENT,DIAG_DEBUG,"Incoming call from %s",buffer); + } } send_kernel(0,sock->id,as_indicate,0,&this->pvc,this->remote,NULL,&new_qos); for (walk = &sock->listen; *walk; walk = &(*walk)->listen); diff -ur --new-file old/atm/sigd/sap.c new/atm/sigd/sap.c --- old/atm/sigd/sap.c Sun Oct 13 17:35:30 1996 +++ new/atm/sigd/sap.c Mon Jun 30 12:54:44 1997 @@ -1,6 +1,6 @@ /* sap.c - SAP manipulations */ -/* Written 1996 by Werner Almesberger, EPFL-LRC */ +/* Written 1996,1997 by Werner Almesberger, EPFL-LRC */ #include @@ -207,9 +207,12 @@ struct atm_blli *blli; int pcr; - if (!*sap->sas_addr.prv) return -EDESTADDRREQ; - else q_write(dsc,QF_cdpn_esa,(void *) sap->sas_addr.prv,ATM_ESA_LEN); - /* improve @@@ */ + if (*sap->sas_addr.pub) + q_write(dsc,QF_cdpn_e164,(void *) sap->sas_addr.pub, + strlen(sap->sas_addr.pub)); + else if (*sap->sas_addr.prv) + q_write(dsc,QF_cdpn_esa,(void *) sap->sas_addr.prv,ATM_ESA_LEN); + else return -EDESTADDRREQ; if (qos->txtp.traffic_class == ATM_UBR || qos->rxtp.traffic_class == ATM_UBR) q_assign(dsc,QF_best_effort,0); switch (qos->txtp.traffic_class) { @@ -348,8 +351,12 @@ memset(sap,0,sizeof(struct sockaddr_atmsvc)+sizeof(struct atm_blli)); memset(qos,0,sizeof(struct atm_qos)); sap->sas_family = AF_ATMSVC; - if (q_present(dsc,QF_cdpn_esa)) /* @@@ handle E.164 too */ - (void) q_read(dsc,QF_cdpn_esa,(void *) &sap->sas_addr.prv,ATM_ESA_LEN); + if (q_present(dsc,QF_cdpn_e164)) + (void) q_read(dsc,QF_cdpn_e164,(void *) &sap->sas_addr.pub, + ATM_E164_LEN); + else if (q_present(dsc,QF_cdpn_esa)) + (void) q_read(dsc,QF_cdpn_esa,(void *) &sap->sas_addr.prv, + ATM_ESA_LEN); if (q_present(dsc,QF_aal_type)) if (q_fetch(dsc,QF_aal_type) != 5) diag(COMPONENT,DIAG_ERROR,"AAL type %d requested", .